Commit 20e0d95087581895c6cce5083d713fce6af3a353
- Diff rendering mode:
- inline
- side by side
swtr/static/js/img_swtr.js
(228 / 0)
  | |||
1 | (function(swtr) { | ||
2 | swtr.ImgAnnoView = Backbone.View.extend({ | ||
3 | el: $("#img-annotation-wrapper"), | ||
4 | events: { | ||
5 | 'change #custom-dropdown ': 'getFormValue', | ||
6 | 'click #setbox': 'showHide' | ||
7 | }, | ||
8 | initialize: function(options) { | ||
9 | this.listenTo(this.collection, 'add', this.render); | ||
10 | // attach event handlers to the anno object | ||
11 | anno.addHandler('onAnnotationCreated', this.showSwtHelp); | ||
12 | anno.addHandler('onAnnotationCreated', this.updateNewAnno); | ||
13 | anno.addHandler('onAnnotationUpdated', this.showSwtHelp); | ||
14 | anno.addHandler('onSelectionStarted', function(annotation) { | ||
15 | anno.hideAnnotations(); | ||
16 | }); | ||
17 | anno.addHandler('onSelectionCompleted', function(annotation) { | ||
18 | anno.showAnnotations(); | ||
19 | }); | ||
20 | anno.addPlugin('CustomFields', {}); | ||
21 | anno.addHandler('onSelectionCompleted', this.hideOriginalEditor); | ||
22 | if(options.img) { | ||
23 | this.img = options.img; | ||
24 | this.$img = options.$img; | ||
25 | options.$img.on('load', this, this.imageLoaded); | ||
26 | options.$img.on('error', this, this.onImageLoadError); | ||
27 | this.setImage(options.url); | ||
28 | } | ||
29 | }, | ||
30 | render: function(model) { | ||
31 | var swt = model.toJSON(); | ||
32 | swt.how['editable'] = false; | ||
33 | swt.how.text = swtr.imgAnnoView.createPopupText(swt.how); | ||
34 | swt.how.text += '\n - by ' + swt.who; | ||
35 | anno.addAnnotation(swt.how); | ||
36 | }, | ||
37 | renderWith: function() { | ||
38 | _.each(this.collection, this.render); | ||
39 | }, | ||
40 | showSwtHelp: function(annotation) { | ||
41 | var self = swtr.imgAnnoView;//TODO: figure out how we can bind the scope when this func is called as a callback | ||
42 | swtr.appView.helpview.step(3); | ||
43 | $('#sweet').show(); | ||
44 | }, | ||
45 | updateNewAnno: function(annotation) { | ||
46 | console.log('updateNewAnno()'); | ||
47 | var self = swtr.imgAnnoView; | ||
48 | // get the final value/input from the editor | ||
49 | var selected = $('select option:selected').text().toLowerCase(); | ||
50 | var text_input = $('.annotorious-editor-text').val(); | ||
51 | if( selected === "tags") { | ||
52 | self.new_anno[selected] = $('#tags-input').tags().getTags(); | ||
53 | } | ||
54 | else { | ||
55 | // update it in our annotation object | ||
56 | self.new_anno[selected] = text_input; | ||
57 | } | ||
58 | // prepare the text field | ||
59 | self.new_anno.text = self.createPopupText(self.new_anno); | ||
60 | // update the annotorious annotation object with the new values | ||
61 | if(self.new_anno.comment) { | ||
62 | annotation.comment = self.new_anno.comment; | ||
63 | } | ||
64 | if(self.new_anno.link) { | ||
65 | annotation.link = self.new_anno.link; | ||
66 | } | ||
67 | if(self.new_anno.tags) { | ||
68 | annotation.tags = self.new_anno.tags; | ||
69 | } | ||
70 | if(self.new_anno.title) { | ||
71 | annotation.title = self.new_anno.title; | ||
72 | } | ||
73 | annotation.text = self.new_anno.text; | ||
74 | console.log(self.new_anno, annotation); | ||
75 | }, | ||
76 | // hide the original editor window, when user has completed selecting part | ||
77 | // of the image to annotate.. | ||
78 | hideOriginalEditor: function(annotation) { | ||
79 | console.log('hideOriginalEditor()'); | ||
80 | var self = swtr.imgAnnoView; | ||
81 | self.new_anno = {}; | ||
82 | self.getSuggestionsForTags(); | ||
83 | //$('.annotorious-editor-text').hide(); | ||
84 | //$('.annotorious-editor').css('width', '100%'); | ||
85 | }, | ||
86 | getFormValue: function(event) { | ||
87 | console.log('getFormValue()'); | ||
88 | |||
89 | var self = swtr.imgAnnoView; | ||
90 | // show the editor field to input text | ||
91 | var $anno_form = $('.annotorious-editor-text'); | ||
92 | //$anno_form.slideDown(); | ||
93 | // get the previous item entered | ||
94 | var $selected = $('select option:selected'); | ||
95 | var text_input = $anno_form.val(); | ||
96 | |||
97 | // if there was a input and it was not tags.. | ||
98 | if(text_input && $selected.prev().text() !== 'Tags') { | ||
99 | var field = $selected.prev().text().toLowerCase(); | ||
100 | // update it in our annotation object | ||
101 | self.new_anno[field] = text_input; | ||
102 | } | ||
103 | // if it was tags.. | ||
104 | else if ($selected.prev().text() === 'Tags') { | ||
105 | // directly save it.. | ||
106 | self.new_anno['tags'] = $('#tags-input').tags().getTags(); | ||
107 | } | ||
108 | |||
109 | // if the current selected is tags | ||
110 | if($selected.text() === 'Tags') { | ||
111 | $('#tags-input').tags({ | ||
112 | tagSize: 'md', | ||
113 | promptText: 'Type word (and press enter)..', | ||
114 | caseInsensitive: true, | ||
115 | suggestions: self.tags_suggestions | ||
116 | }); | ||
117 | $('#tags-input').show(); | ||
118 | $('.annotorious-editor-text').hide(); | ||
119 | } | ||
120 | else { | ||
121 | $('#tags-input').hide(); | ||
122 | $('.annotorious-editor-text').show(); | ||
123 | } | ||
124 | $anno_form.val(''); | ||
125 | $anno_form.attr('placeholder', 'Add ' + $selected.text()); | ||
126 | console.log(self.new_anno); | ||
127 | }, | ||
128 | createPopupText: function(annotation) { | ||
129 | // title | ||
130 | var text = (annotation.title) ? '<h4>' + annotation.title + '</h4>' : ''; | ||
131 | |||
132 | // comment | ||
133 | text += (annotation.comment) ? '<p>' + annotation.comment + '</p>' : ''; | ||
134 | |||
135 | // link | ||
136 | text += (annotation.link) ? '<a target="blank" href="' + | ||
137 | swtr.utils.linkify(annotation.link) + '">' + annotation.link + | ||
138 | '</a>' : ''; | ||
139 | |||
140 | // tags | ||
141 | text += (annotation.tags) ? '<p>' + annotation.tags + '</p>' : ''; | ||
142 | |||
143 | // if older annotation i.e w/o comment,title etc fields | ||
144 | // add text field as text | ||
145 | if(!text) { | ||
146 | text = annotation.text; | ||
147 | } | ||
148 | return text; | ||
149 | }, | ||
150 | // load the suggestions for the tag spraying.. | ||
151 | getSuggestionsForTags: function() { | ||
152 | var self = swtr.imgAnnoView; | ||
153 | $.ajax({ | ||
154 | url: '/static/data/tags_suggestions.json', | ||
155 | success: function(data) { | ||
156 | self.tags_suggestions = data; | ||
157 | } | ||
158 | }); | ||
159 | }, | ||
160 | setImage: function(url) { | ||
161 | this.imgURL = url; | ||
162 | console.log(url); | ||
163 | if(this.$img.attr('src') === this.imgURL) { | ||
164 | return; | ||
165 | } | ||
166 | anno.reset(); | ||
167 | var self = this; | ||
168 | swtr.appView.$overlay.show(); | ||
169 | swtr.appView.helpview.step(7); | ||
170 | this.$img.attr('src', this.imgURL); | ||
171 | }, | ||
172 | imageLoaded: function(event) { | ||
173 | var self = event.data; | ||
174 | console.log('image loaded', self); | ||
175 | swtr.appView.$overlay.hide(); | ||
176 | // reset the collection | ||
177 | swtr.sweets.reset(); | ||
178 | anno.makeAnnotatable(swtr.imgAnnoView.img); | ||
179 | swtr.imgAnnoView.getExistingAnnotations(); | ||
180 | }, | ||
181 | // when image fails to load - could be because of broken URL or network | ||
182 | // issues | ||
183 | onImageLoadError: function(event) { | ||
184 | var self = event.data; | ||
185 | console.log('error while loading image'); | ||
186 | swtr.appView.$overlay.hide(); | ||
187 | swtr.appView.helpview.step(8); | ||
188 | }, | ||
189 | initImageAnno: function() { | ||
190 | // img is a jquery object which annotorious doesn't accept; instead it | ||
191 | // takes the native object returned by a browser API; fortunately, jqeury | ||
192 | // stores a copy of the native object too! | ||
193 | |||
194 | this.getExistingAnnotations(); | ||
195 | |||
196 | }, | ||
197 | getExistingAnnotations: function() { | ||
198 | var self = this; | ||
199 | swtr.appView.helpview.step(0); | ||
200 | swtr.appView.$overlay.show(); | ||
201 | swtr.sweets.getAll({ | ||
202 | where: this.imgURL, | ||
203 | success: function(data) { | ||
204 | if(_.isArray(data)) { | ||
205 | swtr.sweets.add(data); | ||
206 | swtr.appView.$overlay.hide(); | ||
207 | swtr.appView.helpview.step(2); | ||
208 | } | ||
209 | }, | ||
210 | error: function(jqxhr, error, statusText) { | ||
211 | if(jqxhr.status === 404) { //annotations don't exist for this image | ||
212 | console.log('annotations don\'t exist for this image. Create one!'); | ||
213 | } | ||
214 | swtr.appView.$overlay.hide(); | ||
215 | swtr.appView.helpview.step(2); | ||
216 | } | ||
217 | }); | ||
218 | }, | ||
219 | showHide: function() { | ||
220 | if($("#setbox:checked").length) { | ||
221 | $('.annotorious-item-unfocus').css("opacity", "0.5"); | ||
222 | } | ||
223 | else { | ||
224 | $('.annotorious-item-unfocus').css("opacity", "0"); | ||
225 | } | ||
226 | } | ||
227 | }); | ||
228 | })(swtr); |
swtr/static/js/imganno.js
(0 / 228)
  | |||
