diff --git a/app/assets/javascripts/admin/admin.js.coffee b/app/assets/javascripts/admin/admin.js.coffee
index 474ae5ab1d..ba07bb7933 100644
--- a/app/assets/javascripts/admin/admin.js.coffee
+++ b/app/assets/javascripts/admin/admin.js.coffee
@@ -1,3 +1,3 @@
-Admin = angular.module("ofn.admin", ["ngResource", "ofn.shared_services", "ofn.shared_directives"]).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
+window.Admin = angular.module("ofn.admin", ["ngResource","ofn.dropdown"]).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/all.js b/app/assets/javascripts/admin/all.js
index 4cce0bdcea..3cf4fe97e7 100644
--- a/app/assets/javascripts/admin/all.js
+++ b/app/assets/javascripts/admin/all.js
@@ -14,5 +14,6 @@
//= require admin/spree_core
//= require admin/spree_auth
//= require admin/spree_promo
+//= require ./admin
//= require_tree .
diff --git a/app/assets/javascripts/admin/bulk_order_management.js.coffee b/app/assets/javascripts/admin/bulk_order_management.js.coffee
index 6d57d73bc9..7a1edcbca6 100644
--- a/app/assets/javascripts/admin/bulk_order_management.js.coffee
+++ b/app/assets/javascripts/admin/bulk_order_management.js.coffee
@@ -1,104 +1,3 @@
-Admin.value "blankOption", ->
- { id: "0", name: "All" }
-
-Admin.directive "ofnLineItemUpdAttr", [
- "switchClass", "pendingChanges"
- (switchClass, pendingChanges) ->
- require: "ngModel"
- link: (scope, element, attrs, ngModel) ->
- attrName = attrs.ofnLineItemUpdAttr
- element.dbValue = scope.$eval(attrs.ngModel)
- scope.$watch ->
- scope.$eval(attrs.ngModel)
- , (value) ->
- if ngModel.$dirty
- if value == element.dbValue
- pendingChanges.remove(scope.line_item.id, attrName)
- switchClass( element, "", ["update-pending", "update-error", "update-success"], false )
- else
- changeObj =
- lineItem: scope.line_item
- element: element
- attrName: attrName
- url: "/api/orders/#{scope.line_item.order.number}/line_items/#{scope.line_item.id}?line_item[#{attrName}]=#{value}"
- pendingChanges.add(scope.line_item.id, attrName, changeObj)
- switchClass( element, "update-pending", ["update-error", "update-success"], false )
-]
-
-Admin.directive "ofnConfirmModelChange", (ofnConfirmHandler,$timeout) ->
- restrict: "A"
- link: (scope, element, attrs) ->
- handler = ofnConfirmHandler scope, -> scope.fetchOrders()
- scope.$watch attrs.ngModel, (oldValue,newValue) ->
- handler() unless oldValue == undefined || newValue == oldValue
-
-Admin.directive "ofnConfirmLinkPath", (ofnConfirmHandler) ->
- restrict: "A"
- scope:
- path: "@ofnConfirmLinkPath"
- link: (scope, element, attrs) ->
- element.click ofnConfirmHandler scope, ->
- window.location = scope.path
-
-Admin.factory "ofnConfirmHandler", (pendingChanges, $compile, $q) ->
- return (scope, callback) ->
- template = "
Unsaved changes currently exist, save now or ignore?
"
- dialogDiv = $compile(template)(scope)
- return ->
- if pendingChanges.changeCount(pendingChanges.pendingChanges) > 0
- dialogDiv.dialog
- dialogClass: "no-close"
- resizable: false
- height: 140
- modal: true
- buttons:
- "SAVE": ->
- dialogDiv = $(this)
- $q.all(pendingChanges.submitAll()).then ->
- callback()
- dialogDiv.dialog "close"
- "IGNORE": ->
- callback()
- $(this).dialog "close"
- scope.$apply()
- dialogDiv.dialog "open"
- else
- callback()
-
-Admin.factory "pendingChanges",[
- "dataSubmitter"
- (dataSubmitter) ->
- pendingChanges: {}
-
- add: (id, attrName, changeObj) ->
- @pendingChanges["#{id}"] = {} unless @pendingChanges.hasOwnProperty("#{id}")
- @pendingChanges["#{id}"]["#{attrName}"] = changeObj
-
- removeAll: ->
- @pendingChanges = {}
-
- remove: (id, attrName) ->
- if @pendingChanges.hasOwnProperty("#{id}")
- delete @pendingChanges["#{id}"]["#{attrName}"]
- delete @pendingChanges["#{id}"] if @changeCount( @pendingChanges["#{id}"] ) < 1
-
- submitAll: ->
- all = []
- for id,lineItem of @pendingChanges
- for attrName,changeObj of lineItem
- all.push @submit(id, attrName, changeObj)
- all
-
- submit: (id, attrName, change) ->
- dataSubmitter(change).then (data) =>
- @remove id, attrName
- change.element.dbValue = data["#{attrName}"]
-
- changeCount: (lineItem) ->
- Object.keys(lineItem).length
-]
-
-
Admin.controller "AdminOrderMgmtCtrl", [
"$scope", "$http", "dataFetcher", "blankOption", "pendingChanges"
($scope, $http, dataFetcher, blankOption, pendingChanges) ->
@@ -281,50 +180,6 @@ Admin.controller "AdminOrderMgmtCtrl", [
$scope.quickSearch = ""
]
-Admin.filter "selectFilter", (blankOption) ->
- return (lineItems,selectedSupplier,selectedDistributor,selectedOrderCycle) ->
- filtered = []
- filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,"0") || lineItem.supplier.id == selectedSupplier) &&
- (angular.equals(selectedDistributor,"0") || lineItem.order.distributor.id == selectedDistributor) &&
- (angular.equals(selectedOrderCycle,"0") || lineItem.order.order_cycle.id == selectedOrderCycle)
- filtered
-
-Admin.filter "variantFilter", ->
- return (lineItems,selectedUnitsProduct,selectedUnitsVariant,sharedResource) ->
- filtered = []
- filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedUnitsProduct,{}) ||
- (lineItem.units_product.id == selectedUnitsProduct.id && (sharedResource || lineItem.units_variant.id == selectedUnitsVariant.id ) ) )
- filtered
-
-
-Admin.factory "dataSubmitter", [
- "$http", "$q", "switchClass"
- ($http, $q, switchClass) ->
- return (changeObj) ->
- deferred = $q.defer()
- $http.put(changeObj.url).success((data) ->
- switchClass changeObj.element, "update-success", ["update-pending", "update-error"], 3000
- deferred.resolve data
- ).error ->
- switchClass changeObj.element, "update-error", ["update-pending", "update-success"], false
- deferred.reject()
- deferred.promise
-]
-
-Admin.factory "switchClass", [
- "$timeout"
- ($timeout) ->
- return (element,classToAdd,removeClasses,timeout) ->
- $timeout.cancel element.timeout if element.timeout
- element.removeClass className for className in removeClasses
- element.addClass classToAdd
- intRegex = /^\d+$/
- if timeout && intRegex.test(timeout)
- element.timeout = $timeout(->
- element.removeClass classToAdd
- , timeout, true)
-]
-
daysFromToday = (days) ->
now = new Date
now.setHours(0)
diff --git a/app/assets/javascripts/admin/bulk_product_update.js.coffee b/app/assets/javascripts/admin/bulk_product_update.js.coffee
index 59de02c242..ac6309ccf8 100644
--- a/app/assets/javascripts/admin/bulk_product_update.js.coffee
+++ b/app/assets/javascripts/admin/bulk_product_update.js.coffee
@@ -1,97 +1,3 @@
-Admin.factory "Taxons", ($resource) ->
- resource = $resource "/admin/taxons/search"
-
- return {
- findByIDs: (ids) ->
- resource.get { ids: ids }
-
- findByTerm: (term) ->
- resource.get { q: term }
-
- cleanTaxons: (data) ->
- data['taxons'].map (result) -> result
- }
-
-Admin.directive "ofnTaxonAutocomplete", (Taxons) ->
- # Adapted from Spree's existing taxon autocompletion
- require: "ngModel"
- link: (scope,element,attrs,ngModel) ->
- setTimeout ->
- element.select2
- placeholder: Spree.translations.taxon_placeholder
- multiple: true
- initSelection: (element, callback) ->
- Taxons.findByIDs(element.val()).$promise.then (result) ->
- callback Taxons.cleanTaxons(result)
- query: (query) ->
- Taxons.findByTerm(query.term).$promise.then (result) ->
- query.callback { results: Taxons.cleanTaxons(result) }
- formatResult: (taxon) ->
- taxon.pretty_name
- formatSelection: (taxon) ->
- taxon.pretty_name
- element.on "change", ->
- scope.$apply ->
- ngModel.$setViewValue element.val()
-
-Admin.directive "ofnDecimal", ->
- require: "ngModel"
- link: (scope, element, attrs, ngModel) ->
- numRegExp = /^\d+(\.\d+)?$/
- element.bind "blur", ->
- scope.$apply ngModel.$setViewValue(ngModel.$modelValue)
- ngModel.$render()
-
- ngModel.$parsers.push (viewValue) ->
- return viewValue + ".0" if viewValue.indexOf(".") == -1 if angular.isString(viewValue) and numRegExp.test(viewValue)
- viewValue
-
-
-Admin.directive "ofnTrackProduct", ['$parse', ($parse) ->
- require: "ngModel"
- link: (scope, element, attrs, ngModel) ->
- ngModel.$parsers.push (viewValue) ->
- if ngModel.$dirty
- parsedPropertyName = $parse(attrs.ofnTrackProduct)
- addDirtyProperty scope.dirtyProducts, scope.product.id, parsedPropertyName, viewValue
- scope.displayDirtyProducts()
- viewValue
- ]
-
-
-Admin.directive "ofnTrackVariant", ['$parse', ($parse) ->
- require: "ngModel"
- link: (scope, element, attrs, ngModel) ->
- ngModel.$parsers.push (viewValue) ->
- dirtyVariants = {}
- dirtyVariants = scope.dirtyProducts[scope.product.id].variants if scope.dirtyProducts.hasOwnProperty(scope.product.id) and scope.dirtyProducts[scope.product.id].hasOwnProperty("variants")
- if ngModel.$dirty
- parsedPropertyName = $parse(attrs.ofnTrackVariant)
- addDirtyProperty dirtyVariants, scope.variant.id, parsedPropertyName, viewValue
- addDirtyProperty scope.dirtyProducts, scope.product.id, $parse("variants"), dirtyVariants
- scope.displayDirtyProducts()
- viewValue
- ]
-
-Admin.directive "ofnToggleVariants", ->
- link: (scope, element, attrs) ->
- if scope.displayProperties[scope.product.id].showVariants
- element.removeClass "icon-chevron-right"
- element.addClass "icon-chevron-down"
- else
- element.removeClass "icon-chevron-down"
- element.addClass "icon-chevron-right"
- element.on "click", ->
- scope.$apply ->
- if scope.displayProperties[scope.product.id].showVariants
- scope.displayProperties[scope.product.id].showVariants = false
- element.removeClass "icon-chevron-down"
- element.addClass "icon-chevron-right"
- else
- scope.displayProperties[scope.product.id].showVariants = true
- element.removeClass "icon-chevron-right"
- element.addClass "icon-chevron-down"
-
Admin.controller "AdminProductEditCtrl", [
"$scope", "$timeout", "$http", "dataFetcher"
($scope, $timeout, $http, dataFetcher) ->
@@ -516,12 +422,6 @@ Admin.controller "AdminProductEditCtrl", [
Object.keys($scope.dirtyProducts).length
]
-Admin.filter "rangeArray", ->
- return (input,start,end) ->
- input.push(i) for i in [start..end]
- input
-
-
filterSubmitProducts = (productsToFilter) ->
filteredProducts = []
if productsToFilter instanceof Object
diff --git a/app/assets/javascripts/admin/directives/confirm_link_path.js.coffee b/app/assets/javascripts/admin/directives/confirm_link_path.js.coffee
new file mode 100644
index 0000000000..e0e0511f0c
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/confirm_link_path.js.coffee
@@ -0,0 +1,7 @@
+Admin.directive "ofnConfirmLinkPath", (ofnConfirmHandler) ->
+ restrict: "A"
+ scope:
+ path: "@ofnConfirmLinkPath"
+ link: (scope, element, attrs) ->
+ element.click ofnConfirmHandler scope, ->
+ window.location = scope.path
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/confirm_model_change.js.coffee b/app/assets/javascripts/admin/directives/confirm_model_change.js.coffee
new file mode 100644
index 0000000000..aba2cd919e
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/confirm_model_change.js.coffee
@@ -0,0 +1,6 @@
+Admin.directive "ofnConfirmModelChange", (ofnConfirmHandler,$timeout) ->
+ restrict: "A"
+ link: (scope, element, attrs) ->
+ handler = ofnConfirmHandler scope, -> scope.fetchOrders()
+ scope.$watch attrs.ngModel, (oldValue,newValue) ->
+ handler() unless oldValue == undefined || newValue == oldValue
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/date_picker.js.coffee b/app/assets/javascripts/admin/directives/date_picker.js.coffee
new file mode 100644
index 0000000000..3a07bfd3f5
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/date_picker.js.coffee
@@ -0,0 +1,9 @@
+Admin.directive "datepicker", ->
+ require: "ngModel"
+ link: (scope, element, attrs, ngModel) ->
+ element.datepicker
+ dateFormat: "yy-mm-dd"
+ onSelect: (dateText, inst) ->
+ scope.$apply (scope) ->
+ # Fires ngModel.$parsers
+ ngModel.$setViewValue dateText
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/datetime_picker.js.coffee b/app/assets/javascripts/admin/directives/datetime_picker.js.coffee
new file mode 100644
index 0000000000..232d958b99
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/datetime_picker.js.coffee
@@ -0,0 +1,11 @@
+Admin.directive "datetimepicker", ->
+ require: "ngModel"
+ link: (scope, element, attrs, ngModel) ->
+ element.datetimepicker
+ dateFormat: "yy-mm-dd"
+ timeFormat: "HH:mm:ss"
+ stepMinute: 15
+ onSelect: (dateText, inst) ->
+ scope.$apply (scope) ->
+ # Fires ngModel.$parsers
+ ngModel.$setViewValue dateText
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/decimal.js.coffee b/app/assets/javascripts/admin/directives/decimal.js.coffee
new file mode 100644
index 0000000000..8077f90c06
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/decimal.js.coffee
@@ -0,0 +1,11 @@
+Admin.directive "ofnDecimal", ->
+ require: "ngModel"
+ link: (scope, element, attrs, ngModel) ->
+ numRegExp = /^\d+(\.\d+)?$/
+ element.bind "blur", ->
+ scope.$apply ngModel.$setViewValue(ngModel.$modelValue)
+ ngModel.$render()
+
+ ngModel.$parsers.push (viewValue) ->
+ return viewValue + ".0" if viewValue.indexOf(".") == -1 if angular.isString(viewValue) and numRegExp.test(viewValue)
+ viewValue
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/line_item_upd_attr.js.coffee b/app/assets/javascripts/admin/directives/line_item_upd_attr.js.coffee
new file mode 100644
index 0000000000..a71aa42997
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/line_item_upd_attr.js.coffee
@@ -0,0 +1,23 @@
+Admin.directive "ofnLineItemUpdAttr", [
+ "switchClass", "pendingChanges"
+ (switchClass, pendingChanges) ->
+ require: "ngModel"
+ link: (scope, element, attrs, ngModel) ->
+ attrName = attrs.ofnLineItemUpdAttr
+ element.dbValue = scope.$eval(attrs.ngModel)
+ scope.$watch ->
+ scope.$eval(attrs.ngModel)
+ , (value) ->
+ if ngModel.$dirty
+ if value == element.dbValue
+ pendingChanges.remove(scope.line_item.id, attrName)
+ switchClass( element, "", ["update-pending", "update-error", "update-success"], false )
+ else
+ changeObj =
+ lineItem: scope.line_item
+ element: element
+ attrName: attrName
+ url: "/api/orders/#{scope.line_item.order.number}/line_items/#{scope.line_item.id}?line_item[#{attrName}]=#{value}"
+ pendingChanges.add(scope.line_item.id, attrName, changeObj)
+ switchClass( element, "update-pending", ["update-error", "update-success"], false )
+]
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/select2_min_search.js.coffee b/app/assets/javascripts/admin/directives/select2_min_search.js.coffee
new file mode 100644
index 0000000000..c33beb710e
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/select2_min_search.js.coffee
@@ -0,0 +1,9 @@
+Admin.directive "ofnSelect2MinSearch", ->
+ require: 'ngModel'
+ link: (scope, element, attrs, ngModel) ->
+ element.select2
+ minimumResultsForSearch: attrs.ofnSelect2MinSearch
+
+ ngModel.$formatters.push (value) ->
+ if (value)
+ element.select2('val', value);
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/taxon_autocomplete.js.coffee b/app/assets/javascripts/admin/directives/taxon_autocomplete.js.coffee
new file mode 100644
index 0000000000..0705d04a23
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/taxon_autocomplete.js.coffee
@@ -0,0 +1,21 @@
+Admin.directive "ofnTaxonAutocomplete", (Taxons) ->
+ # Adapted from Spree's existing taxon autocompletion
+ require: "ngModel"
+ link: (scope,element,attrs,ngModel) ->
+ setTimeout ->
+ element.select2
+ placeholder: Spree.translations.taxon_placeholder
+ multiple: true
+ initSelection: (element, callback) ->
+ Taxons.findByIDs(element.val()).$promise.then (result) ->
+ callback Taxons.cleanTaxons(result)
+ query: (query) ->
+ Taxons.findByTerm(query.term).$promise.then (result) ->
+ query.callback { results: Taxons.cleanTaxons(result) }
+ formatResult: (taxon) ->
+ taxon.pretty_name
+ formatSelection: (taxon) ->
+ taxon.pretty_name
+ element.on "change", ->
+ scope.$apply ->
+ ngModel.$setViewValue element.val()
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/toggle_column.js.coffee b/app/assets/javascripts/admin/directives/toggle_column.js.coffee
new file mode 100644
index 0000000000..2337a0fb58
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/toggle_column.js.coffee
@@ -0,0 +1,11 @@
+Admin.directive "ofnToggleColumn", ->
+ link: (scope, element, attrs) ->
+ element.addClass "selected" if scope.column.visible
+ element.click "click", ->
+ scope.$apply ->
+ if scope.column.visible
+ scope.column.visible = false
+ element.removeClass "selected"
+ else
+ scope.column.visible = true
+ element.addClass "selected"
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/toggle_variants.js.coffee b/app/assets/javascripts/admin/directives/toggle_variants.js.coffee
new file mode 100644
index 0000000000..8c07490359
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/toggle_variants.js.coffee
@@ -0,0 +1,18 @@
+Admin.directive "ofnToggleVariants", ->
+ link: (scope, element, attrs) ->
+ if scope.displayProperties[scope.product.id].showVariants
+ element.removeClass "icon-chevron-right"
+ element.addClass "icon-chevron-down"
+ else
+ element.removeClass "icon-chevron-down"
+ element.addClass "icon-chevron-right"
+ element.on "click", ->
+ scope.$apply ->
+ if scope.displayProperties[scope.product.id].showVariants
+ scope.displayProperties[scope.product.id].showVariants = false
+ element.removeClass "icon-chevron-down"
+ element.addClass "icon-chevron-right"
+ else
+ scope.displayProperties[scope.product.id].showVariants = true
+ element.removeClass "icon-chevron-right"
+ element.addClass "icon-chevron-down"
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/track_product.js.coffee b/app/assets/javascripts/admin/directives/track_product.js.coffee
new file mode 100644
index 0000000000..31bcb9fae6
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/track_product.js.coffee
@@ -0,0 +1,10 @@
+Admin.directive "ofnTrackProduct", ['$parse', ($parse) ->
+ require: "ngModel"
+ link: (scope, element, attrs, ngModel) ->
+ ngModel.$parsers.push (viewValue) ->
+ if ngModel.$dirty
+ parsedPropertyName = $parse(attrs.ofnTrackProduct)
+ addDirtyProperty scope.dirtyProducts, scope.product.id, parsedPropertyName, viewValue
+ scope.displayDirtyProducts()
+ viewValue
+ ]
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/directives/track_variant.js.coffee b/app/assets/javascripts/admin/directives/track_variant.js.coffee
new file mode 100644
index 0000000000..53e351bc6a
--- /dev/null
+++ b/app/assets/javascripts/admin/directives/track_variant.js.coffee
@@ -0,0 +1,13 @@
+Admin.directive "ofnTrackVariant", ['$parse', ($parse) ->
+ require: "ngModel"
+ link: (scope, element, attrs, ngModel) ->
+ ngModel.$parsers.push (viewValue) ->
+ dirtyVariants = {}
+ dirtyVariants = scope.dirtyProducts[scope.product.id].variants if scope.dirtyProducts.hasOwnProperty(scope.product.id) and scope.dirtyProducts[scope.product.id].hasOwnProperty("variants")
+ if ngModel.$dirty
+ parsedPropertyName = $parse(attrs.ofnTrackVariant)
+ addDirtyProperty dirtyVariants, scope.variant.id, parsedPropertyName, viewValue
+ addDirtyProperty scope.dirtyProducts, scope.product.id, $parse("variants"), dirtyVariants
+ scope.displayDirtyProducts()
+ viewValue
+ ]
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/filters/range_array.js.coffee b/app/assets/javascripts/admin/filters/range_array.js.coffee
new file mode 100644
index 0000000000..5056476f1b
--- /dev/null
+++ b/app/assets/javascripts/admin/filters/range_array.js.coffee
@@ -0,0 +1,4 @@
+Admin.filter "rangeArray", ->
+ return (input,start,end) ->
+ input.push(i) for i in [start..end]
+ input
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/filters/select_filter.js.coffee b/app/assets/javascripts/admin/filters/select_filter.js.coffee
new file mode 100644
index 0000000000..562be954b2
--- /dev/null
+++ b/app/assets/javascripts/admin/filters/select_filter.js.coffee
@@ -0,0 +1,7 @@
+Admin.filter "selectFilter", (blankOption) ->
+ return (lineItems,selectedSupplier,selectedDistributor,selectedOrderCycle) ->
+ filtered = []
+ filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,"0") || lineItem.supplier.id == selectedSupplier) &&
+ (angular.equals(selectedDistributor,"0") || lineItem.order.distributor.id == selectedDistributor) &&
+ (angular.equals(selectedOrderCycle,"0") || lineItem.order.order_cycle.id == selectedOrderCycle)
+ filtered
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/filters/variant_filter.js.coffee b/app/assets/javascripts/admin/filters/variant_filter.js.coffee
new file mode 100644
index 0000000000..039c4cc46f
--- /dev/null
+++ b/app/assets/javascripts/admin/filters/variant_filter.js.coffee
@@ -0,0 +1,6 @@
+Admin.filter "variantFilter", ->
+ return (lineItems,selectedUnitsProduct,selectedUnitsVariant,sharedResource) ->
+ filtered = []
+ filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedUnitsProduct,{}) ||
+ (lineItem.units_product.id == selectedUnitsProduct.id && (sharedResource || lineItem.units_variant.id == selectedUnitsVariant.id ) ) )
+ filtered
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/services/blank_option.js.coffee b/app/assets/javascripts/admin/services/blank_option.js.coffee
new file mode 100644
index 0000000000..9913a6511d
--- /dev/null
+++ b/app/assets/javascripts/admin/services/blank_option.js.coffee
@@ -0,0 +1,2 @@
+Admin.value "blankOption", ->
+ { id: "0", name: "All" }
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/services/confirm_handler.js.coffee b/app/assets/javascripts/admin/services/confirm_handler.js.coffee
new file mode 100644
index 0000000000..51b92848dc
--- /dev/null
+++ b/app/assets/javascripts/admin/services/confirm_handler.js.coffee
@@ -0,0 +1,24 @@
+Admin.factory "ofnConfirmHandler", (pendingChanges, $compile, $q) ->
+ return (scope, callback) ->
+ template = "Unsaved changes currently exist, save now or ignore?
"
+ dialogDiv = $compile(template)(scope)
+ return ->
+ if pendingChanges.changeCount(pendingChanges.pendingChanges) > 0
+ dialogDiv.dialog
+ dialogClass: "no-close"
+ resizable: false
+ height: 140
+ modal: true
+ buttons:
+ "SAVE": ->
+ dialogDiv = $(this)
+ $q.all(pendingChanges.submitAll()).then ->
+ callback()
+ dialogDiv.dialog "close"
+ "IGNORE": ->
+ callback()
+ $(this).dialog "close"
+ scope.$apply()
+ dialogDiv.dialog "open"
+ else
+ callback()
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/shared_services.js.coffee b/app/assets/javascripts/admin/services/data_fetcher.js.coffee
similarity index 67%
rename from app/assets/javascripts/admin/shared_services.js.coffee
rename to app/assets/javascripts/admin/services/data_fetcher.js.coffee
index 0f48f72b40..0227d26fc7 100644
--- a/app/assets/javascripts/admin/shared_services.js.coffee
+++ b/app/assets/javascripts/admin/services/data_fetcher.js.coffee
@@ -1,6 +1,4 @@
-sharedServicesModule = angular.module("ofn.shared_services", [])
-
-sharedServicesModule.factory "dataFetcher", [
+Admin.factory "dataFetcher", [
"$http", "$q"
($http, $q) ->
return (dataLocation) ->
diff --git a/app/assets/javascripts/admin/services/data_submitter.js.coffee b/app/assets/javascripts/admin/services/data_submitter.js.coffee
new file mode 100644
index 0000000000..6a08ca2d33
--- /dev/null
+++ b/app/assets/javascripts/admin/services/data_submitter.js.coffee
@@ -0,0 +1,13 @@
+Admin.factory "dataSubmitter", [
+ "$http", "$q", "switchClass"
+ ($http, $q, switchClass) ->
+ return (changeObj) ->
+ deferred = $q.defer()
+ $http.put(changeObj.url).success((data) ->
+ switchClass changeObj.element, "update-success", ["update-pending", "update-error"], 3000
+ deferred.resolve data
+ ).error ->
+ switchClass changeObj.element, "update-error", ["update-pending", "update-success"], false
+ deferred.reject()
+ deferred.promise
+]
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/services/pending_changes.js.coffee b/app/assets/javascripts/admin/services/pending_changes.js.coffee
new file mode 100644
index 0000000000..df66900aa7
--- /dev/null
+++ b/app/assets/javascripts/admin/services/pending_changes.js.coffee
@@ -0,0 +1,32 @@
+Admin.factory "pendingChanges",[
+ "dataSubmitter"
+ (dataSubmitter) ->
+ pendingChanges: {}
+
+ add: (id, attrName, changeObj) ->
+ @pendingChanges["#{id}"] = {} unless @pendingChanges.hasOwnProperty("#{id}")
+ @pendingChanges["#{id}"]["#{attrName}"] = changeObj
+
+ removeAll: ->
+ @pendingChanges = {}
+
+ remove: (id, attrName) ->
+ if @pendingChanges.hasOwnProperty("#{id}")
+ delete @pendingChanges["#{id}"]["#{attrName}"]
+ delete @pendingChanges["#{id}"] if @changeCount( @pendingChanges["#{id}"] ) < 1
+
+ submitAll: ->
+ all = []
+ for id,lineItem of @pendingChanges
+ for attrName,changeObj of lineItem
+ all.push @submit(id, attrName, changeObj)
+ all
+
+ submit: (id, attrName, change) ->
+ dataSubmitter(change).then (data) =>
+ @remove id, attrName
+ change.element.dbValue = data["#{attrName}"]
+
+ changeCount: (lineItem) ->
+ Object.keys(lineItem).length
+]
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/services/switch_class.js.coffee b/app/assets/javascripts/admin/services/switch_class.js.coffee
new file mode 100644
index 0000000000..bdd61dac2e
--- /dev/null
+++ b/app/assets/javascripts/admin/services/switch_class.js.coffee
@@ -0,0 +1,13 @@
+Admin.factory "switchClass", [
+ "$timeout"
+ ($timeout) ->
+ return (element,classToAdd,removeClasses,timeout) ->
+ $timeout.cancel element.timeout if element.timeout
+ element.removeClass className for className in removeClasses
+ element.addClass classToAdd
+ intRegex = /^\d+$/
+ if timeout && intRegex.test(timeout)
+ element.timeout = $timeout(->
+ element.removeClass classToAdd
+ , timeout, true)
+]
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/services/taxons.js.coffee b/app/assets/javascripts/admin/services/taxons.js.coffee
new file mode 100644
index 0000000000..5e17dca657
--- /dev/null
+++ b/app/assets/javascripts/admin/services/taxons.js.coffee
@@ -0,0 +1,13 @@
+Admin.factory "Taxons", ($resource) ->
+ resource = $resource "/admin/taxons/search"
+
+ return {
+ findByIDs: (ids) ->
+ resource.get { ids: ids }
+
+ findByTerm: (term) ->
+ resource.get { q: term }
+
+ cleanTaxons: (data) ->
+ data['taxons'].map (result) -> result
+ }
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/shared_directives.js.coffee b/app/assets/javascripts/admin/shared_directives.js.coffee
deleted file mode 100644
index 0a8a899a6f..0000000000
--- a/app/assets/javascripts/admin/shared_directives.js.coffee
+++ /dev/null
@@ -1,45 +0,0 @@
-sharedDirectivesModule = angular.module("ofn.shared_directives", [])
-
-sharedDirectivesModule.directive "datetimepicker", ->
- require: "ngModel"
- link: (scope, element, attrs, ngModel) ->
- element.datetimepicker
- dateFormat: "yy-mm-dd"
- timeFormat: "HH:mm:ss"
- stepMinute: 15
- onSelect: (dateText, inst) ->
- scope.$apply (scope) ->
- # Fires ngModel.$parsers
- ngModel.$setViewValue dateText
-
-sharedDirectivesModule.directive "datepicker", ->
- require: "ngModel"
- link: (scope, element, attrs, ngModel) ->
- element.datepicker
- dateFormat: "yy-mm-dd"
- onSelect: (dateText, inst) ->
- scope.$apply (scope) ->
- # Fires ngModel.$parsers
- ngModel.$setViewValue dateText
-
-sharedDirectivesModule.directive "ofnSelect2MinSearch", ->
- require: 'ngModel'
- link: (scope, element, attrs, ngModel) ->
- element.select2
- minimumResultsForSearch: attrs.ofnSelect2MinSearch
-
- ngModel.$formatters.push (value) ->
- if (value)
- element.select2('val', value);
-
-sharedDirectivesModule.directive "ofnToggleColumn", ->
- link: (scope, element, attrs) ->
- element.addClass "selected" if scope.column.visible
- element.click "click", ->
- scope.$apply ->
- if scope.column.visible
- scope.column.visible = false
- element.removeClass "selected"
- else
- scope.column.visible = true
- element.addClass "selected"
\ No newline at end of file
diff --git a/app/views/spree/admin/orders/bulk_management.html.haml b/app/views/spree/admin/orders/bulk_management.html.haml
index 28fd7b3aea..a73c0cea07 100644
--- a/app/views/spree/admin/orders/bulk_management.html.haml
+++ b/app/views/spree/admin/orders/bulk_management.html.haml
@@ -4,7 +4,7 @@
= render :partial => 'spree/admin/shared/order_sub_menu'
-%div{ 'ng-app' => 'ofn.bulk_order_management', 'ng-controller' => 'AdminOrderMgmtCtrl', 'ng-init' => "initialise('#{@spree_api_key}');loading=true;" }
+%div{ 'ng-app' => 'ofn.admin', 'ng-controller' => 'AdminOrderMgmtCtrl', 'ng-init' => "initialise('#{@spree_api_key}');loading=true;" }
%div{ 'ng-show' => '!spree_api_key_ok' }
{{ api_error_msg }}
.filters{ :class => "sixteen columns alpha" }
diff --git a/app/views/spree/admin/products/bulk_edit.html.haml b/app/views/spree/admin/products/bulk_edit.html.haml
index 9098ad81ba..ee74fd9662 100644
--- a/app/views/spree/admin/products/bulk_edit.html.haml
+++ b/app/views/spree/admin/products/bulk_edit.html.haml
@@ -13,7 +13,7 @@
-%div{ 'ng-app' => 'ofn.bulk_product_edit', 'ng-controller' => 'AdminProductEditCtrl', 'ng-init' => "initialise('#{@spree_api_key}');loading=true;" }
+%div{ 'ng-app' => 'ofn.admin', 'ng-controller' => 'AdminProductEditCtrl', 'ng-init' => "initialise('#{@spree_api_key}');loading=true;" }
%div{ 'ng-show' => '!spree_api_key_ok' }
{{ api_error_msg }}
%div.option_tab_titles{ :class => "sixteen columns alpha" }