ki 0.4.10 → 0.4.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +16 -8
  3. data/MIDDLEWARE.md +27 -7
  4. data/README.md +45 -2
  5. data/REALTIME.md +48 -0
  6. data/TODO.md +19 -0
  7. data/ki.gemspec +1 -0
  8. data/lib/ki.rb +5 -0
  9. data/lib/ki/base_request.rb +7 -0
  10. data/lib/ki/channel_manager.rb +58 -0
  11. data/lib/ki/ki.rb +1 -0
  12. data/lib/ki/ki_cli.rb +1 -1
  13. data/lib/ki/ki_config.rb +18 -2
  14. data/lib/ki/middleware/api_handler.rb +11 -16
  15. data/lib/ki/middleware/helpers/redirect_to_helper.rb +13 -0
  16. data/lib/ki/middleware/realtime.rb +81 -0
  17. data/lib/ki/model.rb +6 -4
  18. data/lib/ki/modules/restrictions.rb +4 -7
  19. data/lib/ki/orm.rb +38 -2
  20. data/lib/ki/utils/redirect_to_helper.rb +0 -0
  21. data/lib/ki/version.rb +1 -1
  22. data/spec/examples/json.northpole.ro/.bowerrc +3 -0
  23. data/spec/examples/json.northpole.ro/Gemfile +1 -0
  24. data/spec/examples/json.northpole.ro/bower.json +17 -0
  25. data/spec/examples/json.northpole.ro/config.ru +3 -0
  26. data/spec/examples/json.northpole.ro/config.yml +4 -0
  27. data/spec/examples/json.northpole.ro/config.yml.backup +18 -0
  28. data/spec/examples/json.northpole.ro/config/deploy.rb +2 -1
  29. data/spec/examples/json.northpole.ro/config/deploy/production.rb +4 -38
  30. data/spec/examples/json.northpole.ro/public/app/.bowerrc +3 -0
  31. data/spec/examples/json.northpole.ro/public/app/.gitignore +9 -0
  32. data/spec/examples/json.northpole.ro/public/app/.jshintrc +13 -0
  33. data/spec/examples/json.northpole.ro/public/app/.travis.yml +14 -0
  34. data/spec/examples/json.northpole.ro/public/app/LICENSE +22 -0
  35. data/spec/examples/json.northpole.ro/public/app/README.md +82 -0
  36. data/spec/examples/json.northpole.ro/public/app/bower.json +20 -0
  37. data/spec/examples/json.northpole.ro/public/app/e2e/pages/ContactUser.js +22 -0
  38. data/spec/examples/json.northpole.ro/public/app/e2e/pages/UserDetails.js +11 -0
  39. data/spec/examples/json.northpole.ro/public/app/e2e/pages/UserList.js +12 -0
  40. data/spec/examples/json.northpole.ro/public/app/e2e/protractor.conf.js +26 -0
  41. data/spec/examples/json.northpole.ro/public/app/e2e/scenarios/users.js +34 -0
  42. data/spec/examples/json.northpole.ro/public/app/gulpfile.js +104 -0
  43. data/spec/examples/json.northpole.ro/public/app/karma.conf.js +35 -0
  44. data/spec/examples/json.northpole.ro/public/app/package.json +30 -0
  45. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/avatar-1.svg +11 -0
  46. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/avatar-4.svg +16 -0
  47. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/avatars.svg +244 -0
  48. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/google_plus.svg +1 -0
  49. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/hangouts.svg +1 -0
  50. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_fullscreen_48px.svg +4 -0
  51. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_fullscreen_exit_48px.svg +4 -0
  52. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_music_note_48px.svg +1 -0
  53. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_note_add_48px.svg +1 -0
  54. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_view_list_48px.svg +1 -0
  55. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/icon.svg +1 -0
  56. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/mail.svg +1 -0
  57. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/manggo.svg +1095 -0
  58. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/menu.svg +4 -0
  59. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/phone.svg +1 -0
  60. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/share.svg +3 -0
  61. data/spec/examples/json.northpole.ro/public/app/src/assets/svg/twitter.svg +1 -0
  62. data/spec/examples/json.northpole.ro/public/app/src/css/app.css +138 -0
  63. data/spec/examples/json.northpole.ro/public/app/src/css/app.css.map +7 -0
  64. data/spec/examples/json.northpole.ro/public/app/src/css/app.sass +145 -0
  65. data/spec/examples/json.northpole.ro/public/app/src/index.html +157 -0
  66. data/spec/examples/json.northpole.ro/public/app/src/js/MainController.coffee +167 -0
  67. data/spec/examples/json.northpole.ro/public/app/src/js/app.coffee +58 -0
  68. data/spec/examples/json.northpole.ro/public/app/src/js/blobs/BlobsController.coffee +115 -0
  69. data/spec/examples/json.northpole.ro/public/app/src/js/blobs/blobs.html +48 -0
  70. data/spec/examples/json.northpole.ro/public/app/src/js/tutorial/tutorial.html +15 -0
  71. data/spec/examples/json.northpole.ro/public/app/src/js/users/UserService.coffee +12 -0
  72. data/spec/examples/json.northpole.ro/public/app/src/js/users/Users.coffee +1 -0
  73. data/spec/examples/json.northpole.ro/public/app/src/js/users/users.html +8 -0
  74. data/spec/examples/json.northpole.ro/public/javascripts/jnorthpole.coffee +40 -7
  75. data/spec/examples/json.northpole.ro/public/javascripts/realtime.coffee +28 -0
  76. data/spec/examples/json.northpole.ro/public/{javascripts/music → music}/angular-youtube-embed.js +0 -0
  77. data/spec/examples/json.northpole.ro/public/music/index.html +126 -0
  78. data/spec/examples/json.northpole.ro/public/music/music.coffee +99 -0
  79. data/spec/examples/json.northpole.ro/public/music/music.sass +63 -0
  80. data/spec/examples/json.northpole.ro/public/stylesheets/app.sass +3 -0
  81. data/spec/examples/json.northpole.ro/views/faq.haml +7 -0
  82. data/spec/examples/json.northpole.ro/views/layout.haml +1 -0
  83. data/spec/examples/json.northpole.ro/views/music.haml +2 -0
  84. data/spec/examples/json.northpole.ro/views/websocket.haml +7 -0
  85. data/spec/lib/ki/channel_manager_spec.rb +82 -0
  86. data/spec/lib/ki/helpers_spec.rb +11 -0
  87. data/spec/lib/ki/ki_config_spec.rb +28 -0
  88. data/spec/lib/ki/middleware/admin_generator_spec.rb +8 -0
  89. data/spec/lib/ki/middleware/init_middleware_spec.rb +21 -0
  90. data/spec/lib/ki/middleware/realtime_spec.rb +96 -0
  91. data/spec/lib/ki/model_spec.rb +28 -7
  92. data/spec/lib/ki/modules/model_helper_spec.rb +31 -0
  93. data/spec/lib/ki/orm_spec.rb +26 -0
  94. metadata +211 -9
  95. data/spec/examples/json.northpole.ro/public/javascripts/docs.min.js +0 -16
  96. data/spec/examples/json.northpole.ro/views/awsum.haml +0 -108
