kms 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (196) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/kms/application.js +1 -0
  3. data/app/assets/javascripts/kms/application/controllers/assets_controller.coffee.erb +14 -4
  4. data/app/assets/javascripts/kms/application/controllers/pages_controller.coffee.erb +12 -2
  5. data/app/assets/javascripts/kms/application/controllers/snippets_controller.coffee.erb +13 -3
  6. data/app/assets/javascripts/kms/application/controllers/templates_controller.coffee.erb +13 -3
  7. data/app/assets/javascripts/kms/application/controllers/users_controller.coffee +5 -5
  8. data/app/assets/javascripts/kms/application/module.coffee +6 -2
  9. data/app/assets/javascripts/kms/application/routes.coffee.erb +10 -0
  10. data/app/assets/javascripts/templates/assets/edit.html.slim +2 -1
  11. data/app/assets/javascripts/templates/assets/form.html.slim +1 -1
  12. data/app/assets/javascripts/templates/pages/edit.html.slim +1 -0
  13. data/app/assets/javascripts/templates/shared/hotkey_notification.html.slim +6 -0
  14. data/app/assets/javascripts/templates/snippets/edit.html.slim +1 -0
  15. data/app/assets/javascripts/templates/templates/edit.html.slim +1 -0
  16. data/app/assets/javascripts/templates/users/edit.html.slim +5 -0
  17. data/app/assets/javascripts/templates/users/form.html.slim +3 -2
  18. data/app/assets/javascripts/templates/users/index.html.slim +2 -1
  19. data/app/assets/stylesheets/kms/custom.css.scss +10 -0
  20. data/app/controllers/kms/assets_controller.rb +6 -3
  21. data/app/controllers/kms/users_controller.rb +14 -0
  22. data/app/services/kms/resource_service.rb +3 -1
  23. data/app/views/layouts/kms/kms.html.erb +1 -1
  24. data/config/initializers/devise.rb +9 -0
  25. data/config/locales/en.yml +12 -0
  26. data/config/locales/ru.yml +12 -0
  27. data/config/routes.rb +1 -1
  28. data/lib/kms/engine.rb +1 -1
  29. data/lib/kms/version.rb +1 -1
  30. data/spec/controllers/kms/assets_controller_spec.rb +28 -10
  31. data/spec/controllers/kms/users_controller_spec.rb +23 -0
  32. data/spec/internal/config/routes.rb +1 -1
  33. data/spec/internal/log/test.log +0 -105823
  34. data/vendor/assets/bower.json +5 -4
  35. data/vendor/assets/bower_components/angular-cookies/angular-cookies.js +22 -18
  36. data/vendor/assets/bower_components/angular-cookies/angular-cookies.min.js +4 -4
  37. data/vendor/assets/bower_components/angular-cookies/angular-cookies.min.js.map +2 -2
  38. data/vendor/assets/bower_components/angular-cookies/bower.json +2 -2
  39. data/vendor/assets/bower_components/angular-cookies/package.json +1 -1
  40. data/vendor/assets/bower_components/angular-hotkeys/Gruntfile.js +118 -0
  41. data/vendor/assets/bower_components/angular-hotkeys/LICENSE +20 -0
  42. data/vendor/assets/bower_components/angular-hotkeys/README.md +248 -0
  43. data/vendor/assets/bower_components/angular-hotkeys/bower.json +19 -0
  44. data/vendor/assets/bower_components/angular-hotkeys/build/hotkeys.css +110 -0
  45. data/vendor/assets/bower_components/angular-hotkeys/build/hotkeys.js +1661 -0
  46. data/vendor/assets/bower_components/angular-hotkeys/build/hotkeys.min.css +1 -0
  47. data/vendor/assets/bower_components/angular-hotkeys/build/hotkeys.min.js +7 -0
  48. data/vendor/assets/bower_components/angular-hotkeys/package.json +45 -0
  49. data/vendor/assets/bower_components/angular-hotkeys/src/hotkeys.css +104 -0
  50. data/vendor/assets/bower_components/angular-hotkeys/src/hotkeys.js +633 -0
  51. data/vendor/assets/bower_components/angular-loading-bar/CHANGELOG.md +33 -0
  52. data/vendor/assets/bower_components/angular-loading-bar/CONTRIBUTING.md +17 -0
  53. data/vendor/assets/bower_components/angular-loading-bar/Gruntfile.js +9 -1
  54. data/vendor/assets/bower_components/angular-loading-bar/ISSUE_TEMPLATE.md +14 -0
  55. data/vendor/assets/bower_components/angular-loading-bar/PULL_REQUEST_TEMPLATE.md +13 -0
  56. data/vendor/assets/bower_components/angular-loading-bar/README.md +30 -3
  57. data/vendor/assets/bower_components/angular-loading-bar/bower.json +11 -6
  58. data/vendor/assets/bower_components/angular-loading-bar/build/loading-bar.css +5 -5
  59. data/vendor/assets/bower_components/angular-loading-bar/build/loading-bar.js +39 -12
  60. data/vendor/assets/bower_components/angular-loading-bar/build/loading-bar.min.css +1 -8
  61. data/vendor/assets/bower_components/angular-loading-bar/build/loading-bar.min.js +3 -3
  62. data/vendor/assets/bower_components/angular-loading-bar/index.js +2 -0
  63. data/vendor/assets/bower_components/angular-loading-bar/package.json +12 -15
  64. data/vendor/assets/bower_components/angular-loading-bar/src/loading-bar.css +3 -3
  65. data/vendor/assets/bower_components/angular-loading-bar/src/loading-bar.js +37 -10
  66. data/vendor/assets/bower_components/angular-sanitize/angular-sanitize.js +504 -386
  67. data/vendor/assets/bower_components/angular-sanitize/angular-sanitize.min.js +13 -12
  68. data/vendor/assets/bower_components/angular-sanitize/angular-sanitize.min.js.map +3 -3
  69. data/vendor/assets/bower_components/angular-sanitize/bower.json +2 -2
  70. data/vendor/assets/bower_components/angular-sanitize/package.json +1 -1
  71. data/vendor/assets/bower_components/angular-ui-router/CHANGELOG.md +1410 -0
  72. data/vendor/assets/bower_components/angular-ui-router/CONTRIBUTING.md +64 -16
  73. data/vendor/assets/bower_components/angular-ui-router/DOCS.md +48 -0
  74. data/vendor/assets/bower_components/angular-ui-router/ISSUE_TEMPLATE.md +53 -0
  75. data/vendor/assets/bower_components/angular-ui-router/LICENSE +1 -1
  76. data/vendor/assets/bower_components/angular-ui-router/README.md +24 -211
  77. data/vendor/assets/bower_components/angular-ui-router/artifacts.json +8 -0
  78. data/vendor/assets/bower_components/angular-ui-router/bower.json +1 -23
  79. data/vendor/assets/bower_components/angular-ui-router/karma.conf.js +105 -0
  80. data/vendor/assets/bower_components/angular-ui-router/release/angular-ui-router.js +9744 -3901
  81. data/vendor/assets/bower_components/angular-ui-router/release/angular-ui-router.js.map +192 -0
  82. data/vendor/assets/bower_components/angular-ui-router/release/angular-ui-router.min.js +9 -4
  83. data/vendor/assets/bower_components/angular-ui-router/release/angular-ui-router.min.js.map +1679 -0
  84. data/vendor/assets/bower_components/angular-ui-router/release/resolveService.js +83 -0
  85. data/vendor/assets/bower_components/angular-ui-router/release/resolveService.js.map +19 -0
  86. data/vendor/assets/bower_components/angular-ui-router/release/resolveService.min.js +8 -0
  87. data/vendor/assets/bower_components/angular-ui-router/release/resolveService.min.js.map +47 -0
  88. data/vendor/assets/bower_components/angular-ui-router/release/stateEvents.js +294 -0
  89. data/vendor/assets/bower_components/angular-ui-router/release/stateEvents.js.map +17 -0
  90. data/vendor/assets/bower_components/angular-ui-router/release/stateEvents.min.js +8 -0
  91. data/vendor/assets/bower_components/angular-ui-router/release/stateEvents.min.js.map +102 -0
  92. data/vendor/assets/bower_components/angular-ui-router/release/ui-router-angularjs.js +2014 -0
  93. data/vendor/assets/bower_components/angular-ui-router/release/ui-router-angularjs.js.map +70 -0
  94. data/vendor/assets/bower_components/angular-ui-router/release/ui-router-angularjs.min.js +9 -0
  95. data/vendor/assets/bower_components/angular-ui-router/release/ui-router-angularjs.min.js.map +541 -0
  96. data/vendor/assets/bower_components/angular-ui-router/rollup.config.js +116 -0
  97. data/vendor/assets/bower_components/angular-ui-router/tslint.json +60 -0
  98. data/vendor/assets/bower_components/angular-ui-router/yarn.lock +4146 -0
  99. data/vendor/assets/bower_components/angular-ui-tree/yarn.lock +4945 -0
  100. data/vendor/assets/bower_components/angular/angular.js +4019 -2449
  101. data/vendor/assets/bower_components/angular/angular.min.js +331 -319
  102. data/vendor/assets/bower_components/angular/angular.min.js.gzip +0 -0
  103. data/vendor/assets/bower_components/angular/angular.min.js.map +3 -3
  104. data/vendor/assets/bower_components/angular/bower.json +1 -1
  105. data/vendor/assets/bower_components/angular/package.json +1 -1
  106. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/LICENSE +21 -0
  107. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/README.md +14 -14
  108. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/bower.json +25 -12
  109. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/development_index.html +59 -52
  110. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/dist/angularjs-dropdown-multiselect.min.js +1 -1
  111. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/index.html +73 -0
  112. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/package.json +19 -7
  113. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/pages/javascripts/pages/home/ExampleCtrl.js +126 -3
  114. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/pages/javascripts/pages/home/home.html +1262 -852
  115. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/pages/stylesheets/stylesheet.css +10 -5
  116. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/src/angularjs-dropdown-multiselect.js +612 -287
  117. metadata +66 -169
  118. data/spec/internal/config/database.yml +0 -7
  119. data/spec/internal/public/uploads/kms/asset/file/1/avatar.jpg +0 -0
  120. data/spec/internal/public/uploads/kms/asset/file/2/avatar.jpg +0 -0
  121. data/spec/internal/public/uploads/kms/asset/file/2/style.css +0 -1
  122. data/spec/internal/public/uploads/kms/asset/file/3/style.css +0 -1
  123. data/spec/internal/public/uploads/kms/asset/file/4/style.css +0 -1
  124. data/spec/internal/public/uploads/tmp/1500976987-41025-0002-0883/style.css +0 -1
  125. data/spec/internal/public/uploads/tmp/1500977082-41195-0002-6495/style.css +0 -1
  126. data/spec/internal/public/uploads/tmp/1500977109-41364-0002-4518/style.css +0 -1
  127. data/spec/internal/public/uploads/tmp/1500977152-41405-0002-2345/style.css +0 -1
  128. data/spec/internal/public/uploads/tmp/1500977327-41694-0002-5448/style.css +0 -1
  129. data/spec/internal/public/uploads/tmp/1500977376-41732-0002-7916/style.css +0 -1
  130. data/spec/internal/public/uploads/tmp/1500977392-41759-0002-7593/style.css +0 -1
  131. data/spec/internal/public/uploads/tmp/1500977410-42259-0002-7527/style.css +0 -1
  132. data/spec/internal/public/uploads/tmp/1500977429-42306-0002-5937/style.css +0 -1
  133. data/spec/internal/public/uploads/tmp/1500977437-42324-0002-5880/style.css +0 -1
  134. data/spec/internal/public/uploads/tmp/1500983228-53594-0002-4559/style.css +0 -1
  135. data/spec/internal/public/uploads/tmp/1500983284-53632-0002-6590/style.css +0 -1
  136. data/spec/internal/public/uploads/tmp/1500983360-53784-0002-7289/style.css +0 -1
  137. data/spec/internal/public/uploads/tmp/1500983469-54321-0002-0386/avatar.jpg +0 -0
  138. data/spec/internal/public/uploads/tmp/1500983469-54321-0004-5691/style.css +0 -1
  139. data/spec/internal/public/uploads/tmp/1500983511-54352-0002-5720/avatar.jpg +0 -0
  140. data/spec/internal/public/uploads/tmp/1500983511-54352-0004-1399/style.css +0 -1
  141. data/spec/internal/public/uploads/tmp/1500983610-54507-0002-4280/avatar.jpg +0 -0
  142. data/spec/internal/public/uploads/tmp/1500983610-54507-0004-9758/style.css +0 -1
  143. data/spec/internal/public/uploads/tmp/1500984466-57012-0002-4146/avatar.jpg +0 -0
  144. data/spec/internal/public/uploads/tmp/1500984466-57012-0004-5895/style.css +0 -1
  145. data/spec/internal/public/uploads/tmp/1500984509-57158-0002-9657/avatar.jpg +0 -0
  146. data/spec/internal/public/uploads/tmp/1500984509-57158-0004-5003/style.css +0 -1
  147. data/spec/internal/public/uploads/tmp/1500984616-57697-0002-7201/avatar.jpg +0 -0
  148. data/spec/internal/public/uploads/tmp/1500984616-57697-0004-6255/style.css +0 -1
  149. data/spec/internal/public/uploads/tmp/1500985257-58947-0002-3629/avatar.jpg +0 -0
  150. data/spec/internal/public/uploads/tmp/1500985257-58947-0004-5338/style.css +0 -1
  151. data/spec/internal/public/uploads/tmp/1500985407-58947-0006-5929/style.css +0 -1
  152. data/spec/internal/public/uploads/tmp/1500985473-59264-0002-0397/avatar.jpg +0 -0
  153. data/spec/internal/public/uploads/tmp/1500985473-59264-0004-6493/style.css +0 -1
  154. data/spec/internal/public/uploads/tmp/1500985475-59264-0007-8674/style.css +0 -1
  155. data/spec/internal/public/uploads/tmp/1500985538-59468-0002-9206/avatar.jpg +0 -0
  156. data/spec/internal/public/uploads/tmp/1500985538-59468-0004-2586/style.css +0 -1
  157. data/spec/internal/public/uploads/tmp/1500985538-59468-0007-6200/style.css +0 -1
  158. data/spec/internal/public/uploads/tmp/1500988358-65877-0002-4528/avatar.jpg +0 -0
  159. data/spec/internal/public/uploads/tmp/1500988358-65877-0004-5904/style.css +0 -1
  160. data/spec/internal/public/uploads/tmp/1500988358-65877-0007-7320/style.css +0 -1
  161. data/spec/internal/public/uploads/tmp/1500988407-65916-0002-3138/avatar.jpg +0 -0
  162. data/spec/internal/public/uploads/tmp/1500988407-65916-0004-5400/style.css +0 -1
  163. data/spec/internal/public/uploads/tmp/1500988407-65916-0007-1655/style.css +0 -1
  164. data/spec/internal/public/uploads/tmp/1500988421-65950-0002-9415/avatar.jpg +0 -0
  165. data/spec/internal/public/uploads/tmp/1500988421-65950-0004-7130/style.css +0 -1
  166. data/spec/internal/public/uploads/tmp/1500988421-65950-0007-9886/style.css +0 -1
  167. data/spec/internal/public/uploads/tmp/1500988435-65981-0002-3228/avatar.jpg +0 -0
  168. data/spec/internal/public/uploads/tmp/1500988435-65981-0004-3682/style.css +0 -1
  169. data/spec/internal/public/uploads/tmp/1500988435-65981-0007-1582/style.css +0 -1
  170. data/spec/internal/public/uploads/tmp/1500988475-66122-0002-9516/avatar.jpg +0 -0
  171. data/spec/internal/public/uploads/tmp/1500988475-66122-0004-5634/style.css +0 -1
  172. data/spec/internal/public/uploads/tmp/1500988530-66122-0007-2272/style.css +0 -1
  173. data/spec/internal/public/uploads/tmp/1500988554-66315-0002-6262/avatar.jpg +0 -0
  174. data/spec/internal/public/uploads/tmp/1500988554-66315-0004-6099/style.css +0 -1
  175. data/spec/internal/public/uploads/tmp/1500988554-66315-0007-1632/style.css +0 -1
  176. data/spec/internal/public/uploads/tmp/1500991751-73722-0002-9937/avatar.jpg +0 -0
  177. data/spec/internal/public/uploads/tmp/1500991751-73722-0004-8034/style.css +0 -1
  178. data/spec/internal/public/uploads/tmp/1500991751-73722-0007-7763/style.css +0 -1
  179. data/spec/internal/public/uploads/tmp/1501233238-34385-0002-3210/avatar.jpg +0 -0
  180. data/spec/internal/public/uploads/tmp/1501233238-34385-0004-5881/style.css +0 -1
  181. data/spec/internal/public/uploads/tmp/1501233238-34385-0007-6280/style.css +0 -1
  182. data/spec/internal/tmp/cache/assets/test/sprockets/v3.0/1XyAFYlYI0pK7WAgjR4PgXV6BgU6huJSviWmHetdCRs.cache +0 -1
  183. data/vendor/assets/bower_components/angular-ui-router/api/angular-ui-router.d.ts +0 -126
  184. data/vendor/assets/bower_components/angular-ui-router/src/common.js +0 -292
  185. data/vendor/assets/bower_components/angular-ui-router/src/resolve.js +0 -252
  186. data/vendor/assets/bower_components/angular-ui-router/src/state.js +0 -1373
  187. data/vendor/assets/bower_components/angular-ui-router/src/stateDirectives.js +0 -268
  188. data/vendor/assets/bower_components/angular-ui-router/src/stateFilters.js +0 -39
  189. data/vendor/assets/bower_components/angular-ui-router/src/templateFactory.js +0 -110
  190. data/vendor/assets/bower_components/angular-ui-router/src/urlMatcherFactory.js +0 -1036
  191. data/vendor/assets/bower_components/angular-ui-router/src/urlRouter.js +0 -413
  192. data/vendor/assets/bower_components/angular-ui-router/src/view.js +0 -71
  193. data/vendor/assets/bower_components/angular-ui-router/src/viewDirective.js +0 -302
  194. data/vendor/assets/bower_components/angular-ui-router/src/viewScroll.js +0 -52
  195. data/vendor/assets/bower_components/angularjs-dropdown-multiselect/pages/index.html +0 -67
  196. data/vendor/assets/bower_components/bootstrap/Gemfile.lock +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4167d59e7151bdf01942747de925d31eef38c6d4