1 | (function(swtr) { | ||
2 | swtr.ImgAnnoView = Backbone.View.extend({ | ||
3 | el: $("#img-annotation-wrapper"), | ||
4 | events: { | ||
5 | 'change #custom-dropdown ': 'getFormValue', | ||
6 | 'click #setbox': 'showHide' | ||
7 | }, | ||
8 | initialize: function(options) { | ||
9 | this.listenTo(this.collection, 'add', this.render); | ||
10 | // attach event handlers to the anno object | ||
11 | anno.addHandler('onAnnotationCreated', this.showSwtHelp); | ||
12 | anno.addHandler('onAnnotationCreated', this.updateNewAnno); | ||
13 | anno.addHandler('onAnnotationUpdated', this.showSwtHelp); | ||
14 | anno.addHandler('onSelectionStarted', function(annotation) { | ||
15 | anno.hideAnnotations(); | ||
16 | }); | ||
17 | anno.addHandler('onSelectionCompleted', function(annotation) { | ||
18 | anno.showAnnotations(); | ||
19 | }); | ||
20 | anno.addPlugin('CustomFields', {}); | ||
21 | anno.addHandler('onSelectionCompleted', this.hideOriginalEditor); | ||
22 | if(options.img) { | ||
23 | this.img = options.img; | ||
24 | this.$img = options.$img; | ||
25 | options.$img.on('load', this, this.imageLoaded); | ||
26 | options.$img.on('error', this, this.onImageLoadError); | ||
27 | this.setImage(options.url); | ||
28 | } | ||
29 | }, | ||
30 | render: function(model) { | ||
31 | var swt = model.toJSON(); | ||
32 | swt.how['editable'] = false; | ||
33 | swt.how.text = swtr.imgAnnoView.createPopupText(swt.how); | ||
34 | swt.how.text += '\n - by ' + swt.who; | ||
35 | anno.addAnnotation(swt.how); | ||
36 | }, | ||
37 | renderWith: function() { | ||
38 | _.each(this.collection, this.render); | ||
39 | }, | ||
40 | showSwtHelp: function(annotation) { | ||
41 | var self = swtr.imgAnnoView;//TODO: figure out how we can bind the scope when this func is called as a callback | ||
42 | swtr.appView.helpview.step(3); | ||
43 | $('#sweet').show(); | ||
44 | }, | ||
45 | updateNewAnno: function(annotation) { | ||
46 | console.log('updateNewAnno()'); | ||
47 | var self = swtr.imgAnnoView; | ||
48 | // get the final value/input from the editor | ||
49 | var selected = $('select option:selected').text().toLowerCase(); | ||
50 | var text_input = $('.annotorious-editor-text').val(); | ||
51 | if( selected === "tags") { | ||
52 | self.new_anno[selected] = $('#tags-input').tags().getTags(); | ||
53 | } | ||
54 | else { | ||
55 | // update it in our annotation object | ||
56 | self.new_anno[selected] = text_input; | ||
57 | } | ||
58 | // prepare the text field | ||
59 | self.new_anno.text = self.createPopupText(self.new_anno); | ||
60 | // update the annotorious annotation object with the new values | ||
61 | if(self.new_anno.comment) { | ||
62 | annotation.comment = self.new_anno.comment; | ||
63 | } | ||
64 | if(self.new_anno.link) { | ||
65 | annotation.link = self.new_anno.link; | ||
66 | } | ||
67 | if(self.new_anno.tags) { | ||
68 | annotation.tags = self.new_anno.tags; | ||
69 | } | ||
70 | if(self.new_anno.title) { | ||
71 | annotation.title = self.new_anno.title; | ||
72 | } | ||
73 | annotation.text = self.new_anno.text; | ||
74 | console.log(self.new_anno, annotation); | ||
75 | }, | ||
76 | // hide the original editor window, when user has completed selecting part | ||
77 | // of the image to annotate.. | ||
78 | hideOriginalEditor: function(annotation) { | ||
79 | console.log('hideOriginalEditor()'); | ||
80 | var self = swtr.imgAnnoView; | ||
81 | self.new_anno = {}; | ||
82 | self.getSuggestionsForTags(); | ||
83 | //$('.annotorious-editor-text').hide(); | ||
84 | //$('.annotorious-editor').css('width', '100%'); | ||
85 | }, | ||
86 | getFormValue: function(event) { | ||
87 | console.log('getFormValue()'); | ||
88 | |||
89 | var self = swtr.imgAnnoView; | ||
90 | // show the editor field to input text | ||
91 | var $anno_form = $('.annotorious-editor-text'); | ||
92 | //$anno_form.slideDown(); | ||
93 | // get the previous item entered | ||
94 | var $selected = $('select option:selected'); | ||
95 | var text_input = $anno_form.val(); | ||
96 | |||
97 | // if there was a input and it was not tags.. | ||
98 | if(text_input && $selected.prev().text() !== 'Tags') { | ||
99 | var field = $selected.prev().text().toLowerCase(); | ||
100 | // update it in our annotation object | ||
101 | self.new_anno[field] = text_input; | ||
102 | } | ||
103 | // if it was tags.. | ||
104 | else if ($selected.prev().text() === 'Tags') { | ||
105 | // directly save it.. | ||
106 | self.new_anno['tags'] = $('#tags-input').tags().getTags(); | ||
107 | } | ||
108 | |||
109 | // if the current selected is tags | ||
110 | if($selected.text() === 'Tags') { | ||
111 | $('#tags-input').tags({ | ||
112 | tagSize: 'md', | ||
113 | promptText: 'Type word (and press enter)..', | ||
114 | caseInsensitive: true, | ||
115 | suggestions: self.tags_suggestions | ||
116 | }); | ||
117 | $('#tags-input').show(); | ||
118 | $('.annotorious-editor-text').hide(); | ||
119 | } | ||
120 | else { | ||
121 | $('#tags-input').hide(); | ||
122 | $('.annotorious-editor-text').show(); | ||
123 | } | ||
124 | $anno_form.val(''); | ||
125 | $anno_form.attr('placeholder', 'Add ' + $selected.text()); | ||
126 | console.log(self.new_anno); | ||
127 | }, | ||
128 | createPopupText: function(annotation) { | ||
129 | // title | ||
130 | var text = (annotation.title) ? '<h4>' + annotation.title + '</h4>' : ''; | ||
131 | |||
132 | // comment | ||
133 | text += (annotation.comment) ? '<p>' + annotation.comment + '</p>' : ''; | ||
134 | |||
135 | // link | ||
136 | text += (annotation.link) ? '<a target="blank" href="' + | ||
137 | swtr.utils.linkify(annotation.link) + '">' + annotation.link + | ||
138 | '</a>' : ''; | ||
139 | |||
140 | // tags | ||
141 | text += (annotation.tags) ? '<p>' + annotation.tags + '</p>' : ''; | ||
142 | |||
143 | // if older annotation i.e w/o comment,title etc fields | ||
144 | // add text field as text | ||
145 | if(!text) { | ||
146 | text = annotation.text; | ||
147 | } | ||
148 | return text; | ||
149 | }, | ||
150 | // load the suggestions for the tag spraying.. | ||
151 | getSuggestionsForTags: function() { | ||
152 | var self = swtr.imgAnnoView; | ||
153 | $.ajax({ | ||
154 | url: '/static/data/tags_suggestions.json', | ||
155 | success: function(data) { | ||
156 | self.tags_suggestions = data; | ||
157 | } | ||
158 | }); | ||
159 | }, | ||
160 | setImage: function(url) { | ||
161 | this.imgURL = url; | ||
162 | console.log(url); | ||
163 | if(this.$img.attr('src') === this.imgURL) { | ||
164 | return; | ||
165 | } | ||
166 | anno.reset(); | ||
167 | var self = this; | ||
168 | swtr.appView.$overlay.show(); | ||
169 | swtr.appView.helpview.step(7); | ||
170 | this.$img.attr('src', this.imgURL); | ||
171 | }, | ||
172 | imageLoaded: function(event) { | ||
173 | var self = event.data; | ||
174 | console.log('image loaded', self); | ||
175 | swtr.appView.$overlay.hide(); | ||
176 | // reset the collection | ||
177 | swtr.sweets.reset(); | ||
178 | anno.makeAnnotatable(swtr.imgAnnoView.img); | ||
179 | swtr.imgAnnoView.getExistingAnnotations(); | ||
180 | }, | ||
181 | // when image fails to load - could be because of broken URL or network | ||
182 | // issues | ||
183 | onImageLoadError: function(event) { | ||
184 | var self = event.data; | ||
185 | console.log('error while loading image'); | ||
186 | swtr.appView.$overlay.hide(); | ||
187 | swtr.appView.helpview.step(8); | ||
188 | }, | ||
189 | initImageAnno: function() { | ||
190 | // img is a jquery object which annotorious doesn't accept; instead it | ||
191 | // takes the native object returned by a browser API; fortunately, jqeury | ||
192 | // stores a copy of the native object too! | ||
193 | |||
194 | this.getExistingAnnotations(); | ||
195 | |||
196 | }, | ||
197 | getExistingAnnotations: function() { | ||
198 | var self = this; | ||
199 | swtr.appView.helpview.step(0); | ||
200 | swtr.appView.$overlay.show(); | ||
201 | swtr.sweets.getAll({ | ||
202 | where: this.imgURL, | ||
203 | success: function(data) { | ||
204 | if(_.isArray(data)) { | ||
205 | swtr.sweets.add(data); | ||
206 | swtr.appView.$overlay.hide(); | ||
207 | swtr.appView.helpview.step(2); | ||
208 | } | ||
209 | }, | ||
210 | error: function(jqxhr, error, statusText) { | ||
211 | if(jqxhr.status === 404) { //annotations don't exist for this image | ||
212 | console.log('annotations don\'t exist for this image. Create one!'); | ||
213 | } | ||
214 | swtr.appView.$overlay.hide(); | ||
215 | swtr.appView.helpview.step(2); | ||
216 | } | ||
217 | }); | ||
218 | }, | ||
219 | showHide: function() { | ||
220 | if($("#setbox:checked").length) { | ||
221 | $('.annotorious-item-unfocus').css("opacity", "0.5"); | ||
222 | } | ||
223 | else { | ||
224 | $('.annotorious-item-unfocus').css("opacity", "0"); | ||
225 | } | ||
226 | } | ||
227 | }); | ||
228 | })(swtr); |
swtr/static/js/main.js
(772 / 0)
  | |||