@@ -0,0 +1,167 @@
1
+ DialogController = ($scope, $mdDialog, $localStorage, $mdToast) ->
2
+ # $scope.user =
3
+ # api_key: 'guest'
4
+ # secret: 'guest'
5
+
6
+ $scope.hide = ->
7
+ $mdDialog.hide()
8
+ return
9
+
10
+ $scope.cancel = ->
11
+ $mdDialog.cancel()
12
+ return
13
+
14
+ $scope.showToast = (s) ->
15
+ toast = $mdToast.simple().content(s).position('bottom right').hideDelay(3000)
16
+ $mdToast.show toast
17
+
18
+ apiError = (error) ->
19
+ console.log error
20
+ $scope.showToast error.error
21
+
22
+ userFound = (json) ->
23
+ $localStorage.accounts.push
24
+ api_key: json.api_key
25
+ secret: json.secret
26
+ $mdDialog.hide 'refresh'
27
+
28
+ $scope.register = () ->
29
+ jNorthPole.createUser($scope.user.api_key, $scope.user.secret, userFound, apiError)
30
+ return
31
+
32
+ $scope.connect = () ->
33
+ jNorthPole.getUser($scope.user, (data) ->
34
+ json = data[0]
35
+ exists = (item for item in $localStorage.accounts when item.api_key == json.api_key)
36
+ if exists.length == 0
37
+ userFound(json)
38
+ else
39
+ $scope.showToast "account already connected"
40
+ console.log "account already connected"
41
+ , apiError)
42
+ return
43
+
44
+ return
45
+
46
+ MainController = ($scope, userService, $mdSidenav, $mdBottomSheet, $log, $q, $mdDialog, $localStorage, $location, $mdToast) ->
47
+ self = this
48
+
49
+ toggleList = ->
50
+ pending = $mdBottomSheet.hide() or $q.when(true)
51
+ pending.then ->
52
+ $mdSidenav('left').toggle()
53
+ return
54
+ return
55
+
56
+ selectUser = (user) ->
57
+ $localStorage.selected = angular.copy(user)
58
+ $location.path "/blobs/#{user.api_key}"
59
+ self.toggleList()
60
+ refresh()
61
+ return
62
+
63
+ $scope.showToast = (s) ->
64
+ toast = $mdToast.simple().content(s).position('bottom right').hideDelay(3000)
65
+ $mdToast.show toast
66
+
67
+ $scope.fortune = ->
68
+ # http://www.chinese-fortune-cookie.com/fortune-cookie-quotes.html
69
+ fortunes = [
70
+ 'There is a true and sincere friendship between you and your friends.'
71
+ 'You find beauty in ordinary things, do not lose this ability.'
72
+ 'Ideas are like children; there are none so wonderful as your own.'
73
+ 'It takes more than good memory to have good memories.'
74
+ 'A thrilling time is in your immediate future.'
75
+ 'Your blessing is no more than being safe and sound for the whole lifetime.'
76
+ 'Plan for many pleasures ahead.'
77
+ 'The joyfulness of a man prolongeth his days.'
78
+ 'Your everlasting patience will be rewarded sooner or later.'
79
+ 'Make two grins grow where there was only a grouch before.'
80
+ 'Something you lost will soon turn up.'
81
+ 'Your heart is pure, and your mind clear, and your soul devout.'
82
+ 'Excitement and intrigue follow you closely wherever you go!'
83
+ 'A pleasant surprise is in store for you.'
84
+ 'May life throw you a pleasant curve.'
85
+ 'As the purse is emptied the heart is filled.'
86
+ 'Be mischievous and you will not be lonesome.'
87
+ 'You have a deep appreciation of the arts and music.'
88
+ 'Your flair for the creative takes an important place in your life.'
89
+ 'Your artistic talents win the approval and applause of others.'
90
+ 'Pray for what you want, but work for the things you need.'
91
+ 'Your many hidden talents will become obvious to those around you.'
92
+ 'Don\'t forget, you are always on our minds.'
93
+ 'Your greatest fortune is the large number of friends you have.'
94
+ 'A firm friendship will prove the foundation on your success in life.'
95
+ 'Don\'t ask, don\'t say. Everything lies in silence.'
96
+ 'Look for new outlets for your own creative abilities.'
97
+ 'Be prepared to accept a wondrous opportunity in the days ahead!'
98
+ 'Fame, riches and romance are yours for the asking.'
99
+ 'Good luck is the result of good planning.'
100
+ 'Good things are being said about you.'
101
+ 'Smiling often can make you look and feel younger.'
102
+ 'Someone is speaking well of you.'
103
+ 'The time is right to make new friends.'
104
+ 'You will inherit some money or a small piece of land.'
105
+ 'Your life will be happy and peaceful.'
106
+ 'A friend is a present you give yourself.'
107
+ 'A member of your family will soon do something that will make you proud.'
108
+ 'A quiet evening with friends is the best tonic for a long day.'
109
+ 'A single kind word will keep one warm for years.'
110
+ 'Anger begins with folly, and ends with regret.'
111
+ 'Generosity and perfection are your everlasting goals.'
112
+ 'Happy news is on its way to you.'
113
+ 'He who laughs at himself never runs out of things to laugh at.'
114
+ 'If your desires are not extravagant they will be granted.'
115
+ 'Let there be magic in your smile and firmness in your handshake.'
116
+ 'If you want the rainbow, you must to put up with the rain. D. Parton'
117
+ 'Nature, time and patience are the three best physicians.'
118
+ 'Strong and bitter words indicate a weak cause.'
119
+ 'The beginning of wisdom is to desire it.'
120
+ 'You will have a very pleasant experience.'
121
+ 'You will inherit some money or a small piece of land.'
122
+ 'You will live a long, happy life.'
123
+ 'You will spend old age in comfort and material wealth.'
124
+ 'You will step on the soil of many countries.'
125
+ 'You will take a chance in something in the near future.'
126
+ 'You will witness a special ceremony.'
127
+ 'Your everlasting patience will be rewarded sooner or later.'
128
+ 'Your great attention to detail is both a blessing and a curse.'
129
+ 'Your heart is a place to draw true happiness.'
130
+ 'Your ability to juggle many tasks will take you far.'
131
+ 'A friend asks only for your time, not your money.'
132
+ 'You will be invited to an exciting event.'
133
+ ]
134
+ $scope.showToast(fortunes[Math.floor(Math.random()*fortunes.length)])
135
+
136
+ showAdvanced = (ev) ->
137
+ $mdDialog.show(
138
+ controller: DialogController
139
+ templateUrl: 'js/templates/dialog1.tmpl.html'
140
+ parent: angular.element(document.body)
141
+ targetEvent: ev
142
+ clickOutsideToClose: true)
143
+ .then ((answer) ->
144
+ refresh() if answer == 'refresh'
145
+ return
146
+ ), ->
147
+ # $scope.status = 'You cancelled the dialog.'
148
+ return
149
+ return
150
+
151
+
152
+ self.selected = null
153
+ self.users = []
154
+ self.selectUser = selectUser
155
+ self.toggleList = toggleList
156
+ self.showAdvanced = showAdvanced
157
+
158
+ refresh = ->
159
+ userService.loadAllUsers().then (users) ->
160
+ self.users = [].concat(users)
161
+ $scope.user = $localStorage.selected if $localStorage.selected?
162
+ return
163
+
164
+ refresh()
165
+ return
166
+
167
+ angular.module('app').controller 'MainController', ['$scope', 'userService', '$mdSidenav', '$mdBottomSheet', '$log', '$q', '$mdDialog', '$localStorage', '$location', '$mdToast', MainController]
@@ -0,0 +1,58 @@
1
+ app = angular.module('app', ['ngRoute', 'ngStorage', 'ngMaterial', 'users'])
2
+
3
+ app.constant("myConfig",
4
+ title: 'mango {fruit}'
5
+ )
6
+
7
+ app.config ['$mdThemingProvider', '$mdIconProvider', ($mdThemingProvider, $mdIconProvider) ->
8
+ $mdIconProvider
9
+ .defaultIconSet('./assets/svg/avatars.svg', 128)
10
+ .icon('menu', './assets/svg/menu.svg', 24)
11
+ .icon('share', './assets/svg/share.svg', 24)
12
+ .icon('google_plus', './assets/svg/google_plus.svg', 512)
13
+ .icon('hangouts', './assets/svg/hangouts.svg', 512)
14
+ .icon('twitter', './assets/svg/twitter.svg', 512)
15
+ .icon('phone', './assets/svg/phone.svg', 512)
16
+ .icon('person_add', './assets/svg/ic_person_add_48px.svg', 48)
17
+ .icon('clear', './assets/svg/ic_clear_48px.svg', 48)
18
+ .icon('plus', './assets/svg/ic_add_48px.svg', 48)
19
+ .icon('cog', './assets/svg/ic_settings_48px.svg', 48)
20
+ .icon('delete', './assets/svg/ic_delete_48px.svg', 48)
21
+ .icon('lock', './assets/svg/ic_lock_48px.svg', 48)
22
+ .icon('share', './assets/svg/ic_share_48px.svg', 48)
23
+ .icon('music', './assets/svg/ic_music_note_48px.svg', 48)
24
+ .icon('note_add', './assets/svg/ic_note_add_48px.svg', 48)
25
+ .icon('fullscreen', './assets/svg/ic_fullscreen_48px.svg', 48)
26
+ .icon('fullscreen_exit', './assets/svg/ic_fullscreen_exit_48px.svg', 48)
27
+
28
+ $mdThemingProvider
29
+ .theme('default')
30
+ .primaryPalette('deep-orange')
31
+ .accentPalette('blue')
32
+ .warnPalette('red')
33
+ .backgroundPalette('grey')
34
+ # .dark()
35
+
36
+ return
37
+ ]
38
+
39
+ app.config ['$routeProvider', ($routeProvider) ->
40
+ $routeProvider
41
+ .when('/tutorial', templateUrl: 'js/tutorial/tutorial.html')
42
+ .when('/blobs', templateUrl: 'js/blobs/blobs.html', controller: 'BlobsController')
43
+ .when('/blobs/:id', templateUrl: 'js/blobs/blobs.html', controller: 'BlobsController')
44
+ .otherwise(redirectTo: '/blobs')
45
+ return
46
+ ]
47
+
48
+ app.config(['$localStorageProvider', ($localStorageProvider) ->
49
+ # $localStorageProvider.get('MyKey');
50
+ # $localStorageProvider.set('MyKey', { k: 'value' });
51
+
52
+ $localStorageProvider.setKeyPrefix 'app'
53
+ return
54
+ ])
55
+
56
+ app.run ($rootScope, myConfig) ->
57
+ $rootScope.myConfig = myConfig
58
+ return
@@ -0,0 +1,115 @@
1
+ BlobsController = ($scope, $routeParams, $location, $localStorage, $mdBottomSheet) ->
2
+ if !$routeParams.id? and $localStorage.selected?
3
+ $location.path "/blobs/#{$localStorage.selected.api_key}"
4
+ return
5
+
6
+ $scope.fullItem = null
7
+
8
+ if $routeParams.id?
9
+ unless $localStorage.selected?
10
+ $location.path '/blobs'
11
+ return
12
+
13
+ $scope.user = $localStorage.selected
14
+ jNorthPole.getStorage($scope.user, (data) ->
15
+ $scope.items = data.reverse()
16
+ $scope.$apply()
17
+ , (error) ->
18
+ console.log error
19
+ )
20
+ else
21
+ $location.path '/tutorial'
22
+ return
23
+
24
+ $scope.delete = (item) ->
25
+ item = angular.copy(item)
26
+ item.secret = $scope.user.secret
27
+
28
+ jNorthPole.deleteStorage(item, (data) ->
29
+ for r in $scope.items
30
+ if r.id == item.id
31
+ $scope.items.splice $scope.items.indexOf(r), 1
32
+ break
33
+ $scope.$apply()
34
+ , (error) ->
35
+ console.log error
36
+ )
37
+ return
38
+
39
+ $scope.addItemToList = (item, s) ->
40
+ return if s == ''
41
+ item.list = [] unless item.list?
42
+ item.list.push { checked: false, text: s }
43
+ $scope.save(item)
44
+
45
+ $scope.removeItemFromList = (item, listItem) ->
46
+ index = item.list.indexOf(listItem)
47
+ item.list.splice(index, 1)
48
+ $scope.save(item)
49
+
50
+ $scope.fullscreen = (item) ->
51
+ if $scope.fullItem?
52
+ $scope.fullItem = null
53
+ else
54
+ $scope.fullItem = item
55
+
56
+ $scope.toggleType = (item) ->
57
+ if item.type == 'list'
58
+ item.type = 'text'
59
+ else
60
+ item.type = 'list'
61
+ $scope.save(item)
62
+
63
+ $scope.save = (item) ->
64
+ item = angular.copy(item)
65
+ item.api_key = $scope.user.api_key
66
+ item.secret = $scope.user.secret
67
+
68
+ callback = (data) ->
69
+ console.log data
70
+
71
+ if item.id?
72
+ jNorthPole.putStorage(item, callback)
73
+ else
74
+ jNorthPole.createStorage(item, (data) ->
75
+ $scope.items.unshift data
76
+ $scope.$apply()
77
+ , callback)
78
+
79
+ $scope.newPanel = ->
80
+ $scope.save(text: '')
81
+
82
+ $scope.showContactOptions = ($event, json) ->
83
+ json = angular.copy(json)
84
+
85
+ ContactPanelController = ($mdBottomSheet, $scope) ->
86
+ @json = json
87
+ @actions = [
88
+ {
89
+ name: 'Yes, delete already'
90
+ icon: 'delete'
91
+ }
92
+ ]
93
+
94
+ @submitContact = (action) ->
95
+ $mdBottomSheet.hide action
96
+ return
97
+
98
+ return
99
+
100
+ $mdBottomSheet
101
+ .show(
102
+ parent: angular.element(document.body)
103
+ templateUrl: './js/templates/contactSheet.html'
104
+ controller: ['$mdBottomSheet', '$scope', ContactPanelController]
105
+ controllerAs: 'cp'
106
+ bindToController: true
107
+ targetEvent: $event)
108
+ .then (clickedItem) ->
109
+ if clickedItem.icon == 'delete'
110
+ $scope.delete(json)
111
+ return
112
+
113
+ return
114
+
115
+ angular.module('users').controller 'BlobsController', ['$scope', '$routeParams', '$location', '$localStorage', '$mdBottomSheet', BlobsController]
@@ -0,0 +1,48 @@
1
+ <md-content flex layout="row" layout-align="center">
2
+ <md-content flex style="padding-bottom: 100px">
3
+ <md-card ng-repeat="item in items" class="repeat-item" ng-show="!fullItem || (fullItem && fullItem.id == item.id)">
4
+ <md-card-content>
5
+ <div layout="row" layout-wrap>
6
+ <md-input-container flex ng-show="item.type == 'list'">
7
+ <label class="add-new">{{item.text}}</label>
8
+ <input ng-model="newListItemText" ng-change="addItemToList(item, newListItemText); newListItemText = ''" ng-model-options="{ debounce: 1000 }">
9
+ </md-input-container>
10
+ <md-input-container flex ng-show="item.type != 'list'">
11
+ <!-- used for space -->
12
+ </md-input-container>
13
+ <div ng-include="'./js/templates/dropdown.tmpl.html'"></div>
14
+ </div>
15
+ <div layout="row" layout-wrap>
16
+ <md-input-container flex ng-show="item.type != 'list'">
17
+ <label>Text</label>
18
+ <textarea ng-model="item.text" columns="1" md-maxlength="1024" ng-change="save(item)" ng-model-options="{ debounce: 1000 }"></textarea>
19
+ </md-input-container>
20
+
21
+ <md-container flex ng-show="item.type == 'list'">
22
+ <md-container flex ng-repeat="listItem in item.list" class="repeat-item" layout="row">
23
+ <md-checkbox aria-label="Checkbox" ng-model="listItem.checked" ng-change="save(item)" class="md-primary">
24
+ </md-checkbox>
25
+ <md-input-container flex class="small-bot">
26
+ <input aria-label="checkbox text" ng-model="listItem.text" ng-change="save(item)" ng-model-options="{ debounce: 1000 }" ng-class="{ done: listItem.checked }" ng-disabled="listItem.checked">
27
+ </md-input-container>
28
+ <md-button aria-label="delete checkbox item" class="md-icon-button" ng-click="removeItemFromList(item, listItem)">
29
+ <md-icon md-menu-origin md-svg-icon="delete"></md-icon>
30
+ </md-button>
31
+ </md-container>
32
+ </md-container>
33
+ </div>
34
+ </md-card-content>
35
+ </md-card>
36
+ <md-card ng-show="items.length == 0">
37
+ <md-card-content>
38
+ <div layout="column" layout-align="center center" layout-wrap md-swipe-left="fortune()">
39
+ <p><< Swipe left for fortune</p>
40
+ </div>
41
+ </md-card-content>
42
+ </md-card>
43
+ </md-content>
44
+ </md-content>
45
+
46
+ <md-button ng-show="user.api_key" class="md-fab md-primary md-fab-bottom-right" aria-label="Use Android" ng-click="newPanel()">
47
+ <md-icon md-svg-icon="plus"></md-icon>
48
+ </md-button>
@@ -0,0 +1,15 @@
1
+ <md-card>
2
+ <md-card-content>
3
+ <h2 class="md-title">
4
+ Mango The Polar Bear helps you get your &!@^% together.
5
+ </h2>
6
+ <p>With client side encryption</p>
7
+ <p>Of impossible decryption,</p>
8
+ <p>Your ideas and your notes</p>
9
+ <p>Will floats your boats.</p>
10
+ <br />
11
+ <p>
12
+ Data is stored at the <a href="https://json.northpole.ro/">North Pole</a>.
13
+ </p>
14
+ </md-card-content>
15
+ </md-card>
@@ -0,0 +1,12 @@
1
+ UserService = ($q, $localStorage) ->
2
+ unless $localStorage.accounts?
3
+ $localStorage.accounts = []
4
+
5
+ users = $localStorage.accounts
6
+
7
+ {
8
+ loadAllUsers: ->
9
+ $q.when users
10
+ }
11
+
12
+ angular.module('users').service 'userService', ['$q', '$localStorage', UserService]
@@ -0,0 +1 @@
1
+ angular.module 'users', [ 'ngMaterial' ]
@@ -0,0 +1,8 @@
1
+ <md-icon md-svg-icon="{{ul.selected.avatar}}" class="avatar"></md-icon>
2
+ <h2>{{ul.selected.name}}</h2>
3
+ <p>{{ul.selected.content}}</p>
4
+
5
+ <md-button class="contact" md-no-ink ng-click="ul.showContactOptions($event)" aria-label="Contact User">
6
+ <md-tooltip>Contact {{ ul.selected.name }}</md-tooltip>
7
+ <md-icon md-svg-icon="share"></md-icon>
8
+ </md-button>
@@ -1,6 +1,6 @@
1
1
  window.jNorthPole =