4
- data.tar.gz: 44882c061a23bf582447083ce5973ff9fbb934af
3
+ metadata.gz: 706248cb2d7f607b5308dc373c44dcf914181239
4
+ data.tar.gz: 62c92d2c79550b7c38523df37e00ac90e179871e
5
5
  SHA512:
6
- metadata.gz: f0b92c7cdc197f4d351105cc5ce3cfd13faed9ed725c3f707dee4f8324f79575a4dcf05e7567023a7162db5aebf9105eece7fc279ba1c19560c2df1e7652f6ed
7
- data.tar.gz: 21df959541a30902e1bf145c3b3843512af0572a339d1bc196ac2bd17eafe8aeaa9ade20f89b8e1147f9559037199a54afb02aab30eeb1cd9a50e1a2c4aa887e
6
+ metadata.gz: 528337cf36325329bed39d101417d53338b6f46fe3d92d92a69528aab845ca27127a4bc08e19627cc10ed59c15f9adac9e866ac297f3fd2cba0e604ad5a92922
7
+ data.tar.gz: 56be7cf89aecc717a7e300abec0f4be70dd791976f42b1968ea79607d1880300152f3386bb1cdc776af0951781d3cd98e5880143389987ccdf18b8f3f29a839c
@@ -44,6 +44,7 @@
44
44
  //= require "ng-alertify/ng-alertify"
