fanforce-plugin-factory 2.0.0.rc23 → 2.0.0.rc24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_directives.scss +1 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_layers.coffee +103 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_search_engine.coffee +278 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_typeahead.coffee +86 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_typeahead.scss +78 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/arrow.png +0 -0
- data/lib/fanforce/plugin_factory/directive_views/typeahead.haml +37 -0
- data/lib/fanforce/plugin_factory/version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6005745eca81beede74f73809cde2b98b7565f8d
|
4
|
+
data.tar.gz: b6e59a56b54d2969ad253648cc569a5e90d46694
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c07856ea8ab3aadb691a0b41f27e83d1f774fcbe8ff978ddab3b15fcd8cb6e062ee2aa1cfc1aa22bd756c0b0c194f0fbb5047b89f30c48cf9ad268656fcc4b9
|
7
|
+
data.tar.gz: 9744bf1ffa9026f067a298f67cf4e6e60d4cbc366fea57d27bff55c5411036c116a60b11efe502c3f0fa36b159eb2a1a061886044e572e42886e2190d6d402b2
|
@@ -9,4 +9,5 @@
|
|
9
9
|
@import 'plugin_factory/directives/page/page';
|
10
10
|
@import 'plugin_factory/directives/saving-to-server/saving-to-server';
|
11
11
|
@import 'plugin_factory/directives/start-arrow/start-arrow';
|
12
|
+
@import 'plugin_factory/directives/typeahead/typeahead';
|
12
13
|
@import 'plugin_factory/directives/video-thumbnail/video-thumbnail';
|
data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_layers.coffee
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
$q = null
|
2
|
+
|
3
|
+
LAYERS = []
|
4
|
+
LAYERS_BY_ID = {}
|
5
|
+
CALLBACKS = {}
|
6
|
+
INSTANCE = {}
|
7
|
+
|
8
|
+
App.factory('Layers', ['$q',(q)->
|
9
|
+
$q = q
|
10
|
+
|
11
|
+
createId = (->
|
12
|
+
possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
13
|
+
_id = ''
|
14
|
+
_id += possible.charAt(Math.floor(Math.random() * possible.length)) for i in [0..20]
|
15
|
+
return _id
|
16
|
+
)
|
17
|
+
|
18
|
+
addLayer = (($element, should_fade_body)->
|
19
|
+
_id = createId()
|
20
|
+
layer = {
|
21
|
+
_id: _id,
|
22
|
+
$element: $element,
|
23
|
+
onRemove: ((callback)->
|
24
|
+
addLayerCallback(_id, callback)
|
25
|
+
return layer
|
26
|
+
)
|
27
|
+
remove: ((args...)->
|
28
|
+
removeLayer(_id, args...)
|
29
|
+
return layer
|
30
|
+
)
|
31
|
+
should_fade_body: should_fade_body
|
32
|
+
}
|
33
|
+
setTimeout(-> finishAddLayer(layer))
|
34
|
+
return layer
|
35
|
+
)
|
36
|
+
|
37
|
+
addLayerCallback = ((_id, callback)->
|
38
|
+
CALLBACKS[_id] ||= []
|
39
|
+
CALLBACKS[_id].push(callback) if callback
|
40
|
+
)
|
41
|
+
|
42
|
+
finishAddLayer = ((layer)->
|
43
|
+
LAYERS.unshift(layer)
|
44
|
+
LAYERS_BY_ID[layer._id] = layer
|
45
|
+
$('body').addClass('locked-scroll') if layer.should_fade_body
|
46
|
+
layer.$element.attr('is-active-layer', 'true')
|
47
|
+
)
|
48
|
+
|
49
|
+
removeLayer = ((_id, args...)->
|
50
|
+
layer = LAYERS_BY_ID[_id]
|
51
|
+
return if !layer
|
52
|
+
callbacks = CALLBACKS[_id] || []
|
53
|
+
callback(args...) for callback in callbacks
|
54
|
+
delete CALLBACKS[_id]
|
55
|
+
delete LAYERS_BY_ID[_id]
|
56
|
+
for layer, i in LAYERS
|
57
|
+
return if layer._id != _id
|
58
|
+
layer_i_to_remove = i
|
59
|
+
break
|
60
|
+
LAYERS.splice(layer_i_to_remove, 1)
|
61
|
+
$('body').removeClass('locked-scroll') if layer.should_fade_body
|
62
|
+
layer.$element.attr('is-active-layer', 'false')
|
63
|
+
)
|
64
|
+
|
65
|
+
removeAll = (->
|
66
|
+
removeLayer(layer._id) while layer = LAYERS.shift()
|
67
|
+
)
|
68
|
+
|
69
|
+
######################################################################################################################
|
70
|
+
|
71
|
+
$('body').on('click', (e)->
|
72
|
+
layer = LAYERS[0]
|
73
|
+
return if !layer
|
74
|
+
return if $(e.target).hasClass('dropdown-toggle')
|
75
|
+
|
76
|
+
$target = $(e.target)
|
77
|
+
return if !$.contains(document, $target[0])
|
78
|
+
|
79
|
+
$element = $target if $target.attr('is-active-layer')
|
80
|
+
$element ||= $target.closest('[is-active-layer="true"]')
|
81
|
+
return if ($element and $element.length and $element[0] == layer.$element[0])
|
82
|
+
|
83
|
+
layer.remove()
|
84
|
+
)
|
85
|
+
|
86
|
+
$('body').on('keydown', (e)->
|
87
|
+
return if e.keyCode != 27
|
88
|
+
|
89
|
+
layer = LAYERS[0]
|
90
|
+
return if !layer
|
91
|
+
|
92
|
+
layer.remove()
|
93
|
+
)
|
94
|
+
|
95
|
+
######################################################################################################################
|
96
|
+
|
97
|
+
INSTANCE.add = ((element, should_fade_body=false)->
|
98
|
+
return addLayer($(element), should_fade_body)
|
99
|
+
)
|
100
|
+
INSTANCE.removeAll = removeAll
|
101
|
+
return INSTANCE;
|
102
|
+
]);
|
103
|
+
|
@@ -0,0 +1,278 @@
|
|
1
|
+
$q = null
|
2
|
+
_callbacks = {}
|
3
|
+
_allowed_types = {}
|
4
|
+
instance = {
|
5
|
+
results: []
|
6
|
+
data_by_type: {}
|
7
|
+
has_more_results: false
|
8
|
+
}
|
9
|
+
|
10
|
+
PAGES = [
|
11
|
+
{name: 'Dashboard', type: 'page', icon_class: 'fa fa-tachometer', link: '/#/dashboard', other_names: ['Overview','Home']}
|
12
|
+
{name: 'Insights Engine', type: 'page', icon_class: 'fa fa-lightbulb-o', link: '/#/insights'}
|
13
|
+
{name: 'People', type: 'page', icon_class: 'ff-people', link: '/#/people', other_names: ['Person']},
|
14
|
+
{name: 'Initiatives', type: 'page', icon_class: 'ff-initiatives', link: '/#/initiatives'},
|
15
|
+
{name: 'Campaigns', type: 'page', icon_class: 'fa fa-newspaper-o', link: '/#/campaigns'},
|
16
|
+
{name: 'Experiments', type: 'page', icon_class: 'fa fa-flask', link: '/#/experiments'},
|
17
|
+
{name: 'Platform Admin', type: 'page', icon_class: 'fa fa-cogs', link: '/#/admin'}
|
18
|
+
]
|
19
|
+
|
20
|
+
TYPES = ['pages', 'people', 'initiatives', 'campaigns', 'experiments', 'segments']
|
21
|
+
|
22
|
+
App.factory('SearchEngine', ['$q',(q)->
|
23
|
+
$q = q
|
24
|
+
|
25
|
+
instance.allow = ((types...)->
|
26
|
+
_allowed_types = {}
|
27
|
+
_allowed_types[type] = true for type in (if types[0] == 'all' then TYPES else types)
|
28
|
+
return instance
|
29
|
+
)
|
30
|
+
|
31
|
+
instance.init = (->
|
32
|
+
instance.results = []
|
33
|
+
instance.data_by_type = {}
|
34
|
+
instance.current_results = 0
|
35
|
+
instance.total_results = 0
|
36
|
+
instance.has_more_results = false
|
37
|
+
)
|
38
|
+
|
39
|
+
instance.trigger = ((event_name, args...)->
|
40
|
+
return if !_callbacks[event_name]
|
41
|
+
callback(args...) for callback in _callbacks[event_name]
|
42
|
+
)
|
43
|
+
|
44
|
+
instance.on = ((event_name, callback)->
|
45
|
+
_callbacks[event_name] ||= []
|
46
|
+
_callbacks[event_name].push(callback)
|
47
|
+
)
|
48
|
+
|
49
|
+
instance.updateQuery = ((search_query, prev_search_query)->
|
50
|
+
search_query = search_query.trim() if search_query
|
51
|
+
prev_search_query = prev_search_query.trim() if prev_search_query
|
52
|
+
return instance.trigger('searching-finished') if prev_search_query == search_query
|
53
|
+
|
54
|
+
emptyArray(instance.results)
|
55
|
+
instance.data_by_type = {}
|
56
|
+
instance.current_results = 0
|
57
|
+
instance.total_results = 0
|
58
|
+
instance.has_more_results = false
|
59
|
+
instance.search_query = search_query
|
60
|
+
return instance.trigger('searching-finished') if !search_query or search_query.length < 2
|
61
|
+
|
62
|
+
instance.trigger('searching', instance.results)
|
63
|
+
fetchPages(search_query) || instance.trigger('results-updated', instance.results)
|
64
|
+
|
65
|
+
clearTimeout(instance.future_fetch) if instance.future_fetch
|
66
|
+
instance.future_fetch = setTimeout (->
|
67
|
+
fetchRemote(search_query)
|
68
|
+
instance.future_fetch = null
|
69
|
+
), 500
|
70
|
+
)
|
71
|
+
|
72
|
+
instance.loadMoreResults = loadMoreResults
|
73
|
+
|
74
|
+
return instance;
|
75
|
+
]);
|
76
|
+
|
77
|
+
emptyArray = ((a)->
|
78
|
+
a.splice(0,a.length)
|
79
|
+
)
|
80
|
+
|
81
|
+
fetchPages = ((search_query)->
|
82
|
+
return false if !_allowed_types.pages
|
83
|
+
return false if !search_query
|
84
|
+
data = {current_results:0,total_results:0, results: []}
|
85
|
+
for page in PAGES
|
86
|
+
continue if !pageIsMatchForQuery(page, search_query)
|
87
|
+
data.results.push(page)
|
88
|
+
data.current_results = data.total_results += 1
|
89
|
+
if data.current_results > 0
|
90
|
+
addResults('pages', data)
|
91
|
+
return true
|
92
|
+
else return false
|
93
|
+
)
|
94
|
+
|
95
|
+
loadMoreResults = (->
|
96
|
+
search_query = instance.search_query
|
97
|
+
search_query = null if search_query == '*'
|
98
|
+
promises = []
|
99
|
+
promises.push fetchSegments(search_query, true)
|
100
|
+
promises.push fetchPeople(search_query, true)
|
101
|
+
promises.push fetchInitiatives(search_query, true)
|
102
|
+
promises.push fetchCampaigns(search_query, true)
|
103
|
+
promises.push fetchExperiments(search_query, true)
|
104
|
+
|
105
|
+
$q.all(promises).then(-> instance.trigger('load-more-finished'))
|
106
|
+
)
|
107
|
+
|
108
|
+
fetchRemote = ((search_query) ->
|
109
|
+
search_query = null if search_query == '*'
|
110
|
+
promises = []
|
111
|
+
promises.push fetchSegments(search_query)
|
112
|
+
promises.push fetchPeople(search_query)
|
113
|
+
promises.push fetchInitiatives(search_query)
|
114
|
+
promises.push fetchCampaigns(search_query)
|
115
|
+
promises.push fetchExperiments(search_query)
|
116
|
+
|
117
|
+
$q.all(promises).then(-> instance.trigger('searching-finished'))
|
118
|
+
)
|
119
|
+
|
120
|
+
fetchPeople = ((search_query, should_load_next_page=false)->
|
121
|
+
return if !_allowed_types[type = 'people']
|
122
|
+
attrs = {query: search_query, per_page: 5}
|
123
|
+
if should_load_next_page and instance.data_by_type[type]
|
124
|
+
current_page = instance.data_by_type[type].current_results / attrs.per_page
|
125
|
+
total_pages = instance.data_by_type[type].total_results / attrs.per_page
|
126
|
+
return if current_page >= total_pages
|
127
|
+
attrs.page = current_page + 1
|
128
|
+
|
129
|
+
FF.api.get('/search/people', attrs).success((data) ->
|
130
|
+
FFCore.fillBlankPersonPhotos(data.results)
|
131
|
+
com_database_ids_to_fetch = {}
|
132
|
+
for person in data.results
|
133
|
+
for com_database_id in person.com_database_ids
|
134
|
+
com_database_ids_to_fetch[com_database_id] ||= []
|
135
|
+
com_database_ids_to_fetch[com_database_id].push(person)
|
136
|
+
FFCore.fillBlankPersonPhotos(person)
|
137
|
+
person.type = 'person'
|
138
|
+
person.link = "/#/people/#{person._id}"
|
139
|
+
addResults(type, data)
|
140
|
+
insertMissingComDatabasesIntoPeople(com_database_ids_to_fetch, ->
|
141
|
+
refreshResults()
|
142
|
+
)
|
143
|
+
)
|
144
|
+
)
|
145
|
+
|
146
|
+
fetchInitiatives = ((search_query, should_load_next_page=false)->
|
147
|
+
return if !_allowed_types[type = 'initiatives']
|
148
|
+
attrs = {query: search_query, per_page: 5}
|
149
|
+
if should_load_next_page and instance.data_by_type[type]
|
150
|
+
current_page = instance.data_by_type[type].current_results / attrs.per_page
|
151
|
+
total_pages = instance.data_by_type[type].total_results / attrs.per_page
|
152
|
+
return if current_page >= total_pages
|
153
|
+
attrs.page = current_page + 1
|
154
|
+
|
155
|
+
FF.api.get('/search/initiatives', attrs).success((data)->
|
156
|
+
for initiative in data.results
|
157
|
+
initiative.type = 'initiative'
|
158
|
+
initiative.link = "/#/initiatives/#{initiative._id}"
|
159
|
+
addResults(type, data)
|
160
|
+
)
|
161
|
+
)
|
162
|
+
|
163
|
+
fetchCampaigns = ((search_query, should_load_next_page=false)->
|
164
|
+
return if !_allowed_types[type = 'campaigns']
|
165
|
+
attrs = {query: search_query, per_page: 5}
|
166
|
+
if should_load_next_page and instance.data_by_type[type]
|
167
|
+
current_page = instance.data_by_type[type].current_results / attrs.per_page
|
168
|
+
total_pages = instance.data_by_type[type].total_results / attrs.per_page
|
169
|
+
return if current_page >= total_pages
|
170
|
+
attrs.page = current_page + 1
|
171
|
+
|
172
|
+
FF.api.get('/search/campaigns', attrs).success((data)->
|
173
|
+
for campaign in data.results
|
174
|
+
campaign.type = 'campaign'
|
175
|
+
campaign.link = "/#/campaigns/#{campaign._id}"
|
176
|
+
addResults(type, data)
|
177
|
+
)
|
178
|
+
)
|
179
|
+
|
180
|
+
fetchExperiments = ((search_query, should_load_next_page=false)->
|
181
|
+
return if !_allowed_types[type = 'experiments']
|
182
|
+
attrs = {query: search_query, per_page: 5}
|
183
|
+
if should_load_next_page and instance.data_by_type[type]
|
184
|
+
current_page = instance.data_by_type[type].current_results / attrs.per_page
|
185
|
+
total_pages = instance.data_by_type[type].total_results / attrs.per_page
|
186
|
+
return if current_page >= total_pages
|
187
|
+
attrs.page = current_page + 1
|
188
|
+
|
189
|
+
FF.api.get('/search/experiments', attrs).success((data)->
|
190
|
+
for experiment in data.results
|
191
|
+
experiment.type = 'experiment'
|
192
|
+
experiment.link = "/#/experiments/#{experiment._id}"
|
193
|
+
addResults(type, data)
|
194
|
+
)
|
195
|
+
)
|
196
|
+
|
197
|
+
fetchSegments = ((search_query, should_load_next_page=false)->
|
198
|
+
type = 'segments'
|
199
|
+
attrs = {query: search_query, per_page: 5}
|
200
|
+
if _allowed_types.person_segments
|
201
|
+
attrs.applies_to = 'people'
|
202
|
+
else if _allowed_types.initiative_segments
|
203
|
+
attrs.applies_to = 'initiatives'
|
204
|
+
else if _allowed_types.campaign_segments
|
205
|
+
attrs.applies_to = 'campaigns'
|
206
|
+
else if _allowed_types.experiment_segments
|
207
|
+
attrs.applies_to = 'experiments'
|
208
|
+
else if _allowed_types.activity_segments
|
209
|
+
attrs.applies_to = 'activities'
|
210
|
+
else if !_allowed_types[type]
|
211
|
+
return
|
212
|
+
if should_load_next_page and instance.data_by_type[type]
|
213
|
+
current_page = instance.data_by_type[type].current_results / attrs.per_page
|
214
|
+
total_pages = instance.data_by_type[type].total_results / attrs.per_page
|
215
|
+
return if current_page >= total_pages
|
216
|
+
attrs.page = current_page + 1
|
217
|
+
|
218
|
+
FF.api.get('/search/segments', attrs).success((data)->
|
219
|
+
for segment in data.results
|
220
|
+
segment.type = 'segment'
|
221
|
+
segment.icon_class='ff-people'
|
222
|
+
segment.badge_class='fa fa-filter'
|
223
|
+
segment.link = "/#/segments/#{segment._id}"
|
224
|
+
addResults(type, data)
|
225
|
+
)
|
226
|
+
)
|
227
|
+
|
228
|
+
addResults = ((type, data)->
|
229
|
+
instance.data_by_type[type] ||= {total_results: 0, current_results: 0, results: []}
|
230
|
+
for record in data.results
|
231
|
+
instance.results.push(record)
|
232
|
+
instance.data_by_type[type].results.push(record)
|
233
|
+
|
234
|
+
instance.current_results += data.current_results
|
235
|
+
instance.total_results += (data.total_results - instance.data_by_type[type].total_results)
|
236
|
+
|
237
|
+
instance.data_by_type[type].current_results += data.current_results
|
238
|
+
instance.data_by_type[type].total_results = data.total_results
|
239
|
+
|
240
|
+
instance.has_more_results = (instance.current_results < instance.total_results)
|
241
|
+
instance.trigger('results-updated', instance.results, instance.has_more_results)
|
242
|
+
)
|
243
|
+
|
244
|
+
refreshResults = ((type)->
|
245
|
+
instance.trigger('results-updated', instance.results, instance.has_more_results)
|
246
|
+
)
|
247
|
+
|
248
|
+
pageIsMatchForQuery = ((page, query)->
|
249
|
+
return true if !query
|
250
|
+
return true if page.name.toLowerCase().indexOf(query.toLowerCase()) > -1
|
251
|
+
|
252
|
+
if page.other_names then for other_name in page.other_names
|
253
|
+
return true if other_name.toLowerCase().indexOf(query.toLowerCase()) > -1
|
254
|
+
return false
|
255
|
+
)
|
256
|
+
|
257
|
+
COM_DATABASES_BY_ID = {}
|
258
|
+
insertMissingComDatabasesIntoPeople = ((com_for_updating, callback)->
|
259
|
+
com_ids_to_fetch = []
|
260
|
+
|
261
|
+
for own com_id, people of com_for_updating
|
262
|
+
if !COM_DATABASES_BY_ID[com_id]
|
263
|
+
com_ids_to_fetch.push(com_id)
|
264
|
+
continue
|
265
|
+
for person in people
|
266
|
+
person.com_databases ||= []
|
267
|
+
person.com_databases.push(COM_DATABASES_BY_ID[com_id])
|
268
|
+
return callback() if com_ids_to_fetch.length == 0
|
269
|
+
|
270
|
+
FF.api.get('/com_databases', _ids: com_ids_to_fetch, fields: 'name,public_urls').success((data) ->
|
271
|
+
for com_database in data.results
|
272
|
+
COM_DATABASES_BY_ID[com_database._id] = com_database
|
273
|
+
for person in com_for_updating[com_database._id]
|
274
|
+
person.com_databases ||= []
|
275
|
+
person.com_databases.push(COM_DATABASES_BY_ID[com_database._id])
|
276
|
+
callback()
|
277
|
+
)
|
278
|
+
)
|
@@ -0,0 +1,86 @@
|
|
1
|
+
App.directive('typeahead', ['$http','$q','$timeout','SearchEngine','Layers', ($http, $q, $timeout, SearchEngine, Layers) ->
|
2
|
+
restrict: 'E',
|
3
|
+
templateUrl: '/plugin_factory/directives/typeahead',
|
4
|
+
scope: {
|
5
|
+
button_labels: '=buttonLabels'
|
6
|
+
existing_records_by_id: '=existingRecordsById',
|
7
|
+
onAdd: '='
|
8
|
+
placeholder: '=?'
|
9
|
+
}
|
10
|
+
link: (($scope, $element, attrs, controller)->
|
11
|
+
$scope.$safeApply = Utils.$safeApply
|
12
|
+
|
13
|
+
$scope.search_for = (attrs.searchFor || 'people').split(/,\s*/)
|
14
|
+
$scope.placeholder ||= 'type name of person or segment'
|
15
|
+
|
16
|
+
$input = $element.find('> .search-bar input');
|
17
|
+
$menu = $element.find('> .menu');
|
18
|
+
|
19
|
+
$input.on('focus', ->
|
20
|
+
$scope.activate()
|
21
|
+
)
|
22
|
+
|
23
|
+
$scope.hide = true
|
24
|
+
|
25
|
+
$scope.records = []
|
26
|
+
|
27
|
+
$scope.$watch('query_str', (query_str, prev_query_str)->
|
28
|
+
SearchEngine.updateQuery(query_str, prev_query_str)
|
29
|
+
)
|
30
|
+
SearchEngine.on('searching', ->
|
31
|
+
openMenu()
|
32
|
+
$scope.is_searching = true
|
33
|
+
)
|
34
|
+
SearchEngine.on('searching-finished', ->
|
35
|
+
$scope.is_searching = false
|
36
|
+
$scope.$safeApply()
|
37
|
+
)
|
38
|
+
SearchEngine.on('results-updated', (results, has_more_results)->
|
39
|
+
$scope.results = results
|
40
|
+
$scope.has_more_results = has_more_results
|
41
|
+
$scope.selected_index ||= 0
|
42
|
+
max_index = $scope.results.length - 1
|
43
|
+
max_index = 0 if max_index < 0
|
44
|
+
$scope.selected_index = max_index if $scope.selected_index > max_index
|
45
|
+
$scope.$safeApply()
|
46
|
+
)
|
47
|
+
|
48
|
+
$scope.loadMore = (->
|
49
|
+
SearchEngine.loadMoreResults()
|
50
|
+
)
|
51
|
+
|
52
|
+
layer = null
|
53
|
+
openMenu = (->
|
54
|
+
return if $scope.menu_is_open
|
55
|
+
$scope.menu_is_open = true
|
56
|
+
layer = Layers.add($element).onRemove(->
|
57
|
+
$scope.close()
|
58
|
+
$input.blur()
|
59
|
+
$scope.menu_is_open = false
|
60
|
+
$scope.query_str = null
|
61
|
+
$scope.$safeApply()
|
62
|
+
)
|
63
|
+
)
|
64
|
+
|
65
|
+
$scope.add = ((record)->
|
66
|
+
record.is_adding = true
|
67
|
+
$q.all([$scope.onAdd(record)]).then(->
|
68
|
+
record.is_adding = false
|
69
|
+
record.is_added = true
|
70
|
+
)
|
71
|
+
)
|
72
|
+
|
73
|
+
$scope.activate = (->
|
74
|
+
return if $scope.is_active
|
75
|
+
$scope.is_active = true
|
76
|
+
SearchEngine.allow($scope.search_for...).init()
|
77
|
+
)
|
78
|
+
|
79
|
+
$scope.close = (->
|
80
|
+
$scope.is_active = false
|
81
|
+
)
|
82
|
+
|
83
|
+
setTimeout (-> $input.focus()), 1
|
84
|
+
)
|
85
|
+
])
|
86
|
+
|
data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_typeahead.scss
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
typeahead { //display:block; position:relative;
|
2
|
+
.search-bar { margin-right: 1px; position: relative;
|
3
|
+
i { position: absolute; top: 50%; margin-top: -12px; line-height: 24px; left: 5px; }
|
4
|
+
input[type='text'] { display: block; width: 100%; padding-left: 20px; }
|
5
|
+
}
|
6
|
+
.menu { z-index: 1; background:white; position: relative; width: 100%; padding-top: 3px; margin-top:1px; min-height: 20px; border:1px solid #cccccc; border-top: none; @include box-shadow(1px 1px 1px rgba(0,0,0,.1)); @include border-radius(0 0 3px 3px); @include box-sizing(border-box);
|
7
|
+
.menu-arrow { position:absolute; top:-9px; left: 75px; z-index:1; }
|
8
|
+
h5 { font-size:11px; color:#babdbf; width:73px; float:left; font-weight: normal; clear:left; padding:10px 5px 10px 0; margin:0 1px; text-align: right; border-top: 1px solid #dddddd; }
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
search-results { display: block; overflow-y: auto; margin-bottom: 1px;
|
13
|
+
loading.is-searching { margin: 0 2px; padding: 7px 10px; text-align: left;
|
14
|
+
.bar { margin-top: 0; }
|
15
|
+
}
|
16
|
+
.no-results { color: #cccccc; padding: 20px 12px; font-size: 16px; }
|
17
|
+
ul.results { @include reset-ul(); margin: -2px 2px 0;
|
18
|
+
& ~ loading.is-searching { border-top: 1px solid #eeeeee; margin-top: 2px; }
|
19
|
+
li.result { margin: 2px 0; padding-top: 2px; font-size: 12px; color: #666666; border-top: 1px solid #eeeeee; clear: both; position: relative; text-shadow: 1px 1px 0 white; text-align: left;
|
20
|
+
&.is-added { @include opacity(0.5); }
|
21
|
+
.adjuster-field { display: inline-block; }
|
22
|
+
.select2-container .select2-choice { background: #f6f6f6; @include box-shadow(inset 1px 1px 0 white); border-color: #cccccc; }
|
23
|
+
&:first-child { border-top: none; margin-top: 0; padding-top: 0; }
|
24
|
+
&:last-child { margin-bottom: 0; }
|
25
|
+
}
|
26
|
+
.record { display: block; padding: 4px 8px;
|
27
|
+
&.selected { background: #e9f4fd; }
|
28
|
+
&:hover { text-decoration: none; }
|
29
|
+
}
|
30
|
+
.details { display: inline-block; }
|
31
|
+
.name { display: inline-block; line-height: 22px; padding-top: 1px; vertical-align: middle; }
|
32
|
+
.person-source-icons, .record-source-icons { display: inline-block;
|
33
|
+
img { margin-left:5px; @include opacity(0.5);
|
34
|
+
&:hover { @include opacity(1); }
|
35
|
+
}
|
36
|
+
}
|
37
|
+
.photo-wrapper { width:22px; height:22px; vertical-align: middle; border: 1px solid rgba(0, 0, 0, 0.1); @include box-shadow(1px 1px 0 white); background-color:#eaf2fa; overflow:hidden; display: inline-block; margin-right: 5px; @include border-radius(50%);
|
38
|
+
img { width:20px; height:20px; }
|
39
|
+
}
|
40
|
+
.native-icon { position: relative; width: 21px; height: 21px; display: inline-block; background: #b0becb; border-color: #b0becb; @include box-shadow(1px 1px 0 white); margin-right: 5px; text-align: center; vertical-align: middle; @include border-radius(1px);
|
41
|
+
i { font-size: 15px; line-height: 19px; color: white; text-shadow: none; }
|
42
|
+
.badge-wrapper { width: 12px; height: 12px; position: absolute; top: -2px; right: -2px; background: #779cbf; border: 1px solid #5a83a9; @include border-radius(50%);
|
43
|
+
i { font-size: 8px; line-height: 10px; color: white; vertical-align: top;}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
.icon-wrapper { width: 21px; height: 21px; display: inline-block; margin-right: 5px; text-align: center; vertical-align: middle;
|
47
|
+
img { width: 20px; height: 20px; }
|
48
|
+
}
|
49
|
+
.type { color: #b6c7d4; position: absolute; line-height: 16px; top: 50%; margin-top: -8px; right: 5px; }
|
50
|
+
.control-buttons { float:left; width: 75px; position: relative; top: 2px;
|
51
|
+
.btn { padding: 2px 5px; font-size: 12px; line-height: 1em; }
|
52
|
+
}
|
53
|
+
}
|
54
|
+
.show-more { margin: 2px 0; padding: 4px 8px 2px; font-size: 12px; border-top: 1px solid #eeeeee; clear: both; display: block; }
|
55
|
+
}
|
56
|
+
|
57
|
+
loading { display: block; text-align:center; padding:40px 0;
|
58
|
+
.bar {
|
59
|
+
vertical-align: bottom;
|
60
|
+
display: inline-block;
|
61
|
+
background-color:#e5eaee; border:1px solid #cfd7de;
|
62
|
+
margin-right:4px; margin-top:6px; width:6px; height:14px;
|
63
|
+
@include box-shadow(1px 1px 0 #ffffff);
|
64
|
+
@include animation(loadingbar 1s infinite);
|
65
|
+
}
|
66
|
+
& .bar:nth-child(1) { @include animation-delay(1.0s); }
|
67
|
+
& .bar:nth-child(2) { @include animation-delay(1.1s); }
|
68
|
+
& .bar:nth-child(3) { @include animation-delay(1.2s); }
|
69
|
+
& .bar:nth-child(4) { @include animation-delay(1.3s); }
|
70
|
+
}
|
71
|
+
/* The actual animation */
|
72
|
+
@include keyframes(loadingbar) {
|
73
|
+
0% { border-color:#cfd7de; background-color:#e5eaee; }
|
74
|
+
20% { border-color:#cfd7de; background-color:#e5eaee; }
|
75
|
+
40% { border-color:#bec7d0; background-color:#ced4db; }
|
76
|
+
60% { border-color:#aab5c1; background-color:#bac4cf; }
|
77
|
+
100% { border-color:#9eabb9; background-color:#acb8c5; }
|
78
|
+
}
|
data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/arrow.png
ADDED
Binary file
|
@@ -0,0 +1,37 @@
|
|
1
|
+
.search-bar
|
2
|
+
%i.fa.fa-search
|
3
|
+
%input(type='text' ng-model='query_str' autocomplete='off' placeholder='{{placeholder}}')
|
4
|
+
|
5
|
+
.menu(ng-show='menu_is_open')
|
6
|
+
%img.menu-arrow
|
7
|
+
%search-results
|
8
|
+
%loading.is-searching(ng-show='is_searching')
|
9
|
+
.no-results(ng-show='results.length == 0 && !is_searching')
|
10
|
+
.text No People Found
|
11
|
+
%ul.results(ng-show='results.length > 0 && !is_searching')
|
12
|
+
%li.result(ng-repeat='record in results' ng-class='{"is-added": record.is_added}')
|
13
|
+
.record
|
14
|
+
.native-icon(ng-if='record.icon_class' ng-class='{"page-icon": record.type=="page"}')
|
15
|
+
%i(ng-class='record.icon_class')
|
16
|
+
.badge-wrapper(ng-if='record.badge_class')
|
17
|
+
%i(ng-class='record.badge_class')
|
18
|
+
.photo-wrapper(ng-if='record.photo_small_url')
|
19
|
+
%img(ng-src='{{record.photo_small_url}}')
|
20
|
+
.icon-wrapper(ng-if='record.public_urls')
|
21
|
+
%img(ng-src='{{record.public_urls.icon_32}}')
|
22
|
+
.details
|
23
|
+
.name
|
24
|
+
{{record.name}}
|
25
|
+
%span(ng-if='record.adjuster') =
|
26
|
+
.adjuster-field(ng-class='{disabled: record.is_adding || record.is_added}')
|
27
|
+
%segment-adjuster(id='record.adjuster._id' value='record.adjuster_value' com-database='record.adjuster.com_database' field='record.adjuster.field' input-control='record.adjuster.input_control' placeholder='record.adjuster_placeholder')
|
28
|
+
|
29
|
+
.record-source-icons(ng-if='record.com_databases')
|
30
|
+
%img(ng-repeat='com_database in record.com_databases' ng-src='{{com_database.public_urls.icon_16}}' ng-hide='com_database._id == "unnamed-visitors"' tooltip='{{com_database.name}}')
|
31
|
+
.last-activity-at(ng-if='record.last_activity_at') Last Activity {{record.last_activity_at|fromNow}}
|
32
|
+
.control-buttons
|
33
|
+
%button.btn.btn-small.btn-default(ng-click='add(record)' ng-hide='record.is_added || record.is_adding || existing_records_by_id[record._id]') {{button_labels[0]}}
|
34
|
+
%button.btn.btn-small(ng-show='record.is_adding' disabled) {{button_labels[1]}}
|
35
|
+
%button.btn.btn-small(ng-show='record.is_added || existing_records_by_id[record._id]' disabled) {{button_labels[2]}}
|
36
|
+
.show-more(ng-if='has_more_results')
|
37
|
+
%a(ng-click='loadMore()') Load More
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fanforce-plugin-factory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.rc24
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Caleb Clark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -393,6 +393,11 @@ files:
|
|
393
393
|
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/start-arrow/_start-arrow.coffee
|
394
394
|
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/start-arrow/_start-arrow.scss
|
395
395
|
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/start-arrow/arrow.png
|
396
|
+
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_layers.coffee
|
397
|
+
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_search_engine.coffee
|
398
|
+
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_typeahead.coffee
|
399
|
+
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/_typeahead.scss
|
400
|
+
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/typeahead/arrow.png
|
396
401
|
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/video-thumbnail/_video-thumbnail.scss
|
397
402
|
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/video-thumbnail/icon-play.png
|
398
403
|
- lib/fanforce/plugin_factory/asset_framework/plugin_factory/font-awesome.coffee
|
@@ -441,6 +446,7 @@ files:
|
|
441
446
|
- lib/fanforce/plugin_factory/directive_views/campaign-footer.haml
|
442
447
|
- lib/fanforce/plugin_factory/directive_views/initiative-added.haml
|
443
448
|
- lib/fanforce/plugin_factory/directive_views/initiative-footer.haml
|
449
|
+
- lib/fanforce/plugin_factory/directive_views/typeahead.haml
|
444
450
|
- lib/fanforce/plugin_factory/load.rb
|
445
451
|
- lib/fanforce/plugin_factory/load_from_worker.rb
|
446
452
|
- lib/fanforce/plugin_factory/load_sprockets.rb
|