1 | (function(swtr) { | ||
2 | |||
3 | //TODO: find a better way to init. | ||
4 | //Find a better way to do closure | ||
5 | //Remove script code from the HTML page | ||
6 | swtr.init = function() { | ||
7 | this.sweets = new ImgAnnoSwts(); | ||
8 | this.appView = new AppView(); | ||
9 | this.who = 'Guest'; | ||
10 | |||
11 | this.app_router = new AppRouter(); | ||
12 | Backbone.history.start(); | ||
13 | this.app_router.navigate('home'); | ||
14 | |||
15 | $.ajaxSetup({ | ||
16 | xhrFields: { | ||
17 | // we need this to send cookies to cross-domain requests | ||
18 | withCredentials: true | ||
19 | }, | ||
20 | //some browsers won't make cross-domain ajax until it is explicitly set | ||
21 | crossDomain: true | ||
22 | }); | ||
23 | this.handleOAuth(); | ||
24 | }; | ||
25 | |||
26 | swtr.handleOAuth = function() { | ||
27 | if(swtr.access_token) { | ||
28 | $('#signinview').html('Signing you in..'); | ||
29 | $.ajax({ | ||
30 | url: swtr.swtstoreURL()+'/api/users/me?access_token='+ | ||
31 | swtr.access_token, | ||
32 | success: function(data) { | ||
33 | swtr.appView.userLoggedIn(data.username); | ||
34 | }, | ||
35 | error: function() { | ||
36 | $('#signinview').html('Error signing in! Please try again'); | ||
37 | } | ||
38 | }); | ||
39 | } | ||
40 | }; | ||
41 | |||
42 | /* Model for Image Annotation Sweets */ | ||
43 | var ImgAnnoSwt = Backbone.Model.extend({ | ||
44 | defaults: { | ||
45 | 'who': '', | ||
46 | 'what': 'img-anno', | ||
47 | 'where': '', | ||
48 | 'how': {} | ||
49 | }, | ||
50 | initialize: function() { | ||
51 | } | ||
52 | }); | ||
53 | |||
54 | /* Collection to hold all multiple ImgAnnoSwt */ | ||
55 | var ImgAnnoSwts = Backbone.Collection.extend({ | ||
56 | model: ImgAnnoSwt, | ||
57 | url: function() { | ||
58 | return swtr.swtstoreURL() + '/sweets'; | ||
59 | }, | ||
60 | // get all sweets/annotations of type #img-anno for a particular URI | ||
61 | // (where) | ||
62 | // @options is a javascript object, | ||
63 | // @options.where : URI of the resource for which swts to be fetched | ||
64 | // @options.who: optional username to filter sweets | ||
65 | // @options.success: success callback to call | ||
66 | // @options.error: error callback to call | ||
67 | getAll: function(options) { | ||
68 | // error checking | ||
69 | if(!options.where) { | ||
70 | throw Error('"where" option must be passed to get sweets of a URI'); | ||
71 | return false; | ||
72 | } | ||
73 | // setting up params | ||
74 | var where = options.where, | ||
75 | who = options.who || null; | ||
76 | url = swtr.swtstoreURL() + swtr.endpoints.get + '?where=' + | ||
77 | encodeURIComponent(where) + '&access_token=' + swtr.access_token; | ||
78 | if(who) { | ||
79 | url += '&who=' + who; | ||
80 | } | ||
81 | // get them! | ||
82 | this.sync('read', this, { | ||
83 | url: url, | ||
84 | success: function() { | ||
85 | if(typeof options.success === 'function') { | ||
86 | options.success.apply(this, arguments); | ||
87 | } | ||
88 | }, | ||
89 | error: function() { | ||
90 | if(typeof options.error === 'function') { | ||
91 | options.error.apply(this, arguments); | ||
92 | } | ||
93 | } | ||
94 | }); | ||
95 | }, | ||
96 | // post newly created sweets to a sweet store | ||
97 | // @options is a javascript object, | ||
98 | // @options.where : URI of the resource for which swts to be fetched | ||
99 | // @options.who: optional username to filter sweets | ||
100 | // @options.success: success callback to call | ||
101 | // @options.error: error callback to call, | ||
102 | post: function(options) { | ||
103 | var new_sweets = this.getNew(); | ||
104 | var dummy_collection = new Backbone.Collection(new_sweets); | ||
105 | |||
106 | if(!swtr.access_token) { | ||
107 | throw new Error('Access Token is required to sweet'); | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | var url = swtr.swtstoreURL() + swtr.endpoints.post + | ||
112 | '?access_token=' + swtr.access_token; | ||
113 | |||
114 | this.sync('create', dummy_collection, { | ||
115 | url: url, | ||
116 | success: function() { | ||
117 | if(typeof options.success === 'function') { | ||
118 | options.success.apply(this, arguments); | ||
119 | } | ||
120 | }, | ||
121 | error: function() { | ||
122 | if(typeof options.error === 'function') { | ||
123 | options.error.apply(this, arguments); | ||
124 | } | ||
125 | } | ||
126 | }); | ||
127 | }, | ||
128 | // return newly created models from the collection | ||
129 | getNew: function() { | ||
130 | var new_models = []; | ||
131 | this.each(function(model) { | ||
132 | if(model.isNew()) { | ||
133 | new_models.push(model); | ||
134 | } | ||
135 | }); | ||
136 | return new_models; | ||
137 | }, | ||
138 | // update part of the collection after a save on the server | ||
139 | update: function() { | ||
140 | } | ||
141 | }); | ||
142 | |||
143 | var SweetsView = Backbone.View.extend({ | ||
144 | el: $('#sweet-list-wrapper'), | ||
145 | events: { | ||
146 | 'click #sweet-cancel': 'cancelSweeting', | ||
147 | 'click #post-sweet': 'postSweets' | ||
148 | }, | ||
149 | initialize: function() { | ||
150 | this.template = _.template($('#sweet-template').html()); | ||
151 | }, | ||
152 | render: function() { | ||
153 | $('#sweet-list').html('<h4>These are your sweet annotations!</h4>'); | ||
154 | _.each(this.collection.models, function(swt) { | ||
155 | if(swt.has('id')) { | ||
156 | return false; | ||
157 | } | ||
158 | $('#sweet-list').append(this.template({ | ||
159 | who: swt.get('who'), | ||
160 | what: swt.get('what'), | ||
161 | where: swt.get('where'), | ||
162 | how: JSON.stringify(this.getHumanReadableParts(swt.get('how'))) | ||
163 | })); | ||
164 | }, this); | ||
165 | $(this.el).fadeIn(300); | ||
166 | }, | ||
167 | getHumanReadableParts: function(how) { | ||
168 | var human_readable_json = {}; | ||
169 | if(how.comment) { | ||
170 | human_readable_json['comment'] = how.comment; | ||
171 | } | ||
172 | if(how.title) { | ||
173 | human_readable_json['title'] = how.title; | ||
174 | } | ||
175 | if(how.tags) { | ||
176 | human_readable_json['tags'] = how.tags; | ||
177 | } | ||
178 | if(how.link) { | ||
179 | human_readable_json['link'] = how.link; | ||
180 | } | ||
181 | return human_readable_json; | ||
182 | }, | ||
183 | cancelSweeting: function() { | ||
184 | this.removeSwtsNotPosted(); | ||
185 | this.cleanUp(); | ||
186 | }, | ||
187 | removeSwtsNotPosted: function() { | ||
188 | var notPosted = this.collection.filter(function(model) { | ||
189 | return !model.has('id'); | ||
190 | }); | ||
191 | this.collection.remove(notPosted); | ||
192 | }, | ||
193 | postSweets: function() { | ||
194 | console.log("postSWr"); | ||
195 | var appView = swtr.appView; | ||
196 | appView.helpview.step(5); | ||
197 | appView.$overlay.show(); | ||
198 | try { | ||
199 | this.collection.post({ | ||
200 | success: function(collection, response) { | ||
201 | console.log(collection, response); | ||
202 | swtr.sweets.set(collection); | ||
203 | //TODO: move this to a annotation view or something | ||
204 | // anno.removeAll(); | ||
205 | // _.each(swtr.sweets.models, function(swt) { | ||
206 | // if(!_.has(swt.get('how'), 'editable')) { | ||
207 | // swt.get('how')['editable'] = false; | ||
208 | // //console.log(swt.get('how').text.Comment); | ||
209 | // swt.get('how').text = swtr.imgAnnoView.createPopupText(swt.get('how')); | ||
210 | // //console.log(swt.get('how')); | ||
211 | // swt.get('how').text += '\n - by ' + swt.get('who'); | ||
212 | // } | ||
213 | // //console.log(swt.get('how')); | ||
214 | // anno.addAnnotation(swt.get('how')); | ||
215 | // }); | ||
216 | //console.log(swtr.sweets.toJSON()); | ||
217 | swtr.appView.$overlay.hide(); | ||
218 | swtr.appView.helpview.step(6); | ||
219 | }, | ||
220 | error: function(jqxhr, error, text) { | ||
221 | console.log(jqxhr, error, text); | ||
222 | swtr.appView.$overlay.hide(); | ||
223 | swtr.appView.helpview.step(10); | ||
224 | } | ||
225 | }); | ||
226 | } catch(e) { | ||
227 | if(e.message == 'Access Token is required to sweet') { | ||
228 | appView.$overlay.hide(); | ||
229 | appView.helpview.step(9); | ||
230 | } | ||
231 | } | ||
232 | this.cleanUp(); | ||
233 | return false; | ||
234 | }, | ||
235 | cleanUp: function() { | ||
236 | //console.log('cleaning up'); | ||
237 | $(this.el).hide(); | ||
238 | } | ||
239 | }); | ||
240 | |||
241 | var FilterView = Backbone.View.extend({ | ||
242 | el: $('#filter-div'), | ||
243 | events: { | ||
244 | 'click #filter-user-div input': 'filter', | ||
245 | 'click #filter-tags-div input': 'filter' | ||
246 | }, | ||
247 | initialize: function() { | ||
248 | this.filter_users_template = _.template($('#filter-users').html()); | ||
249 | this.filter_tags_template = _.template($('#filter-tags').html()); | ||
250 | this.render(); | ||
251 | }, | ||
252 | render: function() { | ||
253 | //console.log(this.collection); | ||
254 | // pluck uniq authors of sweets | ||
255 | var authors = _.uniq(this.collection.pluck('who')); | ||
256 | // render them as filter controls | ||
257 | _.each(authors, function(author) { | ||
258 | $('#filter-user-div').append(this.filter_users_template({ | ||
259 | who: author | ||
260 | })); | ||
261 | }, this); | ||
262 | |||
263 | // pluck uniq tags of sweets | ||
264 | var tags = _.chain(this.collection.pluck('how')).pluck('tags').flatten(). | ||
265 | uniq().value(); | ||
266 | // render them as filter controls | ||
267 | _.each(tags, function(tag) { | ||
268 | if(tag) { | ||
269 | $('#filter-tags-div').append(this.filter_tags_template({ | ||
270 | tag: tag | ||
271 | })); | ||
272 | } | ||
273 | }, this); | ||
274 | |||
275 | //this.delegateEvents(); | ||
276 | }, | ||
277 | filter: function(event) { | ||
278 | // get id of div - parent to parent to the clicked input | ||
279 | var target_id = $(event.currentTarget).parent().parent().attr('id'); | ||
280 | // find out user/tag div | ||
281 | var which = target_id.split('-')[1]; | ||
282 | |||
283 | var selected = []; | ||
284 | $('#'+target_id + ' input:checked').each(function() { | ||
285 | selected.push($(this).attr('name')); | ||
286 | }); | ||
287 | |||
288 | if(which === 'user') { | ||
289 | this.filterUsers(selected); | ||
290 | } | ||
291 | else if(which === 'tags') { | ||
292 | this.filterTags(selected); | ||
293 | } | ||
294 | }, | ||
295 | filterUsers: function(users) { | ||
296 | if(!users.length) { | ||
297 | return; | ||
298 | } | ||
299 | var filtered_swts = this.collection.filter(function(model) { | ||
300 | if(_.indexOf(users, model.get('who')) > -1) { | ||
301 | return model; | ||
302 | } | ||
303 | }); | ||
304 | if(filtered_swts.length) { | ||
305 | anno.removeAll(); | ||
306 | _.each(filtered_swts, function(swt) { | ||
307 | anno.addAnnotation(swt.get('how')); | ||
308 | }); | ||
309 | } | ||
310 | }, | ||
311 | filterTags: function(tags) { | ||
312 | if(!tags.length) { | ||
313 | return; | ||
314 | } | ||
315 | var filtered_swts = this.collection.filter(function(model) { | ||
316 | //TODO: find a better way of doing this.. | ||
317 | var flag = false; | ||
318 | _.each(model.get('how').tags, function(tag) { | ||
319 | if(_.indexOf(tags, tag) > -1) { | ||
320 | flag = true; | ||
321 | } | ||
322 | }); | ||
323 | if(flag === true) { | ||
324 | return model; | ||
325 | } | ||
326 | }); | ||
327 | if(filtered_swts.length) { | ||
328 | anno.removeAll(); | ||
329 | _.each(filtered_swts, function(swt) { | ||
330 | anno.addAnnotation(swt.get('how')); | ||
331 | }); | ||
332 | } | ||
333 | }, | ||
334 | filterSweet: function(event) { | ||
335 | /*if(!event.currentTarget.checked) { | ||
336 | var results = this.collection.filter(function(model) { | ||
337 | if(model.get('who') != event.currentTarget.name) | ||
338 | return model; | ||
339 | }); | ||
340 | if(results.length) { | ||
341 | _.each(results, function(result) { | ||
342 | anno.removeAnnotation(result.get('how')); | ||
343 | }); | ||
344 | } | ||
345 | else { // if results is empty then remove all anno. | ||
346 | anno.removeAll(); | ||
347 | } | ||
348 | } | ||
349 | else { | ||
350 | results = this.collection.filter(function(model) { | ||
351 | if(model.get('who') == event.currentTarget.name) | ||
352 | return model; | ||
353 | }); | ||
354 | _.each(results, function(result) { | ||
355 | anno.addAnnotation(result.get('how')); | ||
356 | }); | ||
357 | |||
358 | } | ||
359 | // if(results) { | ||
360 | // anno.removeAll(); | ||
361 | // } | ||
362 | // swtr.annoView.collection = results; | ||
363 | // swtr.annoView.renderWith();*/ | ||
364 | } | ||
365 | }); | ||
366 | |||
367 | var AppView = Backbone.View.extend({ | ||
368 | el: $('body'), | ||
369 | events: { | ||
370 | 'click #user-input-submit': 'submitUserInput', | ||
371 | 'click #sweet': 'sweet', | ||
372 | 'click #sign-in': 'signIn', | ||
373 | 'click #ocd-source': 'sourceChanged' | ||
374 | //'mouseup .annotorious-editor-button-save': 'addnew_anno' | ||
375 | }, | ||
376 | initialize: function() { | ||
377 | // initialize components | ||
378 | this.source = 'none'; | ||
379 | this.helpview = new HelpView(); | ||
380 | this.sweetsview = new SweetsView({collection: swtr.sweets}); | ||
381 | |||
382 | // cache jquery selected elements which are used frequently | ||
383 | this.$overlay = $('#app-overlay'); | ||
384 | this.$img = $('#annotatable-img'); | ||
385 | |||
386 | this.helpview.step(1); | ||
387 | // initialize the oauth stuff | ||
388 | this.oauth = new Oauth({ | ||
389 | app_id: swtr.app_id, | ||
390 | endpoint: swtr.swtstoreURL() + swtr.endpoints.auth, | ||
391 | redirect_uri: swtr.oauth_redirect_uri, | ||
392 | scopes: 'email,sweet' | ||
393 | }); | ||
394 | }, | ||
395 | submitUserInput: function(event) { | ||
396 | event.preventDefault(); | ||
397 | var input = $('#user-input').val(); | ||
398 | if(this.source === 'ocd') { | ||
399 | this.loadOCDSearch(input); | ||
400 | } | ||
401 | else if (this.source === 'none') { | ||
402 | this.loadURL(input); | ||
403 | } | ||
404 | }, | ||
405 | // load a URL for annotation (can be of image or html resource for now) | ||
406 | loadURL: function(url, type) { | ||
407 | //console.log('loadURL()'); | ||
408 | if(this.source !== 'ocd') { | ||
409 | $('#ocd-results').hide(); | ||
410 | } | ||
411 | $('#img-annotation-wrapper').show(); | ||
412 | if(!url || !url.match(/http/)) { | ||
413 | this.helpview.step(13); | ||
414 | return false; | ||
415 | } | ||
416 | // if type is given explicitly; we load it as such. | ||
417 | if(type === 'image') { | ||
418 | if(swtr.imgAnnoView) { | ||
419 | swtr.imgAnnoView.setImage(url); | ||
420 | } | ||
421 | else { | ||
422 | swtr.imgAnnoView = new swtr.ImgAnnoView({collection:swtr.sweets, | ||
423 | img: this.$img[0], | ||
424 | $img: this.$img, | ||
425 | url: url}); | ||
426 | } | ||
427 | return false; | ||
428 | } | ||
429 | // else try to find what resource is the URL.. | ||
430 | // if url has an image extension then load the image annotation | ||
431 | if(url.match(/.jpg|.jpeg|.png|.gif|.bmp|.svg/)) { | ||
432 | if(swtr.imgAnnoView) { | ||
433 | swtr.imgAnnoView.setImage(url); | ||
434 | } | ||
435 | else { | ||
436 | swtr.imgAnnoView = new swtr.ImgAnnoView({collection:swtr.sweets, | ||
437 | img: this.$img[0], | ||
438 | $img: this.$img, | ||
439 | url: url}); | ||
440 | } | ||
441 | |||
442 | return false; | ||
443 | } | ||
444 | // else check with our /media-type endpoint to see what type of resource | ||
445 | // it is | ||
446 | else { | ||
447 | this.helpview.step(12); | ||
448 | this.$overlay.show(); | ||
449 | var self = this; | ||
450 | $.get('/media-type', {where: url}, function(response) { | ||
451 | //console.log(response); | ||
452 | self.$overlay.hide(); | ||
453 | if(response.type === 'image') { | ||
454 | if(swtr.imgAnnoView) { | ||
455 | swtr.imgAnnoView.setImage(url); | ||
456 | } | ||
457 | else { | ||
458 | swtr.imgAnnoView = new swtr.ImgAnnoView({collection:swtr.sweets, | ||
459 | img: self.$img[0], | ||
460 | $img: self.$img, | ||
461 | url: url}); | ||
462 | } | ||
463 | } | ||
464 | else { | ||
465 | window.location.href = '/annotate?where=' + url; | ||
466 | } | ||
467 | }); | ||
468 | } | ||
469 | }, | ||
470 | getSweets: function() { | ||
471 | var annos = _.filter(anno.getAnnotations(), function(anno) { | ||
472 | return (!_.has(anno, 'editable') || anno.editable === true); | ||
473 | }); | ||
474 | |||
475 | _.each(annos, function(anno) { | ||
476 | swtr.sweets.add({ | ||
477 | who: swtr.who, | ||
478 | where: anno.src, | ||
479 | // remove the text field; we don't want to store that in the sweets | ||
480 | how: _.omit(anno, 'text') | ||
481 | }); | ||
482 | }); | ||
483 | }, | ||
484 | showSweets: function() { | ||
485 | this.sweetsview.render(); | ||
486 | }, | ||
487 | sweet: function() { | ||
488 | this.getSweets(); | ||
489 | this.showSweets(); | ||
490 | return false; | ||
491 | }, | ||
492 | signIn: function(event) { | ||
493 | event.preventDefault(); | ||
494 | this.oauth.authorize(); | ||
495 | return false; | ||
496 | }, | ||
497 | userLoggedIn: function(username) { | ||
498 | swtr.who = username; | ||
499 | var text = 'Signed in as <b>' + swtr.who + '</b>'; | ||
500 | $('#signinview').html(text); | ||
501 | }, | ||
502 | userLoggedOut: function() { | ||
503 | swtr.who = 'Guest'; | ||
504 | $('#signinview').html('Logged out'); | ||
505 | }, | ||
506 | changeURLInputPlaceholder: function(source) { | ||
507 | switch (source) { | ||
508 | case 'ocd' : $('#user-input').attr('placeholder', 'Enter search query'); | ||
509 | break; | ||
510 | case 'none' : $('#user-input').attr('placeholder', 'Enter URL of image or web page'); | ||
511 | break; | ||
512 | } | ||
513 | }, | ||
514 | // function to change the source in the application and update the UI | ||
515 | changeSource: function(source) { | ||
516 | switch (source) { | ||
517 | case 'ocd' : this.source = 'ocd'; | ||
518 | this.helpview.step(11); | ||
519 | this.changeURLInputPlaceholder('ocd'); | ||
520 | break; | ||
521 | case 'none' : this.source = 'none'; | ||
522 | this.helpview.step(1); | ||
523 | this.changeURLInputPlaceholder('none'); | ||
524 | break; | ||
525 | } | ||
526 | }, | ||
527 | // event handler to capture control panel UI change of source | ||
528 | sourceChanged: function(event) { | ||
529 | if($('#ocd-source').is(':checked')) { | ||
530 | this.changeSource('ocd'); | ||
531 | } | ||
532 | else { | ||
533 | this.changeSource('none'); | ||
534 | } | ||
535 | }, | ||
536 | loadOCDSearch: function(input) { | ||
537 | var self = this; | ||
538 | $('#img-annotation-wrapper').hide(); | ||
539 | $('#ocd-results').show(); | ||
540 | $('#ocd-results').html('<h4 style="text-align: center;">Loading..</h4>'); | ||
541 | $.ajax({ | ||
542 | type: 'GET', | ||
543 | url: '/search/ocd', | ||
544 | data: {query: input}, | ||
545 | success: function(data) { | ||
546 | self.ocdView = new OCDView({ | ||
547 | query: input, | ||
548 | data: data, | ||
549 | model: data.hits.hits | ||
550 | }); | ||
551 | } | ||
552 | }); | ||
553 | } | ||
554 | }); | ||
555 | |||
556 | var OCDView = Backbone.View.extend({ | ||
557 | el: $('#ocd-view'), | ||
558 | events: { | ||
559 | 'click .ocd-item a': 'onImgClick', | ||
560 | 'click .pager li': 'onPagerClick' | ||
561 | }, | ||
562 | initialize: function(opts) { | ||
563 | this.data = opts.data || {}; | ||
564 | this.query = opts.query || ''; | ||
565 | this.size = 9; // num of items per page | ||
566 | this.page = 0; | ||
567 | this.item_template = _.template($('#ocd-item-template').html()); | ||
568 | this.base_template = _.template($('#ocd-view-base-template').html()); | ||
569 | this.render(); | ||
570 | }, | ||
571 | render: function() { | ||
572 | var $row_el; | ||
573 | this.$el.html(''); | ||
574 | if(!this.model.length) { | ||
575 | this.$el.html('No results could be found from your query.'); | ||
576 | return; | ||
577 | } | ||
578 | this.$el.html(this.base_template()); | ||
579 | var $el = $('#ocd-results'); | ||
580 | _.each(this.model, function(item, idx) { | ||
581 | // put every 3 items in a row | ||
582 | if(idx % 3 === 0) { | ||
583 | $row_el = $('<div class="row"></div>'); | ||
584 | $el.append($row_el); | ||
585 | } | ||
586 | $row_el.append(this.item_template({ | ||
587 | title: item._source.title, | ||
588 | media_url: item._source.media_urls[0].url, | ||
589 | authors: item._source.authors | ||
590 | })); | ||
591 | }, this); | ||
592 | this.resolveOCDURLs(); | ||
593 | this.appendTotal(); | ||
594 | }, | ||
595 | appendTotal: function() { | ||
596 | $('#ocd-total-results').html(this.data.hits.total + ' results found.'); | ||
597 | }, | ||
598 | // resolve the OCD media URLs | ||
599 | resolveOCDURLs: function() { | ||
600 | var self = this; | ||
601 | $('.ocd-item').each(function(idx, elem) { | ||
602 | var temp_arr = self.model[idx]._source.media_urls[0].url.split('/'); | ||
603 | var media_hash = temp_arr[temp_arr.length - 1]; | ||
604 | $.get('/resolve-ocd-media', {hash: media_hash}, function(resp) { | ||
605 | $(elem).find('img').attr('src', resp.url); | ||
606 | }); | ||
607 | }); | ||
608 | }, | ||
609 | rerender: function(data) { | ||
610 | this.data = data; | ||
611 | this.model = data.hits.hits; | ||
612 | this.render(); | ||
613 | }, | ||
614 | onPagerClick: function(event) { | ||
615 | event.preventDefault(); | ||
616 | var elem = $(event.currentTarget); | ||
617 | var self = this; | ||
618 | if(elem.hasClass('next')) { | ||
619 | if((this.page + 1) * this.size >= this.data.hits.total) { | ||
620 | console.log('no next page to go to'); | ||
621 | return false; | ||
622 | } | ||
623 | console.log('clicked next'); | ||
624 | this.search({ | ||
625 | query: this.query, | ||
626 | from: (this.page + 1) * this.size | ||
627 | }, function(resp) { | ||
628 | console.log('reached next page'); | ||
629 | self.page = self.page + 1; | ||
630 | self.rerender(resp); | ||
631 | }); | ||
632 | } | ||
633 | else if (elem.hasClass('previous')) { | ||
634 | if(this.page <= 0) { | ||
635 | console.log('no prev page to go to'); | ||
636 | return false; | ||
637 | } | ||
638 | console.log('clicked prev'); | ||
639 | this.search({ | ||
640 | query: this.query, | ||
641 | from: (this.page - 1) * this.size | ||
642 | }, function(resp) { | ||
643 | console.log('reached prev page'); | ||
644 | self.page = self.page - 1; | ||
645 | self.rerender(resp); | ||
646 | }); | ||
647 | } | ||
648 | return false; | ||
649 | }, | ||
650 | onImgClick: function(event) { | ||
651 | event.preventDefault(); | ||
652 | // TODO: init the image anno | ||
653 | var url = $(event.currentTarget).find('img').attr('src'); | ||
654 | swtr.appView.loadURL(url, 'image'); | ||
655 | return false; | ||
656 | }, | ||
657 | search: function(data, cb) { | ||
658 | swtr.appView.$overlay.show(); | ||
659 | var self = this; | ||
660 | $.ajax({ | ||
661 | type: 'GET', | ||
662 | url: '/search/ocd', | ||
663 | data: data, | ||
664 | success: function(resp) { | ||
665 | swtr.appView.$overlay.hide(); | ||
666 | cb(resp); | ||
667 | } | ||
668 | }); | ||
669 | } | ||
670 | }); | ||
671 | |||
672 | var HelpView = Backbone.View.extend({ | ||
673 | el: $('#helpview'), | ||
674 | events: { | ||
675 | }, | ||
676 | initialize: function() { | ||
677 | this.$text_el = $('#helpview-text'); | ||
678 | }, | ||
679 | //TODO: move from number based steps to something else. number based steps | ||
680 | //implicitly imply sequential processing..which does not happen in this | ||
681 | //case.. | ||
682 | //following helps can be async.. | ||
683 | step: function(n) { | ||
684 | var text = ''; | ||
685 | switch (n) { | ||
686 | case 0 : text = 'Getting annotations..'; | ||
687 | break; | ||
688 | case 1: text = 'Enter URL of an image or web page below, and start annotating!'; | ||
689 | break; | ||
690 | case 2: text = 'Annotate the image, or see other annotations'; | ||
691 | break; | ||
692 | case 3: text = 'Now you can sweet this annotation, or add more annotations'; | ||
693 | break; | ||
694 | case 4: text = 'Click Sweet button to publish these annotations to the Sweet Store'; | ||
695 | break; | ||
696 | case 5: text = 'Publishing your sweets'; | ||
697 | break; | ||
698 | case 6: text = 'Sweets successfully posted'; | ||
699 | break; | ||
700 | case 7: text = 'Fetching your image..'; | ||
701 | break; | ||
702 | case 8: text = 'Oops! Seems like the image URL is wrong! Or we couldn\'t fetch the image.'; | ||
703 | break; | ||
704 | case 9: text = 'You have to be <i>signed in</i> to sweet store to post sweets'; | ||
705 | break; | ||
706 | case 10: text = 'Oops! Something went wrong. We couldn\'t publish the sweets. Try again.' | ||
707 | break; | ||
708 | case 11: text = 'Search in <a href="http://www.opencultuurdata.nl/">Open Cuultur Data API</a>'; | ||
709 | break; | ||
710 | case 12: text = 'Analyzing the resource type..'; | ||
711 | break; | ||
712 | case 13: text = 'This does not seem to be a URL. Please enter a valid URL.'; | ||
713 | break; | ||
714 | } | ||
715 | $(this.$text_el).html(text); | ||
716 | $(window).scrollTop(0, 0); | ||
717 | } | ||
718 | }); | ||
719 | |||
720 | |||
721 | // utilities and helper functions to go here | ||
722 | swtr.utils = { | ||
723 | linkify: function(link) { | ||
724 | if(link.match('http')) { | ||
725 | return link; | ||
726 | } | ||
727 | else { | ||
728 | return 'http://' + link; | ||
729 | } | ||
730 | } | ||
731 | }; | ||
732 | //swtr.AppView = AppView; | ||
733 | |||
734 | var AppRouter = Backbone.Router.extend({ | ||
735 | routes: { | ||
736 | 'home': 'home', | ||
737 | 'linked-data': 'linkedData', | ||
738 | 'play': 'play', | ||
739 | 'search': 'search' | ||
740 | }, | ||
741 | home: function() { | ||
742 | this.hideAll(); | ||
743 | this.show('home-page'); | ||
744 | }, | ||
745 | linkedData: function() { | ||
746 | this.hideAll(); | ||
747 | this.show('linked-data-page'); | ||
748 | }, | ||
749 | play: function() { | ||
750 | this.hideAll(); | ||
751 | this.show('play-page'); | ||
752 | }, | ||
753 | search: function() { | ||
754 | this.hideAll(); | ||
755 | this.show('search-page'); | ||
756 | }, | ||
757 | hideAll: function() { | ||
758 | $('.page').hide(); | ||
759 | }, | ||
760 | show: function(id) { | ||
761 | $('#' + id).show(); | ||
762 | this.highlight(id); | ||
763 | }, | ||
764 | highlight: function(id) { | ||
765 | $('#swtr-navbar-collapse li').removeClass('active'); | ||
766 | var href = id.split('-page')[0]; | ||
767 | var selector = '#swtr-navbar-collapse a[href="#/' + href + '"]'; | ||
768 | $(selector).parent('li').addClass('active'); | ||
769 | } | ||
770 | }); | ||
771 | |||
772 | })(swtr); |
swtr/static/js/swtmaker.js
(0 / 772)
  | |||
1 | (function(swtr) { | ||
2 | |||
3 | //TODO: find a better way to init. | ||
4 | //Find a better way to do closure | ||
5 | //Remove script code from the HTML page | ||
6 | swtr.init = function() { | ||
7 | this.sweets = new ImgAnnoSwts(); | ||
8 | this.appView = new AppView(); | ||
9 | this.who = 'Guest'; | ||
10 | |||
11 | this.app_router = new AppRouter(); | ||
12 | Backbone.history.start(); | ||
13 | this.app_router.navigate('home'); | ||
14 | |||
15 | $.ajaxSetup({ | ||
16 | xhrFields: { | ||
17 | // we need this to send cookies to cross-domain requests | ||
18 | withCredentials: true | ||
19 | }, | ||
20 | //some browsers won't make cross-domain ajax until it is explicitly set | ||
21 | crossDomain: true | ||
22 | }); | ||
23 | this.handleOAuth(); | ||
24 | }; | ||
25 | |||
26 | swtr.handleOAuth = function() { | ||
27 | if(swtr.access_token) { | ||
28 | $('#signinview').html('Signing you in..'); | ||
29 | $.ajax({ | ||
30 | url: swtr.swtstoreURL()+'/api/users/me?access_token='+ | ||
31 | swtr.access_token, | ||
32 | success: function(data) { | ||
33 | swtr.appView.userLoggedIn(data.username); | ||
34 | }, | ||
35 | error: function() { | ||
36 | $('#signinview').html('Error signing in! Please try again'); | ||
37 | } | ||
38 | }); | ||
39 | } | ||
40 | }; | ||
41 | |||
42 | /* Model for Image Annotation Sweets */ | ||
43 | var ImgAnnoSwt = Backbone.Model.extend({ | ||
44 | defaults: { | ||
45 | 'who': '', | ||
46 | 'what': 'img-anno', | ||
47 | 'where': '', | ||
48 | 'how': {} | ||
49 | }, | ||
50 | initialize: function() { | ||
51 | } | ||
52 | }); | ||
53 | |||
54 | /* Collection to hold all multiple ImgAnnoSwt */ | ||
55 | var ImgAnnoSwts = Backbone.Collection.extend({ | ||
56 | model: ImgAnnoSwt, | ||
57 | url: function() { | ||
58 | return swtr.swtstoreURL() + '/sweets'; | ||
59 | }, | ||
60 | // get all sweets/annotations of type #img-anno for a particular URI | ||
61 | // (where) | ||
62 | // @options is a javascript object, | ||
63 | // @options.where : URI of the resource for which swts to be fetched | ||
64 | // @options.who: optional username to filter sweets | ||
65 | // @options.success: success callback to call | ||
66 | // @options.error: error callback to call | ||
67 | getAll: function(options) { | ||
68 | // error checking | ||
69 | if(!options.where) { | ||
70 | throw Error('"where" option must be passed to get sweets of a URI'); | ||
71 | return false; | ||
72 | } | ||
73 | // setting up params | ||
74 | var where = options.where, | ||
75 | who = options.who || null; | ||
76 | url = swtr.swtstoreURL() + swtr.endpoints.get + '?where=' + | ||
77 | encodeURIComponent(where) + '&access_token=' + swtr.access_token; | ||
78 | if(who) { | ||
79 | url += '&who=' + who; | ||
80 | } | ||
81 | // get them! | ||
82 | this.sync('read', this, { | ||
83 | url: url, | ||
84 | success: function() { | ||
85 | if(typeof options.success === 'function') { | ||
86 | options.success.apply(this, arguments); | ||
87 | } | ||
88 | }, | ||
89 | error: function() { | ||
90 | if(typeof options.error === 'function') { | ||
91 | options.error.apply(this, arguments); | ||
92 | } | ||
93 | } | ||
94 | }); | ||
95 | }, | ||
96 | // post newly created sweets to a sweet store | ||
97 | // @options is a javascript object, | ||
98 | // @options.where : URI of the resource for which swts to be fetched | ||
99 | // @options.who: optional username to filter sweets | ||
100 | // @options.success: success callback to call | ||
101 | // @options.error: error callback to call, | ||
102 | post: function(options) { | ||
103 | var new_sweets = this.getNew(); | ||
104 | var dummy_collection = new Backbone.Collection(new_sweets); | ||
105 | |||
106 | if(!swtr.access_token) { | ||
107 | throw new Error('Access Token is required to sweet'); | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | var url = swtr.swtstoreURL() + swtr.endpoints.post + | ||
112 | '?access_token=' + swtr.access_token; | ||
113 | |||
114 | this.sync('create', dummy_collection, { | ||
115 | url: url, | ||
116 | success: function() { | ||
117 | if(typeof options.success === 'function') { | ||
118 | options.success.apply(this, arguments); | ||
119 | } | ||
120 | }, | ||
121 | error: function() { | ||
122 | if(typeof options.error === 'function') { | ||
123 | options.error.apply(this, arguments); | ||
124 | } | ||
125 | } | ||
126 | }); | ||
127 | }, | ||
128 | // return newly created models from the collection | ||
129 | getNew: function() { | ||
130 | var new_models = []; | ||
131 | this.each(function(model) { | ||
132 | if(model.isNew()) { | ||
133 | new_models.push(model); | ||
134 | } | ||
135 | }); | ||
136 | return new_models; | ||
137 | }, | ||
138 | // update part of the collection after a save on the server | ||
139 | update: function() { | ||
140 | } | ||
141 | }); | ||
142 | |||
143 | var SweetsView = Backbone.View.extend({ | ||
144 | el: $('#sweet-list-wrapper'), | ||
145 | events: { | ||
146 | 'click #sweet-cancel': 'cancelSweeting', | ||
147 | 'click #post-sweet': 'postSweets' | ||
148 | }, | ||
149 | initialize: function() { | ||
150 | this.template = _.template($('#sweet-template').html()); | ||
151 | }, | ||
152 | render: function() { | ||
153 | $('#sweet-list').html('<h4>These are your sweet annotations!</h4>'); | ||
154 | _.each(this.collection.models, function(swt) { | ||
155 | if(swt.has('id')) { | ||
156 | return false; | ||
157 | } | ||
158 | $('#sweet-list').append(this.template({ | ||
159 | who: swt.get('who'), | ||
160 | what: swt.get('what'), | ||
161 | where: swt.get('where'), | ||
162 | how: JSON.stringify(this.getHumanReadableParts(swt.get('how'))) | ||
163 | })); | ||
164 | }, this); | ||
165 | $(this.el).fadeIn(300); | ||
166 | }, | ||
167 | getHumanReadableParts: function(how) { | ||
168 | var human_readable_json = {}; | ||
169 | if(how.comment) { | ||
170 | human_readable_json['comment'] = how.comment; | ||
171 | } | ||
172 | if(how.title) { | ||
173 | human_readable_json['title'] = how.title; | ||
174 | } | ||
175 | if(how.tags) { | ||
176 | human_readable_json['tags'] = how.tags; | ||
177 | } | ||
178 | if(how.link) { | ||
179 | human_readable_json['link'] = how.link; | ||
180 | } | ||
181 | return human_readable_json; | ||
182 | }, | ||
183 | cancelSweeting: function() { | ||
184 | this.removeSwtsNotPosted(); | ||
185 | this.cleanUp(); | ||
186 | }, | ||
187 | removeSwtsNotPosted: function() { | ||
188 | var notPosted = this.collection.filter(function(model) { | ||
189 | return !model.has('id'); | ||
190 | }); | ||
191 | this.collection.remove(notPosted); | ||
192 | }, | ||
193 | postSweets: function() { | ||
194 | console.log("postSWr"); | ||
195 | var appView = swtr.appView; | ||
196 | appView.helpview.step(5); | ||
197 | appView.$overlay.show(); | ||
198 | try { | ||
199 | this.collection.post({ | ||
200 | success: function(collection, response) { | ||
201 | console.log(collection, response); | ||
202 | swtr.sweets.set(collection); | ||
203 | //TODO: move this to a annotation view or something | ||
204 | // anno.removeAll(); | ||
205 | // _.each(swtr.sweets.models, function(swt) { | ||
206 | // if(!_.has(swt.get('how'), 'editable')) { | ||
207 | // swt.get('how')['editable'] = false; | ||
208 | // //console.log(swt.get('how').text.Comment); | ||
209 | // swt.get('how').text = swtr.imgAnnoView.createPopupText(swt.get('how')); | ||
210 | // //console.log(swt.get('how')); | ||
211 | // swt.get('how').text += '\n - by ' + swt.get('who'); | ||
212 | // } | ||
213 | // //console.log(swt.get('how')); | ||
214 | // anno.addAnnotation(swt.get('how')); | ||
215 | // }); | ||
216 | //console.log(swtr.sweets.toJSON()); | ||
217 | swtr.appView.$overlay.hide(); | ||
218 | swtr.appView.helpview.step(6); | ||
219 | }, | ||
220 | error: function(jqxhr, error, text) { | ||
221 | console.log(jqxhr, error, text); | ||
222 | swtr.appView.$overlay.hide(); | ||
223 | swtr.appView.helpview.step(10); | ||
224 | } | ||
225 | }); | ||
226 | } catch(e) { | ||
227 | if(e.message == 'Access Token is required to sweet') { | ||
228 | appView.$overlay.hide(); | ||
229 | appView.helpview.step(9); | ||
230 | } | ||
231 | } | ||
232 | this.cleanUp(); | ||
233 | return false; | ||
234 | }, | ||
235 | cleanUp: function() { | ||
236 | //console.log('cleaning up'); | ||
237 | $(this.el).hide(); | ||
238 | } | ||
239 | }); | ||
240 | |||
241 | var FilterView = Backbone.View.extend({ | ||
242 | el: $('#filter-div'), | ||
243 | events: { | ||
244 | 'click #filter-user-div input': 'filter', | ||
245 | 'click #filter-tags-div input': 'filter' | ||
246 | }, | ||
247 | initialize: function() { | ||
248 | this.filter_users_template = _.template($('#filter-users').html()); | ||
249 | this.filter_tags_template = _.template($('#filter-tags').html()); | ||
250 | this.render(); | ||
251 | }, | ||
252 | render: function() { | ||
253 | //console.log(this.collection); | ||
254 | // pluck uniq authors of sweets | ||
255 | var authors = _.uniq(this.collection.pluck('who')); | ||
256 | // render them as filter controls | ||
257 | _.each(authors, function(author) { | ||
258 | $('#filter-user-div').append(this.filter_users_template({ | ||
259 | who: author | ||
260 | })); | ||
261 | }, this); | ||
262 | |||
263 | // pluck uniq tags of sweets | ||
264 | var tags = _.chain(this.collection.pluck('how')).pluck('tags').flatten(). | ||
265 | uniq().value(); | ||
266 | // render them as filter controls | ||
267 | _.each(tags, function(tag) { | ||
268 | if(tag) { | ||
269 | $('#filter-tags-div').append(this.filter_tags_template({ | ||
270 | tag: tag | ||
271 | })); | ||
272 | } | ||
273 | }, this); | ||
274 | |||
275 | //this.delegateEvents(); | ||
276 | }, | ||
277 | filter: function(event) { | ||
278 | // get id of div - parent to parent to the clicked input | ||
279 | var target_id = $(event.currentTarget).parent().parent().attr('id'); | ||
280 | // find out user/tag div | ||
281 | var which = target_id.split('-')[1]; | ||
282 | |||
283 | var selected = []; | ||
284 | $('#'+target_id + ' input:checked').each(function() { | ||
285 | selected.push($(this).attr('name')); | ||
286 | }); | ||
287 | |||
288 | if(which === 'user') { | ||
289 | this.filterUsers(selected); | ||
290 | } | ||
291 | else if(which === 'tags') { | ||
292 | this.filterTags(selected); | ||
293 | } | ||
294 | }, | ||
295 | filterUsers: function(users) { | ||
296 | if(!users.length) { | ||
297 | return; | ||
298 | } | ||
299 | var filtered_swts = this.collection.filter(function(model) { | ||
300 | if(_.indexOf(users, model.get('who')) > -1) { | ||
301 | return model; | ||
302 | } | ||
303 | }); | ||
304 | if(filtered_swts.length) { | ||
305 | anno.removeAll(); | ||
306 | _.each(filtered_swts, function(swt) { | ||
307 | anno.addAnnotation(swt.get('how')); | ||
308 | }); | ||
309 | } | ||
310 | }, | ||
311 | filterTags: function(tags) { | ||
312 | if(!tags.length) { | ||
313 | return; | ||
314 | } | ||
315 | var filtered_swts = this.collection.filter(function(model) { | ||
316 | //TODO: find a better way of doing this.. | ||
317 | var flag = false; | ||
318 | _.each(model.get('how').tags, function(tag) { | ||
319 | if(_.indexOf(tags, tag) > -1) { | ||
320 | flag = true; | ||
321 | } | ||
322 | }); | ||
323 | if(flag === true) { | ||
324 | return model; | ||
325 | } | ||
326 | }); | ||
327 | if(filtered_swts.length) { | ||
328 | anno.removeAll(); | ||
329 | _.each(filtered_swts, function(swt) { | ||
330 | anno.addAnnotation(swt.get('how')); | ||
331 | }); | ||
332 | } | ||
333 | }, | ||
334 | filterSweet: function(event) { | ||
335 | /*if(!event.currentTarget.checked) { | ||
336 | var results = this.collection.filter(function(model) { | ||
337 | if(model.get('who') != event.currentTarget.name) | ||
338 | return model; | ||
339 | }); | ||
340 | if(results.length) { | ||
341 | _.each(results, function(result) { | ||
342 | anno.removeAnnotation(result.get('how')); | ||
343 | }); | ||
344 | } | ||
345 | else { // if results is empty then remove all anno. | ||
346 | anno.removeAll(); | ||
347 | } | ||
348 | } | ||
349 | else { | ||
350 | results = this.collection.filter(function(model) { | ||
351 | if(model.get('who') == event.currentTarget.name) | ||
352 | return model; | ||
353 | }); | ||
354 | _.each(results, function(result) { | ||
355 | anno.addAnnotation(result.get('how')); | ||
356 | }); | ||
357 | |||
358 | } | ||
359 | // if(results) { | ||
360 | // anno.removeAll(); | ||
361 | // } | ||
362 | // swtr.annoView.collection = results; | ||
363 | // swtr.annoView.renderWith();*/ | ||
364 | } | ||
365 | }); | ||
366 | |||
367 | var AppView = Backbone.View.extend({ | ||
368 | el: $('body'), | ||
369 | events: { | ||
370 | 'click #user-input-submit': 'submitUserInput', | ||
371 | 'click #sweet': 'sweet', | ||
372 | 'click #sign-in': 'signIn', | ||
373 | 'click #ocd-source': 'sourceChanged' | ||
374 | //'mouseup .annotorious-editor-button-save': 'addnew_anno' | ||
375 | }, | ||
376 | initialize: function() { | ||
377 | // initialize components | ||
378 | this.source = 'none'; | ||
379 | this.helpview = new HelpView(); | ||
380 | this.sweetsview = new SweetsView({collection: swtr.sweets}); | ||
381 | |||
382 | // cache jquery selected elements which are used frequently | ||
383 | this.$overlay = $('#app-overlay'); | ||
384 | this.$img = $('#annotatable-img'); | ||
385 | |||
386 | this.helpview.step(1); | ||
387 | // initialize the oauth stuff | ||
388 | this.oauth = new Oauth({ | ||
389 | app_id: swtr.app_id, | ||
390 | endpoint: swtr.swtstoreURL() + swtr.endpoints.auth, | ||
391 | redirect_uri: swtr.oauth_redirect_uri, | ||
392 | scopes: 'email,sweet' | ||
393 | }); | ||
394 | }, | ||
395 | submitUserInput: function(event) { | ||
396 | event.preventDefault(); | ||
397 | var input = $('#user-input').val(); | ||
398 | if(this.source === 'ocd') { | ||
399 | this.loadOCDSearch(input); | ||
400 | } | ||
401 | else if (this.source === 'none') { | ||
402 | this.loadURL(input); | ||
403 | } | ||
404 | }, | ||
405 | // load a URL for annotation (can be of image or html resource for now) | ||
406 | loadURL: function(url, type) { | ||
407 | //console.log('loadURL()'); | ||
408 | if(this.source !== 'ocd') { | ||
409 | $('#ocd-results').hide(); | ||
410 | } | ||
411 | $('#img-annotation-wrapper').show(); | ||
412 | if(!url || !url.match(/http/)) { | ||
413 | this.helpview.step(13); | ||
414 | return false; | ||
415 | } | ||
416 | // if type is given explicitly; we load it as such. | ||
417 | if(type === 'image') { | ||
418 | if(swtr.imgAnnoView) { | ||
419 | swtr.imgAnnoView.setImage(url); | ||
420 | } | ||
421 | else { | ||
422 | swtr.imgAnnoView = new swtr.ImgAnnoView({collection:swtr.sweets, | ||
423 | img: this.$img[0], | ||
424 | $img: this.$img, | ||
425 | url: url}); | ||
426 | } | ||
427 | return false; | ||
428 | } | ||
429 | // else try to find what resource is the URL.. | ||
430 | // if url has an image extension then load the image annotation | ||
431 | if(url.match(/.jpg|.jpeg|.png|.gif|.bmp|.svg/)) { | ||
432 | if(swtr.imgAnnoView) { | ||
433 | swtr.imgAnnoView.setImage(url); | ||
434 | } | ||
435 | else { | ||
436 | swtr.imgAnnoView = new swtr.ImgAnnoView({collection:swtr.sweets, | ||
437 | img: this.$img[0], | ||
438 | $img: this.$img, | ||
439 | url: url}); | ||
440 | } | ||
441 | |||
442 | return false; | ||
443 | } | ||
444 | // else check with our /media-type endpoint to see what type of resource | ||
445 | // it is | ||
446 | else { | ||
447 | this.helpview.step(12); | ||
448 | this.$overlay.show(); | ||
449 | var self = this; | ||
450 | $.get('/media-type', {where: url}, function(response) { | ||
451 | //console.log(response); | ||
452 | self.$overlay.hide(); | ||
453 | if(response.type === 'image') { | ||
454 | if(swtr.imgAnnoView) { | ||
455 | swtr.imgAnnoView.setImage(url); | ||
456 | } | ||
457 | else { | ||
458 | swtr.imgAnnoView = new swtr.ImgAnnoView({collection:swtr.sweets, | ||
459 | img: self.$img[0], | ||
460 | $img: self.$img, | ||
461 | url: url}); | ||
462 | } | ||
463 | } | ||
464 | else { | ||
465 | window.location.href = '/annotate?where=' + url; | ||
466 | } | ||
467 | }); | ||
468 | } | ||
469 | }, | ||
470 | getSweets: function() { | ||
471 | var annos = _.filter(anno.getAnnotations(), function(anno) { | ||
472 | return (!_.has(anno, 'editable') || anno.editable === true); | ||
473 | }); | ||
474 | |||
475 | _.each(annos, function(anno) { | ||
476 | swtr.sweets.add({ | ||
477 | who: swtr.who, | ||
478 | where: anno.src, | ||
479 | // remove the text field; we don't want to store that in the sweets | ||
480 | how: _.omit(anno, 'text') | ||
481 | }); | ||
482 | }); | ||
483 | }, | ||
484 | showSweets: function() { | ||
485 | this.sweetsview.render(); | ||
486 | }, | ||
487 | sweet: function() { | ||
488 | this.getSweets(); | ||
489 | this.showSweets(); | ||
490 | return false; | ||
491 | }, | ||
492 | signIn: function(event) { | ||
493 | event.preventDefault(); | ||
494 | this.oauth.authorize(); | ||
495 | return false; | ||
496 | }, | ||
497 | userLoggedIn: function(username) { | ||
498 | swtr.who = username; | ||
499 | var text = 'Signed in as <b>' + swtr.who + '</b>'; | ||
500 | $('#signinview').html(text); | ||
501 | }, | ||
502 | userLoggedOut: function() { | ||
503 | swtr.who = 'Guest'; | ||
504 | $('#signinview').html('Logged out'); | ||
505 | }, | ||
506 | changeURLInputPlaceholder: function(source) { | ||
507 | switch (source) { | ||
508 | case 'ocd' : $('#user-input').attr('placeholder', 'Enter search query'); | ||
509 | break; | ||
510 | case 'none' : $('#user-input').attr('placeholder', 'Enter URL of image or web page'); | ||
511 | break; | ||
512 | } | ||
513 | }, | ||
514 | // function to change the source in the application and update the UI | ||
515 | changeSource: function(source) { | ||
516 | switch (source) { | ||
517 | case 'ocd' : this.source = 'ocd'; | ||
518 | this.helpview.step(11); | ||
519 | this.changeURLInputPlaceholder('ocd'); | ||
520 | break; | ||
521 | case 'none' : this.source = 'none'; | ||
522 | this.helpview.step(1); | ||
523 | this.changeURLInputPlaceholder('none'); | ||
524 | break; | ||
525 | } | ||
526 | }, | ||
527 | // event handler to capture control panel UI change of source | ||
528 | sourceChanged: function(event) { | ||
529 | if($('#ocd-source').is(':checked')) { | ||
530 | this.changeSource('ocd'); | ||
531 | } | ||
532 | else { | ||
533 | this.changeSource('none'); | ||
534 | } | ||
535 | }, | ||
536 | loadOCDSearch: function(input) { | ||
537 | var self = this; | ||
538 | $('#img-annotation-wrapper').hide(); | ||
539 | $('#ocd-results').show(); | ||
540 | $('#ocd-results').html('<h4 style="text-align: center;">Loading..</h4>'); | ||
541 | $.ajax({ | ||
542 | type: 'GET', | ||
543 | url: '/search/ocd', | ||
544 | data: {query: input}, | ||
545 | success: function(data) { | ||
546 | self.ocdView = new OCDView({ | ||
547 | query: input, | ||
548 | data: data, | ||
549 | model: data.hits.hits | ||
550 | }); | ||
551 | } | ||
552 | }); | ||
553 | } | ||
554 | }); | ||
555 | |||
556 | var OCDView = Backbone.View.extend({ | ||
557 | el: $('#ocd-view'), | ||
558 | events: { | ||
559 | 'click .ocd-item a': 'onImgClick', | ||
560 | 'click .pager li': 'onPagerClick' | ||
561 | }, | ||
562 | initialize: function(opts) { | ||
563 | this.data = opts.data || {}; | ||
564 | this.query = opts.query || ''; | ||
565 | this.size = 9; // num of items per page | ||
566 | this.page = 0; | ||
567 | this.item_template = _.template($('#ocd-item-template').html()); | ||
568 | this.base_template = _.template($('#ocd-view-base-template').html()); | ||
569 | this.render(); | ||
570 | }, | ||
571 | render: function() { | ||
572 | var $row_el; | ||
573 | this.$el.html(''); | ||
574 | if(!this.model.length) { | ||
575 | this.$el.html('No results could be found from your query.'); | ||
576 | return; | ||
577 | } | ||
578 | this.$el.html(this.base_template()); | ||
579 | var $el = $('#ocd-results'); | ||
580 | _.each(this.model, function(item, idx) { | ||
581 | // put every 3 items in a row | ||
582 | if(idx % 3 === 0) { | ||
583 | $row_el = $('<div class="row"></div>'); | ||
584 | $el.append($row_el); | ||
585 | } | ||
586 | $row_el.append(this.item_template({ | ||
587 | title: item._source.title, | ||
588 | media_url: item._source.media_urls[0].url, | ||
589 | authors: item._source.authors | ||
590 | })); | ||
591 | }, this); | ||
592 | this.resolveOCDURLs(); | ||
593 | this.appendTotal(); | ||
594 | }, | ||
595 | appendTotal: function() { | ||
596 | $('#ocd-total-results').html(this.data.hits.total + ' results found.'); | ||
597 | }, | ||
598 | // resolve the OCD media URLs | ||
599 | resolveOCDURLs: function() { | ||
600 | var self = this; | ||
601 | $('.ocd-item').each(function(idx, elem) { | ||
602 | var temp_arr = self.model[idx]._source.media_urls[0].url.split('/'); | ||
603 | var media_hash = temp_arr[temp_arr.length - 1]; | ||
604 | $.get('/resolve-ocd-media', {hash: media_hash}, function(resp) { | ||
605 | $(elem).find('img').attr('src', resp.url); | ||
606 | }); | ||
607 | }); | ||
608 | }, | ||
609 | rerender: function(data) { | ||
610 | this.data = data; | ||
611 | this.model = data.hits.hits; | ||
612 | this.render(); | ||
613 | }, | ||
614 | onPagerClick: function(event) { | ||
615 | event.preventDefault(); | ||
616 | var elem = $(event.currentTarget); | ||
617 | var self = this; | ||
618 | if(elem.hasClass('next')) { | ||
619 | if((this.page + 1) * this.size >= this.data.hits.total) { | ||
620 | console.log('no next page to go to'); | ||
621 | return false; | ||
622 | } | ||
623 | console.log('clicked next'); | ||
624 | this.search({ | ||
625 | query: this.query, | ||
626 | from: (this.page + 1) * this.size | ||
627 | }, function(resp) { | ||
628 | console.log('reached next page'); | ||
629 | self.page = self.page + 1; | ||
630 | self.rerender(resp); | ||
631 | }); | ||
632 | } | ||
633 | else if (elem.hasClass('previous')) { | ||
634 | if(this.page <= 0) { | ||
635 | console.log('no prev page to go to'); | ||
636 | return false; | ||
637 | } | ||
638 | console.log('clicked prev'); | ||
639 | this.search({ | ||
640 | query: this.query, | ||
641 | from: (this.page - 1) * this.size | ||
642 | }, function(resp) { | ||
643 | console.log('reached prev page'); | ||
644 | self.page = self.page - 1; | ||
645 | self.rerender(resp); | ||
646 | }); | ||
647 | } | ||
648 | return false; | ||
649 | }, | ||
650 | onImgClick: function(event) { | ||
651 | event.preventDefault(); | ||
652 | // TODO: init the image anno | ||
653 | var url = $(event.currentTarget).find('img').attr('src'); | ||
654 | swtr.appView.loadURL(url, 'image'); | ||
655 | return false; | ||
656 | }, | ||
657 | search: function(data, cb) { | ||
658 | swtr.appView.$overlay.show(); | ||
659 | var self = this; | ||
660 | $.ajax({ | ||
661 | type: 'GET', | ||
662 | url: '/search/ocd', | ||
663 | data: data, | ||
664 | success: function(resp) { | ||
665 | swtr.appView.$overlay.hide(); | ||
666 | cb(resp); | ||
667 | } | ||
668 | }); | ||
669 | } | ||
670 | }); | ||
671 | |||
672 | var HelpView = Backbone.View.extend({ | ||
673 | el: $('#helpview'), | ||
674 | events: { | ||
675 | }, | ||
676 | initialize: function() { | ||
677 | this.$text_el = $('#helpview-text'); | ||
678 | }, | ||
679 | //TODO: move from number based steps to something else. number based steps | ||
680 | //implicitly imply sequential processing..which does not happen in this | ||
681 | //case.. | ||
682 | //following helps can be async.. | ||
683 | step: function(n) { | ||
684 | var text = ''; | ||
685 | switch (n) { | ||
686 | case 0 : text = 'Getting annotations..'; | ||
687 | break; | ||
688 | case 1: text = 'Enter URL of an image or web page below, and start annotating!'; | ||
689 | break; | ||
690 | case 2: text = 'Annotate the image, or see other annotations'; | ||
691 | break; | ||
692 | case 3: text = 'Now you can sweet this annotation, or add more annotations'; | ||
693 | break; | ||
694 | case 4: text = 'Click Sweet button to publish these annotations to the Sweet Store'; | ||
695 | break; | ||
696 | case 5: text = 'Publishing your sweets'; | ||
697 | break; | ||
698 | case 6: text = 'Sweets successfully posted'; | ||
699 | break; | ||
700 | case 7: text = 'Fetching your image..'; | ||
701 | break; | ||
702 | case 8: text = 'Oops! Seems like the image URL is wrong! Or we couldn\'t fetch the image.'; | ||
703 | break; | ||
704 | case 9: text = 'You have to be <i>signed in</i> to sweet store to post sweets'; | ||
705 | break; | ||
706 | case 10: text = 'Oops! Something went wrong. We couldn\'t publish the sweets. Try again.' | ||
707 | break; | ||
708 | case 11: text = 'Search in <a href="http://www.opencultuurdata.nl/">Open Cuultur Data API</a>'; | ||
709 | break; | ||
710 | case 12: text = 'Analyzing the resource type..'; | ||
711 | break; | ||
712 | case 13: text = 'This does not seem to be a URL. Please enter a valid URL.'; | ||
713 | break; | ||
714 | } | ||
715 | $(this.$text_el).html(text); | ||
716 | $(window).scrollTop(0, 0); | ||
717 | } | ||
718 | }); | ||
719 | |||
720 | |||
721 | // utilities and helper functions to go here | ||
722 | swtr.utils = { | ||
723 | linkify: function(link) { | ||
724 | if(link.match('http')) { | ||
725 | return link; | ||
726 | } | ||
727 | else { | ||
728 | return 'http://' + link; | ||
729 | } | ||
730 | } | ||
731 | }; | ||
732 | //swtr.AppView = AppView; | ||
733 | |||
734 | var AppRouter = Backbone.Router.extend({ | ||
735 | routes: { | ||
736 | 'home': 'home', | ||
737 | 'linked-data': 'linkedData', | ||
738 | 'play': 'play', | ||
739 | 'search': 'search' | ||
740 | }, | ||
741 | home: function() { | ||
742 | this.hideAll(); | ||
743 | this.show('home-page'); | ||
744 | }, | ||
745 | linkedData: function() { | ||
746 | this.hideAll(); | ||
747 | this.show('linked-data-page'); | ||
748 | }, | ||
749 | play: function() { | ||
750 | this.hideAll(); | ||
751 | this.show('play-page'); | ||
752 | }, | ||
753 | search: function() { | ||
754 | this.hideAll(); | ||
755 | this.show('search-page'); | ||
756 | }, | ||
757 | hideAll: function() { | ||
758 | $('.page').hide(); | ||
759 | }, | ||
760 | show: function(id) { | ||
761 | $('#' + id).show(); | ||
762 | this.highlight(id); | ||
763 | }, | ||
764 | highlight: function(id) { | ||
765 | $('#swtr-navbar-collapse li').removeClass('active'); | ||
766 | var href = id.split('-page')[0]; | ||
767 | var selector = '#swtr-navbar-collapse a[href="#/' + href + '"]'; | ||
768 | $(selector).parent('li').addClass('active'); | ||
769 | } | ||
770 | }); | ||
771 | |||
772 | })(swtr); |
swtr/templates/index.html
(2 / 2)
  | |||
179 | 179 | <script src="{{ url_for('static', filename='js/lib/custom-fields-plugin.js') }}"></script> | |
180 | 180 | <script src="{{ url_for('static', filename='js/oauth.js') }}"></script> | |
181 | 181 | <script type="text/javascript" src="{{ url_for('static', filename='js/lib/bootstrap-tags.min.js') }}"></script> | |
182 | <script src="{{ url_for('static', filename='js/imganno.js') }}"></script> | ||
183 | <script src="{{ url_for('static', filename='js/swtmaker.js') }}"></script> | ||
182 | <script src="{{ url_for('static', filename='js/img_swtr.js') }}"></script> | ||
183 | <script src="{{ url_for('static', filename='js/main.js') }}"></script> | ||
184 | 184 | ||
185 | 185 | <script type="text/template" id="sweet-template"> | |
186 | 186 | <li class="sweet"> |