45
45
  //= require "angular-xeditable/dist/js/xeditable"
46
46
  //= require "ng-sortable/dist/ng-sortable"
47
+ //= require "angular-hotkeys/build/hotkeys.min"
47
48
  //= require "kms/application/module"
48
49
  //= require "kms/application/routes"
49
50
  //= require angular-rails-templates
@@ -1,4 +1,4 @@
1
- AssetsController = ($scope, $state, $cookieStore, $cookies, Restangular, $stateParams, Alertify, ErrorsService) ->
1
+ AssetsController = ($scope, $state, $cookieStore, $cookies, Restangular, $stateParams, Alertify, ErrorsService, hotkeys) ->
2
2
 
3
3
  $scope.editorOptions = (asset)->
4
4
  lineNumbers: true
@@ -25,13 +25,23 @@ AssetsController = ($scope, $state, $cookieStore, $cookies, Restangular, $stateP
25
25
  $scope.asset = asset
26
26
  if /css|javascript/.test $scope.getAssetGroup(asset)
27
27
  $scope.asset.performing_plain_text = true
28
- else
29
- {}
28
+
29
+ hotkeys.add
30
+ combo: 'ctrl+s'
31
+ description: 'Saving an asset'
32
+ allowIn: ['INPUT', 'TEXTAREA']
33
+ callback: (event) ->
34
+ event.preventDefault()
35
+ $scope.update(event) if $scope.asset.id
36
+
37
+ $scope.handleUploadError = (file, message, flow) ->
38
+ Alertify.error ErrorsService.prepareErrorsString(JSON.parse(message).errors)
30
39
 
31
40
  $scope.update = ($event)->
32
41
  $scope.asset.put().then ->
33
42
  if $event.target.attributes['data-redirect']
34
43
  $state.go('assets')
44
+ Alertify.success('<%= I18n.t(:asset_successfully_updated) %>')
35
45
  ,(response)->
36
46
  Alertify.error(ErrorsService.prepareErrorsString(response.data.errors))
37
47
 
@@ -77,4 +87,4 @@ AssetsController = ($scope, $state, $cookieStore, $cookies, Restangular, $stateP
77
87
 
78
88
 
79
89
  angular.module('KMS')
80
- .controller('AssetsController', ['$scope', '$state', '$cookieStore', '$cookies', 'Restangular', '$stateParams', 'Alertify', 'ErrorsService', AssetsController])
90
+ .controller('AssetsController', ['$scope', '$state', '$cookieStore', '$cookies', 'Restangular', '$stateParams', 'Alertify', 'ErrorsService', 'hotkeys', AssetsController])
@@ -1,4 +1,4 @@
1
- PagesController = ($scope, $state, $cookieStore, Restangular, $stateParams, Alertify, ErrorsService, TransliterationService) ->
1
+ PagesController = ($scope, $state, $cookieStore, Restangular, $stateParams, Alertify, ErrorsService, TransliterationService, hotkeys) ->
2
2
  $scope.editorOptions =
3
3
  filebrowserUploadUrl: '/kms/assets/ckeditor'
4
4
  entities: false
@@ -71,10 +71,19 @@ PagesController = ($scope, $state, $cookieStore, Restangular, $stateParams, Aler
71
71
  if $scope.parentPages.length > 0 and $scope.page and !$scope.page.parent_id and !$stateParams.id
72
72
  $scope.page.parent_id = $scope.parentPages[0].id
73
73
 
74
+ hotkeys.add
75
+ combo: 'ctrl+s'
76
+ description: 'Saving a page'
77
+ allowIn: ['INPUT', 'SELECT', 'TEXTAREA']
78
+ callback: (event) ->
79
+ event.preventDefault()
80
+ if $scope.page.id then $scope.update(event) else $scope.create()
81
+
74
82
 
75
83
  $scope.create = ->
76
84
  $scope.store.post($scope.page).then ->
77
85
  $state.go('pages')
86
+ Alertify.success('<%= I18n.t(:page_successfully_created) %>')
78
87
  ,(response)->
79
88
  Alertify.error(ErrorsService.prepareErrorsString(response.data.errors))
80
89
 
@@ -82,6 +91,7 @@ PagesController = ($scope, $state, $cookieStore, Restangular, $stateParams, Aler
82
91
  $scope.page.put().then ->
83
92
  if $event.target.attributes['data-redirect']
84
93
  $state.go('pages')
94
+ Alertify.success('<%= I18n.t(:page_successfully_updated) %>')
85
95
  ,(response)->
86
96
  Alertify.error(ErrorsService.prepareErrorsString(response.data.errors))
87
97
 
@@ -101,4 +111,4 @@ PagesController = ($scope, $state, $cookieStore, Restangular, $stateParams, Aler
101
111
  }
102
112
 
103
113
  angular.module('KMS')
104
- .controller('PagesController', ['$scope', '$state', '$cookieStore', 'Restangular', '$stateParams', 'Alertify', 'ErrorsService', 'TransliterationService', PagesController])
114
+ .controller('PagesController', ['$scope', '$state', '$cookieStore', 'Restangular', '$stateParams', 'Alertify', 'ErrorsService', 'TransliterationService', 'hotkeys', PagesController])
@@ -1,4 +1,4 @@
1
- SnippetsController = ($scope, $state, Restangular, $stateParams, Alertify, ErrorsService) ->
1
+ SnippetsController = ($scope, $state, Restangular, $stateParams, Alertify, ErrorsService, hotkeys) ->
2
2
  $scope.editorOptions =
3
3
  lineNumbers: true
4
4
  mode:'htmlmixed'
@@ -26,11 +26,20 @@ SnippetsController = ($scope, $state, Restangular, $stateParams, Alertify, Error
26
26
  $scope.store.get($stateParams.id).then (snippet)->
27
27
  $scope.snippet = snippet
28
28
  else
29
- $scope.snippet = {}
29
+ $scope.snippet = {content: ''}
30
+
31
+ hotkeys.add
32
+ combo: 'ctrl+s'
33
+ description: 'Saving a snippet'
34
+ allowIn: ['INPUT', 'SELECT', 'TEXTAREA']
35
+ callback: (event) ->
36
+ event.preventDefault()
37
+ if $scope.snippet.id then $scope.update(event) else $scope.create()
30
38
 
31
39
  $scope.create = ->
32
40
  $scope.store.post($scope.snippet).then ->
33
41
  $state.go('snippets')
42
+ Alertify.success('<%= I18n.t(:snippet_successfully_created) %>')
34
43
  , (response)->
35
44
  Alertify.error(ErrorsService.prepareErrorsString(response.data.errors))
36
45
 
@@ -38,6 +47,7 @@ SnippetsController = ($scope, $state, Restangular, $stateParams, Alertify, Error
38
47
  $scope.snippet.put().then ->
39
48
  if event.target.attributes['data-redirect']
40
49
  $state.go('snippets')
50
+ Alertify.success('<%= I18n.t(:snippet_successfully_updated) %>')
41
51
  ,(response)->
42
52
  Alertify.error(ErrorsService.prepareErrorsString(response.data.errors))
43
53
 
@@ -47,4 +57,4 @@ SnippetsController = ($scope, $state, Restangular, $stateParams, Alertify, Error
47
57
  $scope.snippets = _.without($scope.snippets, snippet)
48
58
 
49
59
  angular.module('KMS')
50
- .controller('SnippetsController', ['$scope', '$state', 'Restangular', '$stateParams', 'Alertify', 'ErrorsService', SnippetsController])
60
+ .controller('SnippetsController', ['$scope', '$state', 'Restangular', '$stateParams', 'Alertify', 'ErrorsService', 'hotkeys', SnippetsController])
@@ -1,4 +1,4 @@
1
- TemplatesController = ($scope, $state, $cookieStore, Restangular, $stateParams, Alertify, ErrorsService) ->
1
+ TemplatesController = ($scope, $state, $cookieStore, Restangular, $stateParams, Alertify, ErrorsService, hotkeys) ->
2
2
  $scope.editorOptions =
3
3
  lineNumbers: true
4
4
  mode:'htmlmixed'
@@ -26,11 +26,20 @@ TemplatesController = ($scope, $state, $cookieStore, Restangular, $stateParams,
26
26
  $scope.store.get($stateParams.id).then (template)->
27
27
  $scope.template = template
28
28
  else
29
- $scope.template = {}
29
+ $scope.template = {name: '', content: ''}
30
+
31
+ hotkeys.add
32
+ combo: 'ctrl+s'
33
+ description: 'Saving a template'
34
+ allowIn: ['INPUT', 'SELECT', 'TEXTAREA']
35
+ callback: (event) ->
36
+ event.preventDefault()
37
+ if $scope.template.id then $scope.update(event) else $scope.create()
30
38
 
31
39
  $scope.create = ->
32
40
  $scope.store.post($scope.template).then ->
33
41
  $state.go('templates')
42
+ Alertify.success('<%= I18n.t(:template_successfully_created) %>')
34
43
  , (response)->
35
44
  Alertify.error(ErrorsService.prepareErrorsString(response.data.errors))
36
45
 
@@ -38,6 +47,7 @@ TemplatesController = ($scope, $state, $cookieStore, Restangular, $stateParams,
38
47
  $scope.template.put().then ->
39
48
  if $event.target.attributes['data-redirect']
40
49
  $state.go('templates')
50
+ Alertify.success('<%= I18n.t(:template_successfully_updated) %>')
41
51
  ,(response)->
42
52
  Alertify.error(ErrorsService.prepareErrorsString(response.data.errors))
43
53
 
@@ -48,4 +58,4 @@ TemplatesController = ($scope, $state, $cookieStore, Restangular, $stateParams,
48
58
 
49
59
 
50
60
  angular.module('KMS')
51
- .controller('TemplatesController', ['$scope', '$state', '$cookieStore', 'Restangular', '$stateParams', 'Alertify', 'ErrorsService', TemplatesController])
61
+ .controller('TemplatesController', ['$scope', '$state', '$cookieStore', 'Restangular', '$stateParams', 'Alertify', 'ErrorsService', 'hotkeys', TemplatesController])
@@ -15,11 +15,11 @@ UsersController = ($scope, $state, $cookieStore, Restangular, $stateParams, Aler
15
15
  , (response)->
16
16
  Alertify.error(ErrorsService.prepareErrorsString(response.data.errors))
17
17
 
18
- #$scope.update = ->
19
- #$scope.user.put().then ->
20
- #$state.go('users')
21
- #,->
22
- #console.log('bug')
18
+ $scope.update = ->
19
+ $scope.user.put().then ->
20
+ $state.go('users')
21
+ , (response) ->
22
+ Alertify.error(ErrorsService.prepareErrorsString(response.data.errors))
23
23
 
24
24
  $scope.destroy = (user)->
25
25
  if(confirm('<%= I18n.t(:are_you_sure) %>'))
@@ -1,4 +1,8 @@
1
- angular.module('KMS', ['ui.bootstrap', 'ui.router', 'ngCookies', 'restangular', 'templates', 'ui.tree', 'ui.codemirror', 'flow', 'ui.select', 'ngSanitize', 'ngCkeditor', 'toggle-switch', 'angular-loading-bar', 'angularjs-dropdown-multiselect', 'Alertify', 'xeditable', 'as.sortable'])
1
+ angular.module('KMS', ['ui.bootstrap', 'ui.router', 'ngCookies', 'restangular',
2
+ 'templates', 'ui.tree', 'ui.codemirror', 'flow', 'ui.select',
3
+ 'ngSanitize', 'ngCkeditor', 'toggle-switch', 'angular-loading-bar',
4
+ 'angularjs-dropdown-multiselect', 'Alertify', 'xeditable', 'as.sortable', 'cfp.hotkeys'
5
+ ])
2
6
 
3
7
  angular.module('KMS').config ['$httpProvider', '$locationProvider', 'RestangularProvider', 'flowFactoryProvider', 'cfpLoadingBarProvider', ($httpProvider, $locationProvider, RestangularProvider, flowFactoryProvider, cfpLoadingBarProvider) ->
4
8
  cfpLoadingBarProvider.includeSpinner = false
@@ -10,7 +14,7 @@ angular.module('KMS').config ['$httpProvider', '$locationProvider', 'Restangular
10
14
 
11
15
  flowFactoryProvider.defaults =
12
16
  target: '/kms/assets.json'
13
- permanentErrors: [404, 500, 501]
17
+ permanentErrors: [404, 422, 500, 501]
14
18
  maxChunkRetries: 1
15
19
  chunkSize: 50*1024*1024
16
20
  chunkRetryInterval: 5000
@@ -138,6 +138,16 @@ angular.module('KMS').config ['$stateProvider', '$urlRouterProvider', ($statePro
138
138
  controllerAs: 'users',
139
139
  templateUrl: 'users/new.html',
140
140
  })
141
+ .state('users.edit', {
142
+ url: '/:id/edit',
143
+ views:
144
+ "header@":
145
+ template: "<%= I18n.t(:edit_user) %>"
146
+ "@":
147
+ controller: 'UsersController',
148
+ controllerAs: 'users',
149
+ templateUrl: 'users/edit.html',
150
+ })
141
151
  .state('snippets', {
142
152
  url: '/kms/snippets',
143
153
  views:
@@ -7,7 +7,8 @@
7
7
  .btn-group
8
8
  button.btn.btn-default type="submit" data-redirect="true" ng-click="update($event)" = I18n.t(:update_asset)
9
9
  button.btn.btn-default type="submit" ng-click="update($event)" = I18n.t(:update_asset_and_continue)
10
- .center-block ng-unless="asset.performing_plain_text" flow-init="{headers: setHeaders, singleFile: true, uploadMethod: 'PUT', target: updateTarget, initFileFn: initFlowFile}" flow-files-submitted="$flow.upload()" flow-file-success="$file.msg = $message" flow-complete="$state.go('assets')" flow-drop=""
10
+ ng-include src="'shared/hotkey_notification.html'"
11
+ .center-block ng-unless="asset.performing_plain_text" flow-init="{headers: setHeaders, singleFile: true, uploadMethod: 'PUT', target: updateTarget, initFileFn: initFlowFile}" flow-files-submitted="$flow.upload()" flow-file-success="$file.msg = $message" flow-complete="$state.go('assets')" flow-drop="" flow-error="handleUploadError( $file, $message, $flow )"
11
12
  .jumbotron.vertical-center.text-center
12
13
  .container
13
14
  h1
@@ -1,4 +1,4 @@
1
- .center-block flow-init="{headers: setHeaders}" flow-files-submitted="$flow.upload()" flow-file-success="$file.msg = $message" flow-complete="$state.go('assets')" flow-drop=""
1
+ .center-block flow-init="{headers: setHeaders}" flow-files-submitted="$flow.upload()" flow-file-success="$file.msg = $message" flow-complete="$state.go('assets')" flow-drop="" flow-error="handleUploadError( $file, $message, $flow )"
2
2
  .jumbotron.vertical-center.text-center
3
3
  .container
4
4
  h1
@@ -5,3 +5,4 @@
5
5
  .btn-group
6
6
  button.btn.btn-default type="submit" data-redirect="true" ng-click="update($event)" = I18n.t(:update_page)
7
7
  button.btn.btn-default type="submit" ng-click="update($event)" = I18n.t(:update_page_and_continue)
8
+ ng-include src="'shared/hotkey_notification.html'"
@@ -0,0 +1,6 @@
1
+ span.btn.hotkey-notification
2
+ = I18n.t(:or_hit)
3
+ span.label.label-info Ctrl
4
+ | &nbsp;+&nbsp;
5
+ span.label.label-info S
6
+ = I18n.t(:while_your_cursor_in_input)
@@ -5,3 +5,4 @@
5
5
  .btn-group
6
6
  button.btn.btn-default type="submit" data-redirect="true" ng-click="update($event)" = I18n.t(:update_snippet)
7
7
  button.btn.btn-default type="submit" ng-click="update($event)" = I18n.t(:update_snippet_and_continue)
8
+ ng-include src="'shared/hotkey_notification.html'"
@@ -5,3 +5,4 @@
5
5
  .btn-group
6
6
  button.btn.btn-default type="submit" data-redirect="true" ng-click="update($event)" = I18n.t(:update_template)
7
7
  button.btn.btn-default type="submit" ng-click="update($event)" = I18n.t(:update_template_and_continue)
8
+ ng-include src="'shared/hotkey_notification.html'"
@@ -0,0 +1,5 @@
1
+ .row
2
+ .col-lg-12
3
+ form role="form" ng-submit="update()"
4
+ ng-include src="'users/form.html'"
5
+ button.btn.btn-default type="submit" = I18n.t(:update_user)
@@ -3,12 +3,13 @@
3
3
  input#email.form-control type="email" ng-model="user.email" required=""
4
4
  .form-group
5
5
  label for="password" = Kms::User.human_attribute_name(:password)
6
- input#password.form-control type="password" ng-model="user.password" required=""
6
+ input#password.form-control type="password" ng-model="user.password" ng-attr-required="{{user.id ? undefined : ''}}"
7
7
  .form-group
8
8
  label for="password_confirmation" = Kms::User.human_attribute_name(:password_confirmation)
9
- input#password_confirmation.form-control type="password" ng-model="user.password_confirmation" required=""
9
+ input#password_confirmation.form-control type="password" ng-model="user.password_confirmation" ng-attr-required="{{user.id ? undefined : ''}}"
10
10
  .form-group
11
11
  label for="role" = Kms::User.human_attribute_name(:role)
12
12
  select#role.form-control ng-model="user.role" required=""
13
13
  - Kms::User::ROLES.each do |role|
14
14
  option value=role.to_s = I18n.t("roles.#{role.to_s}")
15
+ small = I18n.t(:roles_description)
@@ -13,7 +13,8 @@
13
13
  tbody
14
14
  tr ng-repeat="user in users"
15
15
  td style="width: 80%"
16
- | {{ user.email }}
16
+ a ui-sref="users.edit({id: user.id})"
17
+ | {{ user.email }}
17
18
  td
18
19
  | {{ user.localized_role }}
19
20
  td
@@ -124,3 +124,13 @@ ul.sidebar .sidebar-main {
124
124
  line-height: 70px;
125
125
  }
126
126
  }
127
+ .hotkey-notification:active {
128
+ -webkit-box-shadow: none;
129
+ box-shadow: none;
130
+ }
131
+ ul.sidebar .sidebar-list.active a {
132
+ color: #fff;
133
+ border-left: 3px solid #ff5274;
134
+ text-indent: 22px;
135
+ background: #2d3e63;
136
+ }
@@ -14,7 +14,7 @@ module Kms
14
14
  # special json for ng-flow
15
15
  render json: {success: true, files: [@asset]}.to_json
16
16
  else
17
- render text: '', status: :unprocessable_entity
17
+ render json: {errors: @asset.errors}.to_json, status: :unprocessable_entity
18
18
  end
19
19
  end
20
20
 
@@ -33,8 +33,11 @@ module Kms
33
33
 
34
34
  def update
35
35
  @asset = Asset.find(params[:id])
36
- @asset.update(asset_params)
37
- render json: @asset
36
+ if @asset.update(asset_params)
37
+ render json: @asset
38
+ else
39
+ render json: {errors: @asset.errors}.to_json, status: :unprocessable_entity
40
+ end
38
41
  end
39
42
 
40
43
  def show
@@ -18,6 +18,20 @@ module Kms
18
18
  end
19
19
  end
20
20
 
21
+ def update
22
+ @user = User.find(params[:id])
23
+ if @user.update(user_params)
24
+ head :no_content
25
+ else
26
+ render json: {errors: @user.errors}.to_json, status: :unprocessable_entity
27
+ end
28
+ end
29
+
30
+ def show
31
+ @user = User.find(params[:id])
32
+ render json: @user
33
+ end
34
+
21
35
  def destroy
22
36
  @user = User.find(params[:id])
23
37
  @user.destroy
@@ -4,6 +4,8 @@ module Kms
4
4
  {}
5
5
  end
6
6
 
7
+ NON_TEMPLATABLE_CLASSES = [Page, Template, Asset, User, Snippet].freeze
8
+
7
9
  def self.register(group, resource, tab_icon_class)
8
10
  self.resources[group] ||= {}
9
11
  self.resources[group][resource] = tab_icon_class
@@ -14,7 +16,7 @@ module Kms
14
16
  end
15
17
 
16
18
  def self.external_resources_hash
17
- self.resources.values.map(&:keys).flatten.reject {|r| [Page, Template, Asset, User].include?(r)}.map do |resource_class|
19
+ self.resources.values.map(&:keys).flatten.reject {|r| NON_TEMPLATABLE_CLASSES.include?(r)}.map do |resource_class|
18
20
  {type: resource_class.name, title: resource_class.model_name.human}
19
21
  end
20
22
  end
@@ -72,7 +72,7 @@
72
72
  <% end %>
73
73
  <% resources.each do |resource_class, tab_icon_class| %>
74
74
  <% if can? :index, resource_class %>
75
- <li class="sidebar-list">
75
+ <li class="sidebar-list" ui-sref-active-eq="active">
76
76
  <a ui-sref="<%= defined?(Kms::Model) && resource_class.is_a?(Kms::Model) ? "models.entries({modelId: #{resource_class.name}})" : resource_class.name.demodulize.tableize %>" title="<%= resource_class.model_name.human(count: 1.1) %>">
77
77
  <%= truncate(resource_class.model_name.human(count: 1.1), length: 22) %>
78
78
  <span class="menu-icon fa <%= tab_icon_class %>"></span>
@@ -9,6 +9,15 @@ module Kms
9
9
  new_kms_user_session_path
10
10
  end
11
11
 
12
+ # You need to override respond to eliminate recall
13
+ def respond
14
+ if http_auth?
15
+ http_auth
16
+ else
17
+ redirect
18
+ end
19
+ end
20
+
12
21
  end
13
22
 
14
23
  end
@@ -10,11 +10,15 @@ en:
10
10
  new_template: "New Template"
11
11
  edit_template: "Edit Template"
12
12
  update_template: "Update template"
13
+ template_successfully_created: "Template successfully created"
14
+ template_successfully_updated: "Template successfully updated"
13
15
  add_page: "Add page"
14
16
  create_first_page: "Create first page"
15
17
  new_page: "New Page"
16
18
  edit_page: "Edit Page"
17
19
  update_page: "Update page"
20
+ page_successfully_created: "Page successfully created"
21
+ page_successfully_updated: "Page successfully updated"
18
22
  update_page_and_continue: "Update page and continue"
19
23
  update_template_and_continue: "Update template and continue"
20
24
  update_asset_and_continue: "Update asset and continue"
@@ -23,15 +27,20 @@ en:
23
27
  new_asset: "New Asset"
24
28
  edit_asset: "Edit Asset"
25
29
  update_asset: "Update asset"
30
+ asset_successfully_updated: "Asset successfully updated"
26
31
  upload_assets: "Upload assets"
27
32
  add_user: "Add user"
28
33
  new_user: "New User"
34
+ edit_user: "Edit User"
35
+ update_user: "Update user"
29
36
  toggle_fullscreen_mode_instruction: "Press F11 when cursor is in the editor to toggle full screen editing. ESC can also be used to exit full screen editing."
30
37
  add_snippet: "Add snippet"
31
38
  create_first_snippet: "Create first snippet"
32
39
  new_snippet: "New Snippet"
33
40
  edit_snippet: "Edit Snippet"
34
41
  update_snippet: "Update snippet"
42
+ snippet_successfully_created: "Snippet successfully created"
43
+ snippet_successfully_updated: "Snippet successfully updated"
35
44
  documentation: "Documentation"
36
45
  need_help: "Need help?"
37
46
  settings: "Settings"
@@ -52,6 +61,9 @@ en:
52
61
  snippets_description: "Snippets are pieces of HTML that you could include in templates or pages"
53
62
  assets_description: "Upload stylesheets, javascripts, images and other files here (you can even pick multiple)"
54
63
  assets_drop_description: "or just drag and drop them"
64
+ roles_description: "Admins can manage any content. Content managers have access only to \"Pages\" and \"Assets\" under \"Content Management\" section (but also have access to other sections). The second difference is Admins see pages content in html editor, Content Managers - in WYSIWYG editor"
65
+ or_hit: "or hit "
66
+ while_your_cursor_in_input: " while your cursor in input"
55
67
  roles:
56
68
  admin: "Admin"
57
69
  content_manager: "Content manager"