lanes 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/appy-app/.gitignore +3 -0
  3. data/appy-app/Gemfile +6 -0
  4. data/appy-app/Guardfile +13 -0
  5. data/appy-app/Rakefile +2 -0
  6. data/appy-app/client/appy-app/Extension.coffee +7 -0
  7. data/appy-app/client/appy-app/Router.coffee +4 -0
  8. data/appy-app/client/appy-app/components/.gitkeep +0 -0
  9. data/appy-app/client/appy-app/controllers/.gitkeep +0 -0
  10. data/appy-app/client/appy-app/index.js +21 -0
  11. data/appy-app/client/appy-app/models/.gitkeep +0 -0
  12. data/appy-app/client/appy-app/models/Base.coffee +5 -0
  13. data/appy-app/client/appy-app/screens/.gitkeep +0 -0
  14. data/appy-app/client/appy-app/screens/Base.coffee +10 -0
  15. data/appy-app/client/appy-app/styles.scss +1 -0
  16. data/appy-app/client/appy-app/views/.gitkeep +0 -0
  17. data/appy-app/client/appy-app/views/Base.coffee +5 -0
  18. data/appy-app/config/database.yml +9 -0
  19. data/appy-app/config/lanes.rb +7 -0
  20. data/appy-app/config/routes.rb +2 -0
  21. data/appy-app/config/screens.rb +8 -0
  22. data/appy-app/config.ru +5 -0
  23. data/appy-app/db/.gitkeep +0 -0
  24. data/appy-app/lib/appy-app/extension.rb +13 -0
  25. data/appy-app/lib/appy-app/model.rb +11 -0
  26. data/appy-app/lib/appy-app/models/empty.rb +0 -0
  27. data/appy-app/lib/appy-app/version.rb +3 -0
  28. data/appy-app/lib/appy-app.rb +14 -0
  29. data/appy-app/spec/appy-app/helpers/AppyAppHelpers.coffee +5 -0
  30. data/appy-app/spec/appy-app/screens/Base.coffee +5 -0
  31. data/appy-app/spec/server/spec_helpers.rb +16 -0
  32. data/client/{lanes/styles/fonts → fonts/lanes}/icomoon.eot +0 -0
  33. data/client/{lanes/styles/fonts → fonts/lanes}/icomoon.svg +0 -0
  34. data/client/{lanes/styles/fonts → fonts/lanes}/icomoon.ttf +0 -0
  35. data/client/{lanes/styles/fonts → fonts/lanes}/icomoon.woff +0 -0
  36. data/client/{lanes/styles/fonts → fonts/lanes}/selection.json +0 -0
  37. data/client/images/{ajax-loader.gif → lanes/ajax-loader.gif} +0 -0
  38. data/client/images/{dataTables → lanes/dataTables}/Sorting icons.psd +0 -0
  39. data/client/images/{dataTables → lanes/dataTables}/back_disabled.png +0 -0
  40. data/client/images/{dataTables → lanes/dataTables}/back_enabled.png +0 -0
  41. data/client/images/{dataTables → lanes/dataTables}/back_enabled_hover.png +0 -0
  42. data/client/images/{dataTables → lanes/dataTables}/favicon.ico +0 -0
  43. data/client/images/{dataTables → lanes/dataTables}/forward_disabled.png +0 -0
  44. data/client/images/{dataTables → lanes/dataTables}/forward_enabled.png +0 -0
  45. data/client/images/{dataTables → lanes/dataTables}/forward_enabled_hover.png +0 -0
  46. data/client/images/{dataTables → lanes/dataTables}/loading-background.png +0 -0
  47. data/client/images/{dataTables → lanes/dataTables}/sort_asc.png +0 -0
  48. data/client/images/{dataTables → lanes/dataTables}/sort_asc_disabled.png +0 -0
  49. data/client/images/{dataTables → lanes/dataTables}/sort_both.png +0 -0
  50. data/client/images/{dataTables → lanes/dataTables}/sort_desc.png +0 -0
  51. data/client/images/{dataTables → lanes/dataTables}/sort_desc_disabled.png +0 -0
  52. data/client/images/lanes/logo-sm.png +0 -0
  53. data/client/lanes/Config.coffee +19 -0
  54. data/client/lanes/components/grid/styles.scss +6 -6
  55. data/client/lanes/index.js +1 -0
  56. data/client/lanes/index.scss.erb +5 -5
  57. data/client/lanes/models/Base.coffee +11 -11
  58. data/client/lanes/models/Bootstrap.coffee +0 -2
  59. data/client/lanes/models/ChangeMonitor.coffee +16 -13
  60. data/client/lanes/models/Collection.coffee +2 -4
  61. data/client/lanes/models/ModelAssociations.coffee +13 -28
  62. data/client/lanes/models/Sync.coffee +1 -1
  63. data/client/lanes/screens/Instance.coffee +1 -0
  64. data/client/lanes/styles/{fonts/style.scss → font-definitions.scss} +0 -0
  65. data/client/lanes/styles/fonts.scss +1 -1
  66. data/client/lanes/styles/plugins/overlay.scss +1 -1
  67. data/client/lanes/testing/ModelSaver.coffee +23 -0
  68. data/client/lanes/testing/index.js +4 -0
  69. data/client/lanes/workspace/ActiveScreensSwitcher.coffee +2 -3
  70. data/client/lanes/workspace/Pages.coffee +6 -11
  71. data/client/lanes/workspace/styles/header.scss +1 -1
  72. data/lanes.gemspec +1 -1
  73. data/lib/lanes/access/authentication_provider.rb +2 -2
  74. data/lib/lanes/access/config/routes.rb +1 -1
  75. data/lib/lanes/access/role.rb +5 -0
  76. data/lib/lanes/access/role_collection.rb +9 -6
  77. data/lib/lanes/access/roles/administrator.rb +3 -10
  78. data/lib/lanes/api/request_wrapper.rb +21 -8
  79. data/lib/lanes/api/root.rb +2 -4
  80. data/lib/lanes/api/sprockets_extension.rb +8 -6
  81. data/lib/lanes/api/test_specs.rb +1 -0
  82. data/lib/lanes/capistrano.rb +18 -0
  83. data/lib/lanes/command/app.rb +2 -6
  84. data/lib/lanes/command/generate_model.rb +11 -11
  85. data/lib/lanes/command/generate_view.rb +1 -1
  86. data/lib/lanes/command/named_command.rb +7 -4
  87. data/lib/lanes/concerns/set_attribute_data.rb +1 -1
  88. data/lib/lanes/configuration.rb +1 -0
  89. data/lib/lanes/db.rb +1 -0
  90. data/lib/lanes/extension/definition.rb +16 -4
  91. data/lib/lanes/extension.rb +1 -4
  92. data/lib/lanes/version.rb +1 -1
  93. data/spec/server/command-reference-files/initial/.gitignore +3 -0
  94. data/spec/server/command-reference-files/initial/Gemfile +6 -0
  95. data/spec/server/command-reference-files/initial/Guardfile +13 -0
  96. data/spec/server/command-reference-files/initial/Rakefile +2 -0
  97. data/spec/server/command-reference-files/initial/client/appy-app/Extension.coffee +7 -0
  98. data/spec/server/command-reference-files/initial/client/appy-app/Router.coffee +4 -0
  99. data/spec/server/command-reference-files/initial/client/appy-app/components/.gitkeep +0 -0
  100. data/spec/server/command-reference-files/initial/client/appy-app/controllers/.gitkeep +0 -0
  101. data/spec/server/command-reference-files/initial/client/appy-app/index.js +21 -0
  102. data/spec/server/command-reference-files/initial/client/appy-app/models/.gitkeep +0 -0
  103. data/spec/server/command-reference-files/initial/client/appy-app/models/Base.coffee +5 -0
  104. data/spec/server/command-reference-files/initial/client/appy-app/screens/.gitkeep +0 -0
  105. data/spec/server/command-reference-files/initial/client/appy-app/screens/Base.coffee +3 -0
  106. data/spec/server/command-reference-files/initial/client/appy-app/styles.scss +1 -0
  107. data/spec/server/command-reference-files/initial/client/appy-app/views/.gitkeep +0 -0
  108. data/spec/server/command-reference-files/initial/client/appy-app/views/Base.coffee +5 -0
  109. data/spec/server/command-reference-files/initial/config/database.yml +9 -0
  110. data/spec/server/command-reference-files/initial/config/lanes.rb +7 -0
  111. data/spec/server/command-reference-files/initial/config/routes.rb +2 -0
  112. data/spec/server/command-reference-files/initial/config/screens.rb +0 -0
  113. data/spec/server/command-reference-files/initial/config.ru +5 -0
  114. data/spec/server/command-reference-files/initial/db/.gitkeep +0 -0
  115. data/spec/server/command-reference-files/initial/lib/appy-app/extension.rb +13 -0
  116. data/spec/server/command-reference-files/initial/lib/appy-app/model.rb +11 -0
  117. data/spec/server/command-reference-files/initial/lib/appy-app/models/empty.rb +0 -0
  118. data/spec/server/command-reference-files/initial/lib/appy-app/version.rb +3 -0
  119. data/spec/server/command-reference-files/initial/lib/appy-app.rb +12 -0
  120. data/spec/server/command-reference-files/initial/spec/appy-app/helpers/AppyAppHelpers.coffee +5 -0
  121. data/spec/server/command-reference-files/initial/spec/appy-app/screens/Base.coffee +5 -0
  122. data/spec/server/command-reference-files/initial/spec/server/spec_helpers.rb +16 -0
  123. data/spec/server/command-reference-files/model/client/appy-app/models/TestTest.coffee +9 -0
  124. data/spec/server/command-reference-files/model/config/routes.rb +3 -0
  125. data/spec/server/command-reference-files/model/db/migrate/20150218032025_create_test_tests.rb +10 -0
  126. data/spec/server/command-reference-files/model/lib/appy-app/models/test_test.rb +7 -0
  127. data/spec/server/command-reference-files/model/spec/appy-app/models/TestTestSpec.coffee +5 -0
  128. data/spec/server/command-reference-files/model/spec/fixtures/appy-app/test_test.yml +11 -0
  129. data/spec/server/command-reference-files/model/spec/server/test_test_spec.rb +10 -0
  130. data/spec/server/command-reference-files/screen/client/appy-app/screens/ready-set-go/ReadySetGo.coffee +7 -0
  131. data/spec/server/command-reference-files/screen/client/appy-app/screens/ready-set-go/index.js +5 -0
  132. data/spec/server/command-reference-files/screen/client/appy-app/screens/ready-set-go/index.scss +8 -0
  133. data/spec/server/command-reference-files/screen/client/appy-app/screens/ready-set-go/layout.html +3 -0
  134. data/spec/server/command-reference-files/screen/config/screens.rb +9 -0
  135. data/spec/server/command-reference-files/screen/spec/appy-app/screens/ready-set-go/ReadySetGoSpec.coffee +5 -0
  136. data/spec/server/command-reference-files/view/client/appy-app/views/BigView.coffee +10 -0
  137. data/spec/server/command-reference-files/view/spec/appy-app/views/BigViewSpec.coffee +5 -0
  138. data/spec/server/command_spec.rb +40 -15
  139. data/templates/client/screens/Base.coffee +3 -0
  140. data/templates/client/screens/Screen.coffee +1 -1
  141. data/templates/config/screen.rb +0 -1
  142. data/templates/db/create_table_migration.rb +1 -1
  143. data/templates/lib/namespace.rb +2 -4
  144. metadata +118 -25
  145. data/client/images/logo-sm.png +0 -0
  146. data/client/lanes/models/Config.coffee +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc96c5119c604258c8b8f4c2ceb3c8c3028519bc
