help-anywhere 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +46 -0
  4. data/Rakefile +38 -0
  5. data/app/assets/javascripts/help_anywhere/components/bubble.js.coffee +367 -0
  6. data/app/assets/javascripts/help_anywhere/components/component.js.coffee +10 -0
  7. data/app/assets/javascripts/help_anywhere/help_anywhere.js.coffee +254 -0
  8. data/app/assets/javascripts/help_anywhere/help_anywhere_editor.js.coffee +41 -0
  9. data/app/assets/javascripts/help_anywhere/hooks.js.coffee +28 -0
  10. data/app/assets/javascripts/help_anywhere.js.coffee +2 -0
  11. data/app/assets/javascripts/help_anywhere_core_only.js.coffee +11 -0
  12. data/app/assets/stylesheets/generators/bubble.css.scss +195 -0
  13. data/app/assets/stylesheets/help_anywhere.css.scss +4 -0
  14. data/app/assets/stylesheets/help_anywhere_core_only.css.scss +181 -0
  15. data/app/controllers/help_anywhere/base_controller.rb +10 -0
  16. data/app/controllers/help_anywhere/help_anywhere_controller.rb +5 -0
  17. data/app/controllers/help_anywhere/pages_controller.rb +30 -0
  18. data/app/controllers/help_anywhere/resources_controller.rb +84 -0
  19. data/app/helpers/help_anywhere_helper.rb +5 -0
  20. data/app/models/help_anywhere/item.rb +6 -0
  21. data/app/models/help_anywhere/page.rb +34 -0
  22. data/app/models/help_anywhere/resource.rb +14 -0
  23. data/app/models/help_anywhere.rb +2 -0
  24. data/config/routes.rb +11 -0
  25. data/db/migrate/20130825093318_create_help_anywhere_resources.rb +9 -0
  26. data/db/migrate/20130825093414_create_help_anywhere_pages.rb +11 -0
  27. data/db/migrate/20130825093611_create_help_anywhere_items.rb +19 -0
  28. data/db/migrate/20130927171847_refactor_help_anywhere_items.rb +11 -0
  29. data/lib/help-anywhere/configuration.rb +75 -0
  30. data/lib/help-anywhere/engine.rb +10 -0
  31. data/lib/help-anywhere/version.rb +3 -0
  32. data/lib/help-anywhere.rb +9 -0
  33. data/lib/tasks/help-anywhere_tasks.rake +4 -0
  34. data/test/dummy/README.rdoc +261 -0
  35. data/test/dummy/Rakefile +7 -0
  36. data/test/dummy/app/assets/javascripts/application.js +15 -0
  37. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  38. data/test/dummy/app/controllers/application_controller.rb +3 -0
  39. data/test/dummy/app/helpers/application_helper.rb +2 -0
  40. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  41. data/test/dummy/config/application.rb +59 -0
  42. data/test/dummy/config/boot.rb +10 -0
  43. data/test/dummy/config/database.yml +25 -0
  44. data/test/dummy/config/environment.rb +5 -0
  45. data/test/dummy/config/environments/development.rb +37 -0
  46. data/test/dummy/config/environments/production.rb +67 -0
  47. data/test/dummy/config/environments/test.rb +37 -0
  48. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  49. data/test/dummy/config/initializers/inflections.rb +15 -0
  50. data/test/dummy/config/initializers/mime_types.rb +5 -0
  51. data/test/dummy/config/initializers/secret_token.rb +7 -0
  52. data/test/dummy/config/initializers/session_store.rb +8 -0
  53. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  54. data/test/dummy/config/locales/en.yml +5 -0
  55. data/test/dummy/config/routes.rb +58 -0
  56. data/test/dummy/config.ru +4 -0
  57. data/test/dummy/public/404.html +26 -0
  58. data/test/dummy/public/422.html +26 -0
  59. data/test/dummy/public/500.html +25 -0
  60. data/test/dummy/public/favicon.ico +0 -0
  61. data/test/dummy/script/rails +6 -0
  62. data/test/help-anywhere_test.rb +7 -0
  63. data/test/test_helper.rb +15 -0
  64. metadata +165 -0
