From 44fb34d7bec94a596537c2b043ce087901fe96ab Mon Sep 17 00:00:00 2001 From: Rob H Date: Thu, 26 Jun 2014 12:20:42 +1000 Subject: [PATCH 001/145] Rearrange admin title --- .../admin/shared/_head/replace_spree_title.html.haml.deface | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/overrides/spree/admin/shared/_head/replace_spree_title.html.haml.deface b/app/overrides/spree/admin/shared/_head/replace_spree_title.html.haml.deface index 757bfa797f..4b9bd4142d 100644 --- a/app/overrides/spree/admin/shared/_head/replace_spree_title.html.haml.deface +++ b/app/overrides/spree/admin/shared/_head/replace_spree_title.html.haml.deface @@ -1,4 +1,4 @@ / replace_contents "title" -= "OFN #{t(:administration)}:" -= t(controller.controller_name, :default => controller.controller_name.titleize) \ No newline at end of file += t(controller.controller_name, :default => controller.controller_name.titleize) += " - OFN #{t(:administration)}" \ No newline at end of file From 934f960336953fee35e30087ed0d49fb4cfbb682 Mon Sep 17 00:00:00 2001 From: Rob H Date: Thu, 26 Jun 2014 15:27:24 +1000 Subject: [PATCH 002/145] Add display as to new product page --- app/assets/javascripts/admin/admin.js.coffee | 2 +- .../admin/directives/display_as.js.coffee | 2 +- .../admin/products/units_controller.js.coffee | 17 +++++++---------- .../admin/services/option_value_namer.js.coffee | 2 +- app/models/spree/product_decorator.rb | 5 +++-- .../products/new/replace_form.html.haml.deface | 9 +++++---- .../spree/admin/products/_display_as.html.haml | 4 ++++ 7 files changed, 22 insertions(+), 19 deletions(-) create mode 100644 app/views/spree/admin/products/_display_as.html.haml diff --git a/app/assets/javascripts/admin/admin.js.coffee b/app/assets/javascripts/admin/admin.js.coffee index edebc019e5..a0235a568f 100644 --- a/app/assets/javascripts/admin/admin.js.coffee +++ b/app/assets/javascripts/admin/admin.js.coffee @@ -1,3 +1,3 @@ -angular.module("ofn.admin", ["ngResource", "ngAnimate", "ofn.dropdown"]).config ($httpProvider) -> +angular.module("ofn.admin", ["ngResource", "ngAnimate", "ofn.dropdown", "admin.products"]).config ($httpProvider) -> $httpProvider.defaults.headers.common["X-CSRF-Token"] = $("meta[name=csrf-token]").attr("content") $httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*" \ No newline at end of file diff --git a/app/assets/javascripts/admin/directives/display_as.js.coffee b/app/assets/javascripts/admin/directives/display_as.js.coffee index a13d65bc5e..21f83ebf9f 100644 --- a/app/assets/javascripts/admin/directives/display_as.js.coffee +++ b/app/assets/javascripts/admin/directives/display_as.js.coffee @@ -17,7 +17,7 @@ angular.module("ofn.admin").directive "ofnDisplayAs", (optionValueNamer) -> variant_unit_scale: variant_unit_scale variant_unit: variant_unit variant_unit_name: scope.product.variant_unit_name - + scope.placeholder_text = new optionValueNamer(variant_object).name() productUnitProperties = -> diff --git a/app/assets/javascripts/admin/products/units_controller.js.coffee b/app/assets/javascripts/admin/products/units_controller.js.coffee index 9070648e21..e253e701fa 100644 --- a/app/assets/javascripts/admin/products/units_controller.js.coffee +++ b/app/assets/javascripts/admin/products/units_controller.js.coffee @@ -1,10 +1,10 @@ angular.module("admin.products") - .controller "unitsCtrl", ($scope) -> + .controller "unitsCtrl", ($scope, optionValueNamer) -> $scope.product = { master: {} } + $scope.product.master.product = $scope.product + $scope.placeholder_text = "" - $scope.$watch -> - $scope.product.variant_unit_with_scale - , -> + $scope.$watchCollection '[product.variant_unit_with_scale, product.master.unit_value_with_description]', -> if $scope.product.variant_unit_with_scale match = $scope.product.variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/) if match @@ -16,9 +16,6 @@ angular.module("admin.products") else $scope.product.variant_unit = $scope.product.variant_unit_scale = null - $scope.$watch -> - $scope.product.master.unit_value_with_description - , -> if $scope.product.master.hasOwnProperty("unit_value_with_description") match = $scope.product.master.unit_value_with_description.match(/^([\d\.]+(?= |$)|)( |)(.*)$/) if match @@ -27,6 +24,8 @@ angular.module("admin.products") $scope.product.master.unit_value *= $scope.product.variant_unit_scale if $scope.product.master.unit_value && $scope.product.variant_unit_scale $scope.product.master.unit_description = match[3] + $scope.placeholder_text = new optionValueNamer($scope.product.master).name() + $scope.variant_unit_options = [ ["Weight (g)", "weight_1"], ["Weight (kg)", "weight_1000"], @@ -41,6 +40,4 @@ angular.module("admin.products") Object.keys(product.variants).length > 0 $scope.hasUnit = (product) -> - product.variant_unit_with_scale? - - \ No newline at end of file + product.variant_unit_with_scale? \ No newline at end of file diff --git a/app/assets/javascripts/admin/services/option_value_namer.js.coffee b/app/assets/javascripts/admin/services/option_value_namer.js.coffee index 8d127f01c7..b497e3aef2 100644 --- a/app/assets/javascripts/admin/services/option_value_namer.js.coffee +++ b/app/assets/javascripts/admin/services/option_value_namer.js.coffee @@ -1,4 +1,4 @@ -angular.module("ofn.admin").factory "optionValueNamer", ($resource) -> +angular.module("admin.products").factory "optionValueNamer", -> class OptionValueNamer constructor: (@variant) -> diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 6e116d3e4d..22fa5b3b8b 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -12,9 +12,10 @@ Spree::Product.class_eval do accepts_nested_attributes_for :product_distributions, :allow_destroy => true delegate_belongs_to :master, :unit_value, :unit_description - delegate :images_attributes=, to: :master + delegate :images_attributes=, :display_as=, to: :master - attr_accessible :supplier_id, :primary_taxon_id, :distributor_ids, :product_distributions_attributes, :group_buy, :group_buy_unit_size, :variant_unit, :variant_unit_scale, :variant_unit_name, :unit_value, :unit_description, :notes, :images_attributes + attr_accessible :supplier_id, :primary_taxon_id, :distributor_ids, :product_distributions_attributes, :group_buy, :group_buy_unit_size + attr_accessible :variant_unit, :variant_unit_scale, :variant_unit_name, :unit_value, :unit_description, :notes, :images_attributes, :display_as validates_presence_of :supplier validates_presence_of :primary_taxon diff --git a/app/overrides/spree/admin/products/new/replace_form.html.haml.deface b/app/overrides/spree/admin/products/new/replace_form.html.haml.deface index a4e073d40d..334739a4c2 100644 --- a/app/overrides/spree/admin/products/new/replace_form.html.haml.deface +++ b/app/overrides/spree/admin/products/new/replace_form.html.haml.deface @@ -30,10 +30,11 @@ %input.fullwidth{ id: 'product_unit_value_with_description', 'ng-model' => 'product.master.unit_value_with_description', :type => 'text', placeholder: "eg. 2", 'ng-disabled' => "!hasUnit(product)" } %input{ type: 'hidden', 'ng-value' => 'product.master.unit_value', name: 'product[unit_value]' } %input{ type: 'hidden', 'ng-value' => 'product.master.unit_description', name: 'product[unit_description]' } - .three.columns.omega{ 'ng-show' => "product.variant_unit_with_scale == 'items'" } - = f.field_container :unit_name do - = f.label :product_variant_unit_name, :unit_name - %input.fullwidth{ id: 'product_variant_unit_name','ng-model' => 'product.variant_unit_name', :name => 'product[variant_unit_name]', :placeholder => 'eg. bunches', :type => 'text' } + = render 'display_as', f: f + .three.columns.omega{ 'ng-show' => "product.variant_unit_with_scale == 'items'" } + = f.field_container :unit_name do + = f.label :product_variant_unit_name, t(:unit_name) + %input.fullwidth{ id: 'product_variant_unit_name','ng-model' => 'product.variant_unit_name', :name => 'product[variant_unit_name]', :placeholder => 'eg. bunches', :type => 'text' } .twelve.columns.alpha .six.columns.alpha = render 'spree/admin/products/primary_taxon_form', f: f diff --git a/app/views/spree/admin/products/_display_as.html.haml b/app/views/spree/admin/products/_display_as.html.haml new file mode 100644 index 0000000000..33beec2b86 --- /dev/null +++ b/app/views/spree/admin/products/_display_as.html.haml @@ -0,0 +1,4 @@ +.three.columns.omega{ "ng-if" => "product.variant_unit_with_scale != 'items'" } + = f.field_container :display_as do + = f.label :product_display_as, t(:display_as) + %input#product_display_as.fullwidth{name: "product[display_as]", placeholder: "{{ placeholder_text }}", type: "text"} \ No newline at end of file From 083fda0ad008dad21a3e5f1d48ffb4d63dd53730 Mon Sep 17 00:00:00 2001 From: Rob H Date: Fri, 27 Jun 2014 10:46:54 +1000 Subject: [PATCH 003/145] Set columns on BPE error messages --- app/views/spree/admin/products/bulk_edit.html.haml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/spree/admin/products/bulk_edit.html.haml b/app/views/spree/admin/products/bulk_edit.html.haml index d21235cee6..d1cdd6324f 100644 --- a/app/views/spree/admin/products/bulk_edit.html.haml +++ b/app/views/spree/admin/products/bulk_edit.html.haml @@ -51,13 +51,13 @@ %li.column-list-item{ :class => "three columns alpha", 'ofn-toggle-column' => 'column', 'ng-repeat' => 'column in columns' } {{ column.name }} %hr - %div.loading{ 'ng-show' => 'loading' } + %div.sixteen.columns.alpha.loading{ 'ng-show' => 'loading' } %h4 Loading Products... - %div{ 'ng-show' => '!loading && products.length == 0' } + %div.sixteen.columns.alpha{ 'ng-show' => '!loading && products.length == 0' } %h4{ :style => 'color:red;' } No matching products found. - %div{ 'ng-show' => 'products.length == 500' } + %div.sixteen.columns.alpha{ 'ng-show' => '!loading && products.length == 500' } %h6 Search returned too many products to display (500+), please apply more search filters to reduce the number of matching products - %div{ 'ng-hide' => 'loading || products.length == 500 || products.length == 0' } + %div.sixteen.columns.alpha{ 'ng-hide' => 'loading || products.length == 500 || products.length == 0' } %div.quick_search{ :class => "five columns omega" } %input.search{ :class => "four columns alpha", 'ng-model' => 'query', :name => "quick_filter", :type => 'text', 'placeholder' => 'Quick Search' } %div.pagination{ :class => "seven columns omega" } From 1dc0b1bc2f8187fca38cf5e71d1888fc7242d39b Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 27 Jun 2014 15:50:33 +1000 Subject: [PATCH 004/145] Tweak layout and message for 404 --- public/404.html | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/public/404.html b/public/404.html index 9a48320a5f..77830da9f7 100644 --- a/public/404.html +++ b/public/404.html @@ -7,20 +7,31 @@ div.dialog { width: 25em; padding: 0 4em; - margin: 4em auto 0 auto; - border: 1px solid #ccc; - border-right-color: #999; - border-bottom-color: #999; + margin: 2em auto 0 auto; + } + a.go_home { + font-size: 100%; + color: black; + line-height: 1.5em; + text-decoration: none; + border-bottom: 1px dotted black; + padding: 0 0.2rem; + } + a.go_home:hover, a.go_home:focus, a.go_home:active{ + background: #8f301d; + color: white; + border-bottom: none; } - h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
-

The page you were looking for doesn't exist.

-

You may have mistyped the address or the page may have moved.

+ +

It seems the page you're looking for is in a grump. +

Return home

+