2
2
 
3
- BASE_URL: '/'
3
+ BASE_URL: 'https://json.northpole.ro/'
4
4
 
5
5
  help: """
6
6
  NorthPole JS wrapper example usage:
@@ -9,8 +9,11 @@ window.jNorthPole =
9
9
  console.log(data);
10
10
  };
11
11
 
12
- jNorthPole.BASE_URL = '/';
13
12
  jNorthPole.getStorage(json, responseHandler);
13
+
14
+ socket = jNorthPole.getNewRealtimeSocket(responseHandler)
15
+ jNorthPole.subscribe(socket, 'foo')
16
+ jNorthPole.publish(socket, 'foo', { message: 'hello' })
14
17
  """
15
18
 
16
19
  genericRequest: (jsonObj, method, endPoint, responseHandler, errorHandler=responseHandler) ->
@@ -21,7 +24,7 @@ window.jNorthPole =
21
24
 
22
25
  r.onreadystatechange = ->
23
26
  return if r.readyState != 4
24
- if status == 200
27
+ if r.status == 200
25
28
  responseHandler(JSON.parse(r.responseText), r.status)
26
29
  else
27
30
  errorHandler(JSON.parse(r.responseText), r.status)
@@ -34,18 +37,48 @@ window.jNorthPole =
34
37
  @genericRequest(jsonObj, 'POST', 'user', success, failure)
