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