@@ -0,0 +1,254 @@
1
+ do($ = jQuery) ->
2
+ HELP_TEMPLATE = (args) ->
3
+ """
4
+ <div id="help-anywhere-widget">
5
+ <div class="ha-std-button" title="Help">?</div>
6
+ </div>
7
+ """
8
+
9
+ HELP_INTERFACE_TEMPLATE = (pages, edit_mode) ->
10
+ """
11
+ <div id="help-anywhere-layout">
12
+ <div class="ha-page-content"></div>
13
+ #{
14
+ if edit_mode
15
+ HELP_INTERFACE_EDIT_MODE(pages)
16
+ else ''
17
+ }
18
+ </div>
19
+ """
20
+
21
+ HELP_INTERFACE_EDIT_MODE = (pages) ->
22
+ """
23
+ <div class="ha-edit-bottom-layout">
24
+ <div class="ha-new-component">
25
+ Add component:
26
+ <select class="ha-add-component">
27
+ #{HELP_SELECT_COMPONENT()}
28
+ </select>
29
+ <input type="button" class="ha-save-btn btn btn-primary" value="Save"></input>
30
+ <input type="button" class="ha-remove-page-btn btn btn-danger" value="Remove page"></input>
31
+ <input type="button" class="ha-exit-btn btn btn-danger" value="Exit"></input>
32
+ </div>
33
+ <div class="ha-page-list">
34
+ #{HELP_INTERFACE_PAGES(pages)}
35
+ </div>
36
+ </div>
37
+ """
38
+
39
+ HELP_SELECT_COMPONENT = ->
40
+ "<option value='' selected='selected'>Select a component</option>" + (
41
+ for k,v of HelpAnywhere.components
42
+ "<option value='#{k}'>#{k}</option>"
43
+ ).join("")
44
+
45
+ HELP_INTERFACE_PAGES = (pages) ->
46
+ (for page, idx in pages
47
+ HELP_INTERFACE_PAGE(idx) ).join('') +
48
+ """
49
+ <div class="ha-new-page">+</div>
50
+ """
51
+
52
+ HELP_INTERFACE_PAGE = (idx) -> """<div class="ha-page" data-idx="#{idx}">#{idx}</div>"""
53
+
54
+ class HelpAnywhere
55
+ @API_URL: "/help_anywhere"
56
+
57
+ @render: ->
58
+ @instance = new HelpAnywhere
59
+ @instance.init()
60
+ @show: (edit_mode=false) ->
61
+ if @instance
62
+ @instance.openHelpInterface(edit_mode)
63
+ return true
64
+ else
65
+ return false
66
+ @hide: ->
67
+ @instance.closeHelpInterface()
68
+ @edit: -> @show(yes)
69
+
70
+ @saveElement: (elm) ->
71
+ for p in @instance.pageList
72
+ for e, idx in p.items
73
+ if e.id is elm.id
74
+ @instance.elementsChanged = true
75
+ p.items[idx].content = elm.getData()
76
+ return
77
+
78
+ @addRoutes: (routes) ->
79
+ @routes = (@routes ? [])
80
+
81
+ if not routes instanceof Array
82
+ routes = [routes]
83
+
84
+ for [regexp, value] in routes
85
+ regexp = '^' +
86
+ regexp
87
+ .replace('/', '\\/')
88
+ .replace('.', '\\.')
89
+ .replace('**', '.*')
90
+ .replace('*', '[^\\/]*')
91
+ .replace('??', '(.*)')
92
+ .replace('?', '([^\\/]*)') + '$'
93
+ @routes.push [new RegExp(regexp), value]
94
+
95
+ @deleteItem: (elm) ->
96
+ for p in @instance.pageList
97
+ for e, idx in p.items
98
+ if e.id is elm.id
99
+ p.items.splice(idx, 1)
100
+ elm.remove()
101
+ return true
102
+
103
+ selectRoute: (path) ->
104
+ for [regexp, value] in HelpAnywhere.routes
105
+ return path.replace(regexp, value) if regexp.test(path)
106
+
107
+ return false
108
+
109
+ elementsChanged: false
110
+
111
+ init: ->
112
+ @fixBody()
113
+ @retrieveResource()
114
+
115
+ fixBody: ->
116
+ $("body").css
117
+ position: "absolute"
118
+ left: 0
119
+ top: 0
120
+ "min-width": "100%"
121
+ "min-height": "100%"
122
+ margin: 0
123
+
124
+ buildInterface: ->
125
+ unless @help?
126
+ @help = $(HELP_TEMPLATE())
127
+ @help.find('.ha-std-button').on 'click', =>
128
+ @openHelpInterface()
129
+ @help.css(display: 'block', opacity: '0')
130
+ .animate(opacity: '1', 2000)
131
+ .appendTo($('body'))
132
+
133
+ showPage: (pageIndex) ->
134
+ @helpInterface.find('.ha-page-content').empty()
135
+
136
+ @helpInterface.find('.ha-page').removeClass('selected')
137
+ @helpInterface.find(".ha-page:nth-child(#{Number(pageIndex)+1})").addClass('selected')
138
+
139
+ items = @pageList[pageIndex].items
140
+
141
+ for item in items
142
+ g = new HelpAnywhere.components[item.class_id]()
143
+ g.id = item.id
144
+ g.class_id = item.class_id
145
+ g.load(item.content)
146
+
147
+ @helpInterface.find('.ha-page-content').append(g.build(@edit_mode))
148
+
149
+ movePage: (fromIndex, toIndex) ->
150
+ #Magic coffee <3
151
+ [@pageList[fromIndex], @pageList[toIndex]] = [@pageList[toIndex], @pageList[fromIndex]]
152
+ @currentPage = toIndex
153
+ @showPage(@currentPage) #Refreshing interface for edition mode
154
+
155
+
156
+ deletePage: ->
157
+ pageIndex = Number(@helpInterface.find('.ha-page.selected').remove().attr('data-idx'))
158
+ @pageList.splice(pageIndex, 1)
159
+
160
+ #Refreshing the indices
161
+ for page, idx in @helpInterface.find('.ha-page')
162
+ $(page).text(idx).attr('data-idx', idx)
163
+
164
+ @currentPage = pageIndex - 1
165
+
166
+ if @currentPage < 0
167
+ @currentPage = 0
168
+
169
+ if @pageList.length > 0
170
+ @showPage(@currentPage)
171
+
172
+ createNewPage: ->
173
+ @pageList.push items: [], number: @pageList[@pageList.length-1].number+1
174
+
175
+ newPage = $(HELP_INTERFACE_PAGE(@pageList.length-1))
176
+ newPage.insertBefore(@helpInterface.find('.ha-new-page'))
177
+ newPage.on 'click', =>
178
+ @currentPage = newPage.attr('data-idx')
179
+ @showPage(@currentPage)
180
+ @showPage(newPage.attr('data-idx'))
181
+
182
+ temporaryId: (pageIndex) ->
183
+ @_uid ?= 0
184
+ return "_#{@_uid++}" #Temporary ids are discriminated by adding underscore before.
185
+
186
+ createNewComponent: (pageIndex, componentClass) ->
187
+ if componentClass? and componentClass isnt ''
188
+ component = new HelpAnywhere.components[componentClass]()
189
+ @helpInterface.find('.ha-page-content').append(component.build(@edit_mode))
190
+
191
+ component.class_id = componentClass
192
+ component.id = @temporaryId()
193
+
194
+ @pageList[pageIndex].items.push {id: component.id, class_id: componentClass}
195
+ closeHelpInterface: ->
196
+ if @elementsChanged
197
+ return unless confirm("Are you sure? All changes will be losts...")
198
+ @helpInterface.remove()
199
+ @helpInterface = null
200
+
201
+ openHelpInterface: (@edit_mode=false)->
202
+ @helpInterface ?= $ HELP_INTERFACE_TEMPLATE(@pageList, @edit_mode)
203
+ @helpInterface.appendTo($("body"))
204
+ @currentPage = 0
205
+ self = this
206
+
207
+ unless @edit_mode
208
+ @helpInterface.on 'click', =>
209
+ @currentPage += 1
210
+
211
+ if @currentPage >= @pageList.length
212
+ @helpInterface.remove()
213
+ @helpInterface = null
214
+ else
215
+ @showPage(@currentPage)
216
+ else
217
+ @helpInterface.on 'click', -> HelpAnywhereEditor.focus(null)
218
+ @helpInterface.find('.ha-page').on 'click', ->
219
+ self.currentPage = $(this).attr('data-idx')
220
+ self.showPage(self.currentPage)
221
+ @helpInterface.find(".ha-new-page").on 'click', ->
222
+ self.createNewPage()
223
+ @helpInterface.find('.ha-add-component').on 'change', ->
224
+ self.createNewComponent(self.currentPage, $(this).val())
225
+ $(this).val('')
226
+ @helpInterface.find('.ha-save-btn').on 'click', @saveHelp.bind(@)
227
+ @helpInterface.find('.ha-exit-btn').on 'click', @closeHelpInterface.bind(@)
228
+
229
+ @helpInterface.find('.ha-remove-page-btn').on 'click', @deletePage.bind(@)
230
+
231
+ @showPage(@currentPage)
232
+
233
+ saveHelp: ->
234
+ $.post("#{HelpAnywhere.API_URL}/resources/save?name=#{@resource}", content: JSON.stringify(@pageList))
235
+ .success =>
236
+ @elementsChanged = false
237
+ .error =>
238
+ alert('Sorry, but something went wrong')
239
+
240
+ retrieveResource: (resource) ->
241
+ @resource = resource || @selectRoute window.location.pathname
242
+
243
+ if @help?
244
+ @help.css(display: 'none')
245
+
246
+
247
+ if @resource
248
+ $.get("#{HelpAnywhere.API_URL}/resources/?name=#{@resource}").success (data) =>
249
+ if data.pages? and data.pages.length > 0
250
+ @pageList = data.pages
251
+ @buildInterface()
252
+
253
+ window.HelpAnywhere = HelpAnywhere
254
+ window.HelpAnywhere.components = {}
@@ -0,0 +1,41 @@
1
+ do($ = jQuery) ->
2
+ current_mouse_move_target = null
3
+ hook_enabled = true
4
+
5
+ HelpAnywhereEditor =
6
+ focus: (elm) ->
7
+ @focused?.blur?()
8
+ @focused = elm
9
+ render: ->
10
+ @hook()
11
+ hook: ->
12
+ @hook_mouse_move()
13
+ @hook_mouse_click()
14
+ hook_mouse_move: ->
15
+ $('body').mousemove (evt) ->
16
+ return unless hook_enabled
17
+
18
+ $(current_mouse_move_target).removeClass('ha-hover')
19
+
20
+ id = $(evt.target).attr('id')
21
+
22
+ if id? and id isnt ''
23
+ $(evt.target).addClass('ha-hover')
24
+ current_mouse_move_target = evt.target
25
+ else
26
+ nearest_identifiable = do ->
27
+ parents = $(evt.target).parents()
28
+ console.log parents.toArray().map((x) -> $(x).attr('id')).join(', ')
29
+ for ancestor in parents
30
+ ancestor_id = $(ancestor).attr('id')
31
+ if ancestor_id? and id isnt ''
32
+ return ancestor
33
+ return null
34
+ $(nearest_identifiable).addClass('ha-hover')
35
+ current_mouse_move_target = nearest_identifiable
36
+
37
+ hook_mouse_click: ->
38
+ $('body').mousemove (evt) ->
39
+ return unless hook_enabled
40
+
41
+ window.HelpAnywhereEditor = HelpAnywhereEditor
@@ -0,0 +1,28 @@
1
+ #TODO
2
+ jQuery ($) ->
3
+
4
+ current_mouse_move_target = null
5
+
6
+ $('html, body').mousemove (evt) ->
7
+ return unless HelpAnywhereEditor.hook_enabled
8
+
9
+ $(current_mouse_move_target).removeClass('ha-hover')
10
+
11
+ id = $(evt.target).attr('id')
12
+
13
+ if id? and id isnt ''
14
+ $(evt.target).addClass('ha-hover')
15
+ current_mouse_move_target = evt.target
16
+ else
17
+ nearest_identifiable = do ->
18
+ parents = $(evt.target).parents()
19
+ for ancestor in parents
20
+ ancestor_id = $(ancestor).attr('id')
21
+ if ancestor_id? and id isnt ''
22
+ return ancestor
23
+ return null
24
+
25
+ $('html, body').click (evt) ->
26
+ return unless HelpAnywhereEditor.hook_enabled
27
+
28
+
@@ -0,0 +1,2 @@
1
+ #= require help_anywhere_core_only
2
+ #= require help_anywhere/components/bubble
@@ -0,0 +1,11 @@
1
+ #
2
+ # This is the entry point for help_anywhere plugin
3
+ #
4
+ #
5
+ #= require help_anywhere/help_anywhere
6
+ #= require help_anywhere/help_anywhere_editor
7
+ #= require help_anywhere/components/component
8
+ jQuery ($) ->
9
+ $.get('/help_anywhere/routes').success (data)->
10
+ HelpAnywhere.addRoutes(data)
11
+ HelpAnywhere.render()
@@ -0,0 +1,195 @@
1
+ .ha-bubble-box {
2
+ -webkit-touch-callout: none;
3
+ -webkit-user-select: none;
4
+ -khtml-user-select: none;
5
+ -moz-user-select: none;
6
+ -ms-user-select: none;
7
+ user-select: none;
8
+
9
+ padding: 10px;
10
+ background-color: white;
11
+ border-radius: 12px;
12
+ border: solid 3px black;
13
+ box-shadow: 4px 4px 9px rgba(0,0,0,0.3);
14
+ position: absolute;
15
+ display: block;
16
+ width: 100px;
17
+
18
+ .ha-bubble-anchor {
19
+ position: absolute;
20
+ display: none;
21
+ width: 6px;
22
+ height: 6px;
23
+
24
+ border: dotted 2px blue;
25
+ margin: -4px;
26
+
27
+ cursor: pointer;
28
+
29
+ &:hover {
30
+ border: solid 2px blue;
31
+ background-color: white;
32
+ }
33
+
34
+ &.x {
35
+ border: solid 2px blue;
36
+ border-radius: 50%;
37
+ left: 50%; top: 50%;
38
+ cursor: move;
39
+ }
40
+
41
+ &.nw {
42
+ top: 0%; left: 0%;
43
+ cursor: nw-resize;
44
+ }
45
+ &.n {
46
+ top: 0%; left: 50%;
47
+ cursor: n-resize;
48
+ }
49
+
50
+ &.ne {
51
+ top: 0; left: 100%;
52
+ cursor: ne-resize;
53
+ }
54
+
55
+ &.e {
56
+ top: 50%; left: 100%;
57
+ }
58
+
59
+ &.se {
60
+ top: 100%; left: 100%;
61
+ cursor: se-resize;
62
+ }
63
+
64
+ &.s {
65
+ top: 100%; left: 50%;
66
+ cursor: s-resize;
67
+ }
68
+
69
+ &.sw {
70
+ top: 100%; left: 0%;
71
+ cursor: sw-resize;
72
+ }
73
+
74
+ &.w {
75
+ top: 50%; left: 0%;
76
+ cursor: w-resize;
77
+ }
78
+ }
79
+
80
+ .ha-bubble-content {
81
+ &:focus {
82
+ -webkit-touch-callout: auto;
83
+ -webkit-user-select: auto;
84
+ -khtml-user-select: auto;
85
+ -moz-user-select: auto;
86
+ -ms-user-select: auto;
87
+ user-select: auto;
88
+ text-align: left;
89
+ }
90
+
91
+ text-align: justify;
92
+ padding: 0;
93
+ margin: 0;
94
+ }
95
+
96
+ .ha-bubble-edit-box {
97
+ display: none;
98
+ background-color: #333;
99
+ color: white;
100
+
101
+ width: 175px;
102
+ height: auto;
103
+ padding: 5px;
104
+
105
+ position: absolute;
106
+ margin-left: 10px;
107
+ top: 0;
108
+ left: 100%;
109
+ z-index: 1;
110
+
111
+
112
+ opacity: 0.8;
113
+
114
+ transition: opacity ease-in-out 0.3s;
115
+ -moz-transition: opacity ease-in-out 0.3s;
116
+ -o-transition: opacity ease-in-out 0.3s;
117
+ -webkit-transition: opacity ease-in-out 0.3s;
118
+ -ms-transition: opacity ease-in-out 0.3s;
119
+
120
+ &:hover {
121
+ opacity: 1;
122
+ }
123
+
124
+ select, input {
125
+ width: 100%;
126
+ }
127
+
128
+ input {
129
+ border: solid 1px #EEE;
130
+ }
131
+ }
132
+
133
+ .ha-bubble-pointer {
134
+ position: absolute;
135
+
136
+ width: 15px;
137
+ height: 15px;
138
+ background-color: white;
139
+
140
+ -webkit-transform: rotate(-45deg);
141
+ -moz-transform: rotate(-45deg);
142
+ -o-transform: rotate(-45deg);
143
+ -ms-transform: rotate(-45deg);
144
+ transform: rotate(-45deg);
145
+
146
+ /*
147
+ * Note: right, left, bottom and top refer at the position
148
+ * of the target element, not the pointer itself.
149
+ */
150
+ &.pointer-right {
151
+ border-top: solid 3px black;
152
+ border-left: solid 3px black;
153
+
154
+ margin-top: -9px;
155
+ margin-left: -11px;
156
+
157
+
158
+ top: 50%;
159
+ left: 0;
160
+ }
161
+
162
+ &.pointer-left {
163
+ border-bottom: solid 3px black;
164
+ border-right: solid 3px black;
165
+
166
+ margin-top: -9px;
167
+ margin-right: -11px;
168
+
169
+ top: 50%;
170
+ right: 0;
171
+ }
172
+
173
+ &.pointer-bottom {
174
+ border-top: solid 3px black;
175
+ border-right: solid 3px black;
176
+
177
+ margin-top: -11px;
178
+ margin-left: -9px;
179
+
180
+ top: 0;
181
+ left: 50%;
182
+ }
183
+
184
+ &.pointer-top {
185
+ border-bottom: solid 3px black;
186
+ border-left: solid 3px black;
187
+
188
+ margin-bottom: -11px;
189
+ margin-left: -9px;
190
+
191
+ bottom: 0;
192
+ left: 50%;
193
+ }
194
+ }
195
+ }
@@ -0,0 +1,4 @@
1
+ /*
2
+ *=require help_anywhere_core_only
3
+ *=require generators/bubble
4
+ */