35
38
  return
36
39
 
37
- createStorage: (jsonObj, responseHandler, errorHandler) ->
38
- @genericRequest(jsonObj, 'POST', 'storage', responseHandler, errorHandler)
40
+ getUser: (jsonObj, responseHandler, errorHandler) ->
41
+ @genericRequest(jsonObj, 'SEARCH', 'user', responseHandler, errorHandler)
39
42
  return
40
43
 
41
- putStorage: (jsonObj, responseHandler, errorHandler) ->
42
- @genericRequest(jsonObj, 'PUT', 'storage', responseHandler, errorHandler)
44
+ createStorage: (jsonObj, responseHandler, errorHandler) ->
45
+ @genericRequest(jsonObj, 'POST', 'storage', responseHandler, errorHandler)
43
46
  return
44
47
 
45
48
  getStorage: (jsonObj, responseHandler, errorHandler) ->
46
49
  @genericRequest(jsonObj, 'SEARCH', 'storage', responseHandler, errorHandler)
47
50
  return
48
51
 
52
+ putStorage: (jsonObj, responseHandler, errorHandler) ->
53
+ @genericRequest(jsonObj, 'PUT', 'storage', responseHandler, errorHandler)
54
+ return
55
+
49
56
  deleteStorage: (jsonObj, responseHandler, errorHandler) ->
50
57
  @genericRequest(jsonObj, 'DELETE', 'storage', responseHandler, errorHandler)
51
58
  return
59
+
60
+ getNewRealtimeSocket: (responseHandler, errorHandler=responseHandler) ->
61
+ socketUrl = @BASE_URL.replace('http', 'ws')
62
+ socket = new WebSocket("#{socketUrl}realtime")
63
+ socket.onmessage = responseHandler
64
+ socket.onclose = errorHandler
65
+ socket
66
+
67
+ subscribe: (socket, channel_name) ->
68
+ socket.send(JSON.stringify(
69
+ type: 'subscribe'
70
+ channel_name: channel_name
71
+ ))
72
+
73
+ unsubscribe: (socket, channel_name) ->
74
+ socket.send(JSON.stringify(
75
+ type: 'unsubscribe'
76
+ channel_name: channel_name
77
+ ))
78
+
79
+ publish: (socket, channel_name, json) ->
80
+ socket.send(JSON.stringify(
81
+ type: 'publish'
82
+ channel_name: channel_name
83
+ content: json
84
+ ))