4
- data.tar.gz: 4f4f8fd4254620611174e393070c68c257b13790
3
+ metadata.gz: dcfa482b3905ad3ec30faf5fe9569f6f6bc8650b
4
+ data.tar.gz: fd43ec7fc591b2f8310f89bf0c734bdff7be1a9f
5
5
  SHA512:
6
- metadata.gz: f54221e4207bc547a4aaf6015f28c41991c4347fe2bcf328a8bc5b335c480a2c1b48837a63b55993368ee4529cac2165e966cda612d06a0d52dee1aa28592742
7
- data.tar.gz: f7fcb100561a1345cb2280853531b5e12a44ed52a96656e4328581a798bf1b5b54ad4355e54e037f2e26e7d0fa7f90a1c071c990c0f479b34731fb65c4cce43f
6
+ metadata.gz: 953ecd6093ed5e2cdf9e7b29de6f444a82a5299833c1c3166e930047ab8b80bbbf2c7a166d7a08df882a6d26552cf84ffbb577aac4a7299739144eda0708e591
7
+ data.tar.gz: 903218ab0ea98c8c1e290ba9c9976ad5585f84080625433e84e6ed22020e036db9d9263a57afc1ec52d039b1c57ad8b43467b9ba9a1021e8f70154d0210d1fe5
@@ -0,0 +1,3 @@
1
+ public/assets
2
+ tmp/cache
3
+ log/*log
data/appy-app/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "lanes", '0.1.5'
4
+
5
+ gem "rake"
6
+ gem 'puma'
@@ -0,0 +1,13 @@
1
+ require "lanes/guard_tasks"
2
+
3
+ Lanes::GuardTasks.run(self, name: "appy-app") do | tests |
4
+
5
+ tests.client do
6
+
7
+ end
8
+
9
+ tests.server do
10
+
11
+ end
12
+
13
+ end
data/appy-app/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require_relative 'lib/appy-app'
2
+ require 'lanes/rake_tasks'
@@ -0,0 +1,7 @@
1
+ class AppyApp.Extension extends Lanes.Extensions.Base
2
+
3
+ FILE: FILE
4
+
5
+ identifier: "appy-app"
6
+
7
+ setBootstrapData: (data)->
@@ -0,0 +1,4 @@
1
+ class AppyApp.Router extends Lanes.Screens.Router
2
+
3
+ routes:
4
+ {}
File without changes
File without changes
@@ -0,0 +1,21 @@
1
+ //=require ./models/Base
2
+ //=require ./views/Base
3
+ //=require_tree ./models
4
+ //=require_tree ./views
5
+ //=require_tree ./components
6
+ //=require ./screens/Base
7
+ //=require ./Router
8
+ //=require ./Extension
9
+
10
+ /*
11
+ Files located in the above directories are part of the default
12
+ Javascript build and are downloaded to the client on the initial
13
+ request.
14
+
15
+ Accordingly, only essential files should be included here. Code that
16
+ relates to a screen should be placed in the "screens" directory,
17
+ where it will be loaded dynamically when the screen is displayed.
18
+
19
+ Alternatively, feel free to modify the require statements above to
20
+ only include the paths you need.
21
+ */
File without changes
@@ -0,0 +1,5 @@
1
+ # All models in AppyApp will inherit from
2
+ # this common base class.
3
+ class AppyApp.Models.Base extends Lanes.Models.Base
4
+
5
+ abstractClass: true
File without changes
@@ -0,0 +1,10 @@
1
+ class AppyApp.Screens.Base extends Lanes.Screens.Base
2
+
3
+ FILE: FILE
4
+ template: '''
5
+ <div><h1>Base Screen</h1></div>
6
+ '''
7
+
8
+ subviews: {}
9
+
10
+ events: {}
@@ -0,0 +1 @@
1
+ /* Enter styles for your application in scss format here */
File without changes
@@ -0,0 +1,5 @@
1
+ # All views in AppyApp will inherit from
2
+ # this common base class.
3
+ class AppyApp.Views.Base extends Lanes.Views.Base
4
+
5
+ abstractClass: true
@@ -0,0 +1,9 @@
1
+ development:
2
+ adapter: postgresql
3
+ database: appy-app_dev
4
+ host: /tmp
5
+
6
+ test:
7
+ adapter: postgresql
8
+ database: appy-app_test
9
+ host: /tmp
@@ -0,0 +1,7 @@
1
+ # This file will be loaded if the current extension is the
2
+ # one controlling Lanes.
3
+ #
4
+ # It will not be evaluated if another extension is loading this one
5
+ Lanes.configure do | config |
6
+ config.root_view = "AppyApp.Screens.Base"
7
+ end
@@ -0,0 +1,2 @@
1
+ Lanes::API.routes.draw do
2
+ end
@@ -0,0 +1,8 @@
1
+
2
+ Lanes::Screen.define "base" do | screen |
3
+ screen.description = "Base Screen for Appy App"
4
+ screen.icon = ""
5
+ screen.group_id = ""
6
+ screen.model_class = ""
7
+ screen.view_class = "AppyApp.Screens.Base"
8
+ end
@@ -0,0 +1,5 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+ require_relative 'lib/appy-app'
4
+ require 'lanes/api'
5
+ run Lanes::API::Root
File without changes
@@ -0,0 +1,13 @@
1
+ require_relative '../appy-app'
2
+
3
+ module AppyApp
4
+
5
+ class Extension < Lanes::Extensions::Definition
6
+
7
+ identifier "appy-app"
8
+
9
+ root_path Pathname.new(__FILE__).dirname.join("..","..").expand_path
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,11 @@
1
+ module AppyApp
2
+
3
+ # All models in AppyApp will inherit from
4
+ # this common base class.
5
+ class Model < Lanes::Model
6
+
7
+ self.abstract_class = true
8
+
9
+ end
10
+
11
+ end
File without changes
@@ -0,0 +1,3 @@
1
+ module AppyApp
2
+ VERSION=0.1
3
+ end
@@ -0,0 +1,14 @@
1
+ require "lanes"
2
+ require 'require_all'
3
+ require_relative "appy-app/version.rb"
4
+ require_relative "appy-app/extension.rb"
5
+
6
+ # The main namespace for Appy-app
7
+ module AppyApp
8
+ def self.table_name_prefix
9
+ "appy-app_"
10
+ end
11
+ end
12
+
13
+ require_relative "appy-app/model"
14
+ require_rel "appy-app/models"
@@ -0,0 +1,5 @@
1
+ ##
2
+ # Uncomment the below beforeEach method to execute code or set instance variables
3
+ # that will be available to all Specs
4
+
5
+ # beforeEach ->
@@ -0,0 +1,5 @@
1
+ describe "AppyApp.Screens.Base", ->
2
+
3
+ it "can be instantiated", ->
4
+ view = new AppyApp.Screens.Base()
5
+ expect(view).toEqual(jasmine.any(AppyApp.Screens.Base));
@@ -0,0 +1,16 @@
1
+ require_relative '../../lib/AppyApp'
2
+ require 'lanes/spec_helper'
3
+
4
+ module AppyApp
5
+
6
+ # Add more helper methods to be used by all tests here...
7
+
8
+ class TestCase < Lanes::TestCase
9
+ include AppyApp
10
+ end
11
+
12
+ class ApiTestCase < Lanes::ApiTestCase
13
+ include AppyApp
14
+ end
15
+
16
+ end
Binary file
@@ -0,0 +1,19 @@
1
+ class Config extends Lanes.Models.State
2
+ constructor: -> super
3
+
4
+ session:
5
+ csrf_token: { type: 'string', setOnce: true }
6
+ api_path: { type: 'string', setOnce: true }
7
+ environment: { type: 'string', setOnce: true }
8
+
9
+ derived:
10
+ env:
11
+ deps: ['environment'], fn: ->
12
+ {
13
+ test: this.environment == 'test',
14
+ development: this.environment == 'development',
15
+ production: this.environment == 'production'
16
+ }
17
+
18
+
19
+ Lanes.config = new Config
@@ -27,7 +27,7 @@
27
27
  padding-top: 20px;
