lanes 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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;