From 9edec0c849dc0b9ad8b758f373ea97b5c0ac5f7e Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 27 Jun 2014 15:50:45 +1000 Subject: [PATCH 005/145] Tweak layout and message for 422 --- public/422.html | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/public/422.html b/public/422.html index 83660ab187..b222475557 100644 --- a/public/422.html +++ b/public/422.html @@ -7,20 +7,32 @@ div.dialog { width: 25em; padding: 0 4em; - margin: 4em auto 0 auto; - border: 1px solid #ccc; - border-right-color: #999; - border-bottom-color: #999; + margin: 2em auto 0 auto; + } + a.go_home { + font-size: 100%; + color: black; + line-height: 1.5em; + text-decoration: none; + border-bottom: 1px dotted black; + padding: 0 0.2rem; + } + a.go_home:hover, a.go_home:focus, a.go_home:active{ + background: #8f301d; + color: white; + border-bottom: none; } - h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
-

The change you wanted was rejected.

-

Maybe you tried to change something you didn't have access to.

+ +

The change you wanted was rejected. Maybe you tried to change something you don't have access to. +

Return home

+

+ From 0291723239d2af99905b02d1315cd8322aa1bff6 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 27 Jun 2014 15:50:55 +1000 Subject: [PATCH 006/145] Tweak layout and message for 500 --- public/500.html | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/public/500.html b/public/500.html index b80307fc16..b49f24743b 100644 --- a/public/500.html +++ b/public/500.html @@ -7,20 +7,32 @@ div.dialog { width: 25em; padding: 0 4em; - margin: 4em auto 0 auto; - border: 1px solid #ccc; - border-right-color: #999; - border-bottom-color: #999; + margin: 2em auto 0 auto; + } + a.go_home { + font-size: 100%; + color: black; + line-height: 1.5em; + text-decoration: none; + border-bottom: 1px dotted black; + padding: 0 0.2rem; + } + a.go_home:hover, a.go_home:focus, a.go_home:active{ + background: #8f301d; + color: white; + border-bottom: none; } - h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
-

We're sorry, but something went wrong.

-

We've been notified about this issue and we'll take a look at it shortly.

+ +

We're sorry, but something went wrong. +
Try refreshing the page, or +

Return home

+

From fe11e50d3b958563197d46b3758b7d8f94d515d5 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 27 Jun 2014 15:51:22 +1000 Subject: [PATCH 007/145] Adding graphics for error message pages --- public/404.jpg | Bin 0 -> 36611 bytes public/422.jpg | Bin 0 -> 38144 bytes public/500.jpg | Bin 0 -> 40506 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/404.jpg create mode 100644 public/422.jpg create mode 100644 public/500.jpg diff --git a/public/404.jpg b/public/404.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cfe799ef1da0e9024812e91fddfb08d6f479ea7a GIT binary patch literal 36611 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%0AVy0D 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 R00;pC0|7q}{{Z04|Jg0oG$;T7 literal 0 HcmV?d00001 diff --git a/public/500.jpg b/public/500.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2cfabee4233803e3c852d31c989e070874aa3ef0 GIT binary patch literal 40506 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⁡Ch?AsS-TWpRTGi zjhBNU)L3^~SU^LJzZg4G0Y$Wvt$F%4-qglbk@bOROOE&hay2k-i|O!@Gm!f;zF$J; zS(R@3bNps43XCT|-whOi`=g!t=r?0i;yEha)Z~g>ain11bM#s;oGIvLYDO zZxZVAu_Vq&+P5_m6u><2y8pJ#<-ijt+GW`s#|-Ylp-?i^I!1M`2dZkxQOyoD!9tQZ zbMX|L#K?OQIGMWR_+o$FbSWXl7QM20&zNLVrN(qu-832+963S!mtU zT~+u!JI2Q}P8$AG%=d~kELB-;XEJ@wO!a7^3-7Yj%?e0bL>z;bd7t<$3GyA2(6fL0?+7i!QfjijQ5meqO3oc;l- zXW|jdSSOT#1Ot+YSHQ3vD&7Lf$-HNn@6S&UnnAHa>d)heoj8QTfe_gs4i*ZG(Qr$gq~a$-6nQQ+QDjgKz`3|VyvQ}31_rGP^5HVliMaU7aBCUP6l%s+spq!s-(qKmEccQSJZ zi>Nzura(D+L3Z_>Ce;!M?YR5a#)78Bl8!xjL_=5{@TU>LZPDSWq>Ks}efu`@(kd1# zT{P{dC!BUjYLZOyo7JFq>~ds!Od)C4QvX(1*oG4lk2RMXlp8>Boa8Ims0vTY=iN!f z$3s8O#Dy?EhEZ*f@pszAkx_~_y24UWt=IW_M0gfe7Q&Jw9OVzG_!(h9V5Jr4^ur$d zsMQEsVoZ9&pD;FnuYfpG#q=FcN!YV_%ju`u6}TZG9rlfs#W93_ID$ph007U5l+A^) z1VECSzUXA3ZbUCbV2MI2t0zpF)Mbdtt<>qS1JuMc3X!fK#yysAS0QYXbyn$JzYB8M zfL=PfTN$tF7wEU4%{MC|lFlbkCIErDT-%l|ds!?oHa-SGMk@W o{meI4f;@d?xq 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 literal 0 HcmV?d00001 From 9f71ccc3c073c2d9c338ea9699f05c2e6a0231c3 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 27 Jun 2014 17:26:52 +1000 Subject: [PATCH 008/145] Filters partial for search field --- app/views/producers/_filters.html.haml | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 app/views/producers/_filters.html.haml diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml new file mode 100644 index 0000000000..9178f78ed5 --- /dev/null +++ b/app/views/producers/_filters.html.haml @@ -0,0 +1,30 @@ +.row + .small-12.columns.filter-box + .row + .small-12.large-6.columns + %h5.tdhead Filter by Type + .small-12.large-3.columns + %h5.tdhead Filter by Delivery + .small-12.large-3.columns + %h5.tdhead Filter by Open/closed + .row + .small-12.large-6.columns + %ul.small-block-grid-4 + %li + %a + %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} + Bakery + %li + %a + %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} + Bakery + %li + %a + %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} + Bakery + + %li + %a + %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} + Bakery + From 9d397430d41fe2cd8fac90bd242b51093c560f9d Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 27 Jun 2014 17:27:19 +1000 Subject: [PATCH 009/145] Add styling for filters block --- .../darkswarm/active_table_search.css.sass | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index e862f4322b..293333d71c 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -1,4 +1,33 @@ @import mixins +@import branding + +.filter-box + border: 2px solid $clr-brick + .tdhead + background-color: white + padding: 0.25rem 0.5rem + margin-top: 0.9rem + li a + display: block + line-height: 2 + background-color: rgba(0,0,0,0.25) + color: #666 + + &:hover, &:focus, &:active + color: #333 + render-svg + svg + path + fill: #333 + + render-svg + svg + width: 2rem + height: 2rem + display: block + float: left + path + fill: #666 #active-table-search position: relative @@ -16,4 +45,5 @@ @include csstrans @include big-input padding-left: 44px - \ No newline at end of file + + From 97913742047e8e8526db2dfb79406187a4651f2d Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 27 Jun 2014 17:27:46 +1000 Subject: [PATCH 010/145] Add partial to producers index page --- app/views/producers/index.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/producers/index.haml b/app/views/producers/index.haml index 5cde67a512..b0de3dc693 100644 --- a/app/views/producers/index.haml +++ b/app/views/producers/index.haml @@ -18,6 +18,8 @@ "ng-debounce" => "150", "ofn-disable-enter" => true} + = render partial: "producers/filters" + .row{bindonce: true} .small-12.columns .active_table From 106c9f63bb44ffd07bc7eed633e644ee60f564ff Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 11:33:38 +1000 Subject: [PATCH 011/145] Adding animation hooks for Laura --- .../javascripts/darkswarm/darkswarm.js.coffee | 1 + .../stylesheets/darkswarm/animations.sass | 23 +++++++++++++++++++ app/views/home/_hubs.html.haml | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/darkswarm.js.coffee b/app/assets/javascripts/darkswarm/darkswarm.js.coffee index fc6f9dfed4..1e58fe7294 100644 --- a/app/assets/javascripts/darkswarm/darkswarm.js.coffee +++ b/app/assets/javascripts/darkswarm/darkswarm.js.coffee @@ -6,6 +6,7 @@ window.Darkswarm = angular.module("Darkswarm", ["ngResource", 'angular-flash.service', 'templates', 'ngSanitize', + 'ngAnimate', 'google-maps', 'duScroll', ]).config ($httpProvider, $tooltipProvider, $locationProvider, $anchorScrollProvider) -> diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index fc1db55bb5..fec649e55a 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -28,3 +28,26 @@ filter: alpha(opacity = 50) opacity: .5 +.animate-repeat + line-height: 40px + list-style: none + box-sizing: border-box + +.animate-repeat.ng-move, +.animate-repeat.ng-enter, +.animate-repeat.ng-leave + -webkit-transition: all linear 0.5s + transition: all linear 0.5s + +.animate-repeat.ng-leave.ng-leave-active, +.animate-repeat.ng-move, +.animate-repeat.ng-enter + opacity: 0 + max-height: 0 + +.animate-repeat.ng-leave, +.animate-repeat.ng-move.ng-move-active, +.animate-repeat.ng-enter.ng-enter-active + opacity: 1 + max-height: 40px + diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index a7c61f92c4..50b491644d 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -21,7 +21,7 @@ .row{bindonce: true} .small-12.columns .active_table - %hub.active_table_node.row{"ng-repeat" => "hub in filteredHubs = (hubs | hubs:query)", + %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredHubs = (hubs | hubs:query)", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "scroll-after-load" => true, "ng-controller" => "HubNodeCtrl", From 23ae0806e73d4194446b8a27a74c699710392671 Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 2 Jul 2014 11:51:48 +1000 Subject: [PATCH 012/145] Add email link for error messages on 500 page --- public/500.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/public/500.html b/public/500.html index b49f24743b..30379bc44d 100644 --- a/public/500.html +++ b/public/500.html @@ -32,6 +32,13 @@

We're sorry, but something went wrong.
Try refreshing the page, or

+
Want to let us know what went wrong? Email us at: +

+ + hello [at] openfoodnetwork.org +

From 96b4d0f8731c605c4b70ee8b49db707b36ffb6b7 Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 2 Jul 2014 12:26:32 +1000 Subject: [PATCH 013/145] Fix grumpy typo --- public/404.jpg | Bin 36611 -> 36526 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/404.jpg b/public/404.jpg index cfe799ef1da0e9024812e91fddfb08d6f479ea7a..836b4e01886e5fad7ca0a8520de9e78e9a858334 100644 GIT binary patch delta 30444 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 {AQnMWy*K8`*M*SWW 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 delta 30587 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 From 75f3358e2a52290a304bc7bb12b92966fcabbe86 Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 2 Jul 2014 14:44:46 +1000 Subject: [PATCH 014/145] Adding CTA button for crowdfunding site to homepage & countdown timer directive --- app/assets/javascripts/darkswarm/all.js.coffee | 1 + .../javascripts/darkswarm/darkswarm.js.coffee | 1 + .../stylesheets/darkswarm/home_tagline.css.sass | 13 +++++++++---- app/views/home/index.html.haml | 14 ++++++++++---- vendor/assets/javascripts/angular-timer.min.js | 8 ++++++++ 5 files changed, 29 insertions(+), 8 deletions(-) create mode 100755 vendor/assets/javascripts/angular-timer.min.js diff --git a/app/assets/javascripts/darkswarm/all.js.coffee b/app/assets/javascripts/darkswarm/all.js.coffee index f529ac3255..45f91366ba 100644 --- a/app/assets/javascripts/darkswarm/all.js.coffee +++ b/app/assets/javascripts/darkswarm/all.js.coffee @@ -11,6 +11,7 @@ #= require lodash.underscore.js #= require angular-scroll.min.js #= require angular-google-maps.min.js +#= require angular-timer.min.js #= require ../shared/mm-foundation-tpls-0.2.2.min.js #= require ../shared/bindonce.min.js #= require ../shared/ng-infinite-scroll.min.js diff --git a/app/assets/javascripts/darkswarm/darkswarm.js.coffee b/app/assets/javascripts/darkswarm/darkswarm.js.coffee index fc6f9dfed4..c497ea3cfd 100644 --- a/app/assets/javascripts/darkswarm/darkswarm.js.coffee +++ b/app/assets/javascripts/darkswarm/darkswarm.js.coffee @@ -5,6 +5,7 @@ window.Darkswarm = angular.module("Darkswarm", ["ngResource", 'infinite-scroll', 'angular-flash.service', 'templates', + 'timer', 'ngSanitize', 'google-maps', 'duScroll', diff --git a/app/assets/stylesheets/darkswarm/home_tagline.css.sass b/app/assets/stylesheets/darkswarm/home_tagline.css.sass index 3d00cb7a96..2c109a2703 100644 --- a/app/assets/stylesheets/darkswarm/home_tagline.css.sass +++ b/app/assets/stylesheets/darkswarm/home_tagline.css.sass @@ -7,19 +7,24 @@ background-color: black background-image: url("/assets/home/tagline-bg.jpg") @include fullbg - height: 400px + height: 500px padding: 40px 0px - h1, h2, p + h1, h2, span, small, timer color: white + p + color: $clr-brick-light h1 - margin-bottom: 1em + margin-bottom: 3rem h2 font-size: 1.6875rem max-width: 610px margin: 0 auto + padding-bottom: 0.5rem a color: $clr-brick-bright &:hover, &:active, &:focus color: $clr-brick-light-bright - @include textsoftpress \ No newline at end of file + @include textsoftpress + a.button.primary + color: white \ No newline at end of file diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index b441ac647f..ea283f1490 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -2,10 +2,16 @@ .row .small-12.text-center.columns %h1= image_tag "ofn_logo_beta.png", title: "Open Food Network (beta)" - %h2 An open marketplace that makes it easy to find, buy, sell and move sustainable local food. - - %ofn-modal{title: "Learn more"} - = render partial: "modals/learn_more" + %h2 We're crowdfunding right now! + %h5 + %timer{"end-time" => '1407679200000'} + {{days}} days, {{hours}} hrs, {{minutes}} mins & {{seconds}} secs to go + %p Help us make Open Food Network the best it can be: + %a.button.primary{href: "http://startsomegood.com/openfoodnetwork", target:"_blank"} Support now + / %h2 An open marketplace that makes it easy to find, buy, sell and move sustainable local food. + %br + %ofn-modal{title: "Learn more"} + = render partial: "modals/learn_more" = render partial: "home/hubs" diff --git a/vendor/assets/javascripts/angular-timer.min.js b/vendor/assets/javascripts/angular-timer.min.js new file mode 100755 index 0000000000..9fdc966a93 --- /dev/null +++ b/vendor/assets/javascripts/angular-timer.min.js @@ -0,0 +1,8 @@ +/** + * angular-timer - v1.1.6 - 2014-07-01 7:37 AM + * https://github.com/siddii/angular-timer + * + * Copyright (c) 2014 Siddique Hameed + * Licensed MIT + */ +var timerModule=angular.module("timer",[]).directive("timer",["$compile",function(a){return{restrict:"EAC",replace:!1,scope:{interval:"=interval",startTimeAttr:"=startTime",endTimeAttr:"=endTime",countdownattr:"=countdown",finishCallback:"&finishCallback",autoStart:"&autoStart",maxTimeUnit:"="},controller:["$scope","$element","$attrs","$timeout",function(b,c,d,e){function f(){b.timeoutId&&clearTimeout(b.timeoutId)}function g(){b.maxTimeUnit&&"day"!==b.maxTimeUnit?"second"===b.maxTimeUnit?(b.seconds=Math.floor(b.millis/1e3),b.minutes=0,b.hours=0,b.days=0,b.months=0,b.years=0):"minute"===b.maxTimeUnit?(b.seconds=Math.floor(b.millis/1e3%60),b.minutes=Math.floor(b.millis/6e4),b.hours=0,b.days=0,b.months=0,b.years=0):"hour"===b.maxTimeUnit?(b.seconds=Math.floor(b.millis/1e3%60),b.minutes=Math.floor(b.millis/6e4%60),b.hours=Math.floor(b.millis/36e5),b.days=0,b.months=0,b.years=0):"month"===b.maxTimeUnit?(b.seconds=Math.floor(b.millis/1e3%60),b.minutes=Math.floor(b.millis/6e4%60),b.hours=Math.floor(b.millis/36e5%24),b.days=Math.floor(b.millis/36e5/24%30),b.months=Math.floor(b.millis/36e5/24/30),b.years=0):"year"===b.maxTimeUnit&&(b.seconds=Math.floor(b.millis/1e3%60),b.minutes=Math.floor(b.millis/6e4%60),b.hours=Math.floor(b.millis/36e5%24),b.days=Math.floor(b.millis/36e5/24%30),b.months=Math.floor(b.millis/36e5/24/30%12),b.years=Math.floor(b.millis/36e5/24/365)):(b.seconds=Math.floor(b.millis/1e3%60),b.minutes=Math.floor(b.millis/6e4%60),b.hours=Math.floor(b.millis/36e5%24),b.days=Math.floor(b.millis/36e5/24),b.months=0,b.years=0),b.secondsS=1==b.seconds?"":"s",b.minutesS=1==b.minutes?"":"s",b.hoursS=1==b.hours?"":"s",b.daysS=1==b.days?"":"s",b.monthsS=1==b.months?"":"s",b.yearsS=1==b.years?"":"s",b.sseconds=b.seconds<10?"0"+b.seconds:b.seconds,b.mminutes=b.minutes<10?"0"+b.minutes:b.minutes,b.hhours=b.hours<10?"0"+b.hours:b.hours,b.ddays=b.days<10?"0"+b.days:b.days,b.mmonths=b.months<10?"0"+b.months:b.months,b.yyears=b.years<10?"0"+b.years:b.years}"function"!=typeof String.prototype.trim&&(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),b.autoStart=d.autoStart||d.autostart,c.append(0===c.html().trim().length?a("{{millis}}")(b):a(c.contents())(b)),b.startTime=null,b.endTime=null,b.timeoutId=null,b.countdown=b.countdownattr&&parseInt(b.countdownattr,10)>=0?parseInt(b.countdownattr,10):void 0,b.isRunning=!1,b.$on("timer-start",function(){b.start()}),b.$on("timer-resume",function(){b.resume()}),b.$on("timer-stop",function(){b.stop()}),b.$on("timer-clear",function(){b.clear()}),b.$on("timer-set-countdown",function(a,c){b.countdown=c}),b.start=c[0].start=function(){b.startTime=b.startTimeAttr?new Date(b.startTimeAttr):new Date,b.endTime=b.endTimeAttr?new Date(b.endTimeAttr):null,b.countdown||(b.countdown=b.countdownattr&&parseInt(b.countdownattr,10)>0?parseInt(b.countdownattr,10):void 0),f(),h(),b.isRunning=!0},b.resume=c[0].resume=function(){f(),b.countdownattr&&(b.countdown+=1),b.startTime=new Date-(b.stoppedTime-b.startTime),h(),b.isRunning=!0},b.stop=b.pause=c[0].stop=c[0].pause=function(){var a=b.timeoutId;b.clear(),b.$emit("timer-stopped",{timeoutId:a,millis:b.millis,seconds:b.seconds,minutes:b.minutes,hours:b.hours,days:b.days})},b.clear=c[0].clear=function(){b.stoppedTime=new Date,f(),b.timeoutId=null,b.isRunning=!1},c.bind("$destroy",function(){f(),b.isRunning=!1}),b.countdownattr?(b.millis=1e3*b.countdownattr,b.addCDSeconds=c[0].addCDSeconds=function(a){b.countdown+=a,b.$digest(),b.isRunning||b.start()},b.$on("timer-add-cd-seconds",function(a,c){e(function(){b.addCDSeconds(c)})}),b.$on("timer-set-countdown-seconds",function(a,c){b.isRunning||b.clear(),b.countdown=c,b.millis=1e3*c,g()})):b.millis=0,g();var h=function(){b.millis=new Date-b.startTime;var a=b.millis%1e3;return b.endTimeAttr&&(b.millis=b.endTime-new Date,a=b.interval-b.millis%1e3),b.countdownattr&&(b.millis=1e3*b.countdown),b.millis<0?(b.stop(),b.millis=0,g(),void(b.finishCallback&&b.$eval(b.finishCallback))):(g(),b.timeoutId=setTimeout(function(){h(),b.$digest()},b.interval-a),b.$emit("timer-tick",{timeoutId:b.timeoutId,millis:b.millis}),void(b.countdown>0?b.countdown--:b.countdown<=0&&(b.stop(),b.finishCallback&&b.$eval(b.finishCallback))))};(void 0===b.autoStart||b.autoStart===!0)&&b.start()}]}}]);"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports=timerModule); \ No newline at end of file From 570a33db5ff6a8e9ca561d25d2bfc5949540513a Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 2 Jul 2014 12:09:23 +1000 Subject: [PATCH 015/145] Revert "install script". Prototype script should not yet be on master. This reverts commit 39012388a209e0f120c25cdb08a48e0426ed9eaf. --- INSTALL.sh | 97 ------------------------------------------------------ 1 file changed, 97 deletions(-) delete mode 100755 INSTALL.sh diff --git a/INSTALL.sh b/INSTALL.sh deleted file mode 100755 index 8ff0b660a1..0000000000 --- a/INSTALL.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/sh -# -########################### -# Linux install script # -# ----------------------- # -# Tested on Debian wheezy # -########################### - -echo 'Checking dependencies...' - -# Rails is installed by bundler later -#echo -n 'Rails 3.2.. ' -#if rails -v | grep -q 'Rails 3.2'; then -# echo 'ok' -#else -# echo 'not found' -# exit 1 -#fi - -echo -n 'Ruby 1.9.3.. ' -revision=$(ruby -v | grep -E -o '^ruby 1\.9\.([0-9]+)' | cut -d . -f 3) -if [ "$revision" -gt 2 ]; then - echo 'ok' -else - echo 'not found' - exit 1 -fi - -echo -n 'PostgreSQL.. ' -if psql -? > /dev/null 2>&1; then - echo 'ok' -else - echo 'not found' - exit 1 -fi - - -psqlCreateCommands=" - createuser -s ofn - psql postgres -c \"ALTER USER ofn WITH ENCRYPTED PASSWORD 'f00d'\" - createdb -O ofn open_food_network_dev - createdb -O ofn open_food_network_test - createdb -O ofn open_food_network_prod -" -PGPASSFILE=$(mktemp) -echo '' -echo -n 'Checking PostgreSQL database.. ' -echo 'localhost:5432:open_food_network_dev:ofn:f00d1' > $PGPASSFILE -export PGPASSFILE -if psql -w -U ofn open_food_network_dev -c 'select 1' > /dev/null 2>&1; then - echo 'ok' -else - echo 'no access' - echo '' - echo 'Database needs setup. Try automatic setup with sudo? [yes]' - read autosetup - if [ -z "$autosetup" ] || [ "$autosetup" = "yes" ]; then - if sudo su postgres -c "$psqlCreateCommands"; then - echo 'User and databases created.' - else - echo 'Failed to create user and databases.' - autosetup='no' - fi - else - autosetup='no' - fi - if [ "$autosetup" = 'no' ]; then - echo '' - echo 'Execute the following commands as database admin user (e.g. postgres):' - echo "$psqlCreateCommands" - rm "$PGPASSFILE" - exit 1 - fi -fi -rm "$PGPASSFILE" - -echo '' -echo 'Installing all gems. That can take a while.' -bundle install - -echo '' -echo 'Seeding database..' -bundle exec rake db:schema:load db:seed -echo 'Skipping sample data (out of date)' -#bundle exec rake openfoodnetwork:dev:load_sample_data -echo 'You can run `rails server` now to start.' - -echo '' -echo 'Executing tests..' -bundle exec rake db:test:load -bundle exec rspec spec - -if [ "$?" -eq 0 ]; then - echo '' - echo 'All done.' - echo 'You can run `rails server` now.' -fi From e0119a3f1faa352f179eec1048d4affe3eef4f1c Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 3 Jul 2014 14:30:36 +1000 Subject: [PATCH 016/145] Adding perftools.rb perftools.rb can profile your code. The spec_helper contains comments about how to activate it. --- Gemfile | 1 + Gemfile.lock | 2 ++ spec/spec_helper.rb | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/Gemfile b/Gemfile index cb6f7a8f96..346d8c9d51 100644 --- a/Gemfile +++ b/Gemfile @@ -85,6 +85,7 @@ end group :test do gem 'webmock' + gem 'perftools.rb' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 9afad20d05..39afc2ac50 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -341,6 +341,7 @@ GEM activesupport (>= 2.3.2) cocaine (>= 0.0.2) mime-types + perftools.rb (2.0.1) pg (0.13.2) poltergeist (1.5.0) capybara (~> 2.1) @@ -531,6 +532,7 @@ DEPENDENCIES newrelic_rpm oj paperclip + perftools.rb pg poltergeist pry-debugger diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4f96a09070..3f3435eda5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -104,4 +104,25 @@ RSpec.configure do |config| config.include Paperclip::Shoulda::Matchers config.include JsonSpec::Helpers + + # Profiling + # + # This code shouldn't be run in normal circumstances. But if you want to know + # which parts of your code take most time, then you can activate the lines + # below. Keep in mind that it will slow down the execution time heaps. + # + # The PerfTools will write a binary file to the specified path which can then + # be examined by: + # + # bundle exec pprof.rb --text /tmp/rspec_profile + # + + #require 'perftools' + #config.before :suite do + # PerfTools::CpuProfiler.start("/tmp/rspec_profile") + #end + # + #config.after :suite do + # PerfTools::CpuProfiler.stop + #end end From 06400c6202fabb67c4bc51daaa6c4e90758fa6a1 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 3 Jul 2014 14:54:34 +1000 Subject: [PATCH 017/145] Remove unused @include --- app/assets/stylesheets/darkswarm/mixins.sass | 26 -------------------- 1 file changed, 26 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/mixins.sass b/app/assets/stylesheets/darkswarm/mixins.sass index edb41f9ead..9e1230a56f 100644 --- a/app/assets/stylesheets/darkswarm/mixins.sass +++ b/app/assets/stylesheets/darkswarm/mixins.sass @@ -32,32 +32,6 @@ transition: all 100ms ease-in-out -webkit-transform-style: preserve-3d -@mixin animate-in - -webkit-animation: cssAnimation 100ms 1 ease-in - -moz-animation: cssAnimation 100ms 1 ease-in - -o-animation: cssAnimation 100ms 1 ease-in - - @-webkit-keyframes cssAnimation - from - -webkit-transform: rotate(180deg) scale(0.25) skew(0deg) translate(0px) - to - -webkit-transform: rotate(0deg) scale(1) skew(0deg) translate(0px) - - - @-moz-keyframes cssAnimation - from - -moz-transform: rotate(180deg) scale(0.25) skew(0deg) translate(0px) - to - -moz-transform: rotate(0deg) scale(1) skew(0deg) translate(0px) - - - @-o-keyframes cssAnimation - from - -o-transform: rotate(180deg) scale(0.25) skew(0deg) translate(0px) - to - -o-transform: rotate(0deg) scale(1) skew(0deg) translate(0px) - - @mixin box-shadow($box-shadow) -moz-box-shadow: $box-shadow -webkit-box-shadow: $box-shadow From 42c9dcf3de59f8c382cd8622cb94148247327286 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 3 Jul 2014 14:55:39 +1000 Subject: [PATCH 018/145] Remove @include csstrans from all SASS to stop conflicts with ngAnimate classes --- app/assets/stylesheets/darkswarm/active_table.css.sass | 3 --- .../stylesheets/darkswarm/active_table_search.css.sass | 1 - app/assets/stylesheets/darkswarm/checkout.css.sass | 1 - app/assets/stylesheets/darkswarm/footer.sass | 2 -- app/assets/stylesheets/darkswarm/menu.css.sass | 6 +++--- app/assets/stylesheets/darkswarm/modals.css.sass | 1 - app/assets/stylesheets/darkswarm/shop.css.sass | 4 ---- app/assets/stylesheets/darkswarm/tabs.css.sass | 4 ---- app/assets/stylesheets/darkswarm/taxons.css.sass | 4 ---- 9 files changed, 3 insertions(+), 23 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table.css.sass b/app/assets/stylesheets/darkswarm/active_table.css.sass index 33067b022a..d1c8e092a6 100644 --- a/app/assets/stylesheets/darkswarm/active_table.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table.css.sass @@ -12,7 +12,6 @@ cursor: pointer .active_table .active_table_node - @include csstrans display: block border: 1px solid transparent @@ -26,7 +25,6 @@ &.open .active_table_row:first-child - @include csstrans border-top: 1px solid $dark-grey border-left: 1px solid $dark-grey border-right: 1px solid $dark-grey @@ -45,7 +43,6 @@ background-color: rgba(255,255,255,0.2) .active_table_row.link - @include csstrans padding: 0 -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,0.35) box-shadow: 0 1px 1px 0 rgba(0,0,0,0.35) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 293333d71c..ede65a31a4 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -42,7 +42,6 @@ input[type="text"] font-size: 2em - @include csstrans @include big-input padding-left: 44px diff --git a/app/assets/stylesheets/darkswarm/checkout.css.sass b/app/assets/stylesheets/darkswarm/checkout.css.sass index 9caf28ae43..d90c81f673 100644 --- a/app/assets/stylesheets/darkswarm/checkout.css.sass +++ b/app/assets/stylesheets/darkswarm/checkout.css.sass @@ -27,7 +27,6 @@ checkout // Logic to turn on & off the alerts for success against each fieldset label, label.alert, label.success, &.valid label.alert, &.dirty label.success - @include csstrans display: none &.dirty label.alert diff --git a/app/assets/stylesheets/darkswarm/footer.sass b/app/assets/stylesheets/darkswarm/footer.sass index 30f8caf8b4..9e3f9dac55 100644 --- a/app/assets/stylesheets/darkswarm/footer.sass +++ b/app/assets/stylesheets/darkswarm/footer.sass @@ -8,8 +8,6 @@ footer .row &, & * color: white - a, a > i - @include csstrans a, a * color: $clr-brick-light-bright &:hover, &:active, &:focus diff --git a/app/assets/stylesheets/darkswarm/menu.css.sass b/app/assets/stylesheets/darkswarm/menu.css.sass index 0460367e87..7be329824b 100644 --- a/app/assets/stylesheets/darkswarm/menu.css.sass +++ b/app/assets/stylesheets/darkswarm/menu.css.sass @@ -27,7 +27,6 @@ nav .top-bar-section ul li > a font-size: 0.75rem height: 45px - @include csstrans opacity: 0.8 &:hover, &:focus, &:active opacity: 1 @@ -47,7 +46,6 @@ nav @include box-shadow(inset 0 0 6px 2px rgba(0,0,0,0.5)) .off-canvas-wrap .tab-bar .menu-icon - @include csstrans @include box-shadow(none) .off-canvas-wrap.move-right .tab-bar .menu-icon span @@ -72,4 +70,6 @@ nav @media screen and (max-width: 1025px) section.right .nav-branded - padding: 0 1em \ No newline at end of file + padding: 0 1em + + \ No newline at end of file diff --git a/app/assets/stylesheets/darkswarm/modals.css.sass b/app/assets/stylesheets/darkswarm/modals.css.sass index 7121e7ea69..ba46a984ae 100644 --- a/app/assets/stylesheets/darkswarm/modals.css.sass +++ b/app/assets/stylesheets/darkswarm/modals.css.sass @@ -10,7 +10,6 @@ dialog, .reveal-modal background-color: rgba(0,0,0,0.65) dialog .close-reveal-modal.outside, .reveal-modal .close-reveal-modal.outside - @include csstrans top: -2.5rem right: -2.5rem font-size: 2rem diff --git a/app/assets/stylesheets/darkswarm/shop.css.sass b/app/assets/stylesheets/darkswarm/shop.css.sass index 3407916bfc..ae418adda6 100644 --- a/app/assets/stylesheets/darkswarm/shop.css.sass +++ b/app/assets/stylesheets/darkswarm/shop.css.sass @@ -98,7 +98,6 @@ background: $clr-brick-ultra-light product - @include csstrans border: 1px solid #989898 display: block margin-bottom: 1em !important @@ -114,19 +113,16 @@ line-height: 2.4em .row.summary, .row.variants - @include csstrans margin-left: 0 margin-right: 0 background: #f7f7f7 border-top: 1px solid #dfdfdf .row.summary - @include csstrans background: #fff line-height: 1 .summary-header - @include csstrans font-size: 1.15rem &, & * diff --git a/app/assets/stylesheets/darkswarm/tabs.css.sass b/app/assets/stylesheets/darkswarm/tabs.css.sass index a8e3ef4a22..76e4988d2f 100644 --- a/app/assets/stylesheets/darkswarm/tabs.css.sass +++ b/app/assets/stylesheets/darkswarm/tabs.css.sass @@ -20,13 +20,9 @@ .panel border-color: rgba(219, 88, 61, 0.5) background-color: rgba(255, 255, 255, 0) - // @include box-shadow( 0 1px 1px 0 rgba(255,255,255,1)) - - dl dd a @include avenir - @include csstrans background: transparent text-transform: uppercase line-height: 50px diff --git a/app/assets/stylesheets/darkswarm/taxons.css.sass b/app/assets/stylesheets/darkswarm/taxons.css.sass index d7d60fa31c..160d2ce002 100644 --- a/app/assets/stylesheets/darkswarm/taxons.css.sass +++ b/app/assets/stylesheets/darkswarm/taxons.css.sass @@ -2,7 +2,6 @@ @import mixins .fat-taxons - @include csstrans display: inline-block line-height: 1 margin-right: 0.5rem @@ -23,8 +22,6 @@ &, &* display: inline-block color: #555 - // &:hover, &.hover, &:active - // background: rgba(255,255,255,0.5) .product-header render-svg @@ -40,7 +37,6 @@ height: 24px .summary-header - @include csstrans render-svg svg width: 18px From ae8ae1fe41b60315ec7861bc975c9a50012a9c69 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 3 Jul 2014 15:10:07 +1000 Subject: [PATCH 019/145] Fix styling on hubs list to make accordion icons sit vertically aligned --- app/assets/stylesheets/darkswarm/active_table.css.sass | 1 - app/views/home/_skinny.html.haml | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table.css.sass b/app/assets/stylesheets/darkswarm/active_table.css.sass index d1c8e092a6..b472c36915 100644 --- a/app/assets/stylesheets/darkswarm/active_table.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table.css.sass @@ -6,7 +6,6 @@ margin: 2em 0em @include user-select(none) .active_table_row - padding: 0.8em 0.5em display: block &:first-child cursor: pointer diff --git a/app/views/home/_skinny.html.haml b/app/views/home/_skinny.html.haml index 768d16f2b6..e5567f3d38 100644 --- a/app/views/home/_skinny.html.haml +++ b/app/views/home/_skinny.html.haml @@ -15,4 +15,7 @@ Orders closed .columns.small-1.text-right - %i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"} + / This forces line-height to be triggered + %span   + %i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"} + From 9060e18a81ee1d83026b1a4d325ebbbfaf44a346 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 11:32:09 +1000 Subject: [PATCH 020/145] Tweak timings on the modal animations --- app/assets/stylesheets/darkswarm/animations.sass | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index fec649e55a..2dd02148d8 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -7,10 +7,10 @@ opacity: 1 .reveal-modal.fade - -webkit-transition: -webkit-transform .3s ease-out - -moz-transition: -moz-transform .3s ease-out - -o-transition: -o-transform .3s ease-out - transition: transform .3s ease-out + -webkit-transition: -webkit-transform .2s ease-out + -moz-transition: -moz-transform .2s ease-out + -o-transition: -o-transform .2s ease-out + transition: transform .2s ease-out -webkit-transform: translate(0, -25%) -ms-transform: translate(0, -25%) transform: translate(0, -25%) From 87c6feec97738f59bd680be729192ef13f371218 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 11:32:32 +1000 Subject: [PATCH 021/145] Remove padding - tighten up fat view --- app/assets/stylesheets/darkswarm/modal-enterprises.css.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/modal-enterprises.css.sass b/app/assets/stylesheets/darkswarm/modal-enterprises.css.sass index 0560cb742c..701969ef7d 100644 --- a/app/assets/stylesheets/darkswarm/modal-enterprises.css.sass +++ b/app/assets/stylesheets/darkswarm/modal-enterprises.css.sass @@ -90,7 +90,7 @@ .active_table_row .cta-container - padding-bottom: 0.75rem + // padding-bottom: 0.75rem padding-top: 0.5rem // Generic styles for use From 698d1d2637bd783316bce0e2d2a733bf51fbf3aa Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 11:33:05 +1000 Subject: [PATCH 022/145] Add space to force line-height trigger on active table skinny view - producers page --- app/views/producers/_skinny.html.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/producers/_skinny.html.haml b/app/views/producers/_skinny.html.haml index a5608b8b3d..429fd33e4a 100644 --- a/app/views/producers/_skinny.html.haml +++ b/app/views/producers/_skinny.html.haml @@ -7,4 +7,6 @@ .columns.small-4 {{ producer.address.state | uppercase }} .columns.small-1.text-right + / This forces line-height to be triggered + %span   %i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"} \ No newline at end of file From eed39fc971ce3038d49d4a677a1425107b545c60 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 13:37:57 +1000 Subject: [PATCH 023/145] Filters file in --- app/views/producers/_filters.html.haml | 56 ++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 9178f78ed5..4b1a16f89c 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -2,29 +2,69 @@ .small-12.columns.filter-box .row .small-12.large-6.columns - %h5.tdhead Filter by Type + %h5.tdhead + .light Filter by + Type .small-12.large-3.columns - %h5.tdhead Filter by Delivery + %h5.tdhead + .light Filter by + Delivery .small-12.large-3.columns - %h5.tdhead Filter by Open/closed + %h5.tdhead + .light Filter by + Something .row .small-12.large-6.columns %ul.small-block-grid-4 %li %a - %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - Bakery + %render-svg{path: "/spree/taxons/62/original/taxons_bakery.svg?1403150973"} + %span Bakery + %li + %a + %render-svg{path: "/spree/taxons/55/original/taxons_food-boxes.svg?1402988796"} + %span Boxes %li %a %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - Bakery + %span Bakery + + %li + %a + %render-svg{path: "/spree/taxons/24/original/taxons_oils_spreads.svg?1403248784"} + %span Oils & Spreads + %li + %a + %render-svg{path: "/spree/taxons/19/original/taxons_pulses_grains.svg?1402988994"} + %span Pulses & Grains %li %a %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - Bakery + %span Bakery + %li + %a + %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} + %span Bakery %li %a %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - Bakery + %span Bakery + %li + %a + %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} + %span Bakery + %li + %a + %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} + %span Bakery + %li + %a + %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} + %span Bakery + + %li + %a + %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} + %span Bakery From ab4b72b9c7e61d8c19f64d143d3f71b206f51d33 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 13:39:19 +1000 Subject: [PATCH 024/145] Styling to make the taxons sit right for 1 and 2 lines --- .../darkswarm/active_table_search.css.sass | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index ede65a31a4..46cf36401c 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -2,30 +2,39 @@ @import branding .filter-box - border: 2px solid $clr-brick + border-top: 1px solid $clr-brick + background-color: rgba(255,255,255,0.5) .tdhead - background-color: white padding: 0.25rem 0.5rem margin-top: 0.9rem li a - display: block - line-height: 2 - background-color: rgba(0,0,0,0.25) + display: table + height: 2rem + line-height: 1 color: #666 - - &:hover, &:focus, &:active - color: #333 + span + display: table-cell + vertical-align: middle + &:hover, &:focus + color: #000 render-svg svg path - fill: #333 + fill: #000 + &:active, &.active + color: $clr-brick + render-svg + svg + path + fill: $clr-brick + render-svg + width: 2rem + height: 2rem + display: block + margin-right: 0.25rem svg - width: 2rem - height: 2rem - display: block - float: left path fill: #666 From 9d9dd777c11b261e6255a520ca161ce373a0797c Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 13:39:55 +1000 Subject: [PATCH 025/145] Add in simple text style for global use --- app/assets/stylesheets/darkswarm/typography.css.sass | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/stylesheets/darkswarm/typography.css.sass b/app/assets/stylesheets/darkswarm/typography.css.sass index 8dfe9eb9d9..ead907926e 100644 --- a/app/assets/stylesheets/darkswarm/typography.css.sass +++ b/app/assets/stylesheets/darkswarm/typography.css.sass @@ -34,6 +34,9 @@ small, .small margin-bottom: 0.5rem &, & * font-size: 0.875rem +.light + color: #999 + display: inline @mixin avenir font-family: "AvenirBla_IE", "AvenirBla" From 79f42ccc61a227fa2d3b5a80f89566eb9584d453 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 10:26:19 +1000 Subject: [PATCH 026/145] Temporary/demonstration caching behaviour, INCOMPLETE --- app/models/enterprise.rb | 2 +- app/models/enterprise_relationship.rb | 4 +- app/models/spree/classification_decorator.rb | 2 + app/models/spree/product_decorator.rb | 4 +- app/serializers/api/address_serializer.rb | 3 + app/serializers/api/enterprise_serializer.rb | 59 +++++++++++++++++--- app/serializers/api/taxon_serializer.rb | 3 + config/environments/development.rb | 1 + 8 files changed, 64 insertions(+), 14 deletions(-) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 5b922b15e4..d42031273d 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -7,7 +7,7 @@ class Enterprise < ActiveRecord::Base has_many :producer_properties, foreign_key: 'producer_id' has_many :supplied_products, :class_name => 'Spree::Product', :foreign_key => 'supplier_id', :dependent => :destroy has_many :distributed_orders, :class_name => 'Spree::Order', :foreign_key => 'distributor_id' - belongs_to :address, :class_name => 'Spree::Address' + belongs_to :address, :class_name => 'Spree::Address', touch: true has_many :product_distributions, :foreign_key => 'distributor_id', :dependent => :destroy has_many :distributed_products, :through => :product_distributions, :source => :product has_many :enterprise_fees diff --git a/app/models/enterprise_relationship.rb b/app/models/enterprise_relationship.rb index 26bf8fc012..4db650f2e7 100644 --- a/app/models/enterprise_relationship.rb +++ b/app/models/enterprise_relationship.rb @@ -1,6 +1,6 @@ class EnterpriseRelationship < ActiveRecord::Base - belongs_to :parent, class_name: 'Enterprise' - belongs_to :child, class_name: 'Enterprise' + belongs_to :parent, class_name: 'Enterprise', touch: true + belongs_to :child, class_name: 'Enterprise', touch: true validates_presence_of :parent_id, :child_id validates_uniqueness_of :child_id, scope: :parent_id, message: "^That relationship is already established." diff --git a/app/models/spree/classification_decorator.rb b/app/models/spree/classification_decorator.rb index 7e34e6890e..8fa201528c 100644 --- a/app/models/spree/classification_decorator.rb +++ b/app/models/spree/classification_decorator.rb @@ -1,4 +1,6 @@ Spree::Classification.class_eval do + belongs_to :product, :class_name => "Spree::Product", touch: true + belongs_to :taxon, :class_name => "Spree::Taxon", touch: true before_destroy :dont_destroy_if_primary_taxon def dont_destroy_if_primary_taxon diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 6e116d3e4d..0f61011fcd 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -4,8 +4,8 @@ Spree::Product.class_eval do # https://github.com/rails/rails/issues/7618 has_many :option_types, :through => :product_option_types, :dependent => :destroy - belongs_to :supplier, :class_name => 'Enterprise' - belongs_to :primary_taxon, class_name: 'Spree::Taxon' + belongs_to :supplier, :class_name => 'Enterprise', touch: true + belongs_to :primary_taxon, class_name: 'Spree::Taxon', touch: true has_many :product_distributions, :dependent => :destroy has_many :distributors, :through => :product_distributions diff --git a/app/serializers/api/address_serializer.rb b/app/serializers/api/address_serializer.rb index a4dfcb0f5f..98344e0315 100644 --- a/app/serializers/api/address_serializer.rb +++ b/app/serializers/api/address_serializer.rb @@ -1,4 +1,7 @@ class Api::AddressSerializer < ActiveModel::Serializer + cached + delegate :cache_key, to: :object + attributes :id, :zipcode, :city, :state def state diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index a74606dd79..c0b79084f0 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -1,9 +1,58 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer + # To improve this: http://hawkins.io/2013/06/caching_object_graphs_with_active_model_serializers/ + # + # Taxons: + # classifications touch products + # products touch suppliers + # Taxon could change but unlikely: if becomes a problem dereference + # + # Relatives: + # Enterprise_relationships touches parent, child + # Otherwise dereferencing makes easy + # + # Address: + # Fine + # + # Shipping Methods: + # Create distributors_shipping_methods class + # Set up touches + + def serializable_hash + cached_serializer_hash.merge uncached_serializer_hash + end + + private + + def cached_serializer_hash + Api::CachedEnterpriseSerializer.new(object, @options).serializable_hash + end + + def uncached_serializer_hash + Api::UncachedEnterpriseSerializer.new(object, @options).serializable_hash + end +end + +class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer + attributes :orders_close_at, :active + + def orders_close_at + OrderCycle.first_closing_for(object).andand.orders_close_at + end + + def active + @options[:active_distributors].andand.include?(object) + end +end + +class Api::CachedEnterpriseSerializer < ActiveModel::Serializer + cached + delegate :cache_key, to: :object + attributes :name, :id, :description, :latitude, :longitude, :long_description, :website, :instagram, :linkedin, :twitter, :facebook, :is_primary_producer, :is_distributor, :phone, :visible, :email, :hash, :logo, :promo_image, :icon, :path, - :pickup, :delivery, :active, :orders_close_at + :pickup, :delivery has_many :distributed_taxons, key: :taxons, serializer: Api::TaxonSerializer has_many :supplied_taxons, serializer: Api::TaxonSerializer @@ -20,14 +69,6 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer object.shipping_methods.where(:require_ship_address => true).present? end - def active - @options[:active_distributors].andand.include?(object) - end - - def orders_close_at - OrderCycle.first_closing_for(object).andand.orders_close_at - end - def email object.email.to_s.reverse end diff --git a/app/serializers/api/taxon_serializer.rb b/app/serializers/api/taxon_serializer.rb index a907532a6b..352a158e95 100644 --- a/app/serializers/api/taxon_serializer.rb +++ b/app/serializers/api/taxon_serializer.rb @@ -1,4 +1,7 @@ class Api::TaxonSerializer < ActiveModel::Serializer + cached + delegate :cache_key, to: :object + attributes :id, :name, :permalink, :icon def icon diff --git a/config/environments/development.rb b/config/environments/development.rb index 62642f7809..efa229e33c 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -5,6 +5,7 @@ Openfoodnetwork::Application.configure do # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false + config.cache_store = :memory_store # Log error messages when you accidentally call methods on nil. config.whiny_nils = true From f19a02264e782875adf095edd7fc47345f8bcc08 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 12:08:21 +1000 Subject: [PATCH 027/145] Adding all the Angular filters required to make this work --- .../darkswarm/filters/active.js.coffee | 14 +++++++++ .../darkswarm/filters/shipping.js.coffee | 13 ++++++++ .../darkswarm/filters/taxons.js.coffee | 10 +++++++ .../darkswarm/filters/active_spec.js.coffee | 28 +++++++++++++++++ .../darkswarm/filters/shipping_spec.js.coffee | 30 +++++++++++++++++++ .../darkswarm/filters/taxons_spec.js.coffee | 27 +++++++++++++++++ 6 files changed, 122 insertions(+) create mode 100644 app/assets/javascripts/darkswarm/filters/active.js.coffee create mode 100644 app/assets/javascripts/darkswarm/filters/shipping.js.coffee create mode 100644 app/assets/javascripts/darkswarm/filters/taxons.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee diff --git a/app/assets/javascripts/darkswarm/filters/active.js.coffee b/app/assets/javascripts/darkswarm/filters/active.js.coffee new file mode 100644 index 0000000000..93bf1c658c --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/active.js.coffee @@ -0,0 +1,14 @@ +Darkswarm.filter 'active', ()-> + (objects, options)-> + objects ||= [] + options ?= null + + if options.open and !options.closed + objects.filter (obj)-> + obj.active + else if options.closed and !options.open + objects.filter (obj)-> + !obj.active + else + objects + diff --git a/app/assets/javascripts/darkswarm/filters/shipping.js.coffee b/app/assets/javascripts/darkswarm/filters/shipping.js.coffee new file mode 100644 index 0000000000..761e34337d --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/shipping.js.coffee @@ -0,0 +1,13 @@ +Darkswarm.filter 'shipping', ()-> + (objects, options)-> + objects ||= [] + options ?= null + + if options.pickup and !options.delivery + objects.filter (obj)-> + obj.pickup + else if options.delivery and !options.pickup + objects.filter (obj)-> + obj.delivery + else + objects diff --git a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee new file mode 100644 index 0000000000..c060647ac5 --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee @@ -0,0 +1,10 @@ +Darkswarm.filter 'taxons', (Matcher)-> + # Filter anything that responds to object.taxons, and/or object.primary_taxon + (objects, text) -> + objects ||= [] + text ?= "" + objects.filter (obj)-> + Matcher.match([obj.primary_taxon?.name || ""], text) || obj.taxons.some (taxon)-> + Matcher.match [taxon.name], text + + diff --git a/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee new file mode 100644 index 0000000000..337121b1ae --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee @@ -0,0 +1,28 @@ +describe 'filtering by active', -> + filterByActive = null + objects = [ + { + active: true + } + { + active: false + } + ] + + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filterByActive = $filter('active') + + it "filters to active", -> + expect(filterByActive(objects, {closed: false, open: true})[0]).toBe objects[0] + + it "filters to inactive", -> + expect(filterByActive(objects, {closed: true, open: false})[0]).toBe objects[1] + + it "doesn't filter if needed", -> + expect(filterByActive(objects, {closed: false, open: false})).toBe objects + + it "filters to all", -> + expect(filterByActive(objects, {closed: true, open: true})).toBe objects diff --git a/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee new file mode 100644 index 0000000000..bfb5ffe606 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee @@ -0,0 +1,30 @@ +describe 'filtering by shipping method', -> + filterByShippingMethod = null + objects = [ + { + delivery: true + pickup: false + } + { + delivery: false + pickup: true + } + ] + + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filterByShippingMethod = $filter('shipping') + + it "filters to pickup", -> + expect(filterByShippingMethod(objects, {pickup: true, delivery: false})[0]).toBe objects[1] + + it "filters to delivery", -> + expect(filterByShippingMethod(objects, {pickup: false, delivery: true})[0]).toBe objects[0] + + it "filters to both", -> + expect(filterByShippingMethod(objects, {pickup: true, delivery: true})).toBe objects + + it "filters to none", -> + expect(filterByShippingMethod(objects, {pickup: false, delivery: false})).toBe objects diff --git a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee new file mode 100644 index 0000000000..fee894353c --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee @@ -0,0 +1,27 @@ +describe 'filtering by taxons', -> + filterByTaxons = null + objects = [ + { + taxons: [] + primary_taxon: + name: "frogs" + } + { + taxons: [ + {name: "kittens"} + {name: "puppies"} + ] + } + ] + + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filterByTaxons = $filter('taxons') + + it "filters by primary taxon", -> + expect(filterByTaxons(objects, "frogs")[0]).toBe objects[0] + + it "filters by taxons", -> + expect(filterByTaxons(objects, "kittens")[0]).toBe objects[1] From 1955048502412a383e452b744d66f01e2ec46c55 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 12:10:33 +1000 Subject: [PATCH 028/145] Moving taxon filter to ID instead of name --- .../javascripts/darkswarm/filters/taxons.js.coffee | 10 ++++------ .../unit/darkswarm/filters/taxons_spec.js.coffee | 11 +++++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee index c060647ac5..e10228b648 100644 --- a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee @@ -1,10 +1,8 @@ Darkswarm.filter 'taxons', (Matcher)-> # Filter anything that responds to object.taxons, and/or object.primary_taxon - (objects, text) -> + (objects, id) -> objects ||= [] - text ?= "" + id ?= 0 objects.filter (obj)-> - Matcher.match([obj.primary_taxon?.name || ""], text) || obj.taxons.some (taxon)-> - Matcher.match [taxon.name], text - - + obj.primary_taxon?.id == id || obj.taxons.some (taxon)-> + taxon.id == id diff --git a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee index fee894353c..f8b387b9a7 100644 --- a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee @@ -5,11 +5,12 @@ describe 'filtering by taxons', -> taxons: [] primary_taxon: name: "frogs" + id: 1 } { taxons: [ - {name: "kittens"} - {name: "puppies"} + {name: "kittens", id: 2} + {name: "puppies", id: 3} ] } ] @@ -21,7 +22,9 @@ describe 'filtering by taxons', -> filterByTaxons = $filter('taxons') it "filters by primary taxon", -> - expect(filterByTaxons(objects, "frogs")[0]).toBe objects[0] + expect(filterByTaxons(objects, 1)[0]).toBe objects[0] it "filters by taxons", -> - expect(filterByTaxons(objects, "kittens")[0]).toBe objects[1] + expect(filterByTaxons(objects, 2)[0]).toBe objects[1] + + From 55bf59ba966f5a62253682b75ea0a1691137c79d Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 12:13:50 +1000 Subject: [PATCH 029/145] adding by producer id filtering --- .../darkswarm/filters/by_producer.js.coffee | 6 ++++++ .../filters/by_producer_spec.js.coffee | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 app/assets/javascripts/darkswarm/filters/by_producer.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/filters/by_producer_spec.js.coffee diff --git a/app/assets/javascripts/darkswarm/filters/by_producer.js.coffee b/app/assets/javascripts/darkswarm/filters/by_producer.js.coffee new file mode 100644 index 0000000000..3b9ec12d2b --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/by_producer.js.coffee @@ -0,0 +1,6 @@ +Darkswarm.filter "byProducer", -> + (objects, id) -> + objects ||= [] + id ?= 0 + objects.filter (obj)-> + obj.producer.id == id diff --git a/spec/javascripts/unit/darkswarm/filters/by_producer_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/by_producer_spec.js.coffee new file mode 100644 index 0000000000..48b811a11f --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/by_producer_spec.js.coffee @@ -0,0 +1,21 @@ +describe 'filtering by producer', -> + filterByProducer = null + objects = [ + { + producer: + id: 1 + } + { + producer: + id: 2 + } + ] + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filterByProducer = $filter('byProducer') + + it "filters by producer", -> + expect(filterByProducer(objects, 1)[0]).toBe objects[0] + expect(filterByProducer(objects, 2)[0]).toBe objects[1] From 487b8616c0c4f4d6b160b54b443fe73a47f5eb3b Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 12:30:28 +1000 Subject: [PATCH 030/145] Adding dereferencing to taxons and reducing our data-set --- .../darkswarm/services/enterprises.js.coffee | 11 ++++++++--- .../darkswarm/services/taxons.js.coffee | 8 ++++++++ app/helpers/shared_helper.rb | 4 ++++ app/serializers/api/enterprise_serializer.rb | 2 +- app/views/layouts/darkswarm.html.haml | 1 + spec/helpers/shared_helper_spec.rb | 7 ++++++- .../darkswarm/services/enterprise_spec.js.coffee | 9 ++++++++- .../unit/darkswarm/services/taxon_spec.js.coffee | 16 ++++++++++++++++ 8 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/services/taxons.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index b442773d31..84a3c2e7c2 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -1,15 +1,20 @@ -Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Dereferencer)-> +Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer)-> new class Enterprises enterprises_by_id: {} # id/object pairs for lookup constructor: -> @enterprises = enterprises for enterprise in enterprises @enterprises_by_id[enterprise.id] = enterprise - @dereference() + @dereferenceEnterprises() + @dereferenceTaxons() - dereference: -> + dereferenceEnterprises: -> if CurrentHub.hub?.id CurrentHub.hub = @enterprises_by_id[CurrentHub.hub.id] for enterprise in @enterprises Dereferencer.dereference enterprise.hubs, @enterprises_by_id Dereferencer.dereference enterprise.producers, @enterprises_by_id + + dereferenceTaxons: -> + for enterprise in @enterprises + Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id diff --git a/app/assets/javascripts/darkswarm/services/taxons.js.coffee b/app/assets/javascripts/darkswarm/services/taxons.js.coffee new file mode 100644 index 0000000000..cbe6c118e0 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/taxons.js.coffee @@ -0,0 +1,8 @@ +Darkswarm.factory "Taxons", (taxons)-> + new class Taxons + taxons: taxons + taxons_by_id: {} + constructor: -> + for taxon in @taxons + @taxons_by_id[taxon.id] = taxon + diff --git a/app/helpers/shared_helper.rb b/app/helpers/shared_helper.rb index f555a9f695..ff4310a8f0 100644 --- a/app/helpers/shared_helper.rb +++ b/app/helpers/shared_helper.rb @@ -3,6 +3,10 @@ module SharedHelper inject_json_ams "enterprises", Enterprise.all, Api::EnterpriseSerializer, active_distributors: @active_distributors end + def inject_taxons + inject_json_ams "taxons", Spree::Taxon.all, Api::TaxonSerializer + end + def inject_json(name, partial, opts = {}) render partial: "json/injection", locals: {name: name, partial: partial}.merge(opts) end diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index c0b79084f0..c643bf5b21 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -55,7 +55,7 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer :pickup, :delivery has_many :distributed_taxons, key: :taxons, serializer: Api::TaxonSerializer - has_many :supplied_taxons, serializer: Api::TaxonSerializer + has_many :supplied_taxons, serializer: Api::IdSerializer has_many :distributors, key: :hubs, serializer: Api::IdSerializer has_many :suppliers, key: :producers, serializer: Api::IdSerializer diff --git a/app/views/layouts/darkswarm.html.haml b/app/views/layouts/darkswarm.html.haml index 3d246acab8..f831d93d17 100644 --- a/app/views/layouts/darkswarm.html.haml +++ b/app/views/layouts/darkswarm.html.haml @@ -28,6 +28,7 @@ = inject_json "currentOrder", "current_order" = inject_json "user", "current_user" = inject_json "railsFlash", "flash" + = inject_taxons .off-canvas-wrap{offcanvas: true} .inner-wrap diff --git a/spec/helpers/shared_helper_spec.rb b/spec/helpers/shared_helper_spec.rb index 76d2e6e859..d1d99c331f 100644 --- a/spec/helpers/shared_helper_spec.rb +++ b/spec/helpers/shared_helper_spec.rb @@ -32,9 +32,14 @@ describe SharedHelper do end it "injects enterprises" do - Enterprise.stub(:visible).and_return [enterprise] helper.inject_enterprises().should match enterprise.name helper.inject_enterprises().should match enterprise.facebook end + + it "injects taxons" do + taxon = create(:taxon) + helper.inject_taxons.should match taxon.name + end end + end diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee index ebf480d9e8..59d4ae9826 100644 --- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee @@ -1,8 +1,11 @@ describe "Enterprises service", -> Enterprises = null CurrentHubMock = {} + taxons = [ + {id: 1, name: "test"} + ] enterprises = [ - {id: 1, type: "hub", producers: [{id: 2}]}, + {id: 1, type: "hub", producers: [{id: 2}], taxons: [{id: 1}]}, {id: 2, type: "producer", hubs: [{id: 1}]}, {id: 3, type: "producer", hubs: [{id: 1}]} ] @@ -12,6 +15,7 @@ describe "Enterprises service", -> $provide.value "CurrentHub", CurrentHubMock null angular.module('Darkswarm').value('enterprises', enterprises) + angular.module('Darkswarm').value('taxons', taxons) inject ($injector)-> Enterprises = $injector.get("Enterprises") @@ -29,3 +33,6 @@ describe "Enterprises service", -> it "dereferences references to other enterprises", -> expect(Enterprises.enterprises_by_id["1"].producers[0]).toBe enterprises[1] expect(Enterprises.enterprises_by_id["3"].hubs[0]).toBe enterprises[0] + + it "dereferences taxons", -> + expect(Enterprises.enterprises[0].taxons[0]).toBe taxons[0] diff --git a/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee new file mode 100644 index 0000000000..b05c82a13d --- /dev/null +++ b/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee @@ -0,0 +1,16 @@ +describe "Taxons service", -> + Taxons = null + taxons = [ + {id: 1, name: "test"} + {id: 2, name: "Roger"} + ] + + beforeEach -> + module('Darkswarm') + angular.module('Darkswarm').value 'taxons', taxons + + inject ($injector)-> + Taxons = $injector.get("Taxons") + + it "caches taxons in an id-referenced hash", -> + expect(Taxons.taxons_by_id[1]).toBe taxons[0] From b005d0860edb679c806b24d5db5485784dc86ab9 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 13:17:54 +1000 Subject: [PATCH 031/145] cleaning up touches --- app/models/enterprise.rb | 2 +- app/models/spree/classification_decorator.rb | 1 - app/models/spree/product_decorator.rb | 1 - app/serializers/api/enterprise_serializer.rb | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index d42031273d..5b922b15e4 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -7,7 +7,7 @@ class Enterprise < ActiveRecord::Base has_many :producer_properties, foreign_key: 'producer_id' has_many :supplied_products, :class_name => 'Spree::Product', :foreign_key => 'supplier_id', :dependent => :destroy has_many :distributed_orders, :class_name => 'Spree::Order', :foreign_key => 'distributor_id' - belongs_to :address, :class_name => 'Spree::Address', touch: true + belongs_to :address, :class_name => 'Spree::Address' has_many :product_distributions, :foreign_key => 'distributor_id', :dependent => :destroy has_many :distributed_products, :through => :product_distributions, :source => :product has_many :enterprise_fees diff --git a/app/models/spree/classification_decorator.rb b/app/models/spree/classification_decorator.rb index 8fa201528c..c69eb01fcf 100644 --- a/app/models/spree/classification_decorator.rb +++ b/app/models/spree/classification_decorator.rb @@ -1,6 +1,5 @@ Spree::Classification.class_eval do belongs_to :product, :class_name => "Spree::Product", touch: true - belongs_to :taxon, :class_name => "Spree::Taxon", touch: true before_destroy :dont_destroy_if_primary_taxon def dont_destroy_if_primary_taxon diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 0f61011fcd..65b717b8b6 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -5,7 +5,6 @@ Spree::Product.class_eval do has_many :option_types, :through => :product_option_types, :dependent => :destroy belongs_to :supplier, :class_name => 'Enterprise', touch: true - belongs_to :primary_taxon, class_name: 'Spree::Taxon', touch: true has_many :product_distributions, :dependent => :destroy has_many :distributors, :through => :product_distributions diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index c643bf5b21..c929bf2c55 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -4,7 +4,6 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer # Taxons: # classifications touch products # products touch suppliers - # Taxon could change but unlikely: if becomes a problem dereference # # Relatives: # Enterprise_relationships touches parent, child From 514d7179a6dc60349c5812ff4ce6af3dc5959b21 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 2 Jul 2014 12:09:23 +1000 Subject: [PATCH 032/145] Revert "install script". Prototype script should not yet be on master. This reverts commit 39012388a209e0f120c25cdb08a48e0426ed9eaf. --- INSTALL.sh | 97 ------------------------------------------------------ 1 file changed, 97 deletions(-) delete mode 100755 INSTALL.sh diff --git a/INSTALL.sh b/INSTALL.sh deleted file mode 100755 index 8ff0b660a1..0000000000 --- a/INSTALL.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/sh -# -########################### -# Linux install script # -# ----------------------- # -# Tested on Debian wheezy # -########################### - -echo 'Checking dependencies...' - -# Rails is installed by bundler later -#echo -n 'Rails 3.2.. ' -#if rails -v | grep -q 'Rails 3.2'; then -# echo 'ok' -#else -# echo 'not found' -# exit 1 -#fi - -echo -n 'Ruby 1.9.3.. ' -revision=$(ruby -v | grep -E -o '^ruby 1\.9\.([0-9]+)' | cut -d . -f 3) -if [ "$revision" -gt 2 ]; then - echo 'ok' -else - echo 'not found' - exit 1 -fi - -echo -n 'PostgreSQL.. ' -if psql -? > /dev/null 2>&1; then - echo 'ok' -else - echo 'not found' - exit 1 -fi - - -psqlCreateCommands=" - createuser -s ofn - psql postgres -c \"ALTER USER ofn WITH ENCRYPTED PASSWORD 'f00d'\" - createdb -O ofn open_food_network_dev - createdb -O ofn open_food_network_test - createdb -O ofn open_food_network_prod -" -PGPASSFILE=$(mktemp) -echo '' -echo -n 'Checking PostgreSQL database.. ' -echo 'localhost:5432:open_food_network_dev:ofn:f00d1' > $PGPASSFILE -export PGPASSFILE -if psql -w -U ofn open_food_network_dev -c 'select 1' > /dev/null 2>&1; then - echo 'ok' -else - echo 'no access' - echo '' - echo 'Database needs setup. Try automatic setup with sudo? [yes]' - read autosetup - if [ -z "$autosetup" ] || [ "$autosetup" = "yes" ]; then - if sudo su postgres -c "$psqlCreateCommands"; then - echo 'User and databases created.' - else - echo 'Failed to create user and databases.' - autosetup='no' - fi - else - autosetup='no' - fi - if [ "$autosetup" = 'no' ]; then - echo '' - echo 'Execute the following commands as database admin user (e.g. postgres):' - echo "$psqlCreateCommands" - rm "$PGPASSFILE" - exit 1 - fi -fi -rm "$PGPASSFILE" - -echo '' -echo 'Installing all gems. That can take a while.' -bundle install - -echo '' -echo 'Seeding database..' -bundle exec rake db:schema:load db:seed -echo 'Skipping sample data (out of date)' -#bundle exec rake openfoodnetwork:dev:load_sample_data -echo 'You can run `rails server` now to start.' - -echo '' -echo 'Executing tests..' -bundle exec rake db:test:load -bundle exec rspec spec - -if [ "$?" -eq 0 ]; then - echo '' - echo 'All done.' - echo 'You can run `rails server` now.' -fi From 17612f14f578149dcc8ee23d093ad28db82cbf8e Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 16:04:14 +1000 Subject: [PATCH 033/145] Adding tests and full touch behaviour for caching --- app/models/distributor_shipping_method.rb | 5 ++ app/models/enterprise.rb | 3 +- app/models/spree/product_decorator.rb | 6 +++ app/models/spree/shipping_method_decorator.rb | 11 +++- app/serializers/api/enterprise_serializer.rb | 20 +------- ...fields_to_distributors_shipping_methods.rb | 7 +++ db/schema.rb | 10 ++-- .../distributor_shipping_method_spec.rb | 5 ++ spec/models/enterprise_caching_spec.rb | 51 +++++++++++++++++++ 9 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 app/models/distributor_shipping_method.rb create mode 100644 db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb create mode 100644 spec/models/distributor_shipping_method_spec.rb create mode 100644 spec/models/enterprise_caching_spec.rb diff --git a/app/models/distributor_shipping_method.rb b/app/models/distributor_shipping_method.rb new file mode 100644 index 0000000000..e765a23e50 --- /dev/null +++ b/app/models/distributor_shipping_method.rb @@ -0,0 +1,5 @@ +class DistributorShippingMethod < ActiveRecord::Base + self.table_name = "distributors_shipping_methods" + belongs_to :shipping_method, class_name: Spree::ShippingMethod + belongs_to :distributor, class_name: Enterprise, touch: true +end diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 5b922b15e4..e5250309b4 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -14,7 +14,8 @@ class Enterprise < ActiveRecord::Base has_many :enterprise_roles, :dependent => :destroy has_many :users, through: :enterprise_roles has_and_belongs_to_many :payment_methods, join_table: 'distributors_payment_methods', class_name: 'Spree::PaymentMethod', foreign_key: 'distributor_id' - has_and_belongs_to_many :shipping_methods, join_table: 'distributors_shipping_methods', class_name: 'Spree::ShippingMethod', foreign_key: 'distributor_id' + has_many :distributor_shipping_methods, foreign_key: :distributor_id + has_many :shipping_methods, through: :distributor_shipping_methods delegate :latitude, :longitude, :city, :state_name, :to => :address diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 65b717b8b6..8f95f72c3b 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -5,6 +5,7 @@ Spree::Product.class_eval do has_many :option_types, :through => :product_option_types, :dependent => :destroy belongs_to :supplier, :class_name => 'Enterprise', touch: true + belongs_to :primary_taxon, class_name: 'Spree::Taxon' has_many :product_distributions, :dependent => :destroy has_many :distributors, :through => :product_distributions @@ -26,6 +27,7 @@ Spree::Product.class_eval do after_initialize :set_available_on_to_now, :if => :new_record? after_save :update_units + after_touch :touch_distributors before_save :add_primary_taxon_to_taxons @@ -185,6 +187,10 @@ Spree::Product.class_eval do end end + def touch_distributors + Enterprise.distributing_product(self).each(&:touch) + end + def add_primary_taxon_to_taxons taxons << primary_taxon unless taxons.find_by_id(primary_taxon) end diff --git a/app/models/spree/shipping_method_decorator.rb b/app/models/spree/shipping_method_decorator.rb index 303ab7b96f..165a206ec9 100644 --- a/app/models/spree/shipping_method_decorator.rb +++ b/app/models/spree/shipping_method_decorator.rb @@ -1,5 +1,8 @@ Spree::ShippingMethod.class_eval do - has_and_belongs_to_many :distributors, join_table: 'distributors_shipping_methods', :class_name => 'Enterprise', association_foreign_key: 'distributor_id' + has_many :distributor_shipping_methods + has_many :distributors, through: :distributor_shipping_methods, class_name: 'Enterprise', foreign_key: 'distributor_id' + + after_save :touch_distributors attr_accessible :distributor_ids, :description attr_accessible :require_ship_address @@ -41,4 +44,10 @@ Spree::ShippingMethod.class_eval do def adjustment_label 'Shipping' end + + private + + def touch_distributors + distributors.each(&:touch) + end end diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index c929bf2c55..3ef46f1724 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -1,20 +1,5 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer # To improve this: http://hawkins.io/2013/06/caching_object_graphs_with_active_model_serializers/ - # - # Taxons: - # classifications touch products - # products touch suppliers - # - # Relatives: - # Enterprise_relationships touches parent, child - # Otherwise dereferencing makes easy - # - # Address: - # Fine - # - # Shipping Methods: - # Create distributors_shipping_methods class - # Set up touches def serializable_hash cached_serializer_hash.merge uncached_serializer_hash @@ -33,6 +18,7 @@ end class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer attributes :orders_close_at, :active + has_one :address, serializer: Api::AddressSerializer def orders_close_at OrderCycle.first_closing_for(object).andand.orders_close_at @@ -53,13 +39,11 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer :email, :hash, :logo, :promo_image, :icon, :path, :pickup, :delivery - has_many :distributed_taxons, key: :taxons, serializer: Api::TaxonSerializer + has_many :distributed_taxons, key: :taxons, serializer: Api::IdSerializer has_many :supplied_taxons, serializer: Api::IdSerializer has_many :distributors, key: :hubs, serializer: Api::IdSerializer has_many :suppliers, key: :producers, serializer: Api::IdSerializer - has_one :address, serializer: Api::AddressSerializer - def pickup object.shipping_methods.where(:require_ship_address => false).present? end diff --git a/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb b/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb new file mode 100644 index 0000000000..ed54707cb1 --- /dev/null +++ b/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb @@ -0,0 +1,7 @@ +class AddFieldsToDistributorsShippingMethods < ActiveRecord::Migration + def change + add_column :distributors_shipping_methods, :id, :primary_key + add_column :distributors_shipping_methods, :created_at, :datetime + add_column :distributors_shipping_methods, :updated_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 5932749993..608cdb299b 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 => 20140613004344) do +ActiveRecord::Schema.define(:version => 20140702053145) do create_table "adjustment_metadata", :force => true do |t| t.integer "adjustment_id" @@ -163,9 +163,11 @@ ActiveRecord::Schema.define(:version => 20140613004344) do add_index "distributors_payment_methods", ["distributor_id"], :name => "index_distributors_payment_methods_on_distributor_id" add_index "distributors_payment_methods", ["payment_method_id"], :name => "index_distributors_payment_methods_on_payment_method_id" - create_table "distributors_shipping_methods", :id => false, :force => true do |t| - t.integer "distributor_id" - t.integer "shipping_method_id" + create_table "distributors_shipping_methods", :force => true do |t| + t.integer "distributor_id" + t.integer "shipping_method_id" + t.datetime "created_at" + t.datetime "updated_at" end add_index "distributors_shipping_methods", ["distributor_id"], :name => "index_distributors_shipping_methods_on_distributor_id" diff --git a/spec/models/distributor_shipping_method_spec.rb b/spec/models/distributor_shipping_method_spec.rb new file mode 100644 index 0000000000..bd8d7d2973 --- /dev/null +++ b/spec/models/distributor_shipping_method_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe DistributorShippingMethod do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/enterprise_caching_spec.rb b/spec/models/enterprise_caching_spec.rb new file mode 100644 index 0000000000..af05897a6e --- /dev/null +++ b/spec/models/enterprise_caching_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe Enterprise do + context "key-based caching invalidation" do + describe "is touched when a(n)" do + let(:enterprise) { create(:distributor_enterprise, updated_at: 1.week.ago) } + let(:taxon) { create(:taxon) } + + describe "with supplied taxon" do + let(:product) { create(:simple_product, supplier: enterprise) } + let!(:classification) { create(:classification, taxon: taxon, product: product) } + it "supplied taxon is updated" do + expect{classification.save!}.to change{enterprise.updated_at} + end + end + + describe "with distributed taxon" do + let(:product) { create(:simple_product) } + let!(:oc) { create(:simple_order_cycle, distributors: [enterprise], variants: [product.master]) } + let!(:classification) { create(:classification, taxon: taxon, product: product) } + it "distributed taxon is updated" do + expect{classification.save!}.to change{enterprise.reload.updated_at} + end + end + + describe "with relatives" do + let(:child_enterprise) { create(:supplier_enterprise) } + let!(:er) { create(:enterprise_relationship, parent: enterprise, child: child_enterprise) } + it "enterprise relationship is updated" do + expect{er.save!}.to change {enterprise.reload.updated_at } + end + end + + describe "with shipping methods" do + let(:sm) { create(:shipping_method) } + before do + enterprise.shipping_methods << sm + end + it "distributor_shipping_method is updated" do + expect { + enterprise.distributor_shipping_methods.first.save! + }.to change {enterprise.reload.updated_at} + end + + it "shipping method is updated" do + expect{sm.save!}.to change {enterprise.reload.updated_at } + end + end + end + end +end From 22b5e152d16d3a49e84cafdaa210627859bdc51f Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 16:36:37 +1000 Subject: [PATCH 034/145] Tweaking spec names --- spec/models/enterprise_caching_spec.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/models/enterprise_caching_spec.rb b/spec/models/enterprise_caching_spec.rb index af05897a6e..51ed68aace 100644 --- a/spec/models/enterprise_caching_spec.rb +++ b/spec/models/enterprise_caching_spec.rb @@ -6,19 +6,19 @@ describe Enterprise do let(:enterprise) { create(:distributor_enterprise, updated_at: 1.week.ago) } let(:taxon) { create(:taxon) } - describe "with supplied taxon" do + describe "with a supplied product" do let(:product) { create(:simple_product, supplier: enterprise) } let!(:classification) { create(:classification, taxon: taxon, product: product) } - it "supplied taxon is updated" do + it "touches enterprise when a classification on that product changes" do expect{classification.save!}.to change{enterprise.updated_at} end end - describe "with distributed taxon" do + describe "with a distributed product" do let(:product) { create(:simple_product) } let!(:oc) { create(:simple_order_cycle, distributors: [enterprise], variants: [product.master]) } let!(:classification) { create(:classification, taxon: taxon, product: product) } - it "distributed taxon is updated" do + it "touches enterprise when a classification on that product changes" do expect{classification.save!}.to change{enterprise.reload.updated_at} end end @@ -26,7 +26,7 @@ describe Enterprise do describe "with relatives" do let(:child_enterprise) { create(:supplier_enterprise) } let!(:er) { create(:enterprise_relationship, parent: enterprise, child: child_enterprise) } - it "enterprise relationship is updated" do + it "touches enterprise when enterprise relationship is updated" do expect{er.save!}.to change {enterprise.reload.updated_at } end end @@ -36,13 +36,13 @@ describe Enterprise do before do enterprise.shipping_methods << sm end - it "distributor_shipping_method is updated" do + it "touches enterprise when distributor_shipping_method is updated" do expect { enterprise.distributor_shipping_methods.first.save! }.to change {enterprise.reload.updated_at} end - it "shipping method is updated" do + it "touches enterprise when shipping method is updated" do expect{sm.save!}.to change {enterprise.reload.updated_at } end end From a8fde537153eafabf4665e8a33bdc5e343a7bbe7 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 16:40:21 +1000 Subject: [PATCH 035/145] Removing old file, renaming one to match naming conventions --- app/assets/javascripts/templates/test.nghaml | 1 - app/views/producers/{index.haml => index.html.haml} | 0 2 files changed, 1 deletion(-) delete mode 100644 app/assets/javascripts/templates/test.nghaml rename app/views/producers/{index.haml => index.html.haml} (100%) diff --git a/app/assets/javascripts/templates/test.nghaml b/app/assets/javascripts/templates/test.nghaml deleted file mode 100644 index 99fb61374e..0000000000 --- a/app/assets/javascripts/templates/test.nghaml +++ /dev/null @@ -1 +0,0 @@ -Frogs diff --git a/app/views/producers/index.haml b/app/views/producers/index.html.haml similarity index 100% rename from app/views/producers/index.haml rename to app/views/producers/index.html.haml From 2f98da8eef6a5d0d510772a2ec15ca99640f0111 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 16:53:21 +1000 Subject: [PATCH 036/145] Caching address and touching enterprise on save --- app/models/spree/address_decorator.rb | 6 ++++++ app/serializers/api/enterprise_serializer.rb | 3 ++- spec/models/enterprise_caching_spec.rb | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/models/spree/address_decorator.rb b/app/models/spree/address_decorator.rb index 28f292fbd3..8797a91599 100644 --- a/app/models/spree/address_decorator.rb +++ b/app/models/spree/address_decorator.rb @@ -2,6 +2,8 @@ Spree::Address.class_eval do has_one :enterprise belongs_to :country, class_name: "Spree::Country" + after_save :touch_enterprise + geocoded_by :full_address delegate :name, :to => :state, :prefix => true, :allow_nil => true @@ -15,6 +17,10 @@ Spree::Address.class_eval do private + def touch_enterprise + enterprise.andand.touch + end + # We have a hard-to-track-down bug around invalid addresses with all-nil fields finding # their way into the database. I don't know what the source of them is, so this patch # is designed to track them down. diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index 3ef46f1724..23aa2a7458 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -18,7 +18,6 @@ end class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer attributes :orders_close_at, :active - has_one :address, serializer: Api::AddressSerializer def orders_close_at OrderCycle.first_closing_for(object).andand.orders_close_at @@ -44,6 +43,8 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer has_many :distributors, key: :hubs, serializer: Api::IdSerializer has_many :suppliers, key: :producers, serializer: Api::IdSerializer + #has_one :address, serializer: Api::AddressSerializer + def pickup object.shipping_methods.where(:require_ship_address => false).present? end diff --git a/spec/models/enterprise_caching_spec.rb b/spec/models/enterprise_caching_spec.rb index 51ed68aace..72b356df21 100644 --- a/spec/models/enterprise_caching_spec.rb +++ b/spec/models/enterprise_caching_spec.rb @@ -46,6 +46,10 @@ describe Enterprise do expect{sm.save!}.to change {enterprise.reload.updated_at } end end + + it "touches enterprise when address is updated" do + expect{enterprise.address.save!}.to change {enterprise.reload.updated_at } + end end end end From fab96b58a7e748f7085a84a02df2ac8c7dcd03b4 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 3 Jul 2014 12:22:26 +1000 Subject: [PATCH 037/145] Fixing spec regression --- app/models/enterprise.rb | 4 ++-- spec/models/enterprise_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index e5250309b4..e6279bf226 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -17,7 +17,6 @@ class Enterprise < ActiveRecord::Base has_many :distributor_shipping_methods, foreign_key: :distributor_id has_many :shipping_methods, through: :distributor_shipping_methods - delegate :latitude, :longitude, :city, :state_name, :to => :address accepts_nested_attributes_for :address @@ -30,7 +29,7 @@ class Enterprise < ActiveRecord::Base validates_presence_of :address validates_associated :address - after_initialize :initialize_country + before_create :initialize_country before_validation :set_unused_address_fields after_validation :geocode_address @@ -207,6 +206,7 @@ class Enterprise < ActiveRecord::Base url.andand.sub /(https?:\/\/)?(www\.)?/, '' end + # Give us an empty address on create, and set the country to the default def initialize_country self.address ||= Spree::Address.new self.address.country = Spree::Country.find_by_id(Spree::Config[:default_country_id]) if self.address.new_record? diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb index 0fa57d19d3..aa655bebfc 100644 --- a/spec/models/enterprise_spec.rb +++ b/spec/models/enterprise_spec.rb @@ -68,7 +68,7 @@ describe Enterprise do end it "should default address country to system country" do - subject.address.country.should == Spree::Country.find_by_id(Spree::Config[:default_country_id]) + create(:distributor_enterprise).address.country.should == Spree::Country.find_by_id(Spree::Config[:default_country_id]) end describe "scopes" do From 5459a54adab2e7d431da65753b05942f3a74bb6f Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 3 Jul 2014 14:30:36 +1000 Subject: [PATCH 038/145] Adding perftools.rb perftools.rb can profile your code. The spec_helper contains comments about how to activate it. --- Gemfile | 1 + Gemfile.lock | 2 ++ spec/spec_helper.rb | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/Gemfile b/Gemfile index cb6f7a8f96..346d8c9d51 100644 --- a/Gemfile +++ b/Gemfile @@ -85,6 +85,7 @@ end group :test do gem 'webmock' + gem 'perftools.rb' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 9afad20d05..39afc2ac50 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -341,6 +341,7 @@ GEM activesupport (>= 2.3.2) cocaine (>= 0.0.2) mime-types + perftools.rb (2.0.1) pg (0.13.2) poltergeist (1.5.0) capybara (~> 2.1) @@ -531,6 +532,7 @@ DEPENDENCIES newrelic_rpm oj paperclip + perftools.rb pg poltergeist pry-debugger diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4f96a09070..3f3435eda5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -104,4 +104,25 @@ RSpec.configure do |config| config.include Paperclip::Shoulda::Matchers config.include JsonSpec::Helpers + + # Profiling + # + # This code shouldn't be run in normal circumstances. But if you want to know + # which parts of your code take most time, then you can activate the lines + # below. Keep in mind that it will slow down the execution time heaps. + # + # The PerfTools will write a binary file to the specified path which can then + # be examined by: + # + # bundle exec pprof.rb --text /tmp/rspec_profile + # + + #require 'perftools' + #config.before :suite do + # PerfTools::CpuProfiler.start("/tmp/rspec_profile") + #end + # + #config.after :suite do + # PerfTools::CpuProfiler.stop + #end end From ca6068c0957b78fe6c936473be57af38320103ca Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 4 Jul 2014 10:56:19 +1000 Subject: [PATCH 039/145] Fixing a borked test --- spec/serializers/enterprise_serializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/serializers/enterprise_serializer.rb b/spec/serializers/enterprise_serializer.rb index 4e9248be53..263f621598 100644 --- a/spec/serializers/enterprise_serializer.rb +++ b/spec/serializers/enterprise_serializer.rb @@ -11,7 +11,7 @@ describe Api::EnterpriseSerializer do it "includes distributed taxons" do enterprise.stub(:distributed_taxons).and_return [taxon] serializer = Api::EnterpriseSerializer.new enterprise - serializer.to_json.should match taxon.name + serializer.to_json.should match taxon.id.to_s end it "will render urls" do From 3da2461af599329392e702baee3ad35f5d9452d5 Mon Sep 17 00:00:00 2001 From: Rob H Date: Fri, 4 Jul 2014 14:05:44 +1000 Subject: [PATCH 040/145] Require shipping methods to have at least one distributor --- app/models/spree/shipping_method_decorator.rb | 2 ++ app/views/spree/admin/shared/_hubs_sidebar.html.haml | 5 +++-- spec/features/admin/enterprises_spec.rb | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/models/spree/shipping_method_decorator.rb b/app/models/spree/shipping_method_decorator.rb index 303ab7b96f..5d7bb89a8f 100644 --- a/app/models/spree/shipping_method_decorator.rb +++ b/app/models/spree/shipping_method_decorator.rb @@ -3,6 +3,8 @@ Spree::ShippingMethod.class_eval do attr_accessible :distributor_ids, :description attr_accessible :require_ship_address + validates :distributors, presence: { message: "^At least one hub must be selected" } + scope :managed_by, lambda { |user| if user.has_spree_role?('admin') scoped diff --git a/app/views/spree/admin/shared/_hubs_sidebar.html.haml b/app/views/spree/admin/shared/_hubs_sidebar.html.haml index 8998e6d593..4fe9b1078a 100644 --- a/app/views/spree/admin/shared/_hubs_sidebar.html.haml +++ b/app/views/spree/admin/shared/_hubs_sidebar.html.haml @@ -1,10 +1,11 @@ - hubs_color = @hubs.count > 0 ? "blue" : "red" +- hubs_color = 'red' if (controller.action_name == 'create' || controller.action_name == 'update') && @object.errors.full_messages.include?("At least one hub must be selected") .sidebar_item.omega.four.columns#hubs .four.columns.alpha.header{ class: "#{hubs_color}" } - %span.four.columns.alpha.centered Distributors + %span.four.columns.alpha.centered Hubs .four.columns.alpha.list{ class: "#{hubs_color}" } - if @hubs.count > 0 - -# = hidden_field_tag "enterprise[hub_ids][]", [] + = f.hidden_field :distributor_ids, :multiple => true, value: nil - @hubs.each do |hub| %a.four.columns.alpha.list-item{ class: "#{cycle('odd','even')}", href: "#{main_app.edit_admin_enterprise_path(hub)}" } %span.three.columns.alpha diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb index 50ce2aad7f..e481be4635 100644 --- a/spec/features/admin/enterprises_spec.rb +++ b/spec/features/admin/enterprises_spec.rb @@ -110,16 +110,17 @@ feature %q{ scenario "editing an existing enterprise" do @enterprise = create(:enterprise) + e2 = create(:enterprise) eg1 = create(:enterprise_group, name: 'eg1') eg2 = create(:enterprise_group, name: 'eg2') payment_method = create(:payment_method, distributors: []) - shipping_method = create(:shipping_method, distributors: []) + shipping_method = create(:shipping_method, distributors: [e2]) enterprise_fee = create(:enterprise_fee, enterprise: @enterprise ) login_to_admin_section click_link 'Enterprises' - click_link 'Edit Profile' + all("a", text:'Edit Profile').first.click fill_in 'enterprise_name', :with => 'Eaterprises' fill_in 'enterprise_description', :with => 'Connecting farmers and eaters' From f335b6a576ee1dc7d4976f3cd6c5ed9a383d123c Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 4 Jul 2014 14:09:53 +1000 Subject: [PATCH 041/145] Taxon selectors and show/hide behaviour --- .../producers_controller.js.coffee | 4 +- .../directives/active_selector.js.coffee | 10 ++++ .../directives/taxon_selector.js.coffee | 6 ++ .../darkswarm/filters/taxons.js.coffee | 14 +++-- .../services/taxon_selector.js.coffee | 14 +++++ .../templates/active_selector.html.haml | 2 + .../templates/taxon_selector.html.haml | 4 ++ .../stylesheets/darkswarm/animations.sass | 18 ++++++ app/serializers/api/enterprise_serializer.rb | 4 +- app/views/producers/_filters.html.haml | 57 +------------------ app/views/producers/index.html.haml | 2 +- spec/javascripts/application_spec.js | 1 + .../darkswarm/filters/taxons_spec.js.coffee | 12 +++- 13 files changed, 81 insertions(+), 67 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/directives/active_selector.js.coffee create mode 100644 app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee create mode 100644 app/assets/javascripts/darkswarm/services/taxon_selector.js.coffee create mode 100644 app/assets/javascripts/templates/active_selector.html.haml create mode 100644 app/assets/javascripts/templates/taxon_selector.html.haml diff --git a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee index 1a28b5b107..26c90a305e 100644 --- a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee @@ -1,2 +1,4 @@ -Darkswarm.controller "ProducersCtrl", ($scope, Producers) -> +Darkswarm.controller "ProducersCtrl", ($scope, Producers, TaxonSelector) -> $scope.Producers = Producers + $scope.TaxonSelector = TaxonSelector + $scope.filtersActive = false diff --git a/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee new file mode 100644 index 0000000000..574af50b96 --- /dev/null +++ b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee @@ -0,0 +1,10 @@ +Darkswarm.directive "activeSelector", -> + restrict: 'E' + transclude: true + replace: true + templateUrl: 'active_selector.html' + link: (scope, elem, attr)-> + elem.bind "click", -> + scope.$apply -> + elem.toggleClass "active" + scope.selector.active = !scope.selector.active diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee new file mode 100644 index 0000000000..d4b93a3cdb --- /dev/null +++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee @@ -0,0 +1,6 @@ +Darkswarm.directive "taxonSelector", (TaxonSelector) -> + restrict: 'E' + scope: {} + templateUrl: "taxon_selector.html" + link: (scope, elem, attr)-> + scope.TaxonSelector = TaxonSelector diff --git a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee index e10228b648..01c7d98057 100644 --- a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee @@ -1,8 +1,12 @@ Darkswarm.filter 'taxons', (Matcher)-> # Filter anything that responds to object.taxons, and/or object.primary_taxon - (objects, id) -> + (objects, ids) -> objects ||= [] - id ?= 0 - objects.filter (obj)-> - obj.primary_taxon?.id == id || obj.taxons.some (taxon)-> - taxon.id == id + ids ?= [] + console.log ids + if ids.length == 0 + objects + else + objects.filter (obj)-> + obj.primary_taxon?.id in ids || obj.taxons.some (taxon)-> + taxon.id in ids diff --git a/app/assets/javascripts/darkswarm/services/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/services/taxon_selector.js.coffee new file mode 100644 index 0000000000..4628e79f11 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/taxon_selector.js.coffee @@ -0,0 +1,14 @@ +Darkswarm.factory 'TaxonSelector', (Taxons)-> + new class TaxonSelector + selectors: [] + constructor: -> + for taxon in Taxons.taxons + @selectors.push + active: false + taxon: taxon + + active: -> + @selectors.filter (selector)-> + selector.active + .map (selector)-> + selector.taxon.id diff --git a/app/assets/javascripts/templates/active_selector.html.haml b/app/assets/javascripts/templates/active_selector.html.haml new file mode 100644 index 0000000000..449c2bc4d3 --- /dev/null +++ b/app/assets/javascripts/templates/active_selector.html.haml @@ -0,0 +1,2 @@ +%li + %a{"ng-transclude" => true} diff --git a/app/assets/javascripts/templates/taxon_selector.html.haml b/app/assets/javascripts/templates/taxon_selector.html.haml new file mode 100644 index 0000000000..6e376a4ae2 --- /dev/null +++ b/app/assets/javascripts/templates/taxon_selector.html.haml @@ -0,0 +1,4 @@ +%ul.small-block-grid-4 + %active-selector{"ng-repeat" => "selector in TaxonSelector.selectors"} + %render-svg{path: "{{selector.taxon.icon}}"} + %span {{ selector.taxon.name }} diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index 2dd02148d8..7fc54e169c 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -51,3 +51,21 @@ opacity: 1 max-height: 40px + +.animate-show + -webkit-transition: all linear 0.5s + transition: all linear 0.5s + line-height: 20px + opacity: 1 + padding: 10px + border: 1px solid black + background: white + +.animate-show.ng-hide-add, +.animate-show.ng-hide-remove + display: block !important + +.animate-show.ng-hide + line-height: 0 + opacity: 0 + padding: 0 10px diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index 23aa2a7458..c7653db910 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -1,6 +1,4 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer - # To improve this: http://hawkins.io/2013/06/caching_object_graphs_with_active_model_serializers/ - def serializable_hash cached_serializer_hash.merge uncached_serializer_hash end @@ -43,7 +41,7 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer has_many :distributors, key: :hubs, serializer: Api::IdSerializer has_many :suppliers, key: :producers, serializer: Api::IdSerializer - #has_one :address, serializer: Api::AddressSerializer + has_one :address, serializer: Api::AddressSerializer def pickup object.shipping_methods.where(:require_ship_address => false).present? diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 4b1a16f89c..fa8046d3c2 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -1,4 +1,5 @@ -.row +%a{"ng-click" => "filtersActive = !filtersActive"} Toggle +.row.animate-show{"ng-show" => "filtersActive"} .small-12.columns.filter-box .row .small-12.large-6.columns @@ -15,56 +16,4 @@ Something .row .small-12.large-6.columns - %ul.small-block-grid-4 - %li - %a - %render-svg{path: "/spree/taxons/62/original/taxons_bakery.svg?1403150973"} - %span Bakery - %li - %a - %render-svg{path: "/spree/taxons/55/original/taxons_food-boxes.svg?1402988796"} - %span Boxes - %li - %a - %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - %span Bakery - - %li - %a - %render-svg{path: "/spree/taxons/24/original/taxons_oils_spreads.svg?1403248784"} - %span Oils & Spreads - %li - %a - %render-svg{path: "/spree/taxons/19/original/taxons_pulses_grains.svg?1402988994"} - %span Pulses & Grains - %li - %a - %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - %span Bakery - %li - %a - %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - %span Bakery - - %li - %a - %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - %span Bakery - %li - %a - %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - %span Bakery - %li - %a - %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - %span Bakery - %li - %a - %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - %span Bakery - - %li - %a - %render-svg{path: "/spree/taxons/58/original/taxons_fruit.svg?1402988839"} - %span Bakery - + %taxon-selector diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index b0de3dc693..a84d0a050f 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -25,7 +25,7 @@ .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", "scroll-after-load" => true, - "ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query)", + "ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query | taxons:TaxonSelector.active())", "ng-controller" => "ProducerNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} diff --git a/spec/javascripts/application_spec.js b/spec/javascripts/application_spec.js index 4eacb45036..44654e7b32 100644 --- a/spec/javascripts/application_spec.js +++ b/spec/javascripts/application_spec.js @@ -4,6 +4,7 @@ //= require angular-sanitize //= require angular-mocks //= require angular-cookies +//= require angular-timer.min.js //= require angular-backstretch.js //= require lodash.underscore.js //= require angular-flash.min.js diff --git a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee index f8b387b9a7..8c9002f53c 100644 --- a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee @@ -15,16 +15,22 @@ describe 'filtering by taxons', -> } ] - beforeEach -> module 'Darkswarm' inject ($filter) -> filterByTaxons = $filter('taxons') + it "filters by nothing", -> + expect(filterByTaxons(objects, [])).toBe objects + it "filters by primary taxon", -> - expect(filterByTaxons(objects, 1)[0]).toBe objects[0] + expect(filterByTaxons(objects, [1])[0]).toBe objects[0] it "filters by taxons", -> - expect(filterByTaxons(objects, 2)[0]).toBe objects[1] + expect(filterByTaxons(objects, [2])[0]).toBe objects[1] + + it "filters by multiple", -> + expect(filterByTaxons(objects, [1, 2])[0]).toBe objects[0] + expect(filterByTaxons(objects, [1, 2])[1]).toBe objects[1] From 8b439c4e69e48480e47a77897ff7417ee86fe3c1 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 10:26:19 +1000 Subject: [PATCH 042/145] Temporary/demonstration caching behaviour, INCOMPLETE --- app/models/enterprise.rb | 2 +- app/models/enterprise_relationship.rb | 4 +- app/models/spree/classification_decorator.rb | 2 + app/models/spree/product_decorator.rb | 4 +- app/serializers/api/address_serializer.rb | 3 + app/serializers/api/enterprise_serializer.rb | 59 +++++++++++++++++--- app/serializers/api/taxon_serializer.rb | 3 + config/environments/development.rb | 1 + 8 files changed, 64 insertions(+), 14 deletions(-) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 5b922b15e4..d42031273d 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -7,7 +7,7 @@ class Enterprise < ActiveRecord::Base has_many :producer_properties, foreign_key: 'producer_id' has_many :supplied_products, :class_name => 'Spree::Product', :foreign_key => 'supplier_id', :dependent => :destroy has_many :distributed_orders, :class_name => 'Spree::Order', :foreign_key => 'distributor_id' - belongs_to :address, :class_name => 'Spree::Address' + belongs_to :address, :class_name => 'Spree::Address', touch: true has_many :product_distributions, :foreign_key => 'distributor_id', :dependent => :destroy has_many :distributed_products, :through => :product_distributions, :source => :product has_many :enterprise_fees diff --git a/app/models/enterprise_relationship.rb b/app/models/enterprise_relationship.rb index 26bf8fc012..4db650f2e7 100644 --- a/app/models/enterprise_relationship.rb +++ b/app/models/enterprise_relationship.rb @@ -1,6 +1,6 @@ class EnterpriseRelationship < ActiveRecord::Base - belongs_to :parent, class_name: 'Enterprise' - belongs_to :child, class_name: 'Enterprise' + belongs_to :parent, class_name: 'Enterprise', touch: true + belongs_to :child, class_name: 'Enterprise', touch: true validates_presence_of :parent_id, :child_id validates_uniqueness_of :child_id, scope: :parent_id, message: "^That relationship is already established." diff --git a/app/models/spree/classification_decorator.rb b/app/models/spree/classification_decorator.rb index 7e34e6890e..8fa201528c 100644 --- a/app/models/spree/classification_decorator.rb +++ b/app/models/spree/classification_decorator.rb @@ -1,4 +1,6 @@ Spree::Classification.class_eval do + belongs_to :product, :class_name => "Spree::Product", touch: true + belongs_to :taxon, :class_name => "Spree::Taxon", touch: true before_destroy :dont_destroy_if_primary_taxon def dont_destroy_if_primary_taxon diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 22fa5b3b8b..443a9dd8a9 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -4,8 +4,8 @@ Spree::Product.class_eval do # https://github.com/rails/rails/issues/7618 has_many :option_types, :through => :product_option_types, :dependent => :destroy - belongs_to :supplier, :class_name => 'Enterprise' - belongs_to :primary_taxon, class_name: 'Spree::Taxon' + belongs_to :supplier, :class_name => 'Enterprise', touch: true + belongs_to :primary_taxon, class_name: 'Spree::Taxon', touch: true has_many :product_distributions, :dependent => :destroy has_many :distributors, :through => :product_distributions diff --git a/app/serializers/api/address_serializer.rb b/app/serializers/api/address_serializer.rb index a4dfcb0f5f..98344e0315 100644 --- a/app/serializers/api/address_serializer.rb +++ b/app/serializers/api/address_serializer.rb @@ -1,4 +1,7 @@ class Api::AddressSerializer < ActiveModel::Serializer + cached + delegate :cache_key, to: :object + attributes :id, :zipcode, :city, :state def state diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index a74606dd79..c0b79084f0 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -1,9 +1,58 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer + # To improve this: http://hawkins.io/2013/06/caching_object_graphs_with_active_model_serializers/ + # + # Taxons: + # classifications touch products + # products touch suppliers + # Taxon could change but unlikely: if becomes a problem dereference + # + # Relatives: + # Enterprise_relationships touches parent, child + # Otherwise dereferencing makes easy + # + # Address: + # Fine + # + # Shipping Methods: + # Create distributors_shipping_methods class + # Set up touches + + def serializable_hash + cached_serializer_hash.merge uncached_serializer_hash + end + + private + + def cached_serializer_hash + Api::CachedEnterpriseSerializer.new(object, @options).serializable_hash + end + + def uncached_serializer_hash + Api::UncachedEnterpriseSerializer.new(object, @options).serializable_hash + end +end + +class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer + attributes :orders_close_at, :active + + def orders_close_at + OrderCycle.first_closing_for(object).andand.orders_close_at + end + + def active + @options[:active_distributors].andand.include?(object) + end +end + +class Api::CachedEnterpriseSerializer < ActiveModel::Serializer + cached + delegate :cache_key, to: :object + attributes :name, :id, :description, :latitude, :longitude, :long_description, :website, :instagram, :linkedin, :twitter, :facebook, :is_primary_producer, :is_distributor, :phone, :visible, :email, :hash, :logo, :promo_image, :icon, :path, - :pickup, :delivery, :active, :orders_close_at + :pickup, :delivery has_many :distributed_taxons, key: :taxons, serializer: Api::TaxonSerializer has_many :supplied_taxons, serializer: Api::TaxonSerializer @@ -20,14 +69,6 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer object.shipping_methods.where(:require_ship_address => true).present? end - def active - @options[:active_distributors].andand.include?(object) - end - - def orders_close_at - OrderCycle.first_closing_for(object).andand.orders_close_at - end - def email object.email.to_s.reverse end diff --git a/app/serializers/api/taxon_serializer.rb b/app/serializers/api/taxon_serializer.rb index a907532a6b..352a158e95 100644 --- a/app/serializers/api/taxon_serializer.rb +++ b/app/serializers/api/taxon_serializer.rb @@ -1,4 +1,7 @@ class Api::TaxonSerializer < ActiveModel::Serializer + cached + delegate :cache_key, to: :object + attributes :id, :name, :permalink, :icon def icon diff --git a/config/environments/development.rb b/config/environments/development.rb index 62642f7809..efa229e33c 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -5,6 +5,7 @@ Openfoodnetwork::Application.configure do # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false + config.cache_store = :memory_store # Log error messages when you accidentally call methods on nil. config.whiny_nils = true From 8b98c72336e7410b6dc898f5105be50eb6d19995 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 12:08:21 +1000 Subject: [PATCH 043/145] Adding all the Angular filters required to make this work --- .../darkswarm/filters/active.js.coffee | 14 +++++++++ .../darkswarm/filters/shipping.js.coffee | 13 ++++++++ .../darkswarm/filters/taxons.js.coffee | 10 +++++++ .../darkswarm/filters/active_spec.js.coffee | 28 +++++++++++++++++ .../darkswarm/filters/shipping_spec.js.coffee | 30 +++++++++++++++++++ .../darkswarm/filters/taxons_spec.js.coffee | 27 +++++++++++++++++ 6 files changed, 122 insertions(+) create mode 100644 app/assets/javascripts/darkswarm/filters/active.js.coffee create mode 100644 app/assets/javascripts/darkswarm/filters/shipping.js.coffee create mode 100644 app/assets/javascripts/darkswarm/filters/taxons.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee diff --git a/app/assets/javascripts/darkswarm/filters/active.js.coffee b/app/assets/javascripts/darkswarm/filters/active.js.coffee new file mode 100644 index 0000000000..93bf1c658c --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/active.js.coffee @@ -0,0 +1,14 @@ +Darkswarm.filter 'active', ()-> + (objects, options)-> + objects ||= [] + options ?= null + + if options.open and !options.closed + objects.filter (obj)-> + obj.active + else if options.closed and !options.open + objects.filter (obj)-> + !obj.active + else + objects + diff --git a/app/assets/javascripts/darkswarm/filters/shipping.js.coffee b/app/assets/javascripts/darkswarm/filters/shipping.js.coffee new file mode 100644 index 0000000000..761e34337d --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/shipping.js.coffee @@ -0,0 +1,13 @@ +Darkswarm.filter 'shipping', ()-> + (objects, options)-> + objects ||= [] + options ?= null + + if options.pickup and !options.delivery + objects.filter (obj)-> + obj.pickup + else if options.delivery and !options.pickup + objects.filter (obj)-> + obj.delivery + else + objects diff --git a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee new file mode 100644 index 0000000000..c060647ac5 --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee @@ -0,0 +1,10 @@ +Darkswarm.filter 'taxons', (Matcher)-> + # Filter anything that responds to object.taxons, and/or object.primary_taxon + (objects, text) -> + objects ||= [] + text ?= "" + objects.filter (obj)-> + Matcher.match([obj.primary_taxon?.name || ""], text) || obj.taxons.some (taxon)-> + Matcher.match [taxon.name], text + + diff --git a/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee new file mode 100644 index 0000000000..337121b1ae --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee @@ -0,0 +1,28 @@ +describe 'filtering by active', -> + filterByActive = null + objects = [ + { + active: true + } + { + active: false + } + ] + + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filterByActive = $filter('active') + + it "filters to active", -> + expect(filterByActive(objects, {closed: false, open: true})[0]).toBe objects[0] + + it "filters to inactive", -> + expect(filterByActive(objects, {closed: true, open: false})[0]).toBe objects[1] + + it "doesn't filter if needed", -> + expect(filterByActive(objects, {closed: false, open: false})).toBe objects + + it "filters to all", -> + expect(filterByActive(objects, {closed: true, open: true})).toBe objects diff --git a/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee new file mode 100644 index 0000000000..bfb5ffe606 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee @@ -0,0 +1,30 @@ +describe 'filtering by shipping method', -> + filterByShippingMethod = null + objects = [ + { + delivery: true + pickup: false + } + { + delivery: false + pickup: true + } + ] + + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filterByShippingMethod = $filter('shipping') + + it "filters to pickup", -> + expect(filterByShippingMethod(objects, {pickup: true, delivery: false})[0]).toBe objects[1] + + it "filters to delivery", -> + expect(filterByShippingMethod(objects, {pickup: false, delivery: true})[0]).toBe objects[0] + + it "filters to both", -> + expect(filterByShippingMethod(objects, {pickup: true, delivery: true})).toBe objects + + it "filters to none", -> + expect(filterByShippingMethod(objects, {pickup: false, delivery: false})).toBe objects diff --git a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee new file mode 100644 index 0000000000..fee894353c --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee @@ -0,0 +1,27 @@ +describe 'filtering by taxons', -> + filterByTaxons = null + objects = [ + { + taxons: [] + primary_taxon: + name: "frogs" + } + { + taxons: [ + {name: "kittens"} + {name: "puppies"} + ] + } + ] + + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filterByTaxons = $filter('taxons') + + it "filters by primary taxon", -> + expect(filterByTaxons(objects, "frogs")[0]).toBe objects[0] + + it "filters by taxons", -> + expect(filterByTaxons(objects, "kittens")[0]).toBe objects[1] From e858c0d434733bb4a5a2361a793210fdf2573ee2 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 12:10:33 +1000 Subject: [PATCH 044/145] Moving taxon filter to ID instead of name --- .../javascripts/darkswarm/filters/taxons.js.coffee | 10 ++++------ .../unit/darkswarm/filters/taxons_spec.js.coffee | 11 +++++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee index c060647ac5..e10228b648 100644 --- a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee @@ -1,10 +1,8 @@ Darkswarm.filter 'taxons', (Matcher)-> # Filter anything that responds to object.taxons, and/or object.primary_taxon - (objects, text) -> + (objects, id) -> objects ||= [] - text ?= "" + id ?= 0 objects.filter (obj)-> - Matcher.match([obj.primary_taxon?.name || ""], text) || obj.taxons.some (taxon)-> - Matcher.match [taxon.name], text - - + obj.primary_taxon?.id == id || obj.taxons.some (taxon)-> + taxon.id == id diff --git a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee index fee894353c..f8b387b9a7 100644 --- a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee @@ -5,11 +5,12 @@ describe 'filtering by taxons', -> taxons: [] primary_taxon: name: "frogs" + id: 1 } { taxons: [ - {name: "kittens"} - {name: "puppies"} + {name: "kittens", id: 2} + {name: "puppies", id: 3} ] } ] @@ -21,7 +22,9 @@ describe 'filtering by taxons', -> filterByTaxons = $filter('taxons') it "filters by primary taxon", -> - expect(filterByTaxons(objects, "frogs")[0]).toBe objects[0] + expect(filterByTaxons(objects, 1)[0]).toBe objects[0] it "filters by taxons", -> - expect(filterByTaxons(objects, "kittens")[0]).toBe objects[1] + expect(filterByTaxons(objects, 2)[0]).toBe objects[1] + + From 4a116570d1cdb00ca4da7647e9b34e88580b306c Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 12:13:50 +1000 Subject: [PATCH 045/145] adding by producer id filtering --- .../darkswarm/filters/by_producer.js.coffee | 6 ++++++ .../filters/by_producer_spec.js.coffee | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 app/assets/javascripts/darkswarm/filters/by_producer.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/filters/by_producer_spec.js.coffee diff --git a/app/assets/javascripts/darkswarm/filters/by_producer.js.coffee b/app/assets/javascripts/darkswarm/filters/by_producer.js.coffee new file mode 100644 index 0000000000..3b9ec12d2b --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/by_producer.js.coffee @@ -0,0 +1,6 @@ +Darkswarm.filter "byProducer", -> + (objects, id) -> + objects ||= [] + id ?= 0 + objects.filter (obj)-> + obj.producer.id == id diff --git a/spec/javascripts/unit/darkswarm/filters/by_producer_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/by_producer_spec.js.coffee new file mode 100644 index 0000000000..48b811a11f --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/by_producer_spec.js.coffee @@ -0,0 +1,21 @@ +describe 'filtering by producer', -> + filterByProducer = null + objects = [ + { + producer: + id: 1 + } + { + producer: + id: 2 + } + ] + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filterByProducer = $filter('byProducer') + + it "filters by producer", -> + expect(filterByProducer(objects, 1)[0]).toBe objects[0] + expect(filterByProducer(objects, 2)[0]).toBe objects[1] From 24d3abf6d544cf56b64843bbf9364f256e786db3 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 12:30:28 +1000 Subject: [PATCH 046/145] Adding dereferencing to taxons and reducing our data-set --- .../darkswarm/services/enterprises.js.coffee | 11 ++++++++--- .../darkswarm/services/taxons.js.coffee | 8 ++++++++ app/helpers/shared_helper.rb | 4 ++++ app/serializers/api/enterprise_serializer.rb | 2 +- app/views/layouts/darkswarm.html.haml | 1 + spec/helpers/shared_helper_spec.rb | 7 ++++++- .../darkswarm/services/enterprise_spec.js.coffee | 9 ++++++++- .../unit/darkswarm/services/taxon_spec.js.coffee | 16 ++++++++++++++++ 8 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/services/taxons.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index b442773d31..84a3c2e7c2 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -1,15 +1,20 @@ -Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Dereferencer)-> +Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer)-> new class Enterprises enterprises_by_id: {} # id/object pairs for lookup constructor: -> @enterprises = enterprises for enterprise in enterprises @enterprises_by_id[enterprise.id] = enterprise - @dereference() + @dereferenceEnterprises() + @dereferenceTaxons() - dereference: -> + dereferenceEnterprises: -> if CurrentHub.hub?.id CurrentHub.hub = @enterprises_by_id[CurrentHub.hub.id] for enterprise in @enterprises Dereferencer.dereference enterprise.hubs, @enterprises_by_id Dereferencer.dereference enterprise.producers, @enterprises_by_id + + dereferenceTaxons: -> + for enterprise in @enterprises + Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id diff --git a/app/assets/javascripts/darkswarm/services/taxons.js.coffee b/app/assets/javascripts/darkswarm/services/taxons.js.coffee new file mode 100644 index 0000000000..cbe6c118e0 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/taxons.js.coffee @@ -0,0 +1,8 @@ +Darkswarm.factory "Taxons", (taxons)-> + new class Taxons + taxons: taxons + taxons_by_id: {} + constructor: -> + for taxon in @taxons + @taxons_by_id[taxon.id] = taxon + diff --git a/app/helpers/shared_helper.rb b/app/helpers/shared_helper.rb index f555a9f695..ff4310a8f0 100644 --- a/app/helpers/shared_helper.rb +++ b/app/helpers/shared_helper.rb @@ -3,6 +3,10 @@ module SharedHelper inject_json_ams "enterprises", Enterprise.all, Api::EnterpriseSerializer, active_distributors: @active_distributors end + def inject_taxons + inject_json_ams "taxons", Spree::Taxon.all, Api::TaxonSerializer + end + def inject_json(name, partial, opts = {}) render partial: "json/injection", locals: {name: name, partial: partial}.merge(opts) end diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index c0b79084f0..c643bf5b21 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -55,7 +55,7 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer :pickup, :delivery has_many :distributed_taxons, key: :taxons, serializer: Api::TaxonSerializer - has_many :supplied_taxons, serializer: Api::TaxonSerializer + has_many :supplied_taxons, serializer: Api::IdSerializer has_many :distributors, key: :hubs, serializer: Api::IdSerializer has_many :suppliers, key: :producers, serializer: Api::IdSerializer diff --git a/app/views/layouts/darkswarm.html.haml b/app/views/layouts/darkswarm.html.haml index 3d246acab8..f831d93d17 100644 --- a/app/views/layouts/darkswarm.html.haml +++ b/app/views/layouts/darkswarm.html.haml @@ -28,6 +28,7 @@ = inject_json "currentOrder", "current_order" = inject_json "user", "current_user" = inject_json "railsFlash", "flash" + = inject_taxons .off-canvas-wrap{offcanvas: true} .inner-wrap diff --git a/spec/helpers/shared_helper_spec.rb b/spec/helpers/shared_helper_spec.rb index 76d2e6e859..d1d99c331f 100644 --- a/spec/helpers/shared_helper_spec.rb +++ b/spec/helpers/shared_helper_spec.rb @@ -32,9 +32,14 @@ describe SharedHelper do end it "injects enterprises" do - Enterprise.stub(:visible).and_return [enterprise] helper.inject_enterprises().should match enterprise.name helper.inject_enterprises().should match enterprise.facebook end + + it "injects taxons" do + taxon = create(:taxon) + helper.inject_taxons.should match taxon.name + end end + end diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee index ebf480d9e8..59d4ae9826 100644 --- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee @@ -1,8 +1,11 @@ describe "Enterprises service", -> Enterprises = null CurrentHubMock = {} + taxons = [ + {id: 1, name: "test"} + ] enterprises = [ - {id: 1, type: "hub", producers: [{id: 2}]}, + {id: 1, type: "hub", producers: [{id: 2}], taxons: [{id: 1}]}, {id: 2, type: "producer", hubs: [{id: 1}]}, {id: 3, type: "producer", hubs: [{id: 1}]} ] @@ -12,6 +15,7 @@ describe "Enterprises service", -> $provide.value "CurrentHub", CurrentHubMock null angular.module('Darkswarm').value('enterprises', enterprises) + angular.module('Darkswarm').value('taxons', taxons) inject ($injector)-> Enterprises = $injector.get("Enterprises") @@ -29,3 +33,6 @@ describe "Enterprises service", -> it "dereferences references to other enterprises", -> expect(Enterprises.enterprises_by_id["1"].producers[0]).toBe enterprises[1] expect(Enterprises.enterprises_by_id["3"].hubs[0]).toBe enterprises[0] + + it "dereferences taxons", -> + expect(Enterprises.enterprises[0].taxons[0]).toBe taxons[0] diff --git a/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee new file mode 100644 index 0000000000..b05c82a13d --- /dev/null +++ b/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee @@ -0,0 +1,16 @@ +describe "Taxons service", -> + Taxons = null + taxons = [ + {id: 1, name: "test"} + {id: 2, name: "Roger"} + ] + + beforeEach -> + module('Darkswarm') + angular.module('Darkswarm').value 'taxons', taxons + + inject ($injector)-> + Taxons = $injector.get("Taxons") + + it "caches taxons in an id-referenced hash", -> + expect(Taxons.taxons_by_id[1]).toBe taxons[0] From 3195e20b65b5b3bf2d32566b76532d978a80dde0 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 13:17:54 +1000 Subject: [PATCH 047/145] cleaning up touches --- app/models/enterprise.rb | 2 +- app/models/spree/classification_decorator.rb | 1 - app/models/spree/product_decorator.rb | 1 - app/serializers/api/enterprise_serializer.rb | 1 - app/views/producers/index.haml | 60 ++++++++++---------- 5 files changed, 31 insertions(+), 34 deletions(-) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index d42031273d..5b922b15e4 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -7,7 +7,7 @@ class Enterprise < ActiveRecord::Base has_many :producer_properties, foreign_key: 'producer_id' has_many :supplied_products, :class_name => 'Spree::Product', :foreign_key => 'supplier_id', :dependent => :destroy has_many :distributed_orders, :class_name => 'Spree::Order', :foreign_key => 'distributor_id' - belongs_to :address, :class_name => 'Spree::Address', touch: true + belongs_to :address, :class_name => 'Spree::Address' has_many :product_distributions, :foreign_key => 'distributor_id', :dependent => :destroy has_many :distributed_products, :through => :product_distributions, :source => :product has_many :enterprise_fees diff --git a/app/models/spree/classification_decorator.rb b/app/models/spree/classification_decorator.rb index 8fa201528c..c69eb01fcf 100644 --- a/app/models/spree/classification_decorator.rb +++ b/app/models/spree/classification_decorator.rb @@ -1,6 +1,5 @@ Spree::Classification.class_eval do belongs_to :product, :class_name => "Spree::Product", touch: true - belongs_to :taxon, :class_name => "Spree::Taxon", touch: true before_destroy :dont_destroy_if_primary_taxon def dont_destroy_if_primary_taxon diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 443a9dd8a9..6de297cba9 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -5,7 +5,6 @@ Spree::Product.class_eval do has_many :option_types, :through => :product_option_types, :dependent => :destroy belongs_to :supplier, :class_name => 'Enterprise', touch: true - belongs_to :primary_taxon, class_name: 'Spree::Taxon', touch: true has_many :product_distributions, :dependent => :destroy has_many :distributors, :through => :product_distributions diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index c643bf5b21..c929bf2c55 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -4,7 +4,6 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer # Taxons: # classifications touch products # products touch suppliers - # Taxon could change but unlikely: if becomes a problem dereference # # Relatives: # Enterprise_relationships touches parent, child diff --git a/app/views/producers/index.haml b/app/views/producers/index.haml index 5cde67a512..2d4c834191 100644 --- a/app/views/producers/index.haml +++ b/app/views/producers/index.haml @@ -1,35 +1,35 @@ = inject_enterprises -.producers{"ng-controller" => "ProducersCtrl"} - .row - .small-12.columns.text-center.pad-top - %h1 Producers - %div - Select a - %ofn-modal{title: "producer"} - = render partial: "modals/producers" - from the list below: +-#.producers{"ng-controller" => "ProducersCtrl"} + -#.row + -#.small-12.columns.text-center.pad-top + -#%h1 Producers + -#%div + -#Select a + -#%ofn-modal{title: "producer"} + -#= render partial: "modals/producers" + -#from the list below: - #active-table-search.row.pad-top - .small-12.columns - %i.ofn-i_020-search - %input{type: :text, - "ng-model" => "query", - placeholder: "Search postcode, suburb or producer name...", - "ng-debounce" => "150", - "ofn-disable-enter" => true} + -##active-table-search.row.pad-top + -#.small-12.columns + -#%i.ofn-i_020-search + -#%input{type: :text, + -#"ng-model" => "query", + -#placeholder: "Search postcode, suburb or producer name...", + -#"ng-debounce" => "150", + -#"ofn-disable-enter" => true} - .row{bindonce: true} - .small-12.columns - .active_table - %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - "scroll-after-load" => true, - "ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query)", - "ng-controller" => "ProducerNodeCtrl", - "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", - id: "{{producer.hash}}"} + -#.row{bindonce: true} + -#.small-12.columns + -#.active_table + -#%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", + -#"scroll-after-load" => true, + -#"ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query)", + -#"ng-controller" => "ProducerNodeCtrl", + -#"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", + -#id: "{{producer.hash}}"} - .small-12.columns - = render partial: 'producers/skinny' - = render partial: 'producers/fat' + -#.small-12.columns + -#= render partial: 'producers/skinny' + -#= render partial: 'producers/fat' -= render partial: "shared/footer" +-#= render partial: "shared/footer" From 23034a55d47decd29587fc21cb7af7d7451bf043 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 16:04:14 +1000 Subject: [PATCH 048/145] Adding tests and full touch behaviour for caching --- app/models/distributor_shipping_method.rb | 5 ++ app/models/enterprise.rb | 3 +- app/models/spree/product_decorator.rb | 6 +++ app/models/spree/shipping_method_decorator.rb | 11 +++- app/serializers/api/enterprise_serializer.rb | 20 +------- ...fields_to_distributors_shipping_methods.rb | 7 +++ db/schema.rb | 10 ++-- .../distributor_shipping_method_spec.rb | 5 ++ spec/models/enterprise_caching_spec.rb | 51 +++++++++++++++++++ 9 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 app/models/distributor_shipping_method.rb create mode 100644 db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb create mode 100644 spec/models/distributor_shipping_method_spec.rb create mode 100644 spec/models/enterprise_caching_spec.rb diff --git a/app/models/distributor_shipping_method.rb b/app/models/distributor_shipping_method.rb new file mode 100644 index 0000000000..e765a23e50 --- /dev/null +++ b/app/models/distributor_shipping_method.rb @@ -0,0 +1,5 @@ +class DistributorShippingMethod < ActiveRecord::Base + self.table_name = "distributors_shipping_methods" + belongs_to :shipping_method, class_name: Spree::ShippingMethod + belongs_to :distributor, class_name: Enterprise, touch: true +end diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 5b922b15e4..e5250309b4 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -14,7 +14,8 @@ class Enterprise < ActiveRecord::Base has_many :enterprise_roles, :dependent => :destroy has_many :users, through: :enterprise_roles has_and_belongs_to_many :payment_methods, join_table: 'distributors_payment_methods', class_name: 'Spree::PaymentMethod', foreign_key: 'distributor_id' - has_and_belongs_to_many :shipping_methods, join_table: 'distributors_shipping_methods', class_name: 'Spree::ShippingMethod', foreign_key: 'distributor_id' + has_many :distributor_shipping_methods, foreign_key: :distributor_id + has_many :shipping_methods, through: :distributor_shipping_methods delegate :latitude, :longitude, :city, :state_name, :to => :address diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 6de297cba9..e0cc8cc436 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -5,6 +5,7 @@ Spree::Product.class_eval do has_many :option_types, :through => :product_option_types, :dependent => :destroy belongs_to :supplier, :class_name => 'Enterprise', touch: true + belongs_to :primary_taxon, class_name: 'Spree::Taxon' has_many :product_distributions, :dependent => :destroy has_many :distributors, :through => :product_distributions @@ -27,6 +28,7 @@ Spree::Product.class_eval do after_initialize :set_available_on_to_now, :if => :new_record? after_save :update_units + after_touch :touch_distributors before_save :add_primary_taxon_to_taxons @@ -186,6 +188,10 @@ Spree::Product.class_eval do end end + def touch_distributors + Enterprise.distributing_product(self).each(&:touch) + end + def add_primary_taxon_to_taxons taxons << primary_taxon unless taxons.find_by_id(primary_taxon) end diff --git a/app/models/spree/shipping_method_decorator.rb b/app/models/spree/shipping_method_decorator.rb index 5d7bb89a8f..4a2cf75b47 100644 --- a/app/models/spree/shipping_method_decorator.rb +++ b/app/models/spree/shipping_method_decorator.rb @@ -1,5 +1,8 @@ Spree::ShippingMethod.class_eval do - has_and_belongs_to_many :distributors, join_table: 'distributors_shipping_methods', :class_name => 'Enterprise', association_foreign_key: 'distributor_id' + has_many :distributor_shipping_methods + has_many :distributors, through: :distributor_shipping_methods, class_name: 'Enterprise', foreign_key: 'distributor_id' + + after_save :touch_distributors attr_accessible :distributor_ids, :description attr_accessible :require_ship_address @@ -43,4 +46,10 @@ Spree::ShippingMethod.class_eval do def adjustment_label 'Shipping' end + + private + + def touch_distributors + distributors.each(&:touch) + end end diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index c929bf2c55..3ef46f1724 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -1,20 +1,5 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer # To improve this: http://hawkins.io/2013/06/caching_object_graphs_with_active_model_serializers/ - # - # Taxons: - # classifications touch products - # products touch suppliers - # - # Relatives: - # Enterprise_relationships touches parent, child - # Otherwise dereferencing makes easy - # - # Address: - # Fine - # - # Shipping Methods: - # Create distributors_shipping_methods class - # Set up touches def serializable_hash cached_serializer_hash.merge uncached_serializer_hash @@ -33,6 +18,7 @@ end class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer attributes :orders_close_at, :active + has_one :address, serializer: Api::AddressSerializer def orders_close_at OrderCycle.first_closing_for(object).andand.orders_close_at @@ -53,13 +39,11 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer :email, :hash, :logo, :promo_image, :icon, :path, :pickup, :delivery - has_many :distributed_taxons, key: :taxons, serializer: Api::TaxonSerializer + has_many :distributed_taxons, key: :taxons, serializer: Api::IdSerializer has_many :supplied_taxons, serializer: Api::IdSerializer has_many :distributors, key: :hubs, serializer: Api::IdSerializer has_many :suppliers, key: :producers, serializer: Api::IdSerializer - has_one :address, serializer: Api::AddressSerializer - def pickup object.shipping_methods.where(:require_ship_address => false).present? end diff --git a/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb b/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb new file mode 100644 index 0000000000..ed54707cb1 --- /dev/null +++ b/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb @@ -0,0 +1,7 @@ +class AddFieldsToDistributorsShippingMethods < ActiveRecord::Migration + def change + add_column :distributors_shipping_methods, :id, :primary_key + add_column :distributors_shipping_methods, :created_at, :datetime + add_column :distributors_shipping_methods, :updated_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 5932749993..608cdb299b 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 => 20140613004344) do +ActiveRecord::Schema.define(:version => 20140702053145) do create_table "adjustment_metadata", :force => true do |t| t.integer "adjustment_id" @@ -163,9 +163,11 @@ ActiveRecord::Schema.define(:version => 20140613004344) do add_index "distributors_payment_methods", ["distributor_id"], :name => "index_distributors_payment_methods_on_distributor_id" add_index "distributors_payment_methods", ["payment_method_id"], :name => "index_distributors_payment_methods_on_payment_method_id" - create_table "distributors_shipping_methods", :id => false, :force => true do |t| - t.integer "distributor_id" - t.integer "shipping_method_id" + create_table "distributors_shipping_methods", :force => true do |t| + t.integer "distributor_id" + t.integer "shipping_method_id" + t.datetime "created_at" + t.datetime "updated_at" end add_index "distributors_shipping_methods", ["distributor_id"], :name => "index_distributors_shipping_methods_on_distributor_id" diff --git a/spec/models/distributor_shipping_method_spec.rb b/spec/models/distributor_shipping_method_spec.rb new file mode 100644 index 0000000000..bd8d7d2973 --- /dev/null +++ b/spec/models/distributor_shipping_method_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe DistributorShippingMethod do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/enterprise_caching_spec.rb b/spec/models/enterprise_caching_spec.rb new file mode 100644 index 0000000000..af05897a6e --- /dev/null +++ b/spec/models/enterprise_caching_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe Enterprise do + context "key-based caching invalidation" do + describe "is touched when a(n)" do + let(:enterprise) { create(:distributor_enterprise, updated_at: 1.week.ago) } + let(:taxon) { create(:taxon) } + + describe "with supplied taxon" do + let(:product) { create(:simple_product, supplier: enterprise) } + let!(:classification) { create(:classification, taxon: taxon, product: product) } + it "supplied taxon is updated" do + expect{classification.save!}.to change{enterprise.updated_at} + end + end + + describe "with distributed taxon" do + let(:product) { create(:simple_product) } + let!(:oc) { create(:simple_order_cycle, distributors: [enterprise], variants: [product.master]) } + let!(:classification) { create(:classification, taxon: taxon, product: product) } + it "distributed taxon is updated" do + expect{classification.save!}.to change{enterprise.reload.updated_at} + end + end + + describe "with relatives" do + let(:child_enterprise) { create(:supplier_enterprise) } + let!(:er) { create(:enterprise_relationship, parent: enterprise, child: child_enterprise) } + it "enterprise relationship is updated" do + expect{er.save!}.to change {enterprise.reload.updated_at } + end + end + + describe "with shipping methods" do + let(:sm) { create(:shipping_method) } + before do + enterprise.shipping_methods << sm + end + it "distributor_shipping_method is updated" do + expect { + enterprise.distributor_shipping_methods.first.save! + }.to change {enterprise.reload.updated_at} + end + + it "shipping method is updated" do + expect{sm.save!}.to change {enterprise.reload.updated_at } + end + end + end + end +end From 1f6641766d492812e57d865eb61d88ac012ba4ab Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 16:08:19 +1000 Subject: [PATCH 049/145] Restoring Producers page --- app/views/producers/index.haml | 60 +++++++++++++++++----------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/app/views/producers/index.haml b/app/views/producers/index.haml index 2d4c834191..5cde67a512 100644 --- a/app/views/producers/index.haml +++ b/app/views/producers/index.haml @@ -1,35 +1,35 @@ = inject_enterprises --#.producers{"ng-controller" => "ProducersCtrl"} - -#.row - -#.small-12.columns.text-center.pad-top - -#%h1 Producers - -#%div - -#Select a - -#%ofn-modal{title: "producer"} - -#= render partial: "modals/producers" - -#from the list below: +.producers{"ng-controller" => "ProducersCtrl"} + .row + .small-12.columns.text-center.pad-top + %h1 Producers + %div + Select a + %ofn-modal{title: "producer"} + = render partial: "modals/producers" + from the list below: - -##active-table-search.row.pad-top - -#.small-12.columns - -#%i.ofn-i_020-search - -#%input{type: :text, - -#"ng-model" => "query", - -#placeholder: "Search postcode, suburb or producer name...", - -#"ng-debounce" => "150", - -#"ofn-disable-enter" => true} + #active-table-search.row.pad-top + .small-12.columns + %i.ofn-i_020-search + %input{type: :text, + "ng-model" => "query", + placeholder: "Search postcode, suburb or producer name...", + "ng-debounce" => "150", + "ofn-disable-enter" => true} - -#.row{bindonce: true} - -#.small-12.columns - -#.active_table - -#%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - -#"scroll-after-load" => true, - -#"ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query)", - -#"ng-controller" => "ProducerNodeCtrl", - -#"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", - -#id: "{{producer.hash}}"} + .row{bindonce: true} + .small-12.columns + .active_table + %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", + "scroll-after-load" => true, + "ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query)", + "ng-controller" => "ProducerNodeCtrl", + "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", + id: "{{producer.hash}}"} - -#.small-12.columns - -#= render partial: 'producers/skinny' - -#= render partial: 'producers/fat' + .small-12.columns + = render partial: 'producers/skinny' + = render partial: 'producers/fat' --#= render partial: "shared/footer" += render partial: "shared/footer" From 74f29f8c74ad2d84baa7b3faa97dddb83b7a4f02 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 16:36:37 +1000 Subject: [PATCH 050/145] Tweaking spec names --- spec/models/enterprise_caching_spec.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/models/enterprise_caching_spec.rb b/spec/models/enterprise_caching_spec.rb index af05897a6e..51ed68aace 100644 --- a/spec/models/enterprise_caching_spec.rb +++ b/spec/models/enterprise_caching_spec.rb @@ -6,19 +6,19 @@ describe Enterprise do let(:enterprise) { create(:distributor_enterprise, updated_at: 1.week.ago) } let(:taxon) { create(:taxon) } - describe "with supplied taxon" do + describe "with a supplied product" do let(:product) { create(:simple_product, supplier: enterprise) } let!(:classification) { create(:classification, taxon: taxon, product: product) } - it "supplied taxon is updated" do + it "touches enterprise when a classification on that product changes" do expect{classification.save!}.to change{enterprise.updated_at} end end - describe "with distributed taxon" do + describe "with a distributed product" do let(:product) { create(:simple_product) } let!(:oc) { create(:simple_order_cycle, distributors: [enterprise], variants: [product.master]) } let!(:classification) { create(:classification, taxon: taxon, product: product) } - it "distributed taxon is updated" do + it "touches enterprise when a classification on that product changes" do expect{classification.save!}.to change{enterprise.reload.updated_at} end end @@ -26,7 +26,7 @@ describe Enterprise do describe "with relatives" do let(:child_enterprise) { create(:supplier_enterprise) } let!(:er) { create(:enterprise_relationship, parent: enterprise, child: child_enterprise) } - it "enterprise relationship is updated" do + it "touches enterprise when enterprise relationship is updated" do expect{er.save!}.to change {enterprise.reload.updated_at } end end @@ -36,13 +36,13 @@ describe Enterprise do before do enterprise.shipping_methods << sm end - it "distributor_shipping_method is updated" do + it "touches enterprise when distributor_shipping_method is updated" do expect { enterprise.distributor_shipping_methods.first.save! }.to change {enterprise.reload.updated_at} end - it "shipping method is updated" do + it "touches enterprise when shipping method is updated" do expect{sm.save!}.to change {enterprise.reload.updated_at } end end From 61d8be3ddcea38a183226bcff83617882d648a9c Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 16:40:21 +1000 Subject: [PATCH 051/145] Removing old file, renaming one to match naming conventions --- app/assets/javascripts/templates/test.nghaml | 1 - app/views/producers/{index.haml => index.html.haml} | 0 2 files changed, 1 deletion(-) delete mode 100644 app/assets/javascripts/templates/test.nghaml rename app/views/producers/{index.haml => index.html.haml} (100%) diff --git a/app/assets/javascripts/templates/test.nghaml b/app/assets/javascripts/templates/test.nghaml deleted file mode 100644 index 99fb61374e..0000000000 --- a/app/assets/javascripts/templates/test.nghaml +++ /dev/null @@ -1 +0,0 @@ -Frogs diff --git a/app/views/producers/index.haml b/app/views/producers/index.html.haml similarity index 100% rename from app/views/producers/index.haml rename to app/views/producers/index.html.haml From 0177a564086a66b156ce401fd2df2363d52d1948 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 2 Jul 2014 16:53:21 +1000 Subject: [PATCH 052/145] Caching address and touching enterprise on save --- app/models/spree/address_decorator.rb | 6 ++++++ app/serializers/api/enterprise_serializer.rb | 3 ++- spec/models/enterprise_caching_spec.rb | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/models/spree/address_decorator.rb b/app/models/spree/address_decorator.rb index 28f292fbd3..8797a91599 100644 --- a/app/models/spree/address_decorator.rb +++ b/app/models/spree/address_decorator.rb @@ -2,6 +2,8 @@ Spree::Address.class_eval do has_one :enterprise belongs_to :country, class_name: "Spree::Country" + after_save :touch_enterprise + geocoded_by :full_address delegate :name, :to => :state, :prefix => true, :allow_nil => true @@ -15,6 +17,10 @@ Spree::Address.class_eval do private + def touch_enterprise + enterprise.andand.touch + end + # We have a hard-to-track-down bug around invalid addresses with all-nil fields finding # their way into the database. I don't know what the source of them is, so this patch # is designed to track them down. diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index 3ef46f1724..23aa2a7458 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -18,7 +18,6 @@ end class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer attributes :orders_close_at, :active - has_one :address, serializer: Api::AddressSerializer def orders_close_at OrderCycle.first_closing_for(object).andand.orders_close_at @@ -44,6 +43,8 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer has_many :distributors, key: :hubs, serializer: Api::IdSerializer has_many :suppliers, key: :producers, serializer: Api::IdSerializer + #has_one :address, serializer: Api::AddressSerializer + def pickup object.shipping_methods.where(:require_ship_address => false).present? end diff --git a/spec/models/enterprise_caching_spec.rb b/spec/models/enterprise_caching_spec.rb index 51ed68aace..72b356df21 100644 --- a/spec/models/enterprise_caching_spec.rb +++ b/spec/models/enterprise_caching_spec.rb @@ -46,6 +46,10 @@ describe Enterprise do expect{sm.save!}.to change {enterprise.reload.updated_at } end end + + it "touches enterprise when address is updated" do + expect{enterprise.address.save!}.to change {enterprise.reload.updated_at } + end end end end From 6d4dfad3369d563d2d7132a3167c33ee8f830ae2 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 3 Jul 2014 11:40:33 +1000 Subject: [PATCH 053/145] OK address no longer being lazy-loaded --- .../darkswarm/services/enterprises.js.coffee | 1 + app/models/enterprise.rb | 6 -- app/serializers/api/enterprise_serializer.rb | 4 +- app/views/producers/index.html.haml | 60 +++++++++---------- 4 files changed, 32 insertions(+), 39 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 84a3c2e7c2..0f8a6b2b16 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -1,4 +1,5 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer)-> + console.log enterprises[0].address new class Enterprises enterprises_by_id: {} # id/object pairs for lookup constructor: -> diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index e5250309b4..c74144446b 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -30,7 +30,6 @@ class Enterprise < ActiveRecord::Base validates_presence_of :address validates_associated :address - after_initialize :initialize_country before_validation :set_unused_address_fields after_validation :geocode_address @@ -207,11 +206,6 @@ class Enterprise < ActiveRecord::Base url.andand.sub /(https?:\/\/)?(www\.)?/, '' end - def initialize_country - self.address ||= Spree::Address.new - self.address.country = Spree::Country.find_by_id(Spree::Config[:default_country_id]) if self.address.new_record? - end - def set_unused_address_fields address.firstname = address.lastname = address.phone = 'unused' if address.present? end diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index 23aa2a7458..c7653db910 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -1,6 +1,4 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer - # To improve this: http://hawkins.io/2013/06/caching_object_graphs_with_active_model_serializers/ - def serializable_hash cached_serializer_hash.merge uncached_serializer_hash end @@ -43,7 +41,7 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer has_many :distributors, key: :hubs, serializer: Api::IdSerializer has_many :suppliers, key: :producers, serializer: Api::IdSerializer - #has_one :address, serializer: Api::AddressSerializer + has_one :address, serializer: Api::AddressSerializer def pickup object.shipping_methods.where(:require_ship_address => false).present? diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 5cde67a512..2d4c834191 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -1,35 +1,35 @@ = inject_enterprises -.producers{"ng-controller" => "ProducersCtrl"} - .row - .small-12.columns.text-center.pad-top - %h1 Producers - %div - Select a - %ofn-modal{title: "producer"} - = render partial: "modals/producers" - from the list below: +-#.producers{"ng-controller" => "ProducersCtrl"} + -#.row + -#.small-12.columns.text-center.pad-top + -#%h1 Producers + -#%div + -#Select a + -#%ofn-modal{title: "producer"} + -#= render partial: "modals/producers" + -#from the list below: - #active-table-search.row.pad-top - .small-12.columns - %i.ofn-i_020-search - %input{type: :text, - "ng-model" => "query", - placeholder: "Search postcode, suburb or producer name...", - "ng-debounce" => "150", - "ofn-disable-enter" => true} + -##active-table-search.row.pad-top + -#.small-12.columns + -#%i.ofn-i_020-search + -#%input{type: :text, + -#"ng-model" => "query", + -#placeholder: "Search postcode, suburb or producer name...", + -#"ng-debounce" => "150", + -#"ofn-disable-enter" => true} - .row{bindonce: true} - .small-12.columns - .active_table - %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - "scroll-after-load" => true, - "ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query)", - "ng-controller" => "ProducerNodeCtrl", - "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", - id: "{{producer.hash}}"} + -#.row{bindonce: true} + -#.small-12.columns + -#.active_table + -#%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", + -#"scroll-after-load" => true, + -#"ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query)", + -#"ng-controller" => "ProducerNodeCtrl", + -#"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", + -#id: "{{producer.hash}}"} - .small-12.columns - = render partial: 'producers/skinny' - = render partial: 'producers/fat' + -#.small-12.columns + -#= render partial: 'producers/skinny' + -#= render partial: 'producers/fat' -= render partial: "shared/footer" +-#= render partial: "shared/footer" From c57148340c89caa02de1f437fe2b0c7be99e6680 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 3 Jul 2014 12:22:26 +1000 Subject: [PATCH 054/145] Fixing spec regression --- app/models/enterprise.rb | 8 +++- app/views/producers/index.html.haml | 60 ++++++++++++++--------------- spec/models/enterprise_spec.rb | 2 +- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index c74144446b..e6279bf226 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -17,7 +17,6 @@ class Enterprise < ActiveRecord::Base has_many :distributor_shipping_methods, foreign_key: :distributor_id has_many :shipping_methods, through: :distributor_shipping_methods - delegate :latitude, :longitude, :city, :state_name, :to => :address accepts_nested_attributes_for :address @@ -30,6 +29,7 @@ class Enterprise < ActiveRecord::Base validates_presence_of :address validates_associated :address + before_create :initialize_country before_validation :set_unused_address_fields after_validation :geocode_address @@ -206,6 +206,12 @@ class Enterprise < ActiveRecord::Base url.andand.sub /(https?:\/\/)?(www\.)?/, '' end + # Give us an empty address on create, and set the country to the default + def initialize_country + self.address ||= Spree::Address.new + self.address.country = Spree::Country.find_by_id(Spree::Config[:default_country_id]) if self.address.new_record? + end + def set_unused_address_fields address.firstname = address.lastname = address.phone = 'unused' if address.present? end diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 2d4c834191..5cde67a512 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -1,35 +1,35 @@ = inject_enterprises --#.producers{"ng-controller" => "ProducersCtrl"} - -#.row - -#.small-12.columns.text-center.pad-top - -#%h1 Producers - -#%div - -#Select a - -#%ofn-modal{title: "producer"} - -#= render partial: "modals/producers" - -#from the list below: +.producers{"ng-controller" => "ProducersCtrl"} + .row + .small-12.columns.text-center.pad-top + %h1 Producers + %div + Select a + %ofn-modal{title: "producer"} + = render partial: "modals/producers" + from the list below: - -##active-table-search.row.pad-top - -#.small-12.columns - -#%i.ofn-i_020-search - -#%input{type: :text, - -#"ng-model" => "query", - -#placeholder: "Search postcode, suburb or producer name...", - -#"ng-debounce" => "150", - -#"ofn-disable-enter" => true} + #active-table-search.row.pad-top + .small-12.columns + %i.ofn-i_020-search + %input{type: :text, + "ng-model" => "query", + placeholder: "Search postcode, suburb or producer name...", + "ng-debounce" => "150", + "ofn-disable-enter" => true} - -#.row{bindonce: true} - -#.small-12.columns - -#.active_table - -#%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - -#"scroll-after-load" => true, - -#"ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query)", - -#"ng-controller" => "ProducerNodeCtrl", - -#"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", - -#id: "{{producer.hash}}"} + .row{bindonce: true} + .small-12.columns + .active_table + %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", + "scroll-after-load" => true, + "ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query)", + "ng-controller" => "ProducerNodeCtrl", + "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", + id: "{{producer.hash}}"} - -#.small-12.columns - -#= render partial: 'producers/skinny' - -#= render partial: 'producers/fat' + .small-12.columns + = render partial: 'producers/skinny' + = render partial: 'producers/fat' --#= render partial: "shared/footer" += render partial: "shared/footer" diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb index 0fa57d19d3..aa655bebfc 100644 --- a/spec/models/enterprise_spec.rb +++ b/spec/models/enterprise_spec.rb @@ -68,7 +68,7 @@ describe Enterprise do end it "should default address country to system country" do - subject.address.country.should == Spree::Country.find_by_id(Spree::Config[:default_country_id]) + create(:distributor_enterprise).address.country.should == Spree::Country.find_by_id(Spree::Config[:default_country_id]) end describe "scopes" do From 8f6a2575b7eedf555638f00def415fb0b9e86b0e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 2 Jul 2014 16:10:57 +1000 Subject: [PATCH 055/145] Minor code formatting changes --- app/models/enterprise.rb | 12 ++++++++---- app/serializers/api/enterprise_serializer.rb | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index e6279bf226..d3040041e4 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -159,20 +159,22 @@ class Enterprise < ActiveRecord::Base self.relatives.is_distributor end + def suppliers + self.relatives.is_primary_producer + end + def website strip_url read_attribute(:website) end + def facebook strip_url read_attribute(:facebook) end + def linkedin strip_url read_attribute(:linkedin) end - def suppliers - self.relatives.is_primary_producer - end - def distributed_variants Spree::Variant.joins(:product).merge(Spree::Product.in_distributor(self)).select('spree_variants.*') end @@ -192,6 +194,7 @@ class Enterprise < ActiveRecord::Base where('spree_products.id IN (?)', Spree::Product.in_distributor(self)). select('DISTINCT spree_taxons.*') end + # Return all taxons for all supplied products def supplied_taxons Spree::Taxon. @@ -200,6 +203,7 @@ class Enterprise < ActiveRecord::Base select('DISTINCT spree_taxons.*') end + private def strip_url(url) diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index c7653db910..850c88ad15 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -22,7 +22,7 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer end def active - @options[:active_distributors].andand.include?(object) + @options[:active_distributors].andand.include? object end end From da4a00c7209e1f9be7f7d9ab851230f8fe02c584 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 3 Jul 2014 15:14:12 +1000 Subject: [PATCH 056/145] Remove ruby- prefix from .ruby-version, turn off Travis email notifications --- .ruby-version | 2 +- .travis.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 2aaf2528c3..ae6d5b9cbe 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-1.9.3-p392 +1.9.3-p392 diff --git a/.travis.yml b/.travis.yml index 4d9301a327..90328e3a8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,3 +10,5 @@ before_script: script: - RAILS_ENV=test bundle exec rake db:migrate --trace - bundle exec rake spec +notifications: + email: false From 206275b794e0ca943378b993fc3f549e703fa17d Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 4 Jul 2014 11:54:21 +1000 Subject: [PATCH 057/145] Code cleanups --- spec/helpers/shared_helper_spec.rb | 4 ++-- .../javascripts/unit/darkswarm/services/taxon_spec.js.coffee | 2 +- spec/models/distributor_shipping_method_spec.rb | 5 ----- 3 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 spec/models/distributor_shipping_method_spec.rb diff --git a/spec/helpers/shared_helper_spec.rb b/spec/helpers/shared_helper_spec.rb index d1d99c331f..de56a1e4b5 100644 --- a/spec/helpers/shared_helper_spec.rb +++ b/spec/helpers/shared_helper_spec.rb @@ -32,8 +32,8 @@ describe SharedHelper do end it "injects enterprises" do - helper.inject_enterprises().should match enterprise.name - helper.inject_enterprises().should match enterprise.facebook + helper.inject_enterprises.should match enterprise.name + helper.inject_enterprises.should match enterprise.facebook end it "injects taxons" do diff --git a/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee index b05c82a13d..d522eda28d 100644 --- a/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/taxon_spec.js.coffee @@ -12,5 +12,5 @@ describe "Taxons service", -> inject ($injector)-> Taxons = $injector.get("Taxons") - it "caches taxons in an id-referenced hash", -> + it "indexes taxons by id", -> expect(Taxons.taxons_by_id[1]).toBe taxons[0] diff --git a/spec/models/distributor_shipping_method_spec.rb b/spec/models/distributor_shipping_method_spec.rb deleted file mode 100644 index bd8d7d2973..0000000000 --- a/spec/models/distributor_shipping_method_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe DistributorShippingMethod do - pending "add some examples to (or delete) #{__FILE__}" -end From 94902268e25dc6cf08ac30e5ec500752f61b8b62 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 4 Jul 2014 11:55:22 +1000 Subject: [PATCH 058/145] Initialise enterprise country in controller, not model. Fixes address SQL load every time an enterprise is instanciated. --- app/controllers/admin/enterprises_controller.rb | 11 +++++++++++ app/models/enterprise.rb | 7 ------- spec/models/enterprise_spec.rb | 4 ---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/controllers/admin/enterprises_controller.rb b/app/controllers/admin/enterprises_controller.rb index a4f4eea834..53e58d110b 100644 --- a/app/controllers/admin/enterprises_controller.rb +++ b/app/controllers/admin/enterprises_controller.rb @@ -19,6 +19,17 @@ module Admin end + protected + + def build_resource_with_address + enterprise = build_resource_without_address + enterprise.address = Spree::Address.new + enterprise.address.country = Spree::Country.find_by_id(Spree::Config[:default_country_id]) + enterprise + end + alias_method_chain :build_resource, :address + + private # When an enterprise user creates another enterprise, it is granted management diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index d3040041e4..2a4acc1d0a 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -29,7 +29,6 @@ class Enterprise < ActiveRecord::Base validates_presence_of :address validates_associated :address - before_create :initialize_country before_validation :set_unused_address_fields after_validation :geocode_address @@ -210,12 +209,6 @@ class Enterprise < ActiveRecord::Base url.andand.sub /(https?:\/\/)?(www\.)?/, '' end - # Give us an empty address on create, and set the country to the default - def initialize_country - self.address ||= Spree::Address.new - self.address.country = Spree::Country.find_by_id(Spree::Config[:default_country_id]) if self.address.new_record? - end - def set_unused_address_fields address.firstname = address.lastname = address.phone = 'unused' if address.present? end diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb index aa655bebfc..53c78ddc6a 100644 --- a/spec/models/enterprise_spec.rb +++ b/spec/models/enterprise_spec.rb @@ -67,10 +67,6 @@ describe Enterprise do it { should delegate(:state_name).to(:address) } end - it "should default address country to system country" do - create(:distributor_enterprise).address.country.should == Spree::Country.find_by_id(Spree::Config[:default_country_id]) - end - describe "scopes" do describe 'active' do From ae0392b3834b75f7cbdcff1e30daf80f4f4ddcce Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 4 Jul 2014 11:55:34 +1000 Subject: [PATCH 059/145] Fix spec fail with taxons by id --- spec/serializers/enterprise_serializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/serializers/enterprise_serializer.rb b/spec/serializers/enterprise_serializer.rb index 4e9248be53..263f621598 100644 --- a/spec/serializers/enterprise_serializer.rb +++ b/spec/serializers/enterprise_serializer.rb @@ -11,7 +11,7 @@ describe Api::EnterpriseSerializer do it "includes distributed taxons" do enterprise.stub(:distributed_taxons).and_return [taxon] serializer = Api::EnterpriseSerializer.new enterprise - serializer.to_json.should match taxon.name + serializer.to_json.should match taxon.id.to_s end it "will render urls" do From 8b67fc4d6176dc5d8be08ead1c9bbbf21c468140 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 4 Jul 2014 12:02:15 +1000 Subject: [PATCH 060/145] Make DSM timestamp columns NOT NULL --- ..._fields_to_distributors_shipping_methods.rb | 18 +++++++++++++++++- db/schema.rb | 6 +++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb b/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb index ed54707cb1..0e16a13a13 100644 --- a/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb +++ b/db/migrate/20140702053145_add_fields_to_distributors_shipping_methods.rb @@ -1,7 +1,23 @@ class AddFieldsToDistributorsShippingMethods < ActiveRecord::Migration - def change + class DistributorShippingMethod < ActiveRecord::Base + self.table_name = "distributors_shipping_methods" + end + + def up add_column :distributors_shipping_methods, :id, :primary_key add_column :distributors_shipping_methods, :created_at, :datetime add_column :distributors_shipping_methods, :updated_at, :datetime + + DistributorShippingMethod.reset_column_information + DistributorShippingMethod.update_all created_at: Time.now, updated_at: Time.now + + change_column :distributors_shipping_methods, :created_at, :datetime, null: false + change_column :distributors_shipping_methods, :updated_at, :datetime, null: false + end + + def down + remove_column :distributors_shipping_methods, :id + remove_column :distributors_shipping_methods, :created_at + remove_column :distributors_shipping_methods, :updated_at end end diff --git a/db/schema.rb b/db/schema.rb index 608cdb299b..a9eddf99be 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -166,8 +166,8 @@ ActiveRecord::Schema.define(:version => 20140702053145) do create_table "distributors_shipping_methods", :force => true do |t| t.integer "distributor_id" t.integer "shipping_method_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false end add_index "distributors_shipping_methods", ["distributor_id"], :name => "index_distributors_shipping_methods_on_distributor_id" @@ -562,9 +562,9 @@ ActiveRecord::Schema.define(:version => 20140702053145) do t.string "email" t.text "special_instructions" t.integer "distributor_id" + t.integer "order_cycle_id" t.string "currency" t.string "last_ip_address" - t.integer "order_cycle_id" t.integer "cart_id" end From f8572db6833237ea1d07ad0a9cc27cfdff12e60a Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 4 Jul 2014 12:07:14 +1000 Subject: [PATCH 061/145] Install and configure dalli for staging and production environments --- Gemfile | 1 + Gemfile.lock | 2 ++ config/environments/production.rb | 2 +- config/environments/staging.rb | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 346d8c9d51..af6b81b3a8 100644 --- a/Gemfile +++ b/Gemfile @@ -32,6 +32,7 @@ gem "active_model_serializers" gem 'oj' gem 'deface', :github => 'spree/deface', :ref => '1110a13' gem 'paperclip' +gem 'dalli' gem 'geocoder' gem 'gmaps4rails' gem 'spinjs-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 39afc2ac50..329fc1a308 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -206,6 +206,7 @@ GEM compass (>= 0.12.2, < 0.14) crack (0.4.1) safe_yaml (~> 0.9.0) + dalli (2.7.2) database_cleaner (0.7.1) db2fog (0.8.0) activerecord (~> 3.0) @@ -507,6 +508,7 @@ DEPENDENCIES comfortable_mexican_sofa compass-rails custom_error_message! + dalli database_cleaner (= 0.7.1) db2fog debugger-linecache diff --git a/config/environments/production.rb b/config/environments/production.rb index ee6fa16e8a..a55540883d 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -37,7 +37,7 @@ Openfoodnetwork::Application.configure do # config.logger = SyslogLogger.new # Use a different cache store in production - # config.cache_store = :mem_cache_store + config.cache_store = :dalli_store # Enable serving of images, stylesheets, and JavaScripts from an asset server # config.action_controller.asset_host = "http://assets.example.com" diff --git a/config/environments/staging.rb b/config/environments/staging.rb index ee6fa16e8a..a55540883d 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -37,7 +37,7 @@ Openfoodnetwork::Application.configure do # config.logger = SyslogLogger.new # Use a different cache store in production - # config.cache_store = :mem_cache_store + config.cache_store = :dalli_store # Enable serving of images, stylesheets, and JavaScripts from an asset server # config.action_controller.asset_host = "http://assets.example.com" From 30262e1969eab4b7f55787c2eb2c2cf123e1a56a Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 4 Jul 2014 14:03:30 +1000 Subject: [PATCH 062/145] Clean up specs, fix broken spec, remove JS log --- .../javascripts/darkswarm/services/enterprises.js.coffee | 1 - spec/helpers/shared_helper_spec.rb | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 0f8a6b2b16..84a3c2e7c2 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -1,5 +1,4 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer)-> - console.log enterprises[0].address new class Enterprises enterprises_by_id: {} # id/object pairs for lookup constructor: -> diff --git a/spec/helpers/shared_helper_spec.rb b/spec/helpers/shared_helper_spec.rb index de56a1e4b5..14df65c2b9 100644 --- a/spec/helpers/shared_helper_spec.rb +++ b/spec/helpers/shared_helper_spec.rb @@ -24,10 +24,10 @@ describe SharedHelper do helper.distributor_link_class(d1).should =~ /empties-cart/ end - describe "Injecting json" do - let(:enterprise) { create(:distributor_enterprise, facebook: "roger") } + describe "injecting json" do + let!(:enterprise) { create(:distributor_enterprise, facebook: "roger") } - it "Will inject via AMS" do + it "will inject via AMS" do helper.inject_json_ams("test", [enterprise], Api::EnterpriseSerializer).should match enterprise.name end From 470ae7e729e90b7cbc4552643dff814ec6368027 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 4 Jul 2014 14:34:55 +1000 Subject: [PATCH 063/145] Fix unreliable spec --- spec/lib/open_food_network/searcher_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/open_food_network/searcher_spec.rb b/spec/lib/open_food_network/searcher_spec.rb index c57a2c1c53..2fb83ed309 100644 --- a/spec/lib/open_food_network/searcher_spec.rb +++ b/spec/lib/open_food_network/searcher_spec.rb @@ -36,7 +36,7 @@ module OpenFoodNetwork d1 = create(:distributor_enterprise) p1 = create(:product, :supplier => s1) p2 = create(:product, :distributors => [d1]) - p3 = create(:product) + p3 = create(:product, :supplier => s0) # When we search by the supplier enterprise, we should see the supplied products searcher = Searcher.new(:enterprise_id => s1.id.to_s) From eb8f59d65bb4b52aef9300ae4d6c72f746c0346b Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 4 Jul 2014 15:19:45 +1000 Subject: [PATCH 064/145] Tests for the taxon filtering --- .../shipping_type_selector.js.coffee | 7 +++++++ .../directives/taxon_selector.js.coffee | 4 +++- .../darkswarm/filters/taxons.js.coffee | 3 +-- .../darkswarm/services/enterprises.js.coffee | 1 + .../selectors/taxon_selector.js.coffee | 19 +++++++++++++++++++ .../services/taxon_selector.js.coffee | 14 -------------- .../shipping_type_selector.html.haml | 7 +++++++ app/views/producers/_filters.html.haml | 5 ++++- app/views/producers/index.html.haml | 2 +- .../darkswarm/filters/shipping_spec.js.coffee | 3 +++ .../darkswarm/filters/taxons_spec.js.coffee | 2 ++ 11 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee create mode 100644 app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee delete mode 100644 app/assets/javascripts/darkswarm/services/taxon_selector.js.coffee create mode 100644 app/assets/javascripts/templates/shipping_type_selector.html.haml diff --git a/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee new file mode 100644 index 0000000000..b634fc167c --- /dev/null +++ b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee @@ -0,0 +1,7 @@ +Darkswarm.directive "shippingTypeSelector", -> + restrict: 'E' + templateUrl: 'shipping_type_selector.html' + link: (scope, elem, attr)-> + scope.shippingTypes = + pickup: false + delivery: false diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee index d4b93a3cdb..c9ccb1af1a 100644 --- a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee @@ -1,6 +1,8 @@ Darkswarm.directive "taxonSelector", (TaxonSelector) -> restrict: 'E' - scope: {} + scope: + enterprises: "=" templateUrl: "taxon_selector.html" link: (scope, elem, attr)-> scope.TaxonSelector = TaxonSelector + TaxonSelector.collectTaxons scope.enterprises diff --git a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee index 01c7d98057..9fccd20c11 100644 --- a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee @@ -3,10 +3,9 @@ Darkswarm.filter 'taxons', (Matcher)-> (objects, ids) -> objects ||= [] ids ?= [] - console.log ids if ids.length == 0 objects else objects.filter (obj)-> - obj.primary_taxon?.id in ids || obj.taxons.some (taxon)-> + obj.primary_taxon?.id in ids || (obj.taxons.concat obj.supplied_taxons).some (taxon)-> taxon.id in ids diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 84a3c2e7c2..50143e006b 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -18,3 +18,4 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer) dereferenceTaxons: -> for enterprise in @enterprises Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id + Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id diff --git a/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee new file mode 100644 index 0000000000..4ba42f3aa2 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee @@ -0,0 +1,19 @@ +Darkswarm.factory 'TaxonSelector', -> + new class TaxonSelector + selectors: [] + # Collect all taxons on the supplied enterprises + collectTaxons: (enterprises)-> + taxons = {} + for enterprise in enterprises + for taxon in (enterprise.taxons.concat enterprise.supplied_taxons) + taxons[taxon.id] = taxon + for id, taxon of taxons + @selectors.push + active: false + taxon: taxon + + active: -> + @selectors.filter (selector)-> + selector.active + .map (selector)-> + selector.taxon.id diff --git a/app/assets/javascripts/darkswarm/services/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/services/taxon_selector.js.coffee deleted file mode 100644 index 4628e79f11..0000000000 --- a/app/assets/javascripts/darkswarm/services/taxon_selector.js.coffee +++ /dev/null @@ -1,14 +0,0 @@ -Darkswarm.factory 'TaxonSelector', (Taxons)-> - new class TaxonSelector - selectors: [] - constructor: -> - for taxon in Taxons.taxons - @selectors.push - active: false - taxon: taxon - - active: -> - @selectors.filter (selector)-> - selector.active - .map (selector)-> - selector.taxon.id diff --git a/app/assets/javascripts/templates/shipping_type_selector.html.haml b/app/assets/javascripts/templates/shipping_type_selector.html.haml new file mode 100644 index 0000000000..80e70d1c8d --- /dev/null +++ b/app/assets/javascripts/templates/shipping_type_selector.html.haml @@ -0,0 +1,7 @@ +%ul.small-block-grid-4 + %li{"ng-class" => "{active: shippingTypes['delivery']}"} + %a{"ng-click" => "shippingTypes['delivery'] = !shippingTypes['delivery']"} + Delivery + %li{"ng-class" => "{active: shippingTypes['pickup']}"} + %a{"ng-click" => "shippingTypes['pickup'] = !shippingTypes['pickup']"} + Pickup diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index fa8046d3c2..db23606cc2 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -16,4 +16,7 @@ Something .row .small-12.large-6.columns - %taxon-selector + %taxon-selector{enterprises: "Producers.visible"} + + .small-12.large-6.columns + %shipping-type-selector diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index a84d0a050f..386f0e2b5f 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -25,7 +25,7 @@ .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", "scroll-after-load" => true, - "ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query | taxons:TaxonSelector.active())", + "ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query | taxons:TaxonSelector.active() | shipping:shippingTypes)", "ng-controller" => "ProducerNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} diff --git a/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee index bfb5ffe606..1bb436017a 100644 --- a/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/filters/shipping_spec.js.coffee @@ -28,3 +28,6 @@ describe 'filtering by shipping method', -> it "filters to none", -> expect(filterByShippingMethod(objects, {pickup: false, delivery: false})).toBe objects + + it "filters to none with empty", -> + expect(filterByShippingMethod(objects, {})).toBe objects diff --git a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee index 8c9002f53c..1313229ef6 100644 --- a/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/filters/taxons_spec.js.coffee @@ -3,6 +3,7 @@ describe 'filtering by taxons', -> objects = [ { taxons: [] + supplied_taxons: [] primary_taxon: name: "frogs" id: 1 @@ -12,6 +13,7 @@ describe 'filtering by taxons', -> {name: "kittens", id: 2} {name: "puppies", id: 3} ] + supplied_taxons: [] } ] From 7f00f66e825ee3943b529b94b6c135fd2753ee38 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 15:47:39 +1000 Subject: [PATCH 065/145] Styling for filter systems against search --- .../darkswarm/active_table_search.css.sass | 52 +++++++++++++++---- .../stylesheets/darkswarm/animations.sass | 7 +-- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 46cf36401c..78d824e03d 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -1,26 +1,56 @@ @import mixins @import branding +// OVERRIDES +.row .row.filter-box + margin-left: 0 + margin-right: 0 + + .filter-box - border-top: 1px solid $clr-brick - background-color: rgba(255,255,255,0.5) + background: rgba(255,255,255,0.5) + margin-top: 5rem + .tdhead padding: 0.25rem 0.5rem margin-top: 0.9rem + + // OVERRIDES + [class*="block-grid-"] > li + padding-bottom: 0.5rem !important + + li.active a + color: $clr-brick + @include border-radius(12px) + @include box-shadow(inset 0 1px 3px 0 rgba(143,48,29,0.5)) + border: 1px solid $clr-brick + render-svg + svg + path + fill: $clr-brick + &:hover, &:focus + border-color: $clr-brick-bright + li a display: table - height: 2rem + table-layout: fixed + // width: 100% + height: 2.5rem + padding: 0.5rem 0.5rem 0.5rem 0.25rem + border: 1px solid transparent line-height: 1 - color: #666 + color: #444 + font-size: 0.875rem span display: table-cell vertical-align: middle + text-align: left &:hover, &:focus - color: #000 + color: $clr-brick-bright render-svg svg path - fill: #000 + fill: $clr-brick-bright &:active, &.active color: $clr-brick @@ -30,11 +60,15 @@ fill: $clr-brick render-svg - width: 2rem - height: 2rem display: block - margin-right: 0.25rem + width: 1.5rem + height: 1.5rem + margin: 0 + padding: 0 + // margin-right: 0.25rem svg + width: 1.5rem + height: 1.5rem path fill: #666 diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index 7fc54e169c..fccab8d3a0 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -53,13 +53,10 @@ .animate-show - -webkit-transition: all linear 0.5s - transition: all linear 0.5s + -webkit-transition: all linear 0.25s + transition: all linear 0.25s line-height: 20px opacity: 1 - padding: 10px - border: 1px solid black - background: white .animate-show.ng-hide-add, .animate-show.ng-hide-remove From 8186773adba8ef38477ef30c73eed5d12534b00e Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 15:49:23 +1000 Subject: [PATCH 066/145] Adjustments to filters markup --- app/views/producers/_filters.html.haml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index db23606cc2..a67ec630e0 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -1,7 +1,11 @@ -%a{"ng-click" => "filtersActive = !filtersActive"} Toggle +.row + .small-12.columns + %a.right{"ng-click" => "filtersActive = !filtersActive"} + Filter by + %i.ofn-i_052-point-down .row.animate-show{"ng-show" => "filtersActive"} - .small-12.columns.filter-box - .row + .small-12.columns + .row.filter-box .small-12.large-6.columns %h5.tdhead .light Filter by @@ -14,7 +18,7 @@ %h5.tdhead .light Filter by Something - .row + .row.filter-box .small-12.large-6.columns %taxon-selector{enterprises: "Producers.visible"} From b50541fd15e1264c3a17f22b9201f11026166fc2 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 15:50:00 +1000 Subject: [PATCH 067/145] Less padding below search bar --- app/assets/stylesheets/darkswarm/mixins.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/mixins.sass b/app/assets/stylesheets/darkswarm/mixins.sass index 9e1230a56f..2a05c3bf1e 100644 --- a/app/assets/stylesheets/darkswarm/mixins.sass +++ b/app/assets/stylesheets/darkswarm/mixins.sass @@ -15,7 +15,7 @@ box-shadow: 0 padding: 0.75em 1em height: auto - margin-bottom: 1em + margin-bottom: 0.1rem background: rgba(255,255,255,0.65) &:active, &:hover, &:focus background: rgba(255,255,255,1) From 56a1a66d3f0061bcd41ed06504582cfa7238e4a5 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 17:00:03 +1000 Subject: [PATCH 068/145] Styling for big sexy search bar --- .../darkswarm/active_table_search.css.sass | 17 ++-- .../stylesheets/darkswarm/animations.sass | 91 +++++++++++++++++-- app/assets/stylesheets/darkswarm/mixins.sass | 29 ++++-- app/views/producers/index.html.haml | 6 +- 4 files changed, 119 insertions(+), 24 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 78d824e03d..1e3ffbedb9 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -9,7 +9,6 @@ .filter-box background: rgba(255,255,255,0.5) - margin-top: 5rem .tdhead padding: 0.25rem 0.5rem @@ -76,16 +75,18 @@ position: relative i.ofn-i_020-search - position: absolute - left: 26px - top: 12px - font-size: 1.6em - z-index: 2 - color: #b2b2b2 + // position: absolute + // left: 26px + // top: 12px + // font-size: 1.6em + // z-index: 2 + // color: #b2b2b2 input[type="text"] font-size: 2em @include big-input - padding-left: 44px + // padding-left: 44px + placeholder + color: $disabled-dark diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index fccab8d3a0..96bd5b19ae 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -1,3 +1,58 @@ +@import mixins + +// ANIMATION FUNCTIONS + +@-webkit-keyframes slideInDown + 0% + opacity: 0 + -webkit-transform: translateY(-20px) + transform: translateY(-20px) + 100% + -webkit-transform: translateY(0) + transform: translateY(0) + +@keyframes slideInDown + 0% + opacity: 0 + -webkit-transform: translateY(-20px) + -ms-transform: translateY(-20px) + transform: translateY(-20px) + 100% + -webkit-transform: translateY(0) + -ms-transform: translateY(0) + transform: translateY(0) + +@-webkit-keyframes slideOutUp + 0% + -webkit-transform: translateY(0) + transform: translateY(0) + 100% + opacity: 0 + -webkit-transform: translateY(-20px) + transform: translateY(-20px) + + +@keyframes slideOutUp + 0% + -webkit-transform: translateY(0) + -ms-transform: translateY(0) + transform: translateY(0) + +@-webkit-keyframes fadeIn + 0% + opacity: 0 + 100% + opacity: 1 + + +@keyframes fadeIn + 0% + opacity: 0 + 100% + opacity: 1 + +// ANIMATION CLASSES + .fade opacity: 0 -webkit-transition: opacity .15s linear @@ -53,16 +108,36 @@ .animate-show - -webkit-transition: all linear 0.25s - transition: all linear 0.25s - line-height: 20px - opacity: 1 + -webkit-animation-name: slideInDown + animation-name: slideInDown + -webkit-animation-duration: 0.5s + animation-duration: 0.5s + -webkit-animation-fill-mode: both + animation-fill-mode: both + // line-height: 20px + // opacity: 1 .animate-show.ng-hide-add, .animate-show.ng-hide-remove - display: block !important + // display: block !important .animate-show.ng-hide - line-height: 0 - opacity: 0 - padding: 0 10px + -webkit-animation-name: slideOutUp + animation-name: slideOutUp + -webkit-animation-duration: 0.15s + animation-duration: 0.15s + -webkit-animation-fill-mode: both + animation-fill-mode: both + // line-height: 0 + // opacity: 0 + // padding: 0 10px + +.row.animate-show ~ .row + -webkit-animation-name: fadeIn + animation-name: fadeIn + -webkit-animation-duration: 0.5s + animation-duration: 0.5s + -webkit-animation-fill-mode: both + animation-fill-mode: both + + diff --git a/app/assets/stylesheets/darkswarm/mixins.sass b/app/assets/stylesheets/darkswarm/mixins.sass index 2a05c3bf1e..b4845b87fc 100644 --- a/app/assets/stylesheets/darkswarm/mixins.sass +++ b/app/assets/stylesheets/darkswarm/mixins.sass @@ -9,17 +9,22 @@ padding-bottom: 100px @mixin big-input - border: 1px solid #999 - font-size: 18px + // border: 1px solid #999 + background: transparent + border: none + border-bottom: 1px dotted black + font-size: 2rem @extend .avenir box-shadow: 0 - padding: 0.75em 1em + padding: 1rem 0 0.5rem 0 height: auto margin-bottom: 0.1rem - background: rgba(255,255,255,0.65) + box-shadow: none + // background: rgba(255,255,255,0.65) &:active, &:hover, &:focus - background: rgba(255,255,255,1) - border-color: #888 + color: black + // background: rgba(255,255,255,1) + // border-color: #888 @mixin disabled color: $disabled-bright @@ -41,6 +46,18 @@ -webkit-border-radius: $border-radius border-radius: $border-radius +@mixin transform-translate($translate) + -ms-transform: $translate + -webkit-transform: $translate + transform: $translate + +@mixin transform-scale($scale) + -moz-transform: $scale + -webkit-transform: $scale + -o-transform: $scale + -ms-transform: $scale + transform: $scale + // Typography \\ @mixin avenir diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 386f0e2b5f..3775d26481 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -11,12 +11,14 @@ #active-table-search.row.pad-top .small-12.columns - %i.ofn-i_020-search %input{type: :text, "ng-model" => "query", - placeholder: "Search postcode, suburb or producer name...", + placeholder: "Search Producer Suburb / Postcode / State", "ng-debounce" => "150", "ofn-disable-enter" => true} + / %placeholder + / %i.ofn-i_020-search + / Search Producer or by Suburb / Postcode / State = render partial: "producers/filters" From ba964d54d91aedcb7b699854e686a92b94445d2c Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 4 Jul 2014 17:07:58 +1000 Subject: [PATCH 069/145] Update spree and spree_auth_devise --- Gemfile.lock | 77 ++++++++++---------- app/models/spree/product_decorator.rb | 2 +- spec/controllers/checkout_controller_spec.rb | 3 +- 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 329fc1a308..626b1a6a2c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,45 +14,45 @@ GIT GIT remote: git://github.com/openfoodfoundation/spree.git - revision: da651b40f5c6cdd32e00b060729eb9aefd4f615f + revision: bbe5e779bcb883a1726ad4006d7c06b06c3f5372 branch: 1-3-stable specs: - spree (1.3.3) - spree_api (= 1.3.3) - spree_cmd (= 1.3.3) - spree_core (= 1.3.3) - spree_promo (= 1.3.3) - spree_sample (= 1.3.3) - spree_api (1.3.3) - spree_core (= 1.3.3) + spree (1.3.6.beta) + spree_api (= 1.3.6.beta) + spree_cmd (= 1.3.6.beta) + spree_core (= 1.3.6.beta) + spree_promo (= 1.3.6.beta) + spree_sample (= 1.3.6.beta) + spree_api (1.3.6.beta) + spree_core (= 1.3.6.beta) versioncake (= 0.4.0) - spree_cmd (1.3.3) + spree_cmd (1.3.6.beta) thor (>= 0.14.6) - spree_core (1.3.3) + spree_core (1.3.6.beta) activemerchant (~> 1.34) acts_as_list (= 0.1.4) awesome_nested_set (= 2.1.5) - aws-sdk (~> 1.3.4) + aws-sdk (~> 1.11.1) cancan (= 1.6.8) deface (>= 0.9.0) ffaker (~> 1.15.0) highline (= 1.6.18) jquery-rails (~> 2.2.0) json (>= 1.5.5) - kaminari (= 0.13.0) - money (= 5.0.0) + kaminari (= 0.14.1) + money (= 5.1.1) paperclip (~> 2.8) rabl (= 0.7.2) - rails (~> 3.2.14) + rails (~> 3.2.16) ransack (= 0.7.2) select2-rails (= 3.2.1) state_machine (= 1.1.2) stringex (~> 1.3.2) truncate_html (~> 0.5.5) - spree_promo (1.3.3) - spree_core (= 1.3.3) - spree_sample (1.3.3) - spree_core (= 1.3.3) + spree_promo (1.3.6.beta) + spree_core (= 1.3.6.beta) + spree_sample (1.3.6.beta) + spree_core (= 1.3.6.beta) GIT remote: git://github.com/openfoodfoundation/spree_paypal_express.git @@ -74,10 +74,10 @@ GIT GIT remote: git://github.com/spree/spree_auth_devise.git - revision: 6a50345b73bcec614a8fbd358a2367c00c8ab56f + revision: ba95589a85368297c844f096c2a0c121e5b08138 branch: 1-3-stable specs: - spree_auth_devise (1.0.0) + spree_auth_devise (1.3.0) cancan (~> 1.6.7) devise (~> 2.2.3) devise-encryptable (= 0.1.2) @@ -120,10 +120,10 @@ GEM active_link_to (1.0.0) active_model_serializers (0.8.1) activemodel (>= 3.0) - active_utils (2.0.2) + active_utils (2.2.1) activesupport (>= 2.3.11) i18n - activemerchant (1.43.0) + activemerchant (1.43.1) active_utils (~> 2.0, >= 2.0.1) activesupport (>= 2.3.14, < 5.0.0) builder (>= 2.1.2, < 4.0.0) @@ -158,12 +158,13 @@ GEM awesome_nested_set (2.1.5) activerecord (>= 3.0.0) awesome_print (1.0.2) - aws-sdk (1.3.9) - httparty (~> 0.7) + aws-sdk (1.11.1) json (~> 1.4) nokogiri (>= 1.4.4) uuidtools (~> 2.1) - bcrypt-ruby (3.1.2) + bcrypt (3.1.7) + bcrypt-ruby (3.1.5) + bcrypt (>= 3.1.3) bugsnag (1.5.2) httparty (>= 0.6, < 1.0) multi_json (~> 1.0) @@ -192,7 +193,7 @@ GEM coffee-script-source execjs coffee-script-source (1.3.3) - colorize (0.7.2) + colorize (0.7.3) columnize (0.3.6) comfortable_mexican_sofa (1.6.24) active_link_to (~> 1.0.0) @@ -218,7 +219,7 @@ GEM debugger-ruby_core_source (~> 1.2.3) debugger-linecache (1.2.0) debugger-ruby_core_source (1.2.3) - devise (2.2.7) + devise (2.2.8) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) railties (~> 3.1) @@ -301,10 +302,9 @@ GEM json_spec (1.1.1) multi_json (~> 1.0) rspec (~> 2.0) - kaminari (0.13.0) + kaminari (0.14.1) actionpack (>= 3.0.0) activesupport (>= 3.0.0) - railties (>= 3.0.0) kgio (2.7.4) launchy (2.1.2) addressable (~> 2.3) @@ -321,22 +321,21 @@ GEM treetop (~> 1.4.8) method_source (0.8.1) mime-types (1.25.1) - mini_portile (0.5.3) + mini_portile (0.6.0) momentjs-rails (2.5.1) railties (>= 3.1) - money (5.0.0) - i18n (~> 0.4) - json + money (5.1.1) + i18n (~> 0.6.0) multi_json (1.10.1) multi_xml (0.5.5) net-scp (1.1.2) net-ssh (>= 2.6.5) net-ssh (2.6.8) newrelic_rpm (3.6.7.152) - nokogiri (1.6.1) - mini_portile (~> 0.5.0) + nokogiri (1.6.2.1) + mini_portile (= 0.6.0) oj (2.1.2) - orm_adapter (0.4.0) + orm_adapter (0.5.0) paperclip (2.8.0) activerecord (>= 2.3.0) activesupport (>= 2.3.2) @@ -351,7 +350,7 @@ GEM websocket-driver (>= 0.2.0) polyamorous (0.5.0) activerecord (~> 3.0) - polyglot (0.3.4) + polyglot (0.3.5) pry (0.9.12.2) coderay (~> 1.0.5) method_source (~> 0.8) @@ -387,7 +386,7 @@ GEM rdoc (~> 3.4) thor (>= 0.14.6, < 2.0) raindrops (0.9.0) - rake (10.3.1) + rake (10.3.2) ransack (0.7.2) actionpack (~> 3.0) activerecord (~> 3.0) diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index e0cc8cc436..5894e46cc2 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -193,7 +193,7 @@ Spree::Product.class_eval do end def add_primary_taxon_to_taxons - taxons << primary_taxon unless taxons.find_by_id(primary_taxon) + taxons << primary_taxon unless taxons.include? primary_taxon end def self.all_variant_unit_option_types diff --git a/spec/controllers/checkout_controller_spec.rb b/spec/controllers/checkout_controller_spec.rb index d8c6ee738c..e46b9688a2 100644 --- a/spec/controllers/checkout_controller_spec.rb +++ b/spec/controllers/checkout_controller_spec.rb @@ -40,9 +40,7 @@ describe CheckoutController do it "doesn't copy the previous shipping address from a pickup order" do old_order = create(:order, bill_address: create(:address), ship_address: create(:address)) - old_order.shipping_method.stub_chain(:andand, :require_ship_address).and_return(false) Spree::Order.stub_chain(:order, :where, :where, :limit, :detect).and_return(old_order) - controller.send(:find_last_used_addresses, "email").last.should == nil end @@ -81,6 +79,7 @@ describe CheckoutController do context "via xhr" do before do controller.stub(:current_distributor).and_return(distributor) + controller.stub(:current_order_cycle).and_return(order_cycle) controller.stub(:current_order).and_return(order) end From 5d2d4fd007474bcd0feb46a0310359f96bdfc9b8 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 17:32:43 +1000 Subject: [PATCH 070/145] More styling adjustments for big sexy search --- app/assets/stylesheets/darkswarm/active_table_search.css.sass | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 1e3ffbedb9..2ec37eaa2b 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -73,7 +73,6 @@ #active-table-search position: relative - i.ofn-i_020-search // position: absolute // left: 26px From 9ed0ebaa43bc70b6a0d474503f46e35f017b1e67 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 17:33:02 +1000 Subject: [PATCH 071/145] Hubs styling for bit sexy search --- app/assets/stylesheets/darkswarm/hubs.css.sass | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/hubs.css.sass b/app/assets/stylesheets/darkswarm/hubs.css.sass index 87ccb3ef50..43f2b8cbea 100644 --- a/app/assets/stylesheets/darkswarm/hubs.css.sass +++ b/app/assets/stylesheets/darkswarm/hubs.css.sass @@ -2,6 +2,8 @@ @import mixins #hubs - background: $clr-brick-ultra-light url("/assets/home/shopping-bg.jpg") - @include fullwidthbg + background-repeat: repeat + background-image: url("/assets/subtle_white_feathers.png") + // background: $clr-brick-ultra-light url("/assets/home/shopping-bg.jpg") + // @include fullwidthbg @include panepadding From ac5c8ccfd46a7acee00f201893f4d29b6db44515 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 17:34:26 +1000 Subject: [PATCH 072/145] Modal styling for active table removing background --- app/assets/stylesheets/darkswarm/modal-enterprises.css.sass | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/darkswarm/modal-enterprises.css.sass b/app/assets/stylesheets/darkswarm/modal-enterprises.css.sass index 701969ef7d..1ed8fc5823 100644 --- a/app/assets/stylesheets/darkswarm/modal-enterprises.css.sass +++ b/app/assets/stylesheets/darkswarm/modal-enterprises.css.sass @@ -91,6 +91,7 @@ .active_table_row .cta-container // padding-bottom: 0.75rem + background: rgba(0,0,0,0.05) padding-top: 0.5rem // Generic styles for use From 72203c0ad02cc8cd5d2f24bcc63ff1fe7e9362ce Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 17:34:51 +1000 Subject: [PATCH 073/145] Refactoring home fat view to make CTA Button more intuitive --- app/views/home/_fat.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/home/_fat.html.haml b/app/views/home/_fat.html.haml index 16dc3eaafb..e6158dbca0 100644 --- a/app/views/home/_fat.html.haml +++ b/app/views/home/_fat.html.haml @@ -38,7 +38,7 @@ %span{"active-table-hub-link" => "hub", change: "Change hub to", shop: "Shop at"} .row .columns.small-12 - %a.button.hub.expand{"bo-href" => "hub.path", + %a.button.hub{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"} %i.ofn-i_033-open-sign{"bo-if" => "hub.active"} From b0a2dba5e18df5fdec99c2084f6f136cb1eace03 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 17:36:56 +1000 Subject: [PATCH 074/145] Tweaks to markup for new big sexy search --- app/views/home/_hubs.html.haml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index 50b491644d..f8698989c3 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -1,20 +1,20 @@ = inject_enterprises #hubs.hubs{"ng-controller" => "HubsCtrl"} .row - .small-12.columns.text-center - %h1 Ready to shop? - %div - Select a - %ofn-modal{title: "food hub"} - = render partial: "modals/food_hub" - from the list below: + .small-12.columns + %h1 Find hubs in your area... + / %div + / Shop a + / %ofn-modal{title: "food hub"} + / = render partial: "modals/food_hub" + / from the list below: #active-table-search.row.pad-top .small-12.columns - %i.ofn-i_020-search + / %i.ofn-i_020-search %input{type: :text, "ng-model" => "query", - placeholder: "Search postcode, suburb or hub name...", + placeholder: "Search Hub or by Suburb / State", "ng-debounce" => "150", "ofn-disable-enter" => true} From a62410389ed69e222d9e8e7da87094f903b64db9 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 17:38:04 +1000 Subject: [PATCH 075/145] Producers index markup tweak for new sexy search --- app/views/producers/index.html.haml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 3775d26481..61b81084da 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -1,19 +1,19 @@ = inject_enterprises .producers{"ng-controller" => "ProducersCtrl"} .row - .small-12.columns.text-center.pad-top - %h1 Producers - %div - Select a - %ofn-modal{title: "producer"} - = render partial: "modals/producers" - from the list below: + .small-12.columns.pad-top + %h1 Find a local producer... + / %div + / Find a + / %ofn-modal{title: "producer"} + / = render partial: "modals/producers" + / from the list below: #active-table-search.row.pad-top .small-12.columns %input{type: :text, "ng-model" => "query", - placeholder: "Search Producer Suburb / Postcode / State", + placeholder: "Search Producer or by Suburb / State", "ng-debounce" => "150", "ofn-disable-enter" => true} / %placeholder From 730fbc5e948c0eb98ecf0a2b32ab1881fb1c9690 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 4 Jul 2014 17:41:42 +1000 Subject: [PATCH 076/145] New texture for hubs background --- app/assets/images/subtle_white_feathers.png | Bin 0 -> 166566 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/assets/images/subtle_white_feathers.png diff --git a/app/assets/images/subtle_white_feathers.png b/app/assets/images/subtle_white_feathers.png new file mode 100644 index 0000000000000000000000000000000000000000..dd699f66ba4ecf773651227c3eb7ce249eedbbd7 GIT binary patch literal 166566 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ξy+HrKsEL-g< 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�^&=OUQ+78Fw75g#x&M?UUzP+m6 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

%YlGZ(c|lHAZ!99s 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 SkqtHg0000 Date: Wed, 9 Jul 2014 10:53:52 +1000 Subject: [PATCH 077/145] Taxon selection finesse --- .../controllers/producers_controller.js.coffee | 10 +++++++++- .../darkswarm/directives/active_selector.js.coffee | 1 - .../darkswarm/directives/taxon_selector.js.coffee | 3 --- .../services/selectors/taxon_selector.js.coffee | 14 +++++++++++--- .../templates/active_selector.html.haml | 2 +- app/views/producers/index.html.haml | 2 +- 6 files changed, 22 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee index 26c90a305e..7d31c06000 100644 --- a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee @@ -1,4 +1,12 @@ -Darkswarm.controller "ProducersCtrl", ($scope, Producers, TaxonSelector) -> +Darkswarm.controller "ProducersCtrl", ($scope, Producers, TaxonSelector, $filter) -> $scope.Producers = Producers $scope.TaxonSelector = TaxonSelector $scope.filtersActive = false + $scope.oldFiltered = [] + + $scope.filteredProducers = -> + filtered = $filter("filterProducers")(Producers.visible, $scope.query) + if $scope.oldFiltered != filtered + $scope.oldFiltered = filtered + TaxonSelector.collectTaxons filtered + filtered diff --git a/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee index 574af50b96..fbbca3a88b 100644 --- a/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee @@ -6,5 +6,4 @@ Darkswarm.directive "activeSelector", -> link: (scope, elem, attr)-> elem.bind "click", -> scope.$apply -> - elem.toggleClass "active" scope.selector.active = !scope.selector.active diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee index c9ccb1af1a..89d2a4d4ec 100644 --- a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee @@ -1,8 +1,5 @@ Darkswarm.directive "taxonSelector", (TaxonSelector) -> restrict: 'E' - scope: - enterprises: "=" templateUrl: "taxon_selector.html" link: (scope, elem, attr)-> scope.TaxonSelector = TaxonSelector - TaxonSelector.collectTaxons scope.enterprises diff --git a/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee index 4ba42f3aa2..f9d7bfebff 100644 --- a/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee @@ -1,16 +1,24 @@ Darkswarm.factory 'TaxonSelector', -> new class TaxonSelector selectors: [] + selectors_by_id: {} # Collect all taxons on the supplied enterprises collectTaxons: (enterprises)-> taxons = {} + @selectors = [] + selectors = [] for enterprise in enterprises for taxon in (enterprise.taxons.concat enterprise.supplied_taxons) taxons[taxon.id] = taxon for id, taxon of taxons - @selectors.push - active: false - taxon: taxon + if @selectors_by_id[id] + selectors.push @selectors_by_id[id] + else + @selectors_by_id[id] = + active: false + taxon: taxon + selectors.push @selectors_by_id[id] + @selectors = selectors active: -> @selectors.filter (selector)-> diff --git a/app/assets/javascripts/templates/active_selector.html.haml b/app/assets/javascripts/templates/active_selector.html.haml index 449c2bc4d3..14b12bbd9f 100644 --- a/app/assets/javascripts/templates/active_selector.html.haml +++ b/app/assets/javascripts/templates/active_selector.html.haml @@ -1,2 +1,2 @@ -%li +%li{"ng-class" => "{active: selector.active}"} %a{"ng-transclude" => true} diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 61b81084da..876f5a986b 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -27,7 +27,7 @@ .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", "scroll-after-load" => true, - "ng-repeat" => "producer in filteredProducers = (Producers.visible | filterProducers:query | taxons:TaxonSelector.active() | shipping:shippingTypes)", + "ng-repeat" => "producer in veryFilteredProducers = (filteredProducers() | taxons:TaxonSelector.active() | shipping:shippingTypes)", "ng-controller" => "ProducerNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} From 7d39c30dbd49376479494a1b4562d52080a57b12 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 9 Jul 2014 10:54:40 +1000 Subject: [PATCH 078/145] Fixing a taxon bug --- app/assets/javascripts/darkswarm/services/enterprises.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 84a3c2e7c2..50143e006b 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -18,3 +18,4 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer) dereferenceTaxons: -> for enterprise in @enterprises Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id + Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id From 30d78c8da3042b4f072616e35cb87d520cf4cccd Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 9 Jul 2014 11:33:36 +1000 Subject: [PATCH 079/145] Adding a spec to test a regression --- spec/features/consumer/producers_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/features/consumer/producers_spec.rb b/spec/features/consumer/producers_spec.rb index 8e834aaeb3..7d4a122996 100644 --- a/spec/features/consumer/producers_spec.rb +++ b/spec/features/consumer/producers_spec.rb @@ -8,6 +8,8 @@ feature %q{ include UIComponentHelper let!(:producer) { create(:supplier_enterprise) } let!(:invisible_producer) { create(:supplier_enterprise, visible: false) } + let(:taxon) { create(:taxon) } + let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) } before do visit producers_path @@ -16,7 +18,7 @@ feature %q{ it "shows all producers with expandable details" do page.should have_content producer.name expand_active_table_node producer.name - page.should have_content producer.supplied_taxons.join(', ') + page.should have_content producer.supplied_taxons.first.name.upcase end it "doesn't show invisible producers" do From fb8d7907f918bfed1dd1e85ea519245addd799d3 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 9 Jul 2014 14:07:38 +1000 Subject: [PATCH 080/145] Rearchitecting the thing --- .../producers_controller.js.coffee | 14 ++------ .../directives/active_selector.js.coffee | 1 + .../directives/taxon_selector.js.coffee | 32 +++++++++++++++++-- .../selectors/taxon_selector.js.coffee | 27 ---------------- .../templates/taxon_selector.html.haml | 2 +- .../stylesheets/darkswarm/animations.sass | 4 +-- app/views/producers/_filters.html.haml | 3 +- app/views/producers/index.html.haml | 2 +- 8 files changed, 40 insertions(+), 45 deletions(-) delete mode 100644 app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee diff --git a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee index 7d31c06000..5da0fc7912 100644 --- a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee @@ -1,12 +1,4 @@ -Darkswarm.controller "ProducersCtrl", ($scope, Producers, TaxonSelector, $filter) -> +Darkswarm.controller "ProducersCtrl", ($scope, Producers, $filter) -> $scope.Producers = Producers - $scope.TaxonSelector = TaxonSelector - $scope.filtersActive = false - $scope.oldFiltered = [] - - $scope.filteredProducers = -> - filtered = $filter("filterProducers")(Producers.visible, $scope.query) - if $scope.oldFiltered != filtered - $scope.oldFiltered = filtered - TaxonSelector.collectTaxons filtered - filtered + $scope.filtersActive = true + $scope.activeTaxons = [] diff --git a/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee index fbbca3a88b..803c83eee3 100644 --- a/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee @@ -7,3 +7,4 @@ Darkswarm.directive "activeSelector", -> elem.bind "click", -> scope.$apply -> scope.selector.active = !scope.selector.active + scope.emit() diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee index 89d2a4d4ec..888d17d6ec 100644 --- a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee @@ -1,5 +1,33 @@ -Darkswarm.directive "taxonSelector", (TaxonSelector) -> +Darkswarm.directive "taxonSelector", -> restrict: 'E' + scope: + objects: "&" + results: "=" templateUrl: "taxon_selector.html" + link: (scope, elem, attr)-> - scope.TaxonSelector = TaxonSelector + selectors_by_id = {} + selectors = ["foo"] + + scope.emit = -> + scope.results = selectors.filter (selector)-> + selector.active + .map (selector)-> + selector.taxon.id + + scope.selectors = -> + console.log "selectoring" + taxons = {} + selectors = [] + for object in scope.objects() + for taxon in (object.taxons.concat object?.supplied_taxons) + taxons[taxon.id] = taxon + for id, taxon of taxons + if selector = selectors_by_id[id] + selectors.push selector + else + selector = selectors_by_id[id] = + active: false + taxon: taxon + selectors.push selector + selectors diff --git a/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee deleted file mode 100644 index f9d7bfebff..0000000000 --- a/app/assets/javascripts/darkswarm/services/selectors/taxon_selector.js.coffee +++ /dev/null @@ -1,27 +0,0 @@ -Darkswarm.factory 'TaxonSelector', -> - new class TaxonSelector - selectors: [] - selectors_by_id: {} - # Collect all taxons on the supplied enterprises - collectTaxons: (enterprises)-> - taxons = {} - @selectors = [] - selectors = [] - for enterprise in enterprises - for taxon in (enterprise.taxons.concat enterprise.supplied_taxons) - taxons[taxon.id] = taxon - for id, taxon of taxons - if @selectors_by_id[id] - selectors.push @selectors_by_id[id] - else - @selectors_by_id[id] = - active: false - taxon: taxon - selectors.push @selectors_by_id[id] - @selectors = selectors - - active: -> - @selectors.filter (selector)-> - selector.active - .map (selector)-> - selector.taxon.id diff --git a/app/assets/javascripts/templates/taxon_selector.html.haml b/app/assets/javascripts/templates/taxon_selector.html.haml index 6e376a4ae2..e26b36c64a 100644 --- a/app/assets/javascripts/templates/taxon_selector.html.haml +++ b/app/assets/javascripts/templates/taxon_selector.html.haml @@ -1,4 +1,4 @@ %ul.small-block-grid-4 - %active-selector{"ng-repeat" => "selector in TaxonSelector.selectors"} + %active-selector{"ng-repeat" => "selector in selectors()"} %render-svg{path: "{{selector.taxon.icon}}"} %span {{ selector.taxon.name }} diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index 96bd5b19ae..3fcbb41202 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -91,8 +91,8 @@ .animate-repeat.ng-move, .animate-repeat.ng-enter, .animate-repeat.ng-leave - -webkit-transition: all linear 0.5s - transition: all linear 0.5s + -webkit-transition: all linear 0.2s + transition: all linear 0.2s .animate-repeat.ng-leave.ng-leave-active, .animate-repeat.ng-move, diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index a67ec630e0..3cdb4e3e75 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -20,7 +20,8 @@ Something .row.filter-box .small-12.large-6.columns - %taxon-selector{enterprises: "Producers.visible"} + %taxon-selector{objects: "Producers.visible | filterProducers:query", + results: "activeTaxons"} .small-12.large-6.columns %shipping-type-selector diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 876f5a986b..15b02f955f 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -27,7 +27,7 @@ .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", "scroll-after-load" => true, - "ng-repeat" => "producer in veryFilteredProducers = (filteredProducers() | taxons:TaxonSelector.active() | shipping:shippingTypes)", + "ng-repeat" => "producer in producers = (Producers.visible | filterProducers:query | taxons:activeTaxons | shipping:shippingTypes)", "ng-controller" => "ProducerNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} From eb9ec1497c7810e21cfc6fbdc744760c32114921 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 9 Jul 2014 14:26:42 +1000 Subject: [PATCH 081/145] Backwards --- .../javascripts/darkswarm/directives/taxon_selector.js.coffee | 1 - .../javascripts/darkswarm/filters/filter_producers.js.coffee | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee index 888d17d6ec..bc209f1998 100644 --- a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee @@ -16,7 +16,6 @@ Darkswarm.directive "taxonSelector", -> selector.taxon.id scope.selectors = -> - console.log "selectoring" taxons = {} selectors = [] for object in scope.objects() diff --git a/app/assets/javascripts/darkswarm/filters/filter_producers.js.coffee b/app/assets/javascripts/darkswarm/filters/filter_producers.js.coffee index bbbb82fa30..ed5b8c1bea 100644 --- a/app/assets/javascripts/darkswarm/filters/filter_producers.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/filter_producers.js.coffee @@ -2,5 +2,5 @@ Darkswarm.filter 'filterProducers', (hubsFilter)-> (producers, text) -> producers ||= [] text ?= "" - hubsFilter(producers, text) + From 95d519f0f172b679732d2f53fcc43681eebb9808 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 9 Jul 2014 14:29:07 +1000 Subject: [PATCH 082/145] No results option --- app/views/producers/index.html.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 15b02f955f..792ec16cbe 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -35,5 +35,7 @@ .small-12.columns = render partial: 'producers/skinny' = render partial: 'producers/fat' + %producer.active_table_node.row{"ng-show" => "producers.length == 0"} + No Results = render partial: "shared/footer" From 6f3f40e2e6ebe195e654f18862e06cc32491ea16 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 9 Jul 2014 15:45:05 +1000 Subject: [PATCH 083/145] Adding query string to search params --- .../controllers/producers_controller.js.coffee | 11 ++++++++++- .../shipping_type_selector.js.coffee | 15 ++++++++++++--- .../directives/taxon_selector.js.coffee | 5 ++--- .../darkswarm/filters/capitalize.js.coffee | 4 ++++ .../services/filter_selectors.js.coffee | 18 ++++++++++++++++++ .../darkswarm/services/search.js.coffee | 9 +++++++++ .../templates/shipping_type_selector.html.haml | 8 ++------ app/views/producers/_filters.html.haml | 6 +++++- 8 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/filters/capitalize.js.coffee create mode 100644 app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee create mode 100644 app/assets/javascripts/darkswarm/services/search.js.coffee diff --git a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee index 5da0fc7912..61d1960aef 100644 --- a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee @@ -1,4 +1,13 @@ -Darkswarm.controller "ProducersCtrl", ($scope, Producers, $filter) -> +Darkswarm.controller "ProducersCtrl", ($scope, Producers, $filter, FilterSelectorsService, Search) -> $scope.Producers = Producers + $scope.totalActive = FilterSelectorsService.totalActive + $scope.clearAll = FilterSelectorsService.clearAll $scope.filtersActive = true $scope.activeTaxons = [] + $scope.query = Search.search() + + $scope.$watch "query", (query)-> + Search.search query + + + diff --git a/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee index b634fc167c..586dde36ea 100644 --- a/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee @@ -1,7 +1,16 @@ -Darkswarm.directive "shippingTypeSelector", -> +Darkswarm.directive "shippingTypeSelector", (FilterSelectorsService)-> restrict: 'E' templateUrl: 'shipping_type_selector.html' link: (scope, elem, attr)-> - scope.shippingTypes = + scope.shippingTypes = pickup: false - delivery: false + delivery: false + + scope.selectors = + delivery: FilterSelectorsService.new() + pickup: FilterSelectorsService.new() + + scope.emit = -> + scope.shippingTypes = + pickup: scope.selectors.pickup.active + delivery: scope.selectors.delivery.active diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee index bc209f1998..88dbe919a2 100644 --- a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.directive "taxonSelector", -> +Darkswarm.directive "taxonSelector", (FilterSelectorsService)-> restrict: 'E' scope: objects: "&" @@ -25,8 +25,7 @@ Darkswarm.directive "taxonSelector", -> if selector = selectors_by_id[id] selectors.push selector else - selector = selectors_by_id[id] = - active: false + selector = selectors_by_id[id] = FilterSelectorsService.new taxon: taxon selectors.push selector selectors diff --git a/app/assets/javascripts/darkswarm/filters/capitalize.js.coffee b/app/assets/javascripts/darkswarm/filters/capitalize.js.coffee new file mode 100644 index 0000000000..acbd3fd637 --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/capitalize.js.coffee @@ -0,0 +1,4 @@ +Darkswarm.filter "capitalize", -> + (input, scope) -> + input = input.toLowerCase() if input? + input.substring(0, 1).toUpperCase() + input.substring(1) diff --git a/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee b/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee new file mode 100644 index 0000000000..d9c6848880 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee @@ -0,0 +1,18 @@ +Darkswarm.factory "FilterSelectorsService", -> + # This stores all filters so we can access in-use counts etc + # Accessed via activeSelector Directive + new class FilterSelectorsService + selectors: [] + new: (obj = {})-> + obj.active = false + @selectors.push obj + obj + + totalActive: => + @selectors.filter (selector)-> + selector.active + .length + + clearAll: => + for selector in @selectors + selector.active = false diff --git a/app/assets/javascripts/darkswarm/services/search.js.coffee b/app/assets/javascripts/darkswarm/services/search.js.coffee new file mode 100644 index 0000000000..10e601c4e0 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/search.js.coffee @@ -0,0 +1,9 @@ +Darkswarm.factory "Search", ($location)-> + new class Search + search: (query = false)-> + if query + $location.search('query', query) + else if query == "" + $location.search('query', null) + else + $location.search()['query'] diff --git a/app/assets/javascripts/templates/shipping_type_selector.html.haml b/app/assets/javascripts/templates/shipping_type_selector.html.haml index 80e70d1c8d..b0300857b4 100644 --- a/app/assets/javascripts/templates/shipping_type_selector.html.haml +++ b/app/assets/javascripts/templates/shipping_type_selector.html.haml @@ -1,7 +1,3 @@ %ul.small-block-grid-4 - %li{"ng-class" => "{active: shippingTypes['delivery']}"} - %a{"ng-click" => "shippingTypes['delivery'] = !shippingTypes['delivery']"} - Delivery - %li{"ng-class" => "{active: shippingTypes['pickup']}"} - %a{"ng-click" => "shippingTypes['pickup'] = !shippingTypes['pickup']"} - Pickup + %active-selector{"ng-repeat" => "(name, selector) in selectors"} + {{ name | capitalize }} diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 3cdb4e3e75..91f1e50ec7 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -2,6 +2,7 @@ .small-12.columns %a.right{"ng-click" => "filtersActive = !filtersActive"} Filter by + {{ totalActive() }} %i.ofn-i_052-point-down .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns @@ -24,4 +25,7 @@ results: "activeTaxons"} .small-12.large-6.columns - %shipping-type-selector + %shipping-type-selector{results: "shippingTypes"} + +.row.animate-show{"ng-show" => "filtersActive"} + %a{"ng-click" => "clearAll()"} Clear all From 242c03e7534e3d0d7975288d411d1d57e7d75c37 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 9 Jul 2014 16:03:20 +1000 Subject: [PATCH 084/145] Filter text logic --- app/views/producers/_filters.html.haml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 91f1e50ec7..8957132423 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -1,9 +1,19 @@ .row .small-12.columns %a.right{"ng-click" => "filtersActive = !filtersActive"} - Filter by - {{ totalActive() }} - %i.ofn-i_052-point-down + %span{"ng-show" => "!filtersActive && totalActive() == 0"} + Filter by + %i.ofn-i_052-point-down + + %span{"ng-show" => "filtersActive && totalActive() == 0"} + Hide filters + %i.ofn-i_053-point-up + + %span{"ng-show" => "totalActive() > 0"} + {{ totalActive() }} filters applied + %i.ofn-i_052-point-down{"ng-show" => "!filtersActive"} + %i.ofn-i_053-point-up{"ng-show" => "filtersActive"} + .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns .row.filter-box From c8ee4a594c426d7a5a1b3d69db76ddf8c7950ad2 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 9 Jul 2014 16:10:08 +1000 Subject: [PATCH 085/145] Some text changes and similar magic --- .../controllers/producers_controller.js.coffee | 1 + .../darkswarm/services/filter_selectors.js.coffee | 6 ++++++ app/views/producers/_filters.html.haml | 15 +++------------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee index 61d1960aef..3b8152dca3 100644 --- a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee @@ -2,6 +2,7 @@ Darkswarm.controller "ProducersCtrl", ($scope, Producers, $filter, FilterSelecto $scope.Producers = Producers $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll + $scope.filterText = FilterSelectorsService.filterText $scope.filtersActive = true $scope.activeTaxons = [] $scope.query = Search.search() diff --git a/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee b/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee index d9c6848880..92aa780b8a 100644 --- a/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee +++ b/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee @@ -13,6 +13,12 @@ Darkswarm.factory "FilterSelectorsService", -> selector.active .length + filterText: (active)=> + if @totalActive() == 0 + if active then "Hide filters" else "Filter by" + else + "#{@totalActive()} filters active" + clearAll: => for selector in @selectors selector.active = false diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 8957132423..fd14ccd3e3 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -1,18 +1,9 @@ .row .small-12.columns %a.right{"ng-click" => "filtersActive = !filtersActive"} - %span{"ng-show" => "!filtersActive && totalActive() == 0"} - Filter by - %i.ofn-i_052-point-down - - %span{"ng-show" => "filtersActive && totalActive() == 0"} - Hide filters - %i.ofn-i_053-point-up - - %span{"ng-show" => "totalActive() > 0"} - {{ totalActive() }} filters applied - %i.ofn-i_052-point-down{"ng-show" => "!filtersActive"} - %i.ofn-i_053-point-up{"ng-show" => "filtersActive"} + {{ filterText(filtersActive) }} + %i.ofn-i_052-point-down{"ng-show" => "!filtersActive"} + %i.ofn-i_053-point-up{"ng-show" => "filtersActive"} .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns From 263060611d722edb32bb66d0018ba5987bfaa2ed Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 16:13:43 +1000 Subject: [PATCH 086/145] Search and filter styling and markup tweaks --- .../darkswarm/active_table_search.css.sass | 46 +++++++++++----- .../stylesheets/darkswarm/animations.sass | 11 ++++ .../stylesheets/darkswarm/big-input.sass | 54 +++++++++++++++++++ app/assets/stylesheets/darkswarm/mixins.sass | 26 --------- .../stylesheets/darkswarm/shop.css.sass | 10 ++-- app/views/producers/_filters.html.haml | 4 +- app/views/producers/index.html.haml | 8 +-- 7 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 app/assets/stylesheets/darkswarm/big-input.sass diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 2ec37eaa2b..05d7495f94 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -1,14 +1,18 @@ @import mixins @import branding +@import big-input +@import animations // OVERRIDES .row .row.filter-box margin-left: 0 margin-right: 0 +.row.filter-box:first-child + border-top: 1px solid $clr-brick .filter-box - background: rgba(255,255,255,0.5) + background: rgba(255,255,255,0.65) .tdhead padding: 0.25rem 0.5rem @@ -18,11 +22,19 @@ [class*="block-grid-"] > li padding-bottom: 0.5rem !important + li + @include border-radius(12px) + padding-top: 0.5rem + margin-bottom: 0.25rem + &:hover, &:focus + background: rgba(255,255,255,0.25) + li.active + background: white + @include box-shadow(inset 0 1px 3px 0 rgba(143,48,29,0.5)) + li.active a color: $clr-brick - @include border-radius(12px) - @include box-shadow(inset 0 1px 3px 0 rgba(143,48,29,0.5)) - border: 1px solid $clr-brick + // border: 1px solid $clr-brick render-svg svg path @@ -31,12 +43,12 @@ border-color: $clr-brick-bright li a + @include csstrans display: table table-layout: fixed + overflow: visible // width: 100% - height: 2.5rem - padding: 0.5rem 0.5rem 0.5rem 0.25rem - border: 1px solid transparent + height: 2rem line-height: 1 color: #444 font-size: 0.875rem @@ -46,6 +58,7 @@ text-align: left &:hover, &:focus color: $clr-brick-bright + render-svg svg path @@ -71,6 +84,9 @@ path fill: #666 +.button.filterbtn + margin-bottom: 0 !important + #active-table-search position: relative i.ofn-i_020-search @@ -81,11 +97,13 @@ // z-index: 2 // color: #b2b2b2 - input[type="text"] - font-size: 2em - @include big-input - // padding-left: 44px - - placeholder - color: $disabled-dark + @include placeholder(rgba(0,0,0,0.3), #888) + + input[type="text"] + @include big-input(rgba(0,0,0,0.2), #999, #000) + + + + + diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index 3fcbb41202..ff51d36199 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -141,3 +141,14 @@ animation-fill-mode: both +@mixin csstrans + -webkit-transition: all 300ms ease + -moz-transition: all 300ms ease + -ms-transition: all 300ms ease + -o-transition: all 300ms ease + transition: all 300ms ease + -webkit-transform-style: preserve-3d + + + + diff --git a/app/assets/stylesheets/darkswarm/big-input.sass b/app/assets/stylesheets/darkswarm/big-input.sass new file mode 100644 index 0000000000..c917602fa8 --- /dev/null +++ b/app/assets/stylesheets/darkswarm/big-input.sass @@ -0,0 +1,54 @@ +@import typography +@import branding +@import animations + +//Big search used in active table search \\ + +@mixin big-input($input, $inputhvr, $inputactv) + @extend .avenir + @include csstrans + // transition: all 0.5s ease + background: transparent + border: none + border-bottom: 2px dotted $input + font-size: 2rem + box-shadow: 0 + padding: 0rem 0.5rem 0.2rem 0.5rem + height: auto + margin-bottom: 0.5rem + box-shadow: none + color: $inputactv + + &:hover + -webkit-box-shadow: 0 1px 1px 0 rgba(255,255,255,0.25) + box-shadow: 0 1px 1px 0 rgba(255,255,255,0.25) + border-bottom: 2px dotted $inputhvr + color: $inputactv + + &:active, &:focus, &.active + border-bottom: 2px dotted $inputactv + color: $inputactv + text-shadow: 0 0 10px #ffffff + padding: 1rem 0.5rem 0.5rem 0.5rem + letter-spacing: 0.02rem + +@mixin placeholder($placeholder, $placeholderhvr) + ::-webkit-input-placeholder + color: $placeholder + :-moz-placeholder + color: $placeholder + ::-moz-placeholder + color: $placeholder + :-ms-input-placeholder + color: $placeholder + + &:hover + ::-webkit-input-placeholder + color: $placeholderhvr + :-moz-placeholder + color: $placeholderhvr + ::-moz-placeholder + color: $placeholderhvr + :-ms-input-placeholder + color: $placeholderhvr + diff --git a/app/assets/stylesheets/darkswarm/mixins.sass b/app/assets/stylesheets/darkswarm/mixins.sass index b4845b87fc..b7207335bb 100644 --- a/app/assets/stylesheets/darkswarm/mixins.sass +++ b/app/assets/stylesheets/darkswarm/mixins.sass @@ -8,35 +8,9 @@ padding-top: 100px padding-bottom: 100px -@mixin big-input - // border: 1px solid #999 - background: transparent - border: none - border-bottom: 1px dotted black - font-size: 2rem - @extend .avenir - box-shadow: 0 - padding: 1rem 0 0.5rem 0 - height: auto - margin-bottom: 0.1rem - box-shadow: none - // background: rgba(255,255,255,0.65) - &:active, &:hover, &:focus - color: black - // background: rgba(255,255,255,1) - // border-color: #888 - @mixin disabled color: $disabled-bright -@mixin csstrans - -webkit-transition: all 100ms ease-in-out - -moz-transition: all 100ms ease-in-out - -ms-transition: all 100ms ease-in-out - -o-transition: all 100ms ease-in-out - transition: all 100ms ease-in-out - -webkit-transform-style: preserve-3d - @mixin box-shadow($box-shadow) -moz-box-shadow: $box-shadow -webkit-box-shadow: $box-shadow diff --git a/app/assets/stylesheets/darkswarm/shop.css.sass b/app/assets/stylesheets/darkswarm/shop.css.sass index ae418adda6..53e7515b1c 100644 --- a/app/assets/stylesheets/darkswarm/shop.css.sass +++ b/app/assets/stylesheets/darkswarm/shop.css.sass @@ -1,12 +1,16 @@ @import mixins @import variables @import branding +@import big-input .darkswarm - #search - font-size: 2em - @include big-input + // #search + @include placeholder(rgba(0,0,0,0.3), #999) + + input#search + @include big-input(rgba(0,0,0,0.2), #999, #000) + color: #666 display: block navigation diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 3cdb4e3e75..2cf8caf866 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -1,7 +1,7 @@ .row .small-12.columns - %a.right{"ng-click" => "filtersActive = !filtersActive"} - Filter by + %a.button.primary.tiny.filterbtn{"ng-click" => "filtersActive = !filtersActive"} + Filter options %i.ofn-i_052-point-down .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 792ec16cbe..5cde408aba 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -2,18 +2,18 @@ .producers{"ng-controller" => "ProducersCtrl"} .row .small-12.columns.pad-top - %h1 Find a local producer... + %h1 Find local producers / %div / Find a / %ofn-modal{title: "producer"} / = render partial: "modals/producers" / from the list below: - #active-table-search.row.pad-top + #active-table-search.row .small-12.columns - %input{type: :text, + %input.animate-show{type: :text, "ng-model" => "query", - placeholder: "Search Producer or by Suburb / State", + placeholder: "Search by Producer name or Suburb / State", "ng-debounce" => "150", "ofn-disable-enter" => true} / %placeholder From a4729a8d12fc67f282845a79d5e1078503af7d49 Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 16:15:27 +1000 Subject: [PATCH 087/145] Tweak layout on taxon filters --- app/assets/javascripts/templates/taxon_selector.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/templates/taxon_selector.html.haml b/app/assets/javascripts/templates/taxon_selector.html.haml index e26b36c64a..0f36e9a8f4 100644 --- a/app/assets/javascripts/templates/taxon_selector.html.haml +++ b/app/assets/javascripts/templates/taxon_selector.html.haml @@ -1,4 +1,4 @@ -%ul.small-block-grid-4 +%ul.small-block-grid-2.large-block-grid-4 %active-selector{"ng-repeat" => "selector in selectors()"} %render-svg{path: "{{selector.taxon.icon}}"} %span {{ selector.taxon.name }} From 9474ec49c62acfc14372787c6a0f4041da87eafc Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 16:21:36 +1000 Subject: [PATCH 088/145] Fix unbalanced brackets issue --- app/views/producers/_filters.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index cdb7c7d25e..b46df416c3 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -1,6 +1,6 @@ .row .small-12.columns - %a.button.primary.tiny.filterbtn{{"ng-click" => "filtersActive = !filtersActive"} + %a.button.primary.tiny.filterbtn{{"ng-click" => "filtersActive = !filtersActive"}} {{ filterText(filtersActive) }} %i.ofn-i_052-point-down{"ng-show" => "!filtersActive"} %i.ofn-i_053-point-up{"ng-show" => "filtersActive"} From d9a3d22330e5dfca36779a5bf2c2dbd0a64756af Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 16:53:26 +1000 Subject: [PATCH 089/145] Tweak labels for filter button --- .../darkswarm/services/filter_selectors.js.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee b/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee index 92aa780b8a..370f98f88f 100644 --- a/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee +++ b/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee @@ -14,10 +14,13 @@ Darkswarm.factory "FilterSelectorsService", -> .length filterText: (active)=> - if @totalActive() == 0 + total = @totalActive() + if total == 0 if active then "Hide filters" else "Filter by" + else if total == 1 + "1 filter applied" else - "#{@totalActive()} filters active" + "#{@totalActive()} filters applied" clearAll: => for selector in @selectors From b43f687cf4d5656642158393135e3dd86d49fc81 Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 16:54:35 +1000 Subject: [PATCH 090/145] Tweak to producers - turn filters off by default --- .../darkswarm/controllers/producers_controller.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee index 3b8152dca3..cb2c4c6dc3 100644 --- a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee @@ -3,7 +3,7 @@ Darkswarm.controller "ProducersCtrl", ($scope, Producers, $filter, FilterSelecto $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll $scope.filterText = FilterSelectorsService.filterText - $scope.filtersActive = true + $scope.filtersActive = false $scope.activeTaxons = [] $scope.query = Search.search() From 0451dbe6b0758da98cc267d72c2233d02674b3af Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 16:55:05 +1000 Subject: [PATCH 091/145] More styling to filters and search --- app/assets/stylesheets/darkswarm/active_table.css.sass | 5 ++++- app/views/producers/_filters.html.haml | 10 ++++++++-- app/views/producers/index.html.haml | 10 +++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table.css.sass b/app/assets/stylesheets/darkswarm/active_table.css.sass index b472c36915..a386328a5a 100644 --- a/app/assets/stylesheets/darkswarm/active_table.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table.css.sass @@ -9,6 +9,9 @@ display: block &:first-child cursor: pointer + + .no-results + font-size: 1.875rem .active_table .active_table_node display: block @@ -18,7 +21,7 @@ border: 1px solid transparent &, & > a.row display: block - + .active_table_row.link border: 0 diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index b46df416c3..01364baf1a 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -27,5 +27,11 @@ .small-12.large-6.columns %shipping-type-selector{results: "shippingTypes"} -.row.animate-show{"ng-show" => "filtersActive"} - %a{"ng-click" => "clearAll()"} Clear all + .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} + .small-12.columns + %a.button.secondary.small.expand{"ng-click" => "clearAll()"} + %i.ofn-i_009-close + Clear all filters + +/ .row.animate-show{"ng-show" => "filtersActive"} +/ %a{"ng-click" => "clearAll()"} Clear all diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 5cde408aba..5b5c6f27ac 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -1,5 +1,5 @@ = inject_enterprises -.producers{"ng-controller" => "ProducersCtrl"} +.producers.pad-top{"ng-controller" => "ProducersCtrl"} .row .small-12.columns.pad-top %h1 Find local producers @@ -35,7 +35,11 @@ .small-12.columns = render partial: 'producers/skinny' = render partial: 'producers/fat' - %producer.active_table_node.row{"ng-show" => "producers.length == 0"} - No Results + + %producer.row{"ng-show" => "producers.length == 0"} + %p.no-results + Sorry, no results found for + %strong {{query}}. + Try another search? = render partial: "shared/footer" From eda5119bfc6f0d4644830bcf9c49dd658b53dbce Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 16:57:33 +1000 Subject: [PATCH 092/145] Remove unused styling and unneeded comments --- .../darkswarm/active_table_search.css.sass | 13 +------------ app/views/producers/_filters.html.haml | 5 +---- app/views/producers/index.html.haml | 5 +---- 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 05d7495f94..271ae6d086 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -34,7 +34,6 @@ li.active a color: $clr-brick - // border: 1px solid $clr-brick render-svg svg path @@ -77,7 +76,6 @@ height: 1.5rem margin: 0 padding: 0 - // margin-right: 0.25rem svg width: 1.5rem height: 1.5rem @@ -88,17 +86,8 @@ margin-bottom: 0 !important #active-table-search - position: relative - i.ofn-i_020-search - // position: absolute - // left: 26px - // top: 12px - // font-size: 1.6em - // z-index: 2 - // color: #b2b2b2 - + position: relative @include placeholder(rgba(0,0,0,0.3), #888) - input[type="text"] @include big-input(rgba(0,0,0,0.2), #999, #000) diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 01364baf1a..b5510c9156 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -31,7 +31,4 @@ .small-12.columns %a.button.secondary.small.expand{"ng-click" => "clearAll()"} %i.ofn-i_009-close - Clear all filters - -/ .row.animate-show{"ng-show" => "filtersActive"} -/ %a{"ng-click" => "clearAll()"} Clear all + Clear all filters \ No newline at end of file diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 5b5c6f27ac..821c8e9323 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -16,9 +16,6 @@ placeholder: "Search by Producer name or Suburb / State", "ng-debounce" => "150", "ofn-disable-enter" => true} - / %placeholder - / %i.ofn-i_020-search - / Search Producer or by Suburb / Postcode / State = render partial: "producers/filters" @@ -35,7 +32,7 @@ .small-12.columns = render partial: 'producers/skinny' = render partial: 'producers/fat' - + %producer.row{"ng-show" => "producers.length == 0"} %p.no-results Sorry, no results found for From 37924c652aba2fbe692589bd20d808e3002f64bb Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 17:23:30 +1000 Subject: [PATCH 093/145] Add filters partial for Hubs search --- app/views/home/_filters.html.haml | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 app/views/home/_filters.html.haml diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml new file mode 100644 index 0000000000..367025391d --- /dev/null +++ b/app/views/home/_filters.html.haml @@ -0,0 +1,33 @@ +.row + .small-12.columns + %a.button.primary.tiny.filterbtn{{"ng-click" => "filtersActive = !filtersActive"}} + {{ filterText(filtersActive) }} + %i.ofn-i_052-point-down{"ng-show" => "!filtersActive"} + %i.ofn-i_053-point-up{"ng-show" => "filtersActive"} + +.row.animate-show{"ng-show" => "filtersActive"} + .small-12.columns + + .row.filter-box + .small-12.large-8.columns + %h5.tdhead + .light Filter by + Type + .small-12.large-4.columns + %h5.tdhead + .light Filter by + Delivery + + .row.filter-box + .small-12.large-8.columns + %taxon-selector{objects: "Hubs.visible | filterHubs:query", + results: "activeTaxons"} + + .small-12.large-4.columns + %shipping-type-selector{results: "shippingTypes"} + + .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} + .small-12.columns + %a.button.secondary.small.expand{"ng-click" => "clearAll()"} + %i.ofn-i_009-close + Clear all filters \ No newline at end of file From 11ec5961336d17e8db850caab3a63b9f98f7de6c Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 17:23:58 +1000 Subject: [PATCH 094/145] Layout adjust for taxon filters --- app/assets/javascripts/templates/taxon_selector.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/templates/taxon_selector.html.haml b/app/assets/javascripts/templates/taxon_selector.html.haml index 0f36e9a8f4..c8304bc6e6 100644 --- a/app/assets/javascripts/templates/taxon_selector.html.haml +++ b/app/assets/javascripts/templates/taxon_selector.html.haml @@ -1,4 +1,4 @@ -%ul.small-block-grid-2.large-block-grid-4 +%ul.small-block-grid-2.large-block-grid-6 %active-selector{"ng-repeat" => "selector in selectors()"} %render-svg{path: "{{selector.taxon.icon}}"} %span {{ selector.taxon.name }} From 864df410525a2e435ab53cb6516bd0185072e702 Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 17:24:10 +1000 Subject: [PATCH 095/145] Add filters partial --- app/views/home/_hubs.html.haml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index f8698989c3..e92eb81147 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -14,10 +14,12 @@ / %i.ofn-i_020-search %input{type: :text, "ng-model" => "query", - placeholder: "Search Hub or by Suburb / State", + placeholder: "Search by Hub or Suburb name", "ng-debounce" => "150", "ofn-disable-enter" => true} + = render partial: "home/filters" + .row{bindonce: true} .small-12.columns .active_table @@ -30,6 +32,9 @@ = render partial: 'home/skinny' = render partial: 'home/fat' - .row{"ng-show" => "filteredHubs.length == 0"} - .columns.small-12.text-center - No results + .row{"ng-show" => "filteredHubs.length == 0"} + .columns.small-12 + %p.no-results + Sorry, no results found for + %strong {{query}}. + Try another search? From 2c157a939d7ec48961aa8010e6a0604a0618f704 Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 17:24:24 +1000 Subject: [PATCH 096/145] Tweak markup / filters available for Producers page --- app/views/producers/_filters.html.haml | 19 +++++++------------ app/views/producers/index.html.haml | 2 +- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index b5510c9156..566ce460c3 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -4,28 +4,23 @@ {{ filterText(filtersActive) }} %i.ofn-i_052-point-down{"ng-show" => "!filtersActive"} %i.ofn-i_053-point-up{"ng-show" => "filtersActive"} + .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns + .row.filter-box - .small-12.large-6.columns + .small-12.columns %h5.tdhead .light Filter by Type - .small-12.large-3.columns - %h5.tdhead - .light Filter by - Delivery - .small-12.large-3.columns - %h5.tdhead - .light Filter by - Something + .row.filter-box - .small-12.large-6.columns + .small-12.columns %taxon-selector{objects: "Producers.visible | filterProducers:query", results: "activeTaxons"} - .small-12.large-6.columns - %shipping-type-selector{results: "shippingTypes"} + / .small-12.large-6.columns + / %shipping-type-selector{results: "shippingTypes"} .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} .small-12.columns diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 821c8e9323..1f883645e4 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -13,7 +13,7 @@ .small-12.columns %input.animate-show{type: :text, "ng-model" => "query", - placeholder: "Search by Producer name or Suburb / State", + placeholder: "Search by Producer or Suburb name", "ng-debounce" => "150", "ofn-disable-enter" => true} From ac8d3f8c96a8edb0a40f753a66f760edfd44b4db Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 17:35:04 +1000 Subject: [PATCH 097/145] Make a static (non animated) version of big input --- app/assets/stylesheets/darkswarm/big-input.sass | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/big-input.sass b/app/assets/stylesheets/darkswarm/big-input.sass index c917602fa8..3e74c70ec8 100644 --- a/app/assets/stylesheets/darkswarm/big-input.sass +++ b/app/assets/stylesheets/darkswarm/big-input.sass @@ -1,6 +1,7 @@ @import typography @import branding @import animations +@import mixins //Big search used in active table search \\ @@ -20,8 +21,7 @@ color: $inputactv &:hover - -webkit-box-shadow: 0 1px 1px 0 rgba(255,255,255,0.25) - box-shadow: 0 1px 1px 0 rgba(255,255,255,0.25) + @include box-shadow(0 1px 1px 0 rgba(255,255,255,0.25)) border-bottom: 2px dotted $inputhvr color: $inputactv @@ -32,6 +32,12 @@ padding: 1rem 0.5rem 0.5rem 0.5rem letter-spacing: 0.02rem +@mixin big-input-static + outline: 0 + &:active, &:focus, &.active + padding: 0rem 0.5rem 0.2rem 0.5rem + letter-spacing: 0 + @mixin placeholder($placeholder, $placeholderhvr) ::-webkit-input-placeholder color: $placeholder From c744c61f2524ff9b8cc95af9659c76282a40604b Mon Sep 17 00:00:00 2001 From: summerscope Date: Wed, 9 Jul 2014 17:35:21 +1000 Subject: [PATCH 098/145] Styling for shopfront page with search input --- app/assets/stylesheets/darkswarm/shop.css.sass | 1 + app/views/shop/products/_form.html.haml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/shop.css.sass b/app/assets/stylesheets/darkswarm/shop.css.sass index 53e7515b1c..9011f99a7f 100644 --- a/app/assets/stylesheets/darkswarm/shop.css.sass +++ b/app/assets/stylesheets/darkswarm/shop.css.sass @@ -10,6 +10,7 @@ input#search @include big-input(rgba(0,0,0,0.2), #999, #000) + @include big-input-static color: #666 display: block diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index eee0e16332..193b2dd9b6 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -5,7 +5,7 @@ .row .small-6.columns %input#search.text{"ng-model" => "query", - placeholder: "Search", + placeholder: "Search products", "ng-debounce" => "150", "ofn-disable-enter" => true} .small-6.columns From 7c1dfa7b23900f15eddf18ce247054d6b0835dd7 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 10 Jul 2014 10:36:56 +1000 Subject: [PATCH 099/145] Add min width to filter button --- app/assets/stylesheets/darkswarm/active_table_search.css.sass | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 271ae6d086..9de5fdf640 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -84,6 +84,7 @@ .button.filterbtn margin-bottom: 0 !important + min-width: 160px #active-table-search position: relative From 0b3b8883cda2eb76bd3496f20080f2d51e702f2f Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Wed, 9 Jul 2014 16:34:13 +1000 Subject: [PATCH 100/145] Disabling infinite scrolling due to bugs on iPad --- app/views/shop/products/_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index 193b2dd9b6..391ad83227 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -13,7 +13,7 @@ %div{bindonce: true} %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", - "ng-repeat" => "product in Product.products | products:query | orderBy:ordering.order | limitTo: limit track by product.id"} + "ng-repeat" => "product in Product.products | products:query | orderBy:ordering.order"} %div = render partial: "shop/products/summary" %div{"bo-if" => "hasVariants"} From 409d647f624ac25d7fbe427baac8c00e8a192025 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 10 Jul 2014 11:37:27 +1000 Subject: [PATCH 101/145] Fixing up hubs page --- .../darkswarm/controllers/hubs_controller.js.coffee | 9 ++++++++- .../darkswarm/controllers/producers_controller.js.coffee | 3 --- .../darkswarm/directives/active_selector.js.coffee | 2 ++ .../darkswarm/services/filter_selectors.js.coffee | 1 + app/views/home/_filters.html.haml | 4 ++-- app/views/home/_hubs.html.haml | 2 +- app/views/producers/_filters.html.haml | 5 +---- app/views/producers/index.html.haml | 2 +- 8 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee index acc71b1172..769b47cbe8 100644 --- a/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee @@ -1,6 +1,13 @@ -Darkswarm.controller "HubsCtrl", ($scope, Hubs, $document, $rootScope, HashNavigation) -> +Darkswarm.controller "HubsCtrl", ($scope, Hubs, Search, $document, $rootScope, HashNavigation, FilterSelectorsService) -> $scope.Hubs = Hubs $scope.hubs = Hubs.visible + $scope.totalActive = FilterSelectorsService.totalActive + $scope.clearAll = FilterSelectorsService.clearAll + $scope.filterText = FilterSelectorsService.filterText + $scope.query = Search.search() + + $scope.$watch "query", (query)-> + Search.search query $rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) -> if HashNavigation.active "hubs" diff --git a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee index cb2c4c6dc3..6fdb589529 100644 --- a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee @@ -9,6 +9,3 @@ Darkswarm.controller "ProducersCtrl", ($scope, Producers, $filter, FilterSelecto $scope.$watch "query", (query)-> Search.search query - - - diff --git a/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee index 803c83eee3..74523c2c3d 100644 --- a/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee @@ -4,7 +4,9 @@ Darkswarm.directive "activeSelector", -> replace: true templateUrl: 'active_selector.html' link: (scope, elem, attr)-> + scope.selector.emit = scope.emit elem.bind "click", -> scope.$apply -> scope.selector.active = !scope.selector.active scope.emit() + diff --git a/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee b/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee index 370f98f88f..47ed12806d 100644 --- a/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee +++ b/app/assets/javascripts/darkswarm/services/filter_selectors.js.coffee @@ -25,3 +25,4 @@ Darkswarm.factory "FilterSelectorsService", -> clearAll: => for selector in @selectors selector.active = false + selector.emit() diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml index 367025391d..eaebe08025 100644 --- a/app/views/home/_filters.html.haml +++ b/app/views/home/_filters.html.haml @@ -20,7 +20,7 @@ .row.filter-box .small-12.large-8.columns - %taxon-selector{objects: "Hubs.visible | filterHubs:query", + %taxon-selector{objects: "hubs | hubs:query", results: "activeTaxons"} .small-12.large-4.columns @@ -30,4 +30,4 @@ .small-12.columns %a.button.secondary.small.expand{"ng-click" => "clearAll()"} %i.ofn-i_009-close - Clear all filters \ No newline at end of file + Clear all filters diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index e92eb81147..5669014bcf 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -23,7 +23,7 @@ .row{bindonce: true} .small-12.columns .active_table - %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredHubs = (hubs | hubs:query)", + %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredHubs = (hubs | hubs:query | taxons:activeTaxons | shipping:shippingTypes)", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "scroll-after-load" => true, "ng-controller" => "HubNodeCtrl", diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 566ce460c3..5fd89d4323 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -19,11 +19,8 @@ %taxon-selector{objects: "Producers.visible | filterProducers:query", results: "activeTaxons"} - / .small-12.large-6.columns - / %shipping-type-selector{results: "shippingTypes"} - .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} .small-12.columns %a.button.secondary.small.expand{"ng-click" => "clearAll()"} %i.ofn-i_009-close - Clear all filters \ No newline at end of file + Clear all filters diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 1f883645e4..1a2c827068 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -24,7 +24,7 @@ .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", "scroll-after-load" => true, - "ng-repeat" => "producer in producers = (Producers.visible | filterProducers:query | taxons:activeTaxons | shipping:shippingTypes)", + "ng-repeat" => "producer in producers = (Producers.visible | filterProducers:query | taxons:activeTaxons)", "ng-controller" => "ProducerNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} From 9d519f5f4b726f3c642648658727553ac9fcc3bb Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 10 Jul 2014 11:52:32 +1000 Subject: [PATCH 102/145] Fixing a minor test regression --- spec/features/consumer/authentication_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/consumer/authentication_spec.rb b/spec/features/consumer/authentication_spec.rb index 8853a07c3d..f8b405374e 100644 --- a/spec/features/consumer/authentication_spec.rb +++ b/spec/features/consumer/authentication_spec.rb @@ -11,7 +11,7 @@ feature "Authentication", js: true do fill_in "Email", with: user.email fill_in "Password", with: user.password click_login_button - page.should have_content "Select a producer from the list below" + page.should have_content "Find local producers" current_path.should == producers_path end end From da02f9c0b0c311d84ca58d423407f06c7d2ac6d1 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 10 Jul 2014 12:02:34 +1000 Subject: [PATCH 103/145] Adding icons to shipping selectors --- .../darkswarm/directives/shipping_type_selector.js.coffee | 6 ++++-- .../javascripts/templates/shipping_type_selector.html.haml | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee index 586dde36ea..856b6dcac2 100644 --- a/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee @@ -7,8 +7,10 @@ Darkswarm.directive "shippingTypeSelector", (FilterSelectorsService)-> delivery: false scope.selectors = - delivery: FilterSelectorsService.new() - pickup: FilterSelectorsService.new() + delivery: FilterSelectorsService.new + icon: "ofn-i_039-delivery" + pickup: FilterSelectorsService.new + icon: "ofn-i_038-takeaway" scope.emit = -> scope.shippingTypes = diff --git a/app/assets/javascripts/templates/shipping_type_selector.html.haml b/app/assets/javascripts/templates/shipping_type_selector.html.haml index b0300857b4..ee01002669 100644 --- a/app/assets/javascripts/templates/shipping_type_selector.html.haml +++ b/app/assets/javascripts/templates/shipping_type_selector.html.haml @@ -1,3 +1,4 @@ %ul.small-block-grid-4 %active-selector{"ng-repeat" => "(name, selector) in selectors"} + %i{"ng-class" => "selector.icon"} {{ name | capitalize }} From 3e24e4310014f14bc638fd5ff4f79854ede78c3c Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 10 Jul 2014 12:05:11 +1000 Subject: [PATCH 104/145] Tweak icons for up / down --- app/views/home/_filters.html.haml | 4 ++-- app/views/producers/_filters.html.haml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml index eaebe08025..cf157a611e 100644 --- a/app/views/home/_filters.html.haml +++ b/app/views/home/_filters.html.haml @@ -2,8 +2,8 @@ .small-12.columns %a.button.primary.tiny.filterbtn{{"ng-click" => "filtersActive = !filtersActive"}} {{ filterText(filtersActive) }} - %i.ofn-i_052-point-down{"ng-show" => "!filtersActive"} - %i.ofn-i_053-point-up{"ng-show" => "filtersActive"} + %i.ofn-i_005-caret-down{"ng-show" => "!filtersActive"} + %i.ofn-i_006-caret-up{"ng-show" => "filtersActive"} .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 5fd89d4323..d5158858b1 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -2,8 +2,8 @@ .small-12.columns %a.button.primary.tiny.filterbtn{{"ng-click" => "filtersActive = !filtersActive"}} {{ filterText(filtersActive) }} - %i.ofn-i_052-point-down{"ng-show" => "!filtersActive"} - %i.ofn-i_053-point-up{"ng-show" => "filtersActive"} + %i.ofn-i_005-caret-down{"ng-show" => "!filtersActive"} + %i.ofn-i_006-caret-up{"ng-show" => "filtersActive"} .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns From cf4c51e0d90cc4bd5477541c9af50fa303911424 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 10 Jul 2014 12:05:32 +1000 Subject: [PATCH 105/145] STyling taxon filters --- app/assets/stylesheets/darkswarm/active_table_search.css.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 9de5fdf640..506f62d6b0 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -74,7 +74,7 @@ display: block width: 1.5rem height: 1.5rem - margin: 0 + margin: 0 0.2rem 0 0 padding: 0 svg width: 1.5rem From 8296a4131eec42ce3c220e7ea07010731958acf7 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 10 Jul 2014 12:07:21 +1000 Subject: [PATCH 106/145] Partializing filter controls --- app/views/home/_filters.html.haml | 7 +------ app/views/producers/_filters.html.haml | 7 +------ app/views/shared/components/_filter_controls.html.haml | 6 ++++++ 3 files changed, 8 insertions(+), 12 deletions(-) create mode 100644 app/views/shared/components/_filter_controls.html.haml diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml index cf157a611e..4fd3360d5c 100644 --- a/app/views/home/_filters.html.haml +++ b/app/views/home/_filters.html.haml @@ -1,9 +1,4 @@ -.row - .small-12.columns - %a.button.primary.tiny.filterbtn{{"ng-click" => "filtersActive = !filtersActive"}} - {{ filterText(filtersActive) }} - %i.ofn-i_005-caret-down{"ng-show" => "!filtersActive"} - %i.ofn-i_006-caret-up{"ng-show" => "filtersActive"} += render partial: 'shared/components/filter_controls' .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index d5158858b1..0f1f2f483a 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -1,9 +1,4 @@ -.row - .small-12.columns - %a.button.primary.tiny.filterbtn{{"ng-click" => "filtersActive = !filtersActive"}} - {{ filterText(filtersActive) }} - %i.ofn-i_005-caret-down{"ng-show" => "!filtersActive"} - %i.ofn-i_006-caret-up{"ng-show" => "filtersActive"} += render partial: 'shared/components/filter_controls' .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns diff --git a/app/views/shared/components/_filter_controls.html.haml b/app/views/shared/components/_filter_controls.html.haml new file mode 100644 index 0000000000..7fe95c324a --- /dev/null +++ b/app/views/shared/components/_filter_controls.html.haml @@ -0,0 +1,6 @@ +.row + .small-12.columns + %a.button.primary.tiny.filterbtn{{"ng-click" => "filtersActive = !filtersActive"}} + {{ filterText(filtersActive) }} + %i.ofn-i_005-caret-down{"ng-show" => "!filtersActive"} + %i.ofn-i_006-caret-up{"ng-show" => "filtersActive"} From 76b25945e931257ca0ca5532f72deedacd25bbb0 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 10 Jul 2014 12:21:18 +1000 Subject: [PATCH 107/145] Adjust layout for small views --- app/views/home/_filters.html.haml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml index 4fd3360d5c..ab98389e82 100644 --- a/app/views/home/_filters.html.haml +++ b/app/views/home/_filters.html.haml @@ -1,26 +1,19 @@ = render partial: 'shared/components/filter_controls' .row.animate-show{"ng-show" => "filtersActive"} - .small-12.columns - + .small-12.columns .row.filter-box - .small-12.large-8.columns + .small-12.large-9.columns %h5.tdhead .light Filter by Type - .small-12.large-4.columns + %taxon-selector{objects: "hubs | hubs:query", + results: "activeTaxons"} + .small-12.large-3.columns %h5.tdhead .light Filter by Delivery - - .row.filter-box - .small-12.large-8.columns - %taxon-selector{objects: "hubs | hubs:query", - results: "activeTaxons"} - - .small-12.large-4.columns %shipping-type-selector{results: "shippingTypes"} - .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} .small-12.columns %a.button.secondary.small.expand{"ng-click" => "clearAll()"} From c8f51ec9179cb9ae72c95a718f9c052943569bf3 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 10 Jul 2014 12:21:32 +1000 Subject: [PATCH 108/145] Adjust layout for small views --- app/views/producers/_filters.html.haml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 0f1f2f483a..2419e0478d 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -2,15 +2,11 @@ .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns - .row.filter-box .small-12.columns %h5.tdhead .light Filter by Type - - .row.filter-box - .small-12.columns %taxon-selector{objects: "Producers.visible | filterProducers:query", results: "activeTaxons"} From 34cb672a8db1e197f58064f3e72c509ac4b259d5 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 10 Jul 2014 12:21:54 +1000 Subject: [PATCH 109/145] Adjust column layouts / responsive breakpoints for filter systems --- .../javascripts/templates/shipping_type_selector.html.haml | 2 +- app/assets/javascripts/templates/taxon_selector.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/templates/shipping_type_selector.html.haml b/app/assets/javascripts/templates/shipping_type_selector.html.haml index ee01002669..cdbe702f32 100644 --- a/app/assets/javascripts/templates/shipping_type_selector.html.haml +++ b/app/assets/javascripts/templates/shipping_type_selector.html.haml @@ -1,4 +1,4 @@ -%ul.small-block-grid-4 +%ul.small-block-grid-2.large-block-grid-1 %active-selector{"ng-repeat" => "(name, selector) in selectors"} %i{"ng-class" => "selector.icon"} {{ name | capitalize }} diff --git a/app/assets/javascripts/templates/taxon_selector.html.haml b/app/assets/javascripts/templates/taxon_selector.html.haml index c8304bc6e6..dd40453e3f 100644 --- a/app/assets/javascripts/templates/taxon_selector.html.haml +++ b/app/assets/javascripts/templates/taxon_selector.html.haml @@ -1,4 +1,4 @@ -%ul.small-block-grid-2.large-block-grid-6 +%ul.small-block-grid-2.large-block-grid-5 %active-selector{"ng-repeat" => "selector in selectors()"} %render-svg{path: "{{selector.taxon.icon}}"} %span {{ selector.taxon.name }} From 9fa62b39af41d03e501049400f0e707ded7d00b1 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 10 Jul 2014 12:22:08 +1000 Subject: [PATCH 110/145] More styling for filters and search --- .../stylesheets/darkswarm/active_table_search.css.sass | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 506f62d6b0..f6ae36bcc1 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -47,7 +47,7 @@ table-layout: fixed overflow: visible // width: 100% - height: 2rem + // height: 2rem line-height: 1 color: #444 font-size: 0.875rem @@ -55,6 +55,11 @@ display: table-cell vertical-align: middle text-align: left + i + display: block + font-size: 1.5rem + margin: 0 0.2rem 0 0 + &:hover, &:focus color: $clr-brick-bright @@ -70,6 +75,7 @@ path fill: $clr-brick + render-svg display: block width: 1.5rem From 0e0cf5576d486aebbf7150e26957d96ea9d3e1b5 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 10 Jul 2014 12:58:38 +1000 Subject: [PATCH 111/145] Restyle big search to make it MORE OBVIOUS. --- .../darkswarm/active_table_search.css.sass | 4 ++-- app/assets/stylesheets/darkswarm/big-input.sass | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index f6ae36bcc1..d8f253ee28 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -94,9 +94,9 @@ #active-table-search position: relative - @include placeholder(rgba(0,0,0,0.3), #888) + @include placeholder(rgba(0,0,0,0.4), #777) input[type="text"] - @include big-input(rgba(0,0,0,0.2), #999, #000) + @include big-input(rgba(0,0,0,0.3), #777, $clr-brick) diff --git a/app/assets/stylesheets/darkswarm/big-input.sass b/app/assets/stylesheets/darkswarm/big-input.sass index 3e74c70ec8..72769e80c6 100644 --- a/app/assets/stylesheets/darkswarm/big-input.sass +++ b/app/assets/stylesheets/darkswarm/big-input.sass @@ -8,13 +8,14 @@ @mixin big-input($input, $inputhvr, $inputactv) @extend .avenir @include csstrans + @include border-radius(0.5rem) + // transition: all 0.5s ease - background: transparent - border: none - border-bottom: 2px dotted $input + background: rgba(255,255,255,0.1) + border: 2px solid $input font-size: 2rem box-shadow: 0 - padding: 0rem 0.5rem 0.2rem 0.5rem + padding: 0.75rem 1rem 0.35rem 1rem height: auto margin-bottom: 0.5rem box-shadow: none @@ -22,14 +23,16 @@ &:hover @include box-shadow(0 1px 1px 0 rgba(255,255,255,0.25)) - border-bottom: 2px dotted $inputhvr + border: 2px solid $inputhvr color: $inputactv &:active, &:focus, &.active - border-bottom: 2px dotted $inputactv + border: 2px solid $inputactv color: $inputactv + background: white + background: rgba(255,255,255,0.5) text-shadow: 0 0 10px #ffffff - padding: 1rem 0.5rem 0.5rem 0.5rem + padding: 1.5rem 1rem 1rem 1rem letter-spacing: 0.02rem @mixin big-input-static From 31cf01ba1b78f8db405bcf7980233fa1934f4451 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 10 Jul 2014 12:59:59 +1000 Subject: [PATCH 112/145] Sorting hubs by active --- app/views/producers/_fat.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/producers/_fat.html.haml b/app/views/producers/_fat.html.haml index b1eb7196aa..86ed3ad7b7 100644 --- a/app/views/producers/_fat.html.haml +++ b/app/views/producers/_fat.html.haml @@ -26,7 +26,7 @@ %h5 Shop for {{ producer.name }} products at: .row .columns.small-12 - %a.button.hub{"ng-repeat" => "hub in producer.hubs", + %a.button.hub{"ng-repeat" => "hub in producer.hubs | orderBy:'-active'", "bo-href" => "hub.path", "ofn-empties-cart" => "hub", "bo-class" => "{primary: hub.active, secondary: !hub.active}"} %i.ofn-i_033-open-sign{"bo-if" => "hub.active"} From 6681beae4d6c4c61b887770bb4ac7cd26bd5bb88 Mon Sep 17 00:00:00 2001 From: summerscope Date: Thu, 10 Jul 2014 13:04:20 +1000 Subject: [PATCH 113/145] Fix spacing for shopfront page search box --- app/assets/stylesheets/darkswarm/big-input.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/big-input.sass b/app/assets/stylesheets/darkswarm/big-input.sass index 72769e80c6..70cb3bd4f9 100644 --- a/app/assets/stylesheets/darkswarm/big-input.sass +++ b/app/assets/stylesheets/darkswarm/big-input.sass @@ -38,7 +38,7 @@ @mixin big-input-static outline: 0 &:active, &:focus, &.active - padding: 0rem 0.5rem 0.2rem 0.5rem + padding: 0.75rem 1rem 0.35rem 1rem letter-spacing: 0 @mixin placeholder($placeholder, $placeholderhvr) From 932ca95ec5037e220dd02876347d3ef36166f40c Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 10 Jul 2014 12:59:59 +1000 Subject: [PATCH 114/145] Sorting hubs by active --- app/views/producers/_fat.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/producers/_fat.html.haml b/app/views/producers/_fat.html.haml index b1eb7196aa..86ed3ad7b7 100644 --- a/app/views/producers/_fat.html.haml +++ b/app/views/producers/_fat.html.haml @@ -26,7 +26,7 @@ %h5 Shop for {{ producer.name }} products at: .row .columns.small-12 - %a.button.hub{"ng-repeat" => "hub in producer.hubs", + %a.button.hub{"ng-repeat" => "hub in producer.hubs | orderBy:'-active'", "bo-href" => "hub.path", "ofn-empties-cart" => "hub", "bo-class" => "{primary: hub.active, secondary: !hub.active}"} %i.ofn-i_033-open-sign{"bo-if" => "hub.active"} From 7dde7214860a177e6312ed2f8afac27149b99864 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Thu, 10 Jul 2014 15:26:35 +1000 Subject: [PATCH 115/145] Adding taxon filtering --- .../controllers/products_controller.js.coffee | 5 ++++- .../directives/taxon_selector.js.coffee | 5 ++++- app/views/shop/products/_filters.html.haml | 17 +++++++++++++++++ app/views/shop/products/_form.html.haml | 7 +++++-- 4 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 app/views/shop/products/_filters.html.haml diff --git a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee index 3860a2d56e..e29797e4e8 100644 --- a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee @@ -1,5 +1,8 @@ -Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Product, OrderCycle) -> +Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Product, OrderCycle, FilterSelectorsService) -> $scope.Product = Product + $scope.totalActive = FilterSelectorsService.totalActive + $scope.clearAll = FilterSelectorsService.clearAll + $scope.filterText = FilterSelectorsService.filterText $scope.limit = 3 $scope.ordering = {order: "name"} $scope.order_cycle = OrderCycle.order_cycle diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee index 88dbe919a2..bf665bb23d 100644 --- a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee @@ -19,8 +19,11 @@ Darkswarm.directive "taxonSelector", (FilterSelectorsService)-> taxons = {} selectors = [] for object in scope.objects() - for taxon in (object.taxons.concat object?.supplied_taxons) + for taxon in object.taxons taxons[taxon.id] = taxon + if object.supplied_taxons + for taxon in object.supplied_taxons + taxons[taxon.id] = taxon for id, taxon of taxons if selector = selectors_by_id[id] selectors.push selector diff --git a/app/views/shop/products/_filters.html.haml b/app/views/shop/products/_filters.html.haml new file mode 100644 index 0000000000..3e7a24a44c --- /dev/null +++ b/app/views/shop/products/_filters.html.haml @@ -0,0 +1,17 @@ += render partial: 'shared/components/filter_controls' + +.row.animate-show{"ng-show" => "filtersActive"} + .small-12.columns + .row.filter-box + .small-12.columns + %h5.tdhead + .light Filter by + Type + %taxon-selector{objects: "Product.products | products:query", + results: "activeTaxons"} + + .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} + .small-12.columns + %a.button.secondary.small.expand{"ng-click" => "clearAll()"} + %i.ofn-i_009-close + Clear all filters diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index 391ad83227..c3f3911f5a 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -1,6 +1,7 @@ %products.small-12.columns{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null", "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1"} + = form_for :order, :url => populate_orders_path, html: {:class => "custom"} do .row .small-6.columns @@ -8,12 +9,14 @@ placeholder: "Search products", "ng-debounce" => "150", "ofn-disable-enter" => true} + .small-6.columns %input.button.primary.right{type: :submit, value: "Add to Cart"} - + = render partial: "shop/products/filters" + %div{bindonce: true} %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", - "ng-repeat" => "product in Product.products | products:query | orderBy:ordering.order"} + "ng-repeat" => "product in Product.products | products:query | taxons:activeTaxons | orderBy:ordering.order"} %div = render partial: "shop/products/summary" %div{"bo-if" => "hasVariants"} From fa337fcd6ea0c3bfcdc60ca910602bdd5e1fa901 Mon Sep 17 00:00:00 2001 From: Rob H Date: Thu, 10 Jul 2014 17:04:35 +1000 Subject: [PATCH 116/145] Prevent display_as and display_name from being used when blank --- app/models/spree/variant_decorator.rb | 6 ++++-- spec/models/spree/variant_spec.rb | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/models/spree/variant_decorator.rb b/app/models/spree/variant_decorator.rb index 81977bc05a..12593215ba 100644 --- a/app/models/spree/variant_decorator.rb +++ b/app/models/spree/variant_decorator.rb @@ -51,11 +51,13 @@ Spree::Variant.class_eval do end def name_to_display - display_name || product.name + return product.name if display_name.blank? + display_name end def unit_to_display - display_as || options_text + return options_text if display_as.blank? + display_as end diff --git a/spec/models/spree/variant_spec.rb b/spec/models/spree/variant_spec.rb index bf13cf978c..0abf9ea431 100644 --- a/spec/models/spree/variant_spec.rb +++ b/spec/models/spree/variant_spec.rb @@ -133,6 +133,8 @@ module Spree it "returns product name if display_name is empty" do v = create(:variant, product: create(:product)) v.name_to_display.should == v.product.name + v1 = create(:variant, display_name: "", product: create(:product)) + v1.name_to_display.should == v1.product.name end end @@ -142,10 +144,13 @@ module Spree v.unit_to_display.should == "foo" end - it "returns options_text if display_as is empty" do + it "returns options_text if display_as is blank" do v = create(:variant) + v1 = create(:variant, display_as: "") v.stub(:options_text).and_return "ponies" + v1.stub(:options_text).and_return "ponies" v.unit_to_display.should == "ponies" + v1.unit_to_display.should == "ponies" end end From 46017be45cde5fa3887d218563861c0ce951e003 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 12:27:17 +1000 Subject: [PATCH 117/145] Make big input fill out all width available --- app/assets/stylesheets/darkswarm/big-input.sass | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/darkswarm/big-input.sass b/app/assets/stylesheets/darkswarm/big-input.sass index 70cb3bd4f9..133097a5ac 100644 --- a/app/assets/stylesheets/darkswarm/big-input.sass +++ b/app/assets/stylesheets/darkswarm/big-input.sass @@ -17,6 +17,7 @@ box-shadow: 0 padding: 0.75rem 1rem 0.35rem 1rem height: auto + width: 100% margin-bottom: 0.5rem box-shadow: none color: $inputactv From 6adc056ce08ee889389955bc54b3c543cbfcad53 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 12:27:35 +1000 Subject: [PATCH 118/145] Styling filters and search on shopfront --- app/assets/stylesheets/darkswarm/shop.css.sass | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/shop.css.sass b/app/assets/stylesheets/darkswarm/shop.css.sass index 9011f99a7f..595c900386 100644 --- a/app/assets/stylesheets/darkswarm/shop.css.sass +++ b/app/assets/stylesheets/darkswarm/shop.css.sass @@ -6,10 +6,10 @@ .darkswarm // #search - @include placeholder(rgba(0,0,0,0.3), #999) + @include placeholder(rgba(0,0,0,0.4), #777) input#search - @include big-input(rgba(0,0,0,0.2), #999, #000) + @include big-input(rgba(0,0,0,0.3), #777, $clr-brick) @include big-input-static color: #666 From 88b1b8b104c55b7d48de939f3a9833453bb22fca Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 12:27:51 +1000 Subject: [PATCH 119/145] Styling search for shopfront page --- .../darkswarm/active_table_search.css.sass | 3 +++ app/views/shop/products/_form.html.haml | 15 +++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index d8f253ee28..8bb131e9a9 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -14,6 +14,9 @@ .filter-box background: rgba(255,255,255,0.65) +products .filter-box + background: #f7f7f7 + .tdhead padding: 0.25rem 0.5rem margin-top: 0.9rem diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index c3f3911f5a..891a903fa5 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -4,17 +4,20 @@ = form_for :order, :url => populate_orders_path, html: {:class => "custom"} do .row - .small-6.columns + .small-12.medium-8.large-8.columns %input#search.text{"ng-model" => "query", - placeholder: "Search products", + placeholder: "Search by product or producer", "ng-debounce" => "150", "ofn-disable-enter" => true} - .small-6.columns - %input.button.primary.right{type: :submit, value: "Add to Cart"} - = render partial: "shop/products/filters" + = render partial: "shop/products/filters" - %div{bindonce: true} + .small-12.medium-4.large-4.columns + %input.button.primary.right{type: :submit, value: "Add to Cart"} + + + + %div.pad-top{bindonce: true} %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in Product.products | products:query | taxons:activeTaxons | orderBy:ordering.order"} %div From 40b858306b1a409af7e8724fa4b7ddc5e5e01558 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 12:36:27 +1000 Subject: [PATCH 120/145] Make all taxons sentence case. ALl of them! for reals yo. --- .../stylesheets/darkswarm/active_table_search.css.sass | 7 ++++--- app/assets/stylesheets/darkswarm/taxons.css.sass | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 8bb131e9a9..5b36c0da1f 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -11,12 +11,12 @@ .row.filter-box:first-child border-top: 1px solid $clr-brick -.filter-box - background: rgba(255,255,255,0.65) - products .filter-box background: #f7f7f7 +.filter-box + background: rgba(255,255,255,0.65) + .tdhead padding: 0.25rem 0.5rem margin-top: 0.9rem @@ -48,6 +48,7 @@ products .filter-box @include csstrans display: table table-layout: fixed + text-transform: capitalize overflow: visible // width: 100% // height: 2rem diff --git a/app/assets/stylesheets/darkswarm/taxons.css.sass b/app/assets/stylesheets/darkswarm/taxons.css.sass index 160d2ce002..32ba3aba1b 100644 --- a/app/assets/stylesheets/darkswarm/taxons.css.sass +++ b/app/assets/stylesheets/darkswarm/taxons.css.sass @@ -6,7 +6,7 @@ line-height: 1 margin-right: 0.5rem margin-bottom: 0.35rem - text-transform: uppercase + text-transform: capitalize font-weight: 300 font-size: 0.875rem background: rgba(235,235,235,0.5) From d4a6624c28b792886508e5ddbe8dbcd7096b0a25 Mon Sep 17 00:00:00 2001 From: Rob H Date: Thu, 10 Jul 2014 17:04:35 +1000 Subject: [PATCH 121/145] Prevent display_as and display_name from being used when blank --- app/models/spree/variant_decorator.rb | 6 ++++-- spec/models/spree/variant_spec.rb | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/models/spree/variant_decorator.rb b/app/models/spree/variant_decorator.rb index 81977bc05a..12593215ba 100644 --- a/app/models/spree/variant_decorator.rb +++ b/app/models/spree/variant_decorator.rb @@ -51,11 +51,13 @@ Spree::Variant.class_eval do end def name_to_display - display_name || product.name + return product.name if display_name.blank? + display_name end def unit_to_display - display_as || options_text + return options_text if display_as.blank? + display_as end diff --git a/spec/models/spree/variant_spec.rb b/spec/models/spree/variant_spec.rb index bf13cf978c..0abf9ea431 100644 --- a/spec/models/spree/variant_spec.rb +++ b/spec/models/spree/variant_spec.rb @@ -133,6 +133,8 @@ module Spree it "returns product name if display_name is empty" do v = create(:variant, product: create(:product)) v.name_to_display.should == v.product.name + v1 = create(:variant, display_name: "", product: create(:product)) + v1.name_to_display.should == v1.product.name end end @@ -142,10 +144,13 @@ module Spree v.unit_to_display.should == "foo" end - it "returns options_text if display_as is empty" do + it "returns options_text if display_as is blank" do v = create(:variant) + v1 = create(:variant, display_as: "") v.stub(:options_text).and_return "ponies" + v1.stub(:options_text).and_return "ponies" v.unit_to_display.should == "ponies" + v1.unit_to_display.should == "ponies" end end From ef55bf97c6f433925b7e74d879e3300d24a74cef Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 12:37:04 +1000 Subject: [PATCH 122/145] Bunch of small fixes for Laura --- .../darkswarm/controllers/hubs_controller.js.coffee | 1 + .../darkswarm/controllers/producers_controller.js.coffee | 1 + .../darkswarm/controllers/products_controller.js.coffee | 1 + .../darkswarm/directives/taxon_selector.js.coffee | 1 + app/views/shared/components/_filter_controls.html.haml | 6 +++++- app/views/shop/products.rabl | 2 +- app/views/shop/products/_form.html.haml | 8 +++++++- 7 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee index 769b47cbe8..98053daebf 100644 --- a/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee @@ -4,6 +4,7 @@ Darkswarm.controller "HubsCtrl", ($scope, Hubs, Search, $document, $rootScope, H $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll $scope.filterText = FilterSelectorsService.filterText + $scope.FilterSelectorsService = FilterSelectorsService $scope.query = Search.search() $scope.$watch "query", (query)-> diff --git a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee index 6fdb589529..d88af1e53d 100644 --- a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee @@ -3,6 +3,7 @@ Darkswarm.controller "ProducersCtrl", ($scope, Producers, $filter, FilterSelecto $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll $scope.filterText = FilterSelectorsService.filterText + $scope.FilterSelectorsService = FilterSelectorsService $scope.filtersActive = false $scope.activeTaxons = [] $scope.query = Search.search() diff --git a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee index e29797e4e8..361c1ebca4 100644 --- a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee @@ -3,6 +3,7 @@ Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Product, OrderCycle, F $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll $scope.filterText = FilterSelectorsService.filterText + $scope.FilterSelectorsService = FilterSelectorsService $scope.limit = 3 $scope.ordering = {order: "name"} $scope.order_cycle = OrderCycle.order_cycle diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee index bf665bb23d..9c05de3c8f 100644 --- a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee @@ -24,6 +24,7 @@ Darkswarm.directive "taxonSelector", (FilterSelectorsService)-> if object.supplied_taxons for taxon in object.supplied_taxons taxons[taxon.id] = taxon + for id, taxon of taxons if selector = selectors_by_id[id] selectors.push selector diff --git a/app/views/shared/components/_filter_controls.html.haml b/app/views/shared/components/_filter_controls.html.haml index 7fe95c324a..c8fccb0558 100644 --- a/app/views/shared/components/_filter_controls.html.haml +++ b/app/views/shared/components/_filter_controls.html.haml @@ -1,6 +1,10 @@ .row .small-12.columns - %a.button.primary.tiny.filterbtn{{"ng-click" => "filtersActive = !filtersActive"}} + %a.button.primary.tiny.filterbtn{"ng-click" => "filtersActive = !filtersActive", + "ng-show" => "FilterSelectorsService.selectors.length > 0"} {{ filterText(filtersActive) }} %i.ofn-i_005-caret-down{"ng-show" => "!filtersActive"} %i.ofn-i_006-caret-up{"ng-show" => "filtersActive"} + + %a.button.secondary.tiny.filterbtn.disabled{"ng-show" => "FilterSelectorsService.selectors.length == 0"} + No filters diff --git a/app/views/shop/products.rabl b/app/views/shop/products.rabl index b934272b9a..dca5ea1673 100644 --- a/app/views/shop/products.rabl +++ b/app/views/shop/products.rabl @@ -43,7 +43,7 @@ node :variants do |product| end child :taxons => :taxons do |taxon| - attributes :name + attributes :name, :id end child :properties => :properties do |property| diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index 891a903fa5..ecd693d8ad 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -19,7 +19,7 @@ %div.pad-top{bindonce: true} %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", - "ng-repeat" => "product in Product.products | products:query | taxons:activeTaxons | orderBy:ordering.order"} + "ng-repeat" => "product in filteredProducts = (Product.products | products:query | taxons:activeTaxons | orderBy:ordering.order)"} %div = render partial: "shop/products/summary" %div{"bo-if" => "hasVariants"} @@ -31,6 +31,12 @@ .row.summary .small-12.columns.text-center Loading products + + %product{"ng-show" => "filteredProducts.length == 0 && !Product.loading"} + .row.summary + .small-12.columns.text-center + No results for {{ query }} + .row .small-12.columns %input.button.primary.right.add_to_cart{type: :submit, value: "Add to Cart"} From fecc68cff8102e09df0f5fb4ec776fb2f010236b Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 12:40:49 +1000 Subject: [PATCH 123/145] Dereferencing product Taxons --- app/assets/javascripts/darkswarm/services/product.js.coffee | 4 +++- app/views/shop/products.rabl | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/product.js.coffee b/app/assets/javascripts/darkswarm/services/product.js.coffee index 2c57512bff..e33a037a61 100644 --- a/app/assets/javascripts/darkswarm/services/product.js.coffee +++ b/app/assets/javascripts/darkswarm/services/product.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.factory 'Product', ($resource, Enterprises) -> +Darkswarm.factory 'Product', ($resource, Enterprises, Dereferencer, Taxons) -> new class Product constructor: -> @update() @@ -18,3 +18,5 @@ Darkswarm.factory 'Product', ($resource, Enterprises) -> dereference: -> for product in @products product.supplier = Enterprises.enterprises_by_id[product.supplier.id] + Dereferencer.dereference product.taxons, Taxons.taxons_by_id + diff --git a/app/views/shop/products.rabl b/app/views/shop/products.rabl index dca5ea1673..a337ec3b16 100644 --- a/app/views/shop/products.rabl +++ b/app/views/shop/products.rabl @@ -43,7 +43,7 @@ node :variants do |product| end child :taxons => :taxons do |taxon| - attributes :name, :id + attributes :id end child :properties => :properties do |property| From 190e320bad67bf3ee9bf1d201814c1fdcbd3314a Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 12:45:08 +1000 Subject: [PATCH 124/145] Pulling some structure out of directives --- .../templates/shipping_type_selector.html.haml | 7 +++---- app/assets/javascripts/templates/taxon_selector.html.haml | 7 +++---- app/views/home/_filters.html.haml | 8 +++++--- app/views/producers/_filters.html.haml | 5 +++-- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/templates/shipping_type_selector.html.haml b/app/assets/javascripts/templates/shipping_type_selector.html.haml index cdbe702f32..8feb23e59f 100644 --- a/app/assets/javascripts/templates/shipping_type_selector.html.haml +++ b/app/assets/javascripts/templates/shipping_type_selector.html.haml @@ -1,4 +1,3 @@ -%ul.small-block-grid-2.large-block-grid-1 - %active-selector{"ng-repeat" => "(name, selector) in selectors"} - %i{"ng-class" => "selector.icon"} - {{ name | capitalize }} +%active-selector{"ng-repeat" => "(name, selector) in selectors"} + %i{"ng-class" => "selector.icon"} + {{ name | capitalize }} diff --git a/app/assets/javascripts/templates/taxon_selector.html.haml b/app/assets/javascripts/templates/taxon_selector.html.haml index dd40453e3f..02450c8d12 100644 --- a/app/assets/javascripts/templates/taxon_selector.html.haml +++ b/app/assets/javascripts/templates/taxon_selector.html.haml @@ -1,4 +1,3 @@ -%ul.small-block-grid-2.large-block-grid-5 - %active-selector{"ng-repeat" => "selector in selectors()"} - %render-svg{path: "{{selector.taxon.icon}}"} - %span {{ selector.taxon.name }} +%active-selector{"ng-repeat" => "selector in selectors()"} + %render-svg{path: "{{selector.taxon.icon}}"} + %span {{ selector.taxon.name }} diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml index ab98389e82..19976cbe34 100644 --- a/app/views/home/_filters.html.haml +++ b/app/views/home/_filters.html.haml @@ -7,13 +7,15 @@ %h5.tdhead .light Filter by Type - %taxon-selector{objects: "hubs | hubs:query", - results: "activeTaxons"} + %ul.small-block-grid-2.large-block-grid-5 + %taxon-selector{objects: "hubs | hubs:query", + results: "activeTaxons"} .small-12.large-3.columns %h5.tdhead .light Filter by Delivery - %shipping-type-selector{results: "shippingTypes"} + %ul.small-block-grid-2.large-block-grid-1 + %shipping-type-selector{results: "shippingTypes"} .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} .small-12.columns %a.button.secondary.small.expand{"ng-click" => "clearAll()"} diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 2419e0478d..a0667a4373 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -7,8 +7,9 @@ %h5.tdhead .light Filter by Type - %taxon-selector{objects: "Producers.visible | filterProducers:query", - results: "activeTaxons"} + %ul.small-block-grid-2.large-block-grid-5 + %taxon-selector{objects: "Producers.visible | filterProducers:query", + results: "activeTaxons"} .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} .small-12.columns From 21d1d2d1c184583892f28d1b345e0abaaeeba2ca Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 12:53:32 +1000 Subject: [PATCH 125/145] Replacing taxon directive --- .../javascripts/darkswarm/directives/taxon_selector.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee index 9c05de3c8f..a682176d77 100644 --- a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee @@ -1,5 +1,6 @@ Darkswarm.directive "taxonSelector", (FilterSelectorsService)-> restrict: 'E' + replace: true scope: objects: "&" results: "=" From 61dbc2cd636b947a4df87f582ce925ff2317643e Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 12:54:40 +1000 Subject: [PATCH 126/145] Replace for shipping selector --- .../darkswarm/directives/shipping_type_selector.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee index 856b6dcac2..3f752f8a3d 100644 --- a/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee @@ -1,5 +1,6 @@ Darkswarm.directive "shippingTypeSelector", (FilterSelectorsService)-> restrict: 'E' + replace: true templateUrl: 'shipping_type_selector.html' link: (scope, elem, attr)-> scope.shippingTypes = From c907e35834103d8c9556263aa5ccbc40be20b144 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 12:44:43 +1000 Subject: [PATCH 127/145] More styling on search and filters --- app/assets/stylesheets/darkswarm/active_table_search.css.sass | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 5b36c0da1f..6c411b9d40 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -22,9 +22,12 @@ products .filter-box margin-top: 0.9rem // OVERRIDES + [class*="block-grid-"] + margin: 0 0 0.5rem 0 [class*="block-grid-"] > li padding-bottom: 0.5rem !important + li @include border-radius(12px) padding-top: 0.5rem From 068e3cce1c724d5c5acdc2d555a5e872c7d25385 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 13:09:42 +1000 Subject: [PATCH 128/145] More tweaks to filters styling --- app/assets/stylesheets/darkswarm/active_table_search.css.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.sass b/app/assets/stylesheets/darkswarm/active_table_search.css.sass index 6c411b9d40..9920dc1d87 100644 --- a/app/assets/stylesheets/darkswarm/active_table_search.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table_search.css.sass @@ -15,7 +15,7 @@ products .filter-box background: #f7f7f7 .filter-box - background: rgba(255,255,255,0.65) + background: rgba(245,245,245,0.6) .tdhead padding: 0.25rem 0.5rem From 23182a90260277fac7fdd0529d1eff2b62cb66e5 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 13:10:22 +1000 Subject: [PATCH 129/145] Grid system layout for filter buttons for all sizes and breakpoints --- app/views/home/_filters.html.haml | 4 ++-- app/views/producers/_filters.html.haml | 2 +- app/views/shop/products/_filters.html.haml | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml index 19976cbe34..78d755f1bc 100644 --- a/app/views/home/_filters.html.haml +++ b/app/views/home/_filters.html.haml @@ -7,14 +7,14 @@ %h5.tdhead .light Filter by Type - %ul.small-block-grid-2.large-block-grid-5 + %ul.small-block-grid-2.medium-block-grid-4.large-block-grid-5 %taxon-selector{objects: "hubs | hubs:query", results: "activeTaxons"} .small-12.large-3.columns %h5.tdhead .light Filter by Delivery - %ul.small-block-grid-2.large-block-grid-1 + %ul.small-block-grid-2.medium-block-grid-4.large-block-grid-2 %shipping-type-selector{results: "shippingTypes"} .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} .small-12.columns diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index a0667a4373..63ccef2f0c 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -7,7 +7,7 @@ %h5.tdhead .light Filter by Type - %ul.small-block-grid-2.large-block-grid-5 + %ul.small-block-grid-2.medium-block-grid-4.large-block-grid-6 %taxon-selector{objects: "Producers.visible | filterProducers:query", results: "activeTaxons"} diff --git a/app/views/shop/products/_filters.html.haml b/app/views/shop/products/_filters.html.haml index 3e7a24a44c..7879bcc5d1 100644 --- a/app/views/shop/products/_filters.html.haml +++ b/app/views/shop/products/_filters.html.haml @@ -7,8 +7,9 @@ %h5.tdhead .light Filter by Type - %taxon-selector{objects: "Product.products | products:query", - results: "activeTaxons"} + %ul.small-block-grid-2.medium-block-grid-3.large-block-grid-4 + %taxon-selector{objects: "Product.products | products:query", + results: "activeTaxons"} .row.filter-box.animate-show{"ng-show" => "filtersActive && totalActive() > 0"} .small-12.columns From 13cc9ba44d32ef26fe7832140c0ad84444554bc3 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 14:41:18 +1000 Subject: [PATCH 130/145] Remove line-height stuff which was making the animation in juddery --- app/assets/stylesheets/darkswarm/animations.sass | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index ff51d36199..966f2a2d48 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -84,7 +84,7 @@ opacity: .5 .animate-repeat - line-height: 40px + // line-height: 40px list-style: none box-sizing: border-box @@ -104,7 +104,7 @@ .animate-repeat.ng-move.ng-move-active, .animate-repeat.ng-enter.ng-enter-active opacity: 1 - max-height: 40px + max-height: inherit .animate-show From 16d39aeacc7fba8aceaafba68919571c3859dd8d Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 14:41:46 +1000 Subject: [PATCH 131/145] Tweak line-height on product row in shopfront --- app/assets/stylesheets/darkswarm/shop.css.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/shop.css.sass b/app/assets/stylesheets/darkswarm/shop.css.sass index 595c900386..6e6001ce6e 100644 --- a/app/assets/stylesheets/darkswarm/shop.css.sass +++ b/app/assets/stylesheets/darkswarm/shop.css.sass @@ -115,7 +115,7 @@ .columns padding-top: 1em padding-bottom: 1em - line-height: 2.4em + line-height: 1em .row.summary, .row.variants margin-left: 0 From 1eb18e84787751fc4388a2b5aeca380c977dbf3f Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 14:42:44 +1000 Subject: [PATCH 132/145] Add some padding to first child in active table - should not be styled from animation classes --- app/assets/stylesheets/darkswarm/active_table.css.sass | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/darkswarm/active_table.css.sass b/app/assets/stylesheets/darkswarm/active_table.css.sass index a386328a5a..fffc6d9347 100644 --- a/app/assets/stylesheets/darkswarm/active_table.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table.css.sass @@ -9,6 +9,7 @@ display: block &:first-child cursor: pointer + padding: 1rem 0 .no-results font-size: 1.875rem From 26d6ac5a8d619a7a60ebef8ac149a83092fb7014 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 14:50:40 +1000 Subject: [PATCH 133/145] Styling no results message for shopfront --- app/assets/stylesheets/darkswarm/active_table.css.sass | 7 ++++--- app/views/shop/products/_form.html.haml | 10 ++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/active_table.css.sass b/app/assets/stylesheets/darkswarm/active_table.css.sass index fffc6d9347..a08f2c794b 100644 --- a/app/assets/stylesheets/darkswarm/active_table.css.sass +++ b/app/assets/stylesheets/darkswarm/active_table.css.sass @@ -2,6 +2,10 @@ @import mixins @import "compass/css3/user-interface" + +.no-results + font-size: 1.875rem + .active_table margin: 2em 0em @include user-select(none) @@ -10,9 +14,6 @@ &:first-child cursor: pointer padding: 1rem 0 - - .no-results - font-size: 1.875rem .active_table .active_table_node display: block diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index ecd693d8ad..37ae4e61d6 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -32,11 +32,13 @@ .small-12.columns.text-center Loading products - %product{"ng-show" => "filteredProducts.length == 0 && !Product.loading"} + %div{"ng-show" => "filteredProducts.length == 0 && !Product.loading"} .row.summary - .small-12.columns.text-center - No results for {{ query }} - + .small-12.columns + %p.no-results + Sorry, no results found for + %strong {{query}}. + Try another search? .row .small-12.columns %input.button.primary.right.add_to_cart{type: :submit, value: "Add to Cart"} From d67992eb7b4972b87d2948c5b8842cde6cec05b7 Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 15:07:29 +1000 Subject: [PATCH 134/145] Tweak animation stylings --- app/assets/stylesheets/darkswarm/animations.sass | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index 966f2a2d48..27df090ebc 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -91,20 +91,25 @@ .animate-repeat.ng-move, .animate-repeat.ng-enter, .animate-repeat.ng-leave - -webkit-transition: all linear 0.2s - transition: all linear 0.2s + -webkit-transition: all linear 300ms + transition: all linear 300ms + + -webkit-transition: border linear 500ms ease-in + transition : border 500ms ease-in .animate-repeat.ng-leave.ng-leave-active, .animate-repeat.ng-move, .animate-repeat.ng-enter opacity: 0 max-height: 0 + border-color: transparent .animate-repeat.ng-leave, .animate-repeat.ng-move.ng-move-active, .animate-repeat.ng-enter.ng-enter-active opacity: 1 max-height: inherit + border-color: inherit .animate-show From c852eefdbc898a0d58c34df041d70ba9fd3f726a Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 13:05:14 +1000 Subject: [PATCH 135/145] Re-enabling infinite scroll --- app/views/shop/products/_form.html.haml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index 37ae4e61d6..940df58b29 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -7,19 +7,17 @@ .small-12.medium-8.large-8.columns %input#search.text{"ng-model" => "query", placeholder: "Search by product or producer", - "ng-debounce" => "150", + "ng-debounce" => "100", "ofn-disable-enter" => true} = render partial: "shop/products/filters" .small-12.medium-4.large-4.columns %input.button.primary.right{type: :submit, value: "Add to Cart"} - - %div.pad-top{bindonce: true} %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", - "ng-repeat" => "product in filteredProducts = (Product.products | products:query | taxons:activeTaxons | orderBy:ordering.order)"} + "ng-repeat" => "product in filteredProducts = (Product.products | products:query | taxons:activeTaxons | orderBy:ordering.order | limitTo:limit) track by product.id "} %div = render partial: "shop/products/summary" %div{"bo-if" => "hasVariants"} From 7bd65d78549dab137b9e0cdf055cd44fb32d30d0 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 15:09:20 +1000 Subject: [PATCH 136/145] Performance improvements --- .../products/product_node_controller.js.coffee | 14 +++++--------- .../darkswarm/directives/product_modal.js.coffee | 9 --------- .../darkswarm/services/product.js.coffee | 12 +++++++++--- app/views/shop/products/_form.html.haml | 2 +- app/views/shop/products/_summary.html.haml | 7 +++---- app/views/shop/products/_variants.html.haml | 2 +- 6 files changed, 19 insertions(+), 27 deletions(-) delete mode 100644 app/assets/javascripts/darkswarm/directives/product_modal.js.coffee diff --git a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee index 73406e072b..08797080e8 100644 --- a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee @@ -1,11 +1,7 @@ -Darkswarm.controller "ProductNodeCtrl", ($scope) -> - - $scope.price = -> - if $scope.product.variants.length > 0 - prices = (v.price for v in $scope.product.variants) - Math.min.apply(null, prices) - else - $scope.product.price - +Darkswarm.controller "ProductNodeCtrl", ($scope, $modal) -> $scope.enterprise = $scope.product.supplier # For the modal, so it's consistent $scope.hasVariants = $scope.product.variants.length > 0 + + $scope.triggerProductModal = -> + $modal.open(templateUrl: "product_modal.html", scope: $scope) + diff --git a/app/assets/javascripts/darkswarm/directives/product_modal.js.coffee b/app/assets/javascripts/darkswarm/directives/product_modal.js.coffee deleted file mode 100644 index 428fde3633..0000000000 --- a/app/assets/javascripts/darkswarm/directives/product_modal.js.coffee +++ /dev/null @@ -1,9 +0,0 @@ -Darkswarm.directive "productModal", ($modal)-> - restrict: 'E' - replace: true - template: "" - transclude: true - link: (scope, elem, attrs, ctrl)-> - elem.on "click", => - scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'product_modal.html', scope: scope) - diff --git a/app/assets/javascripts/darkswarm/services/product.js.coffee b/app/assets/javascripts/darkswarm/services/product.js.coffee index e33a037a61..478647d2db 100644 --- a/app/assets/javascripts/darkswarm/services/product.js.coffee +++ b/app/assets/javascripts/darkswarm/services/product.js.coffee @@ -1,5 +1,5 @@ Darkswarm.factory 'Product', ($resource, Enterprises, Dereferencer, Taxons) -> - new class Product + new class Products constructor: -> @update() @@ -10,7 +10,8 @@ Darkswarm.factory 'Product', ($resource, Enterprises, Dereferencer, Taxons) -> update: => @loading = true - @products = $resource("/shop/products").query => + @products = $resource("/shop/products").query (products)=> + @extend() @dereference() @loading = false @ @@ -19,4 +20,9 @@ Darkswarm.factory 'Product', ($resource, Enterprises, Dereferencer, Taxons) -> for product in @products product.supplier = Enterprises.enterprises_by_id[product.supplier.id] Dereferencer.dereference product.taxons, Taxons.taxons_by_id - + + extend: -> + for product in @products + if product.variants.length > 0 + prices = (v.price for v in product.variants) + product.price = Math.min.apply(null, prices) diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index 940df58b29..fc43f05e9b 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -17,7 +17,7 @@ %div.pad-top{bindonce: true} %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", - "ng-repeat" => "product in filteredProducts = (Product.products | products:query | taxons:activeTaxons | orderBy:ordering.order | limitTo:limit) track by product.id "} + "ng-repeat" => "product in filteredProducts = (Product.products | products:query | taxons:activeTaxons | orderBy:ordering.order) track by product.id "} %div = render partial: "shop/products/summary" %div{"bo-if" => "hasVariants"} diff --git a/app/views/shop/products/_summary.html.haml b/app/views/shop/products/_summary.html.haml index b21b535315..b1cd7b0e78 100644 --- a/app/views/shop/products/_summary.html.haml +++ b/app/views/shop/products/_summary.html.haml @@ -1,11 +1,10 @@ .row.summary .small-1.columns - %product-modal - %img{"bo-src" => "product.master.images[0].small_url"} + %img{"bo-src" => "product.master.images[0].small_url", "ng-click" => "triggerProductModal()"} .small-4.columns.summary-header %render-svg{path: "{{product.primary_taxon.icon}}"} - %product-modal {{ product.name }} + %a{"ng-click" => "triggerProductModal()"}{{ product.name }} .small-5.columns %i.ofn-i_036-producers @@ -14,4 +13,4 @@ .small-2.columns.summary-price.text-right.price %span{"ng-if" => "hasVariants"} %em from - {{ price() | currency }} + {{ product.price | currency }} diff --git a/app/views/shop/products/_variants.html.haml b/app/views/shop/products/_variants.html.haml index 5d6a59535e..2d281dafe8 100644 --- a/app/views/shop/products/_variants.html.haml +++ b/app/views/shop/products/_variants.html.haml @@ -1,5 +1,5 @@ .row.variants{bindonce: true, - "ng-repeat" => "variant in product.variants"} + "ng-repeat" => "variant in product.variants track by variant.id"} .small-1.columns %i.ofn-i_056-bulk{"bo-if" => "product.group_buy"} From 500e067cfb2f7812fae2f39c02744177ea84d88e Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 16:14:44 +1000 Subject: [PATCH 137/145] Performance enhancements --- .../controllers/products/product_node_controller.js.coffee | 1 - app/assets/javascripts/darkswarm/services/product.js.coffee | 2 ++ app/views/shop/products/_form.html.haml | 4 ++-- app/views/shop/products/_summary.html.haml | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee index 08797080e8..07ddb4bc61 100644 --- a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee @@ -1,6 +1,5 @@ Darkswarm.controller "ProductNodeCtrl", ($scope, $modal) -> $scope.enterprise = $scope.product.supplier # For the modal, so it's consistent - $scope.hasVariants = $scope.product.variants.length > 0 $scope.triggerProductModal = -> $modal.open(templateUrl: "product_modal.html", scope: $scope) diff --git a/app/assets/javascripts/darkswarm/services/product.js.coffee b/app/assets/javascripts/darkswarm/services/product.js.coffee index 478647d2db..48cdd6ae33 100644 --- a/app/assets/javascripts/darkswarm/services/product.js.coffee +++ b/app/assets/javascripts/darkswarm/services/product.js.coffee @@ -26,3 +26,5 @@ Darkswarm.factory 'Product', ($resource, Enterprises, Dereferencer, Taxons) -> if product.variants.length > 0 prices = (v.price for v in product.variants) product.price = Math.min.apply(null, prices) + + product.hasVariants = product.variants.length > 0 diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index fc43f05e9b..2aaf7a4f5f 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -20,9 +20,9 @@ "ng-repeat" => "product in filteredProducts = (Product.products | products:query | taxons:activeTaxons | orderBy:ordering.order) track by product.id "} %div = render partial: "shop/products/summary" - %div{"bo-if" => "hasVariants"} + %div{"bo-if" => "product.hasVariants"} = render partial: "shop/products/variants" - .variants.row{"bo-if" => "!hasVariants"} + .variants.row{"bo-if" => "!product.hasVariants"} = render partial: "shop/products/master" %product{"ng-show" => "Product.loading"} diff --git a/app/views/shop/products/_summary.html.haml b/app/views/shop/products/_summary.html.haml index b1cd7b0e78..bded87c50c 100644 --- a/app/views/shop/products/_summary.html.haml +++ b/app/views/shop/products/_summary.html.haml @@ -11,6 +11,6 @@ %producer-modal {{ enterprise.name }} .small-2.columns.summary-price.text-right.price - %span{"ng-if" => "hasVariants"} + %span{"ng-if" => "product.hasVariants"} %em from {{ product.price | currency }} From d43fa7eed54528efe2d19e0d553f21d744adaa1a Mon Sep 17 00:00:00 2001 From: summerscope Date: Fri, 11 Jul 2014 16:16:56 +1000 Subject: [PATCH 138/145] Fixing animations for shopfront --- .../stylesheets/darkswarm/animations.sass | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index 27df090ebc..bf80c681a0 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -83,33 +83,37 @@ filter: alpha(opacity = 50) opacity: .5 + .animate-repeat - // line-height: 40px - list-style: none - box-sizing: border-box -.animate-repeat.ng-move, -.animate-repeat.ng-enter, -.animate-repeat.ng-leave - -webkit-transition: all linear 300ms - transition: all linear 300ms + &.ng-move, &.ng-enter, &.ng-leave + // -webkit-transition: border 0s + -webkit-transform: translateZ(0) + transform: translateZ(0) + -webkit-transition: all 300ms ease-in + // transition: border 0s + transition: all 300ms ease-in - -webkit-transition: border linear 500ms ease-in - transition : border 500ms ease-in + &.ng-leave + opacity: 1 + max-height: 1000px + border-color: transparent + &.ng-leave-active + opacity: 0 + max-height: 0px + border-color: transparent -.animate-repeat.ng-leave.ng-leave-active, -.animate-repeat.ng-move, -.animate-repeat.ng-enter - opacity: 0 - max-height: 0 - border-color: transparent + &.ng-enter + opacity: 0 + max-height: 0px + border-color: transparent + &.ng-enter-active + opacity: 1 + max-height: 1000px + border-color: transparent -.animate-repeat.ng-leave, -.animate-repeat.ng-move.ng-move-active, -.animate-repeat.ng-enter.ng-enter-active - opacity: 1 - max-height: inherit - border-color: inherit + &.ng-move + &.ng-move-active .animate-show From e940777ede78fd9ec19e9c7a2e16a909950a3c62 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 16:33:23 +1000 Subject: [PATCH 139/145] Few more animation fixes --- .../stylesheets/darkswarm/animations.sass | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index bf80c681a0..944e2320ed 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -85,32 +85,32 @@ .animate-repeat - + border-color: rgba(153, 153, 153, 1) + -webkit-transform: translateZ(0) + transform: translateZ(0) &.ng-move, &.ng-enter, &.ng-leave // -webkit-transition: border 0s - -webkit-transform: translateZ(0) - transform: translateZ(0) - -webkit-transition: all 300ms ease-in + -webkit-transition: all 300ms linear // transition: border 0s - transition: all 300ms ease-in + transition: all 300ms linear &.ng-leave opacity: 1 - max-height: 1000px - border-color: transparent + border-color: rgba(153, 153, 153, 1) + max-height: 200px &.ng-leave-active opacity: 0 max-height: 0px - border-color: transparent + border-color: rgba(153, 153, 153, 0) &.ng-enter opacity: 0 + border-color: rgba(153, 153, 153, 0) max-height: 0px - border-color: transparent &.ng-enter-active + max-height: 200px opacity: 1 - max-height: 1000px - border-color: transparent + border-color: rgba(153, 153, 153, 1) &.ng-move &.ng-move-active From 06047a380ee0f2f543df69da3bf02f10d03c858c Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 16:40:44 +1000 Subject: [PATCH 140/145] Provisional animations --- app/assets/stylesheets/darkswarm/animations.sass | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index 944e2320ed..d1952d1c4c 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -89,26 +89,24 @@ -webkit-transform: translateZ(0) transform: translateZ(0) &.ng-move, &.ng-enter, &.ng-leave - // -webkit-transition: border 0s - -webkit-transition: all 300ms linear - // transition: border 0s - transition: all 300ms linear + -webkit-transition: all 1s linear + transition: all 1s linear &.ng-leave opacity: 1 border-color: rgba(153, 153, 153, 1) - max-height: 200px + //max-height: 200px &.ng-leave-active opacity: 0 - max-height: 0px + //max-height: 0px border-color: rgba(153, 153, 153, 0) &.ng-enter opacity: 0 border-color: rgba(153, 153, 153, 0) - max-height: 0px + //max-height: 0px &.ng-enter-active - max-height: 200px + //max-height: 200px opacity: 1 border-color: rgba(153, 153, 153, 1) From 5e68d0bab770f3e8a9c997433dcb09ff9da49e39 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 16:51:46 +1000 Subject: [PATCH 141/145] Basic final version --- app/assets/stylesheets/darkswarm/animations.sass | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index d1952d1c4c..8ef5756ecf 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -89,24 +89,20 @@ -webkit-transform: translateZ(0) transform: translateZ(0) &.ng-move, &.ng-enter, &.ng-leave - -webkit-transition: all 1s linear - transition: all 1s linear + -webkit-transition: all 300ms linear + transition: all 300ms linear &.ng-leave opacity: 1 border-color: rgba(153, 153, 153, 1) - //max-height: 200px &.ng-leave-active opacity: 0 - //max-height: 0px border-color: rgba(153, 153, 153, 0) &.ng-enter opacity: 0 border-color: rgba(153, 153, 153, 0) - //max-height: 0px &.ng-enter-active - //max-height: 200px opacity: 1 border-color: rgba(153, 153, 153, 1) From 744f2543536de4f9cac092fd0e58ea550f63b6fb Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 17:02:43 +1000 Subject: [PATCH 142/145] Patching a minor bug --- app/assets/javascripts/darkswarm/filters/taxons.js.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee index 9fccd20c11..3eb32ce1a4 100644 --- a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee @@ -7,5 +7,7 @@ Darkswarm.filter 'taxons', (Matcher)-> objects else objects.filter (obj)-> - obj.primary_taxon?.id in ids || (obj.taxons.concat obj.supplied_taxons).some (taxon)-> + taxons = obj.taxons + taxons.concat obj.supplied_taxons if obj.supplied_taxons + obj.primary_taxon?.id in ids || taxons.some (taxon)-> taxon.id in ids From 353ee20feba1e6b5256672453298ab8380f196ed Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 17:07:54 +1000 Subject: [PATCH 143/145] Animations fix --- .../stylesheets/darkswarm/animations.sass | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index 8ef5756ecf..6532cce60d 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -85,7 +85,6 @@ .animate-repeat - border-color: rgba(153, 153, 153, 1) -webkit-transform: translateZ(0) transform: translateZ(0) &.ng-move, &.ng-enter, &.ng-leave @@ -94,22 +93,25 @@ &.ng-leave opacity: 1 - border-color: rgba(153, 153, 153, 1) &.ng-leave-active opacity: 0 - border-color: rgba(153, 153, 153, 0) &.ng-enter opacity: 0 - border-color: rgba(153, 153, 153, 0) &.ng-enter-active opacity: 1 + +product.animate-repeat + &.ng-leave + border-color: rgba(153, 153, 153, 1) + &.ng-leave-active + border-color: rgba(153, 153, 153, 0) + + &.ng-enter + border-color: rgba(153, 153, 153, 0) + &.ng-enter-active border-color: rgba(153, 153, 153, 1) - &.ng-move - &.ng-move-active - - .animate-show -webkit-animation-name: slideInDown animation-name: slideInDown From a73bc2405dd9fe79acd6c834494a15e86220874c Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 17:08:39 +1000 Subject: [PATCH 144/145] Fixing one regression --- spec/features/consumer/producers_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/consumer/producers_spec.rb b/spec/features/consumer/producers_spec.rb index 7d4a122996..7748eb22e7 100644 --- a/spec/features/consumer/producers_spec.rb +++ b/spec/features/consumer/producers_spec.rb @@ -18,7 +18,7 @@ feature %q{ it "shows all producers with expandable details" do page.should have_content producer.name expand_active_table_node producer.name - page.should have_content producer.supplied_taxons.first.name.upcase + page.should have_content producer.supplied_taxons.first.name end it "doesn't show invisible producers" do From 9f5f319edb5af3aef65eeabf972ae550f46e84d5 Mon Sep 17 00:00:00 2001 From: Will Marshall Date: Fri, 11 Jul 2014 17:55:06 +1000 Subject: [PATCH 145/145] Further patching regression --- spec/features/consumer/producers_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/consumer/producers_spec.rb b/spec/features/consumer/producers_spec.rb index 7748eb22e7..98bef7f084 100644 --- a/spec/features/consumer/producers_spec.rb +++ b/spec/features/consumer/producers_spec.rb @@ -18,7 +18,7 @@ feature %q{ it "shows all producers with expandable details" do page.should have_content producer.name expand_active_table_node producer.name - page.should have_content producer.supplied_taxons.first.name + page.should have_content producer.supplied_taxons.first.name.split.map(&:capitalize).join(' ') end it "doesn't show invisible producers" do

Return home