28
28
  text-align: center;
29
29
  font-size: 1.2em;
30
- background:url(asset_path('images/ajax-loader.gif')) no-repeat scroll 40% 7px $body-bg;
30
+ background:url(asset_path('images/lanes/ajax-loader.gif')) no-repeat scroll 40% 7px $body-bg;
31
31
  }
32
32
 
33
33
 
@@ -87,12 +87,12 @@
87
87
  cursor: pointer;
88
88
  }
89
89
 
90
- thead .sorting { background: url(image-path('images/dataTables/sort_both.png')) no-repeat center right; }
91
- thead .sorting_asc { background: url(image-path('images/dataTables/sort_asc.png')) no-repeat center right; }
92
- thead .sorting_desc { background: url(image-path('images/dataTables/sort_desc.png')) no-repeat center right; }
90
+ thead .sorting { background: url(image-path('images/lanes/dataTables/sort_both.png')) no-repeat center right; }
91
+ thead .sorting_asc { background: url(image-path('images/lanes/dataTables/sort_asc.png')) no-repeat center right; }
92
+ thead .sorting_desc { background: url(image-path('images/lanes/dataTables/sort_desc.png')) no-repeat center right; }
93
93
 
94
- thead .sorting_asc_disabled { background: url(image-path('images/dataTables/sort_asc_disabled.png')) no-repeat center right; }
95
- thead .sorting_desc_disabled { background: url(image-path('images/dataTables/sort_desc_disabled.png')) no-repeat center right; }
94
+ thead .sorting_asc_disabled { background: url(image-path('images/lanes/dataTables/sort_asc_disabled.png')) no-repeat center right; }
95
+ thead .sorting_desc_disabled { background: url(image-path('images/lanes/dataTables/sort_desc_disabled.png')) no-repeat center right; }
96
96
 
