spontaneous 0.2.0.beta5 → 0.2.0.beta6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (227) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +39 -0
  4. data/Gemfile +2 -0
  5. data/Readme.markdown +4 -4
  6. data/application/css/core.css.scss +144 -43
  7. data/application/css/definitions.css.scss +50 -16
  8. data/application/css/dialogue.css.scss +5 -2
  9. data/application/css/editing.css.scss +7 -7
  10. data/application/css/font.css.scss +1 -1
  11. data/application/css/meta.css.scss +6 -6
  12. data/application/css/popover.css.scss +6 -6
  13. data/application/css/top.css.scss +8 -1
  14. data/application/js/add_alias_dialogue.js +137 -36
  15. data/application/js/add_home_dialogue.js +10 -10
  16. data/application/js/ajax.js +26 -26
  17. data/application/js/authentication.js +2 -2
  18. data/application/js/box.js +21 -10
  19. data/application/js/box_container.js +13 -7
  20. data/application/js/compatibility.js +19 -17
  21. data/application/js/conflicted_field_dialogue.js +5 -5
  22. data/application/js/content.js +22 -16
  23. data/application/js/content_area.js +62 -33
  24. data/application/js/dialogue.js +16 -16
  25. data/application/js/dom.js +9 -10
  26. data/application/js/edit_panel.js +25 -20
  27. data/application/js/editing.js +21 -8
  28. data/application/js/entry.js +1 -1
  29. data/application/js/extensions.js +11 -11
  30. data/application/js/field/boolean.js +6 -6
  31. data/application/js/field/date.js +1 -1
  32. data/application/js/field/file.js +17 -17
  33. data/application/js/field/image.js +27 -27
  34. data/application/js/field/markdown.js +72 -71
  35. data/application/js/field/select.js +9 -9
  36. data/application/js/field/string.js +3 -3
  37. data/application/js/field/webvideo.js +2 -2
  38. data/application/js/field_preview.js +3 -0
  39. data/application/js/init.js +3 -2
  40. data/application/js/jquery-selection-position.js +13 -13
  41. data/application/js/location.js +17 -12
  42. data/application/js/login.js +2 -2
  43. data/application/js/meta_view/user_admin.js +101 -101
  44. data/application/js/metadata.js +1 -1
  45. data/application/js/page.js +2 -2
  46. data/application/js/page_browser.js +13 -13
  47. data/application/js/page_entry.js +1 -1
  48. data/application/js/panel/root_menu.js +10 -10
  49. data/application/js/popover.js +6 -5
  50. data/application/js/popover_view.js +5 -5
  51. data/application/js/preview.js +10 -4
  52. data/application/js/progress.js +6 -6
  53. data/application/js/properties.js +35 -6
  54. data/application/js/publish.js +43 -43
  55. data/application/js/require.js +14 -14
  56. data/application/js/services.js +3 -3
  57. data/application/js/sharded_upload.js +9 -8
  58. data/application/js/side_bar.js +5 -5
  59. data/application/js/state.js +2 -2
  60. data/application/js/status_bar.js +6 -6
  61. data/application/js/top_bar.js +97 -65
  62. data/application/js/types.js +9 -6
  63. data/application/js/upload.js +4 -4
  64. data/application/js/upload_manager.js +21 -21
  65. data/application/js/user.js +1 -1
  66. data/application/js/vendor/jquery.velocity.min.js +7 -0
  67. data/application/js/views.js +32 -8
  68. data/application/js/views/box_view.js +51 -31
  69. data/application/js/views/page_piece_view.js +17 -15
  70. data/application/js/views/page_view.js +54 -43
  71. data/application/js/views/piece_view.js +44 -37
  72. data/application/static/font/fontawesome-webfont-4f0022f25672c7f501c339cbf98d9117.ttf +0 -0
  73. data/application/views/index.erb +1 -0
  74. data/db/migrations/20130114120000_create_revision_tables.rb +2 -1
  75. data/db/migrations/20130813111009_increase_path_length.rb +11 -2
  76. data/db/migrations/20140506171823_add_index_to_target_id.rb +11 -0
  77. data/db/migrations/20140514090204_add_content_hash.rb +59 -0
  78. data/db/migrations/20140519150253_add_content_hash_timestamp.rb +20 -0
  79. data/lib/spontaneous.rb +0 -1
  80. data/lib/spontaneous/asset/environment.rb +77 -15
  81. data/lib/spontaneous/box.rb +21 -0
  82. data/lib/spontaneous/capistrano/deploy.rb +1 -1
  83. data/lib/spontaneous/capistrano/sync.rb +8 -7
  84. data/lib/spontaneous/change.rb +4 -2
  85. data/lib/spontaneous/cli/fields.rb +7 -3
  86. data/lib/spontaneous/cli/generate.rb +2 -0
  87. data/lib/spontaneous/cli/init.rb +24 -93
  88. data/lib/spontaneous/cli/init/db.rb +94 -0
  89. data/lib/spontaneous/cli/init/mysql.rb +17 -0
  90. data/lib/spontaneous/cli/init/postgresql.rb +33 -0
  91. data/lib/spontaneous/cli/init/sqlite.rb +14 -0
  92. data/lib/spontaneous/cli/site.rb +45 -20
  93. data/lib/spontaneous/collections/box_set.rb +3 -0
  94. data/lib/spontaneous/collections/entry_set.rb +43 -4
  95. data/lib/spontaneous/collections/field_set.rb +14 -2
  96. data/lib/spontaneous/data_mapper.rb +40 -7
  97. data/lib/spontaneous/data_mapper/content_model.rb +1 -1
  98. data/lib/spontaneous/data_mapper/content_model/associations.rb +63 -12
  99. data/lib/spontaneous/data_mapper/content_model/timestamps.rb +9 -14
  100. data/lib/spontaneous/data_mapper/content_table.rb +4 -2
  101. data/lib/spontaneous/data_mapper/dataset.rb +31 -2
  102. data/lib/spontaneous/data_mapper/scope.rb +37 -20
  103. data/lib/spontaneous/errors.rb +6 -0
  104. data/lib/spontaneous/facet.rb +20 -10
  105. data/lib/spontaneous/field/base.rb +8 -1
  106. data/lib/spontaneous/field/file.rb +28 -3
  107. data/lib/spontaneous/field/image.rb +2 -0
  108. data/lib/spontaneous/field/update.rb +6 -0
  109. data/lib/spontaneous/field/webvideo/vimeo.rb +6 -1
  110. data/lib/spontaneous/field/webvideo/vine.rb +1 -1
  111. data/lib/spontaneous/field/webvideo/youtube.rb +1 -1
  112. data/lib/spontaneous/generators/site.rb +6 -4
  113. data/lib/spontaneous/generators/site/.gitignore +1 -0
  114. data/lib/spontaneous/generators/site/Gemfile.tt +3 -3
  115. data/lib/spontaneous/generators/site/config/{indexes.rb.tt → initializers/indexes.rb.tt} +0 -0
  116. data/lib/spontaneous/generators/site/config/initializers/publishing.rb.tt +78 -0
  117. data/lib/spontaneous/generators/site/{config/database.yml.tt → db/mysql2.yml.tt} +7 -6
  118. data/lib/spontaneous/generators/site/db/postgres.yml.tt +25 -0
  119. data/lib/spontaneous/generators/site/db/sqlite3.yml.tt +18 -0
  120. data/lib/spontaneous/generators/site/public/humans.txt.tt +14 -0
  121. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +51 -0
  122. data/lib/spontaneous/loader.rb +1 -1
  123. data/lib/spontaneous/logger.rb +1 -1
  124. data/lib/spontaneous/media/image/optimizer.rb +1 -1
  125. data/lib/spontaneous/media/image/processor.rb +11 -2
  126. data/lib/spontaneous/media/image/renderable.rb +2 -0
  127. data/lib/spontaneous/model.rb +3 -0
  128. data/lib/spontaneous/model/box/allowed_types.rb +17 -4
  129. data/lib/spontaneous/model/core.rb +36 -3
  130. data/lib/spontaneous/model/core/aliases.rb +5 -2
  131. data/lib/spontaneous/model/core/boxes.rb +6 -0
  132. data/lib/spontaneous/model/core/cascading_change.rb +38 -0
  133. data/lib/spontaneous/model/core/content_hash.rb +171 -0
  134. data/lib/spontaneous/model/core/entries.rb +0 -19
  135. data/lib/spontaneous/model/core/fields.rb +11 -0
  136. data/lib/spontaneous/model/core/modifications.rb +22 -21
  137. data/lib/spontaneous/model/core/render.rb +3 -0
  138. data/lib/spontaneous/model/core/serialisation.rb +18 -17
  139. data/lib/spontaneous/model/page.rb +35 -8
  140. data/lib/spontaneous/model/page/page_tree.rb +20 -8
  141. data/lib/spontaneous/model/page/paths.rb +79 -50
  142. data/lib/spontaneous/model/page/singleton.rb +71 -0
  143. data/lib/spontaneous/model/page/site_map.rb +2 -1
  144. data/lib/spontaneous/model/page/site_timestamps.rb +2 -2
  145. data/lib/spontaneous/model/piece.rb +10 -0
  146. data/lib/spontaneous/output/context.rb +13 -6
  147. data/lib/spontaneous/output/format.rb +30 -5
  148. data/lib/spontaneous/output/helpers/script_helper.rb +8 -0
  149. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +7 -0
  150. data/lib/spontaneous/output/renderable.rb +16 -0
  151. data/lib/spontaneous/output/store.rb +1 -1
  152. data/lib/spontaneous/output/template/renderer.rb +2 -2
  153. data/lib/spontaneous/page_piece.rb +25 -1
  154. data/lib/spontaneous/prototypes/box_prototype.rb +13 -0
  155. data/lib/spontaneous/prototypes/field_prototype.rb +7 -4
  156. data/lib/spontaneous/publishing.rb +10 -5
  157. data/lib/spontaneous/publishing/immediate.rb +32 -349
  158. data/lib/spontaneous/publishing/pipeline.rb +43 -0
  159. data/lib/spontaneous/publishing/progress.rb +186 -0
  160. data/lib/spontaneous/publishing/publish.rb +107 -0
  161. data/lib/spontaneous/publishing/rerender.rb +17 -0
  162. data/lib/spontaneous/publishing/revision.rb +53 -18
  163. data/lib/spontaneous/publishing/simultaneous.rb +1 -1
  164. data/lib/spontaneous/publishing/steps.rb +154 -0
  165. data/lib/spontaneous/publishing/steps/activate_revision.rb +45 -0
  166. data/lib/spontaneous/publishing/steps/archive_old_revisions.rb +22 -0
  167. data/lib/spontaneous/publishing/steps/base_step.rb +49 -0
  168. data/lib/spontaneous/publishing/steps/copy_static_files.rb +74 -0
  169. data/lib/spontaneous/publishing/steps/create_revision_directory.rb +24 -0
  170. data/lib/spontaneous/publishing/steps/generate_rackup_file.rb +51 -0
  171. data/lib/spontaneous/publishing/steps/generate_search_indexes.rb +24 -0
  172. data/lib/spontaneous/publishing/steps/render_revision.rb +69 -0
  173. data/lib/spontaneous/publishing/steps/write_revision_file.rb +43 -0
  174. data/lib/spontaneous/rack/back.rb +3 -1
  175. data/lib/spontaneous/rack/back/alias.rb +9 -8
  176. data/lib/spontaneous/rack/front.rb +1 -1
  177. data/lib/spontaneous/rack/middleware.rb +7 -4
  178. data/lib/spontaneous/rack/middleware/transaction.rb +14 -0
  179. data/lib/spontaneous/rack/page_controller.rb +23 -8
  180. data/lib/spontaneous/revision.rb +5 -10
  181. data/lib/spontaneous/schema.rb +5 -0
  182. data/lib/spontaneous/server.rb +3 -1
  183. data/lib/spontaneous/site.rb +17 -10
  184. data/lib/spontaneous/site/publishing.rb +25 -3
  185. data/lib/spontaneous/site/state.rb +7 -3
  186. data/lib/spontaneous/tasks/database.rake +5 -10
  187. data/lib/spontaneous/utils/database/mysql_dumper.rb +5 -1
  188. data/lib/spontaneous/version.rb +1 -1
  189. data/spontaneous.gemspec +4 -3
  190. data/test/fixtures/example_application/config/initializers/initializer1.rb +1 -0
  191. data/test/fixtures/example_application/config/initializers/initializer2.rb +1 -0
  192. data/test/fixtures/example_application/config/initializers/publishing.rb +13 -0
  193. data/test/fixtures/search/config/{indexes.rb → initializers/indexes.rb} +0 -0
  194. data/test/fixtures/serialisation/root_hash.yaml.erb +10 -4
  195. data/test/functional/test_application.rb +10 -0
  196. data/test/functional/test_back.rb +23 -5
  197. data/test/functional/test_cli.rb +98 -34
  198. data/test/functional/test_front.rb +7 -3
  199. data/test/test_helper.rb +35 -28
  200. data/test/unit/test_alias.rb +20 -3
  201. data/test/unit/test_assets.rb +58 -30
  202. data/test/unit/test_changesets.rb +20 -12
  203. data/test/unit/test_content_hash.rb +496 -0
  204. data/test/unit/test_context.rb +28 -1
  205. data/test/unit/test_controllers.rb +96 -61
  206. data/test/unit/test_crypt.rb +1 -8
  207. data/test/unit/test_datamapper.rb +95 -19
  208. data/test/unit/test_features.rb +1 -4
  209. data/test/unit/test_fields.rb +61 -12
  210. data/test/unit/test_generators.rb +39 -2
  211. data/test/unit/test_images.rb +3 -1
  212. data/test/unit/test_modifications.rb +224 -219
  213. data/test/unit/test_output_store.rb +10 -0
  214. data/test/unit/{test_formats.rb → test_outputs.rb} +75 -6
  215. data/test/unit/test_page.rb +61 -15
  216. data/test/unit/test_plugins.rb +2 -42
  217. data/test/unit/test_publishing_pipeline.rb +1050 -0
  218. data/test/unit/test_render.rb +30 -0
  219. data/test/unit/test_revisions.rb +110 -2
  220. data/test/unit/test_schema.rb +4 -0
  221. data/test/unit/test_search.rb +1 -1
  222. data/test/unit/test_serialisation.rb +6 -1
  223. data/test/unit/test_singletons.rb +159 -0
  224. data/test/unit/test_site.rb +71 -44
  225. metadata +140 -86
  226. data/application/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf +0 -0
  227. data/test/unit/test_publishing.rb +0 -330
