Hmm..
[redakcja.git] / project / static / js / views / gallery.js
1 /*global View render_template panels */
2 var ImageGalleryView = View.extend({
3   _className: 'ImageGalleryView',
4   element: null,
5   model: null,
6   currentPage: -1,
7   pageZoom: 1.0,
8   template: 'image-gallery-view-template',
9   
10   init: function(element, model, parent, template) 
11   {    
12     console.log("init for gallery");
13     this._super(element, model, template);
14     this.parent = parent;
15        
16     this.model
17       .addObserver(this, 'data', this.modelDataChanged.bind(this))
18       .addObserver(this, 'state', this.modelStateChanged.bind(this));
19    
20     //$('.image-gallery-view', this.element).html(this.model.get('data'));
21     this.modelStateChanged('state', this.model.get('state'));
22     this.model.load();    
23   },
24   
25   modelDataChanged: function(property, value) 
26   {    
27     if( property == 'data')
28     {
29         this.render();
30         this.gotoPage(this.currentPage);        
31     }   
32   },
33
34   gotoPage: function(index) 
35   {
36      if (index < 0) 
37          index = 0;
38     
39      var n = this.$pages.length;
40      if (index >= n) index = n-1;
41
42      if( (this.currentPage == index) )
43          return;
44
45      var cpage = this.$currentPage();
46
47      if(cpage) {
48          var offset = this.pageViewOffset(cpage);
49          this.cleanPage(cpage);
50      }
51      
52      this.currentPage = index;
53
54      cpage = this.$currentPage()
55      this.renderImage(cpage);
56
57      if(offset) {
58          cpage.css({top: offset.y, left: offset.x});
59      }
60
61      var self = this;
62      $('img', cpage).bind('load', function() {
63         if(offset)
64              self.setPageViewOffset(cpage, offset);
65      });
66      
67      cpage.show();
68
69      if(this.currentPage == n-1)
70           this.$nextButton.attr('disabled', 'disabled');
71      else
72           this.$nextButton.removeAttr('disabled');
73
74       if(this.currentPage == 0)
75           this.$prevButton.attr('disabled', 'disabled');
76       else
77           this.$prevButton.removeAttr('disabled');
78
79       this.$pageInput.val( (this.currentPage+1) );
80   },
81   
82   reload: function() {},
83   
84   modelStateChanged: function(property, value) {   
85     if (value == 'loading') {
86       this.parent.freeze('Ɓadowanie...');
87     } else {
88       this.parent.unfreeze();
89     }
90   },
91
92   $currentPage: function() {
93       if(this.currentPage >= 0 && this.currentPage < this.$pages.length)
94           return $(this.$pages[this.currentPage]);
95       else
96           return undefined;
97   },    
98
99   cleanPage: function($page) {
100     $page.hide();
101     $('img', $page).unbind();
102     
103     $page.empty();
104     
105     this.setPageViewOffset($page, {x:0, y:0});
106   },
107
108   pageDragStart: function(event)
109   {      
110       this.dragStart = {x: event.clientX, y: event.clientY};
111       $(window).bind('mousemove.imagedrag', this.pageDrag.bind(this));
112       $(window).bind('mouseup.imagedrag', this.pageDragStop.bind(this));
113       
114       this.$currentPage().css('cursor', 'move');
115
116       return false;
117   },
118
119   pageDrag: function(event)
120   {
121       if(!this.dragStart) return;
122
123       var delta = {
124            x: this.dragStart.x - event.clientX,
125            y: this.dragStart.y - event.clientY };     
126
127       var offset = this.pageViewOffset( $(this.$pages[this.currentPage]) );
128       offset.x -= delta.x;
129       offset.y -= delta.y;
130       this.setPageViewOffset( $(this.$pages[this.currentPage]), offset);
131       
132       this.dragStart = {x: event.clientX, y: event.clientY };     
133       return false;
134   },
135
136   pageDragStop: function(event) {
137       this.$currentPage().css('cursor', 'auto');
138
139       this.dragStart = undefined;
140       $(window).unbind('mousemove.imagedrag');
141       $(window).unbind('mouseup.imagedrag');
142
143       return false;
144   },
145
146   pageViewOffset: function($page) {
147       var left = parseInt($page.css('left'));
148       var top = parseInt($page.css('top'));
149
150       return {x: left, y: top};
151   },
152
153   setPageViewOffset: function($page, offset) {
154       // check if the image will be actually visible
155       // and correct
156       var MARGIN = 30;
157
158
159       var vp_width = this.$pageListRoot.width();
160       var vp_height = this.$pageListRoot.height();
161       
162       var width = $page.outerWidth();
163       var height = $page.outerHeight();
164
165       // console.log(offset, vp_width, vp_height, width, height);
166       if( offset.x+width-MARGIN < 0 ) {
167         // console.log('too much on the left', offset.x, -width)
168         offset.x = -width+MARGIN;
169       }
170       
171       // too much on the right
172       if( offset.x > vp_width-MARGIN) {
173           offset.x = vp_width-MARGIN;
174           // console.log('too much on the right', offset.x, vp_width, width)
175       }
176       
177       if( offset.y+height-MARGIN < 0)
178         offset.y = -height+MARGIN;      
179
180       if( offset.y > vp_height-MARGIN)
181           offset.y = vp_height-MARGIN;               
182       
183       $page.css({left: offset.x, top: offset.y});           
184   }, 
185   
186   renderImage: function(target) 
187   {
188       var source = target.attr('ui:model');
189       var orig_width = parseInt(target.attr('ui:width'));
190       var orig_height = parseInt(target.attr('ui:height'));
191
192       target.html('<img src="' + source
193            + '" width="' + Math.floor(orig_width * this.pageZoom)
194            + '" height="' + Math.floor(orig_height * this.pageZoom)
195            + '" />');
196        
197       $('img', target).
198         css({
199             'user-select': 'none',
200             '-webkit-user-select': 'none',
201             '-khtml-user-select': 'none',
202             '-moz-user-select': 'none'
203         }).
204         attr('unselectable', 'on').
205         mousedown(this.pageDragStart.bind(this));    
206   },
207
208   render: function() 
209   {
210       console.log('rendering:', this._className);
211       
212       /* first unbind all */    
213       if(this.$nextButton) this.$nextButton.unbind();
214       if(this.$prevButton) this.$prevButton.unbind();
215       if(this.$jumpButton) this.$jumpButton.unbind();
216       if(this.$pageInput) this.$pageInput.unbind();
217
218       if(this.$zoomInButton) this.$zoomInButton.unbind();
219       if(this.$zoomOutButton) this.$zoomOutButton.unbind();
220       if(this.$zoomResetButton) this.$zoomResetButton.unbind();
221
222       /* render */
223       this.element.html(render_template(this.template, this));
224
225       /* fetch important parts */
226       this.$pageListRoot = $('.image-gallery-page-list', this.element);
227       this.$pages = $('.image-gallery-page-container', this.$pageListRoot);
228
229       this.$nextButton = $('.image-gallery-next-button', this.element);
230       this.$prevButton = $('.image-gallery-prev-button', this.element);
231       this.$pageInput = $('.image-gallery-current-page', this.element);
232
233       // this.$zoomSelect = $('.image-gallery-current-zoom', this.element);
234       this.$zoomInButton = $('.image-gallery-zoom-in', this.element);
235       this.$zoomOutButton = $('.image-gallery-zoom-out', this.element);
236       this.$zoomResetButton = $('.image-gallery-zoom-reset', this.element);
237
238       /* re-bind events */
239       this.$nextButton.click( this.nextPage.bind(this) );
240       this.$prevButton.click( this.prevPage.bind(this) );
241       this.$pageInput.change( this.jumpToPage.bind(this) );
242
243       // this.$zoomSelect.change( this.zoomChanged.bind(this) );
244       this.$zoomInButton.click( this.zoomInOneStep.bind(this) );
245       this.$zoomOutButton.click( this.zoomOutOneStep.bind(this) );
246       this.$zoomResetButton.click( this.zoomReset.bind(this) );
247
248       this.gotoPage(this.currentPage);
249       this.changePageZoom(this.pageZoom);
250   },
251
252   jumpToPage: function() {     
253         this.gotoPage(parseInt(this.$pageInput.val())-1);
254   },
255   
256   nextPage: function() {
257       this.gotoPage(this.currentPage + 1);    
258   },
259
260   prevPage: function() {
261       this.gotoPage(this.currentPage - 1);
262   },
263
264   zoomReset: function() {
265       this.changePageZoom(1.0);
266   },
267
268   zoomInOneStep: function() {
269       var zoom = this.pageZoom + 0.1;
270       if(zoom > 3.0) zoom = 3.0;
271       this.changePageZoom(zoom);
272   },
273
274   zoomOutOneStep: function() {
275       var zoom = this.pageZoom - 0.1;
276       if(zoom < 0.3) zoom = 0.3;
277       this.changePageZoom(zoom);
278   },
279
280   changePageZoom: function(value) {
281       var current = this.$currentPage();
282
283       if(!current) return;
284
285       var alpha = value/this.pageZoom;
286       this.pageZoom = value;
287
288       var nwidth = current.attr('ui:width') * this.pageZoom;
289       var nheight = current.attr('ui:height') * this.pageZoom;
290       var off_top = parseInt(current.css('top'));
291       var off_left = parseInt(current.css('left'));
292       
293       var vpx = this.$pageListRoot.width() * 0.5;
294       var vpy = this.$pageListRoot.height() * 0.5;
295       
296       var new_off_left = vpx - alpha*(vpx-off_left);
297       var new_off_top = vpy - alpha*(vpy-off_top);
298                  
299       $('img', current).attr('width', nwidth);
300       $('img', current).attr('height', nheight);
301       
302       this.setPageViewOffset(current, {
303           y: new_off_top, x: new_off_left
304       });
305
306       // this.$zoomSelect.val(this.pageZoom);
307       // console.log('Zoom is now', this.pageZoom);
308   },
309   
310   dispose: function()
311   {
312       console.log("Disposing gallery.");
313       this.model.removeObserver(this);
314       this._super();
315   }
316 });
317
318 // Register view
319 panels['gallery'] = ImageGalleryView;