97
97
  thead > tr > th {
98
98
  padding-left: 18px;
@@ -3,6 +3,7 @@
3
3
  //= require ./lib
4
4
  //= require ./extension
5
5
  //= require ./models
6
+ //= require ./Config
6
7
  //= require ./plugins
7
8
  //= require ./views
8
9
  //= require ./components/Base
@@ -1,10 +1,10 @@
1
1
  @font-face {
2
2
  font-family: 'lanes-icon';
3
- src:url(font-path('lanes/styles/fonts/icomoon.eot') + '?-7u8s0f');
4
- src:url(font-path('lanes/styles/fonts/icomoon.eot') + '?#iefix-7u8s0f') format('embedded-opentype'),
5
- url(font-path('lanes/styles/fonts/icomoon.woff') + '?-7u8s0f') format('woff'),
6
- url(font-path('lanes/styles/fonts/icomoon.ttf') + '?-7u8s0f') format('truetype'),
7
- url(font-path('lanes/styles/fonts/icomoon.svg') + '?-7u8s0f#icomoon') format('svg');
3
+ src:url(font-path('fonts/lanes/icomoon.eot'));
4
+ src:url(font-path('fonts/lanes/icomoon.eot')) format('embedded-opentype'),
5
+ url(font-path('fonts/lanes/icomoon.woff')) format('woff'),
6
+ url(font-path('fonts/lanes/icomoon.ttf')) format('truetype'),
7
+ url(font-path('fonts/lanes/icomoon.svg')) format('svg');
8
8
  font-weight: normal;
9
9
  font-style: normal;
10
10
  }
@@ -6,9 +6,9 @@ class BaseModel
6
6
  changes: { type: 'collection', setOnce: true }
7
7
  lastServerMessage: { type: 'string' }
8
8
  parent: 'state'
9
+ isDirty: { type: 'boolean', default: false }
9
10
 
10
11
  derived:
11
-
12
12
  errorMessage:
13
13
  deps:['errors'], fn: ->
14
14
  if !@errors then ''
@@ -50,7 +50,7 @@ class BaseModel
50
50
  @changeMonitor = new Lanes.Models.ChangeMonitor(this)
51
51
  # The model was created with attributes and it did not originate from a XHR request
52
52
  if attrs and !options.xhr
53
- @changeMonitor.recordChanged(_.keys(attrs))
53
+ @changeMonitor.recordChanges(this, _.keys(attrs))
54
54
 
55
55
  # In some cases a model's security should depend on the parent record, not on itself.
56
56
  # For instance, a Customer's Address should have the same permissions as the Customer
@@ -73,7 +73,7 @@ class BaseModel
73
73
  _.pluralize(_.dasherize(path))
74
74
 
75
75
  urlRoot: ->
76
- Lanes.Models.Config.api_path + '/' + _.result(this,'api_path')
76
+ Lanes.config.api_path + '/' + _.result(this,'api_path')
77
77
 
78
78
  # Default URL for the model's representation on the server
79
79
  url: ->
@@ -134,8 +134,9 @@ class BaseModel
134
134
 
135
135
  # Sets the attribute data from a server respose
136
136
  setFromServer: (data,options)->
137
- this.set( if _.isArray(data) then data[0] else data )
138
- this.changeMonitor.reset()
137
+ BaseModel.__super__.set.call(this, if _.isArray(data) then data[0] else data )
138
+ this.associations.setFromServer(this,data) if this.associations
139
+ this.isDirty = false
139
140
 
140
141
  # save the model's data to the server
141
142
  # Only unsaved attributes will be sent unless
@@ -144,6 +145,7 @@ class BaseModel
144
145
  options = _.clone(options)
145
146
 
146
147
  options.saving=true
148
+
147
149
  handlers = Lanes.Models.Sync.wrapRequest(this,options)
148
150
 
149
151
  method = if this.isNew()
@@ -187,9 +189,12 @@ class BaseModel
187
189
 
188
190
  # returns any attributes that have been set and not saved
189
191
  unsavedAttributes: ->
190
- attrs = if this.isNew() then {} else { id: this.getId() }
192
+ attrs = {} #if this.isNew() then {} else { id: this.getId() }
191
193
  _.extend(attrs, _.pick( this.getAttributes(props:true, true),
192
194
  @changeMonitor.changedAttributes() ) )
195
+ unless _.isEmpty(attrs) or this.isNew()
196
+ attrs.id = this.getId()
197
+ attrs
193
198
 
194
199
  # returns data to save to server. If options.saveAll is true,
195
200
  # all data is returned. Otherwise only unsaved attributes (and associations)
@@ -204,11 +209,6 @@ class BaseModel
204
209
  data
205
210
 
206
211
 
207
- # returns true if any server-side attributes are unsaved
208
- # Does not care about session-only properties
209
- isDirty: ->
210
- @changeMonitor.isDirty()
211
-
212
212
  # True if the model has "name" as eitehr a prop or session attribute
213
213
  hasAttribute: (name)->
214
214
  !! (this._definition[name] || this._derived[name])
@@ -1,7 +1,5 @@
1
1
  Lanes.Models.Bootstrap = {
2
2
 
3
3
  initialize: (options)->
4
- Lanes.Models.Config.csrf_token = options.csrf
5
- Lanes.Models.Config.api_path = options.api_path
6
4
  Lanes.Extensions.setBootstrapData(options);
7
5
  }
@@ -2,28 +2,31 @@
2
2
  # The ModelChangeMonitor watches for changes on the #
3
3
  # Model and remembers which attributes have been changed #
4
4
  # ------------------------------------------------------------------ #
5
+
5
6
  class Lanes.Models.ChangeMonitor
6
- constructor: (@model)->
7
- @model.on('change', this.onChange, this)
7
+ constructor: (model)->
8
+ model.on('change', this.onChange, this)
9
+ model.on('change:isDirty', this.onDirtyChange, this)
8
10
 
9
11
  onChange: (record,options)->
10
- attrs = @model.changedAttributes()
11
- this.recordChanged( _.keys(attrs) )
12
-
13
- recordChanged: (names)->
12
+ attrs = record.changedAttributes()
13
+ return if _.isEmpty(attrs)
14
14
  @_unsaved ||= {}
15
+ this.recordChanges(record,_.keys(attrs))
16
+
17
+
18
+ recordChanges: (record,names) ->
15
19
  for name in names
16
- this.recordChangedAttribute(name)
20
+ if name != record.idAttribute && record._definition[name] && !record._definition[name].session
21
+ record.isDirty = true
22
+ @_unsaved[ name ] = true
23
+
24
+ onDirtyChange: (record,isDirty)->
25
+ delete @_unsaved if !isDirty
17
26
 
18
27
  changedAttributes: ->
19
28
  _.keys(@_unsaved)
20
29
 
21
- recordChangedAttribute:(name)->
22
- if @model._definition[name] && !@model._definition[name].session
23
- @_unsaved[ name ] = true
24
-
25
- reset: ->
26
- delete @_unsaved
27
30
 
28
31
  isDirty: ->
29
32
  !_.isEmpty(@_unsaved)
@@ -83,9 +83,7 @@ class ModelsCollection
83
83
 
84
84
  # true if any models have unsaved data
85
85
  isDirty: ->
86
- for model in @models
87
- return true if model.isDirty()
88
- false
86
+ !!this.findWhere(isDirty: true)
89
87
 
90
88
  url: -> @model::urlRoot()
91
89
 
@@ -102,7 +100,7 @@ class ModelsCollection
102
100
  dataForSave: (options)->
103
101
  unsaved = []
104
102
  for model in @models
105
- if options.saveAll || model.isDirty()
103
+ if options.saveAll || model.isDirty
106
104
  unsaved.push( model.dataForSave(options) )
107
105
  unsaved
108
106
 
@@ -47,44 +47,29 @@ class Lanes.Models.AssocationMap
47
47
  new Lanes.Models.AssociationCollection(options.models||[],options)
48
48
  # returns the definition for the derived property
49
49
  derivedDefinition: (name,definition)->
50
- # me = this
51
- # target_klass = this.getClassFor(name)
52
- # fk = this.fk(name) ; pk = this.pk(name)
53
-
54
- # if definition.defaultValue
55
- # _.defaults(args, _.evaluateFunction(definition.defaultValue))
56
50
  createFn = _.partial(
57
51
  if definition.model then this.createModel else this.createCollection,
58
52
  this, name, definition, this.fk(name), this.pk(name), this.getClassFor(name)
59
53
  )
60
54
  { deps: [this.pk(name)], fn: createFn }
61
55
 
62
- # createAssocation = if definition.model then ->
63
- # target_klass ||= me.getClassFor(name)
64
- # _.extend(args, parent: this)
65
- # model_id = this.get(pk)
66
- # if model_id && model_id == this._cache[name]?.id
67
- # this._cache[name]
68
- # else
69
- # target_klass.findOrCreate(args)
70
- # else ->
71
- # target_klass ||= me.getClassFor(name)
72
- # filter = {}
73
- # filter[ fk ] = this.get( pk)
74
- # _.extend(args, filter: filter, parent: this)
75
- # if target_klass::isCollection
76
- # new target_klass([],args)
77
- # else
78
- # args.model=target_klass
79
- # new Lanes.Models.AssociationCollection(args)
80
- # { deps: [pk], fn: createFn }
81
56
 
82
57
  # Sets the assocations for "model"
83
58
  set: (model, data)->
59
+ this._set(model, data, 'set')
60
+
61
+ setFromServer: (model, data)->
62
+ this._set(model, data, 'setFromServer')
63
+
64
+ _set: (model, data, fn_name)->
84
65
  for name, value of data
85
66
  if @definitions[name]
86
67
  attributes = if _.isFunction(value.serialize) then value.serialize() else value
87
- model[name].set( attributes )
68
+ association = model[name]
69
+ association[fn_name]( attributes )
70
+ # if we're replaceing the model's contents with another, copy the dirty status as well
71
+ if association.isModel && value.isModel
72
+ association.isDirty = value.isDirty
88
73
 
89
74
  pk: (name)->
90
75
  def = @definitions[name]
@@ -101,8 +86,8 @@ class Lanes.Models.AssocationMap
101
86
  ret = {}
102
87
  options.saveDepth = ( if options.saveDepth then options.saveDepth+1 else 1 )
103
88
  return ret if options.saveDepth > 5
104
- for name, assoc_options of @definitions
105
- unless assoc_options.readOnly
89
+ for name, options of @definitions
90
+ unless options.readOnly
106
91
  data = model[name].dataForSave(options)
107
92
  unless _.isEmpty( data )
108
93
  ret[name] = data
@@ -78,7 +78,7 @@ Lanes.Models.Sync = {
78
78
  params.url = _.result(model, "url") or Lanes.Models.Sync.urlError() unless options.url
79
79
  params.url += '.json'
80
80
  params.headers = {
81
- X_CSRF_TOKEN: Lanes.Models.Config.csrf_token
81
+ X_CSRF_TOKEN: Lanes.config.csrf_token
82
82
  }
83
83
  params.contentType = "application/json"
84
84
  if options.data || _.contains(['create','update','patch'], method)
@@ -6,6 +6,7 @@ class Lanes.Screens.Instance
6
6
 
7
7
  constructor: (selector, options)->
8
8
  this.viewport = new Lanes.Views.Viewport({ selector: selector, instance: this })
9
+ Lanes.config.set(options)
9
10
  Lanes.Models.Bootstrap.initialize(options)
10
11
  Lanes.$(document).ready => @boot(options)
11
12
 
@@ -20,7 +20,7 @@
20
20
  @extend .font-icon-display;
21
21
  }
22
22
 
23
- @import "./fonts/style";
23
+ @import "./font-definitions";
24
24
 
25
25
  .icon-reset:before {
26
26
  @extend .icon-refresh:before;
@@ -29,7 +29,7 @@
29
29
  font-size: 3.2rem;
30
30
  float: left;
31
31
  &.loading-spinner {
32
- background:url(image-path('images/ajax-loader.gif')) no-repeat;
32
+ background:url(image-path('images/lanes/ajax-loader.gif')) no-repeat;
33
33
  height: 32px;
34
34
  margin-top: 10px;
35
35
  width: 32px;