@@ -102,6 +102,7 @@ $target-name-size: 14px;
102
102
  content: ".";
103
103
  display: block;
104
104
  height: 0;
105
+ width: 0;
105
106
  clear: both;
106
107
  visibility: hidden; }
107
108
 
@@ -111,9 +112,9 @@ $target-name-size: 14px;
111
112
  }
112
113
 
113
114
  @mixin display-box {
114
- display: -webkit-box;
115
- display: -moz-box;
116
- display: box;
115
+ // display: -webkit-box;
116
+ // display: -moz-box;
117
+ display: flex;
117
118
  }
118
119
  @mixin box-sizing($model: border-box) {
119
120
  -webkit-box-sizing: $model;
@@ -121,25 +122,17 @@ $target-name-size: 14px;
121
122
  box-sizing: $model;
122
123
  }
123
124
 
124
- @mixin box-orient($direction: horizontal) {
125
- box-orient: $direction;
126
- -webkit-box-orient: $direction;
127
- -moz-box-orient: $direction;
125
+ @mixin box-orient($direction: row) {
126
+ flex-direction: $direction;
128
127
  }
129
128
  @mixin box-pack($packing: center) {
130
- box-pack: $packing;
131
- -webkit-box-pack: $packing;
132
- -moz-box-pack: $packing;
129
+ justify-content: $packing;
133
130
  }
134
131
  @mixin box-align($aligning: start) {
135
- box-align: $aligning;
136
- -webkit-box-align: $aligning;
137
- -moz-box-align: $aligning;
132
+ align-items: $aligning;
138
133
  }
139
134
  @mixin box-flex($flex: 1) {
140
- -webkit-box-flex: $flex;
141
- -moz-box-flex: $flex;
142
- box-flex: $flex;
135
+ flex-grow: $flex;
143
136
  }
144
137
 
145
138
  @mixin no-select {
@@ -347,3 +340,44 @@ $editing-focus: rgba(0, 0, 0, 0.6);
347
340
  font-size: 11px;
348
341
  line-height: 14px;
349
342
  }
343
+
344
+ @mixin animation($name: fadeIn, $duration: 1s, $delay: .2s, $function: ease, $mode: both) {
345
+ -webkit-animation: $name $duration $delay $function $mode;
346
+ -moz-animation: $name $duration $delay $function $mode;
347
+ -o-animation: $name $duration $delay $function $mode;
348
+ animation: $name $duration $delay $function $mode;
349
+ }
350
+ @-moz-keyframes spin {
351
+ 0% {
352
+ -moz-transform: rotate(0deg);
353
+ }
354
+ 100% {
355
+ -moz-transform: rotate(359deg);
356
+ }
357
+ }
358
+ @-webkit-keyframes spin {
359
+ 0% {
360
+ -webkit-transform: rotate(0deg);
361
+ }
362
+ 100% {
363
+ -webkit-transform: rotate(359deg);
364
+ }
365
+ }
366
+ @-o-keyframes spin {
367
+ 0% {
368
+ -o-transform: rotate(0deg);
369
+ }
370
+ 100% {
371
+ -o-transform: rotate(359deg);
372
+ }
373
+ }
374
+ @keyframes spin {
375
+ 0% {
376
+ -webkit-transform: rotate(0deg);
377
+ transform: rotate(0deg);
378
+ }
379
+ 100% {
380
+ -webkit-transform: rotate(359deg);
381
+ transform: rotate(359deg);
382
+ }
383
+ }
@@ -27,6 +27,9 @@ $dialogue-title-height: 32px;
27
27
  @extend .controls-gradient;
28
28
  @include header;
29
29
  @include rounded-top;
30
+ position: absolute;
31
+ right: 0;
32
+ left: 0;
30
33
  height: $dialogue-title-height;
31
34
  color: #fff;
32
35
  padding: 0 $unit 0 ($unit+$dialogue-frame-width);
@@ -144,7 +147,7 @@ $dialogue-title-height: 32px;
144
147
  #publishing-dialogue {
145
148
  @include fullsize;
146
149
  @include display-box;
147
- @include box-orient(horizontal);
150
+ @include box-orient(row);
148
151
 
149
152
  .spinner {
150
153
  position: absolute;
@@ -184,7 +187,7 @@ $dialogue-title-height: 32px;
184
187
  .actions {
185
188
  @include interface;
186
189
  @include display-box;
187
- @include box-orient(horizontal);
190
+ @include box-orient(row);
188
191
  @include box-align(center);
189
192
  @include box-sizing;
190
193
  position: absolute;
@@ -41,8 +41,8 @@ $text-edit-width: 621px;
41
41
  }
42
42
  .buttons {
43
43
  @include display-box;
44
- @include box-orient(horizontal);
45
- @include box-pack(justify);
44
+ @include box-orient(row);
45
+ @include box-pack(space-between);
46
46
  width: $text-edit-width;
47
47
  .save, .cancel {
48
48
  @include button($action);
@@ -161,7 +161,7 @@ $text-edit-width: 621px;
161
161
 
162
162
  .editing-fields {
163
163
  padding: 0;
164
- @include box-orient(vertical);
164
+ @include box-orient(column);
165
165
  }
166
166
  .editing-toolbar {
167
167
  padding-left: $unit;
@@ -256,15 +256,15 @@ $text-edit-width: 621px;
256
256
  @include interface;
257
257
  text-transform: none;
258
258
  @include display-box;
259
- @include box-orient(vertical);
259
+ @include box-orient(column);
260
260
  .filename {
261
261
  word-wrap: break-word;
262
262
  }
263
263
  .sizes {
264
264
  padding-top: $unit/2;
265
265
  @include display-box;
266
- @include box-orient(horizontal);
267
- @include box-pack(justify);
266
+ @include box-orient(row);
267
+ @include box-pack(space-between);
268
268
  }
269
269
  }
270
270
  .landscape {
@@ -406,7 +406,7 @@ $text-edit-width: 621px;
406
406
  .image-field-conflict.changes {
407
407
  .diff {
408
408
  @include display-box;
409
- @include box-orient(horizontal);
409
+ @include box-orient(row);
410
410
  @include box-pack(center);
411
411
  @include box-align(center);
412
412
  img {
@@ -1,6 +1,6 @@
1
1
  @font-face {
2
2
  font-family: 'FontAwesome';
3
- src: url('/@spontaneous/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf') format('truetype');
3
+ src: url('/@spontaneous/static/font/fontawesome-webfont-4f0022f25672c7f501c339cbf98d9117.ttf') format('truetype');
4
4
  font-weight: normal;
5
5
  font-style: normal;
6
6
  }
@@ -18,7 +18,7 @@
18
18
  $user-admin-dialogue-width: 680px;
19
19
  @include calc(max-height, "100% - #{ 2 * $container-margin }");
20
20
  @include display-box;
21
- @include box-orient(vertical);
21
+ @include box-orient(column);
22
22
 
23
23
  @include rounded;
24
24
  min-height: 450px;
@@ -134,7 +134,7 @@
134
134
  }
135
135
  .admin {
136
136
  @include display-box;
137
- @include box-orient(horizontal);
137
+ @include box-orient(row);
138
138
  @include box-align(stretch);
139
139
  margin-bottom: $container-padding / 2;
140
140
  p {
@@ -178,7 +178,7 @@
178
178
  }
179
179
  .save {
180
180
  @include display-box;
181
- @include box-orient(horizontal);
181
+ @include box-orient(row);
182
182
  @include box-align(stretch);
183
183
  margin-top: ($container-padding / 2);
184
184
  .button {
@@ -212,7 +212,7 @@
212
212
  .level {
213
213
  @include display-box;
214
214
  @include box-align(stretch);
215
- @include box-orient(horizontal);
215
+ @include box-orient(row);
216
216
  padding: $unit/2 $unit;
217
217
  // position: relative;
218
218
  span {
@@ -259,8 +259,8 @@
259
259
  @include box-sizing;
260
260
  @include display-box;
261
261
  @include box-align(stretch);
262
- @include box-orient(horizontal);
263
- @include box-pack(top);
262
+ @include box-orient(row);
263
+ @include box-pack(flex-start);
264
264
  @include rounded;
265
265
 
266
266
  cursor: pointer;
@@ -105,7 +105,7 @@
105
105
  }
106
106
  header {
107
107
  @include display-box;
108
- @include box-orient(horizontal);
108
+ @include box-orient(row);
109
109
  @include box-align(stretch);
110
110
  }
111
111
  .menuHandle {
@@ -167,8 +167,8 @@
167
167
  }
168
168
  .buttons {
169
169
  @include display-box;
170
- @include box-orient(horizontal);
171
- @include box-pack(justify);
170
+ @include box-orient(row);
171
+ @include box-pack(space-between);
172
172
  a {
173
173
  display: block;
174
174
  }
@@ -286,7 +286,7 @@
286
286
 
287
287
  ul {
288
288
  @include display-box;
289
- @include box-orient(horizontal);
289
+ @include box-orient(row);
290
290
  margin: 0;
291
291
  padding: 0;
292
292
  // outline: solid 1px red;
@@ -318,8 +318,8 @@
318
318
  }
319
319
  #popover-delete {
320
320
  @include display-box;
321
- @include box-orient(horizontal);
322
- @include box-pack(justify);
321
+ @include box-orient(row);
322
+ @include box-pack(space-between);
323
323
 
324
324
  a.ok {
325
325
  @include button;
@@ -147,10 +147,14 @@ $navigation-color: #555;
147
147
  #switch-mode, #open-publish {
148
148
  @include button;
149
149
  @include display-box;
150
- @include box-orient(vertical);
150
+ @include box-orient(column);
151
151
  @include box-align(center);
152
152
  margin: 0;
153
153
  width: 70px;
154
+ &.disabled {
155
+ opacity: 0.5;
156
+ @include button-color(#666);
157
+ }
154
158
  }
155
159
  #open-publish {
156
160
  position: relative;
@@ -220,6 +224,9 @@ $navigation-color: #555;
220
224
  .page:hover {
221
225
  color: $action;
222
226
  }
227
+ .page.current {
228
+ color: $highlight;
229
+ }
223
230
  .box {
224
231
  margin-top: 8px;
225
232
  }
@@ -1,36 +1,110 @@
1
1
 
2
- Spontaneous.AddAliasDialogue = (function($, S) {
2
+ Spontaneous.AddAliasDialogue = (function($, S, window) {
3
+ 'use strict';
3
4
  var dom = S.Dom, Dialogue = Spontaneous.Dialogue;
4
5
 
6
+ var Target = function(data, element) {
7
+ this.id = data.id;
8
+ this.data = data;
9
+ this.element = element;
10
+ this.selected = false;
11
+ };
12
+ Target.prototype = {
13
+ redraw: function() {
14
+ var el = this.element;
15
+ if (this.selected) {
16
+ if (!el.hasClass('selected')) {
17
+ el.addClass('selected');
18
+ }
19
+ } else {
20
+ if (el.hasClass('selected')) {
21
+ el.removeClass('selected');
22
+ }
23
+ }
24
+ }
25
+ };
26
+
5
27
  var AddAliasDialogue = new JS.Class(Dialogue, {
6
28
  initialize: function(box_view, type, position) {
7
29
  this.box_view = box_view;
8
- this.box_view.bind('entry_added', this.alias_added.bind(this))
30
+ this.box_view.bind('entry_added', this.alias_added.bind(this));
9
31
  this.type = type;
10
32
  this.insert_position = position;
33
+ this.shiftSelectStartPosition = false;
11
34
  },
12
35
  title: function() {
13
- return 'Add alias to “' + this.box_view.name() + '”';
36
+ return 'Add “'+(this.type.title)+'” alias to “' + this.box_view.name() + '”';
14
37
  },
15
38
  buttons: function() {
16
39
  var btns = {};
17
- btns["Add"] = this.add_alias.bind(this);
40
+ btns.Add = this.add_alias.bind(this);
18
41
  return btns;
19
42
  },
20
43
 
44
+ cleanup: function() {
45
+ this._outer.add(this._contents, window).unbind('mouseup.addAliasDialogue');
46
+ },
47
+
21
48
  uid: function() {
22
49
  return this.content.uid() + '!add-alias';
23
50
  },
24
51
  add_alias: function() {
25
- if (this.target) {
26
- this.box_view.add_alias(this.target.id, this.type, this.insert_position);
52
+ var self = this, selected = self.selected();
53
+ if (selected.length > 0) {
54
+ self.box_view.add_alias(selected.map(function(target) { return target.id; }), self.type, self.insert_position);
27
55
  }
28
56
  },
29
57
  alias_added: function() {
30
58
  this.close();
31
59
  },
32
- select_target: function(target) {
33
- this.target = target;
60
+ selected: function() {
61
+ return this.targets.filter(function(t) { return t.selected; });
62
+ },
63
+ // toggle a target in the list
64
+ // returns true if the targe is in the list
65
+ // false if not
66
+ toggle_target: function(target, position, shiftKey) {
67
+ var self = this, targets = self.shiftSelectTargets(target, position, shiftKey);
68
+ if (target.selected) {
69
+ self.remove_target(targets);
70
+ } else {
71
+ self.add_target(targets);
72
+ }
73
+ },
74
+
75
+ remove_target: function(targets) {
76
+ targets.forEach(function(target) {
77
+ target.selected = false;
78
+ });
79
+ return false;
80
+ },
81
+
82
+ add_target: function(targets) {
83
+ targets.forEach(function(target) {
84
+ target.selected = true;
85
+ });
86
+ return true;
87
+ },
88
+
89
+ shiftSelectTargets: function(target, position, shiftKey) {
90
+ var self = this, allTargets = self.targets, startPosition = self.shiftSelectStartPosition, targets = [target], i;
91
+ if (!shiftKey) {
92
+ self.shiftSelectStartPosition = position;
93
+ } else {
94
+ if (startPosition !== false) {
95
+ if (position > startPosition) { // down
96
+ for (i = startPosition + 1; i < position; i++) {
97
+ targets.push(allTargets[i]);
98
+ }
99
+ } else if (position < startPosition) { // up
100
+ for (i = startPosition - 1; i > position; i--) {
101
+ targets.push(allTargets[i]);
102
+ }
103
+ }
104
+ }
105
+ self.shiftSelectStartPosition = false;
106
+ }
107
+ return targets;
34
108
  },
35
109
  box_owner: function() {
36
110
  return this.box_view.box.container;
@@ -40,11 +114,11 @@ Spontaneous.AddAliasDialogue = (function($, S) {
40
114
  },
41
115
  body: function() {
42
116
  var self = this
43
- , editing = dom.div('#add-alias-dialogue')
117
+ , editing = dom.div('#add-alias-dialogue')
44
118
  , outer = dom.div('.typelist')
45
- , paging = dom.div(".paging")
46
- , search = dom.div(".search")
47
- , progress = dom.div(".progress")
119
+ , paging = dom.div('.paging')
120
+ , search = dom.div('.search')
121
+ , progress = dom.div('.progress')
48
122
  , instructions = dom.p('.instructions')
49
123
  , __dialogue = this
50
124
  , timeout = null
@@ -55,38 +129,38 @@ Spontaneous.AddAliasDialogue = (function($, S) {
55
129
  , load_targets = function(query) {
56
130
  clearTimeout();
57
131
  var params = {};
58
- if (query !== "") {
59
- params["query"] = query;
132
+ if (query !== '') {
133
+ params.query = query;
60
134
  }
61
135
 
62
136
  self.spinner.start();
63
137
  Spontaneous.Ajax.get(['/alias', self.type.schema_id, self.box().id()].join('/'), params, self.targets_loaded.bind(self));
64
138
  }
65
- , input = dom.input({"type":"search", "placeholder":"Search..."}).keydown(function(event) {
139
+ , input = dom.input({'type':'search', 'placeholder':'Search...'}).keydown(function(event) {
66
140
  if (event.keyCode === 13) {
67
141
  load_targets(input.val());
68
142
  }
69
143
  if (event.keyCode === 27) {
70
- if (input.val() === "") {
144
+ if (input.val() === '') {
71
145
  return true;
72
146
  }
73
- input.val("");
147
+ input.val('');
74
148
  load_targets();
75
149
  return false;
76
150
  }
77
151
  }).keyup(function() {
78
152
  clearTimeout();
79
153
  var val = input.val();
80
- if (val === "" || val.length > 1) {
154
+ if (val === '' || val.length > 1) {
81
155
  timeout = window.setTimeout(function() {
82
156
  load_targets(val);
83
157
  }, searchDelay);
84
158
  }
85
- })
86
- instructions.html("Choose a target:");
159
+ });
160
+ instructions.html('Choose a target:');
87
161
 
88
- search.append(input)
89
- paging.append(progress, search)
162
+ search.append(input);
163
+ paging.append(progress, search);
90
164
  this.spinner = S.Progress(progress[0], 16);
91
165
  editing.append(paging, outer);
92
166
  load_targets();
@@ -96,22 +170,49 @@ Spontaneous.AddAliasDialogue = (function($, S) {
96
170
  },
97
171
 
98
172
  targets_loaded: function(results) {
99
- var outer = this._outer, wrap, self = __dialogue = this, targets = results.targets;
100
- window.setTimeout(function() { self.spinner.stop() }, 300);
101
- this.targets = this.sort_targets(targets);
173
+ var outer = this._outer, wrap, self = this, targets = self.sort_targets(results.targets);
174
+ window.setTimeout(function() { self.spinner.stop(); }, 300);
175
+ self.targets = [];
102
176
  outer.empty();
103
177
  wrap = dom.div();
104
- $.each(targets, function(i, target) {
105
- var d = dom.div('.type').html(target.title).click(function() {
106
- $('.type', outer).removeClass('selected');
107
- __dialogue.select_target(target);
108
- $(this).addClass('selected');;
178
+ var _select = function(target, i) {
179
+ return function(shiftKey) {
180
+ self.toggle_target(target, i, shiftKey);
181
+ self.redraw();
182
+ };
183
+ };
184
+ $.each(targets, function(i, targetData) {
185
+ var d = dom.div('.type').html(targetData.title), target = new Target(targetData, d);
186
+ d.mouseup(function(e) {
187
+ if (!self.dragSelect) {
188
+ _select(target, i)(false);
189
+ }
109
190
  });
110
- wrap.append(d)
191
+ d.mousedown(function(e) {
192
+ self.dragSelect = true;
193
+ _select(target, i)(e.shiftKey);
194
+ });
195
+ d.mouseenter(function(e) {
196
+ if (self.dragSelect) {
197
+ _select(target, i)(false);
198
+ }
199
+ });
200
+ wrap.append(d);
201
+ self.targets.push(target);
202
+ });
203
+ wrap.add(outer, window).bind('mouseup.addAliasDialogue', function() {
204
+ if (self.dragSelect) {
205
+ self.dragSelect = false;
206
+ }
207
+ });
208
+ outer.append(wrap);
209
+ self._contents = wrap;
210
+ self.manager.updateLayout();
211
+ },
212
+ redraw: function() {
213
+ this.targets.forEach(function(t) {
214
+ t.redraw();
111
215
  });
112
- outer.append(wrap)
113
- this._contents = wrap;
114
- this.manager.updateLayout();
115
216
  },
116
217
  contentsHeight: function() {
117
218
  return this.paging.outerHeight() + this._contents.outerHeight();
@@ -122,10 +223,10 @@ Spontaneous.AddAliasDialogue = (function($, S) {
122
223
  if (at > bt) { return 1; }
123
224
  if (at < bt) { return -1; }
124
225
  return 0;
125
- }
226
+ };
126
227
  return targets.sort(comparator);
127
228
  }
128
229
  });
129
230
  return AddAliasDialogue;
130
- })(jQuery, Spontaneous);
231
+ })(jQuery, Spontaneous, window);
131
232