1 | /** |
||
2 | * EGroupware eTemplate2 - JS object implementing expose view of media and a gallery view |
||
3 | * |
||
4 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||
5 | * @package etemplate |
||
6 | * @subpackage api |
||
7 | * @link http://www.egroupware.org |
||
8 | * @author Hadi Nategh <hn[at]stylite.de> |
||
9 | * @copyright Stylite AG |
||
10 | * @version $Id$ |
||
11 | */ |
||
12 | |||
13 | /*egw:uses |
||
14 | /vendor/bower-asset/jquery/dist/jquery.js; |
||
15 | /api/js/jquery/blueimp/js/blueimp-gallery.min.js; |
||
16 | */ |
||
17 | |||
18 | /** |
||
19 | * Interface all exposed widget must support in order to getMedia for the blueimp Gallery. |
||
20 | */ |
||
21 | var et2_IExposable = new Interface( |
||
22 | { |
||
23 | /** |
||
24 | * get media an array of media objects to pass to blueimp Gallery |
||
25 | * @param {array} _attrs |
||
26 | */ |
||
27 | getMedia: function(_attrs) {} |
||
28 | }); |
||
29 | |||
30 | /** |
||
31 | * This function extends the given widget with blueimp gallery plugin |
||
32 | * |
||
33 | * @param {type} widget |
||
34 | * @returns {widget} |
||
35 | */ |
||
36 | function expose (widget) |
||
37 | { |
||
38 | "use strict"; |
||
39 | |||
40 | // Common expose functions |
||
41 | var THUMBNAIL_MAX = 100; |
||
42 | |||
43 | // Minimum data to qualify as an image and not cause errors |
||
44 | var IMAGE_DEFAULT = { |
||
45 | title: egw.lang('loading'), |
||
46 | href: '', |
||
47 | type: 'image/png', |
||
48 | thumbnail: '', |
||
49 | loading: true |
||
50 | }; |
||
51 | |||
52 | // For filtering to only show things we can handle |
||
53 | var mime_regex = new RegExp(/(video\/(mp4|ogg|webm))|(image\/:*(?!tif|x-xcf|pdf))/); |
||
54 | |||
55 | // open office document mime type currently supported by webodf editor |
||
56 | var mime_odf_regex = new RegExp(/application\/vnd\.oasis\.opendocument\.text/); |
||
57 | |||
58 | // IE only supports video/mp4 mime type |
||
59 | if (navigator.userAgent.match(/(MSIE|Trident)/)) mime_regex.compile(/(video\/mp4)|(image\/:*(?!tif|x-xcf|pdf))/); |
||
60 | |||
61 | // Only one gallery |
||
62 | var gallery = null; |
||
63 | |||
64 | /** |
||
65 | * See if the current widget is in a nextmatch, as this allows us to display |
||
66 | * thumbnails underneath |
||
67 | * |
||
68 | * @param {et2_IExposable} widget |
||
69 | * @returns {et2_nextmatch | null} |
||
70 | */ |
||
71 | var find_nextmatch = function(widget) |
||
72 | { |
||
73 | var current = widget; |
||
74 | var nextmatch = null; |
||
75 | while(nextmatch == null && current) |
||
76 | { |
||
77 | current = current.getParent(); |
||
78 | if(typeof current !='undefined' && current.instanceOf(et2_nextmatch)) |
||
79 | { |
||
80 | nextmatch = current; |
||
81 | } |
||
82 | } |
||
83 | // No nextmatch, or nextmatch not quite ready |
||
84 | // At the moment only filemanger nm would work |
||
85 | // as gallery, thus we disable other nestmatches |
||
86 | // to build up gallery but filemanager |
||
87 | if(nextmatch == null || nextmatch.controller == null || !nextmatch.dom_id.match(/filemanager/,'ig')) return null; |
||
88 | |||
89 | return nextmatch; |
||
90 | }; |
||
91 | |||
92 | /** |
||
93 | * Read images out of the data for the nextmatch |
||
94 | * |
||
95 | * @param {et2_nextmatch} nm |
||
96 | * @param {Object[]} images |
||
97 | * @param {number} start_at |
||
98 | * @returns {undefined} |
||
99 | */ |
||
100 | var read_from_nextmatch = function(nm, images, start_at) |
||
101 | { |
||
102 | if(!start_at) start_at = 0; |
||
103 | var image_index = start_at; |
||
104 | var stop = Math.max.apply(null,Object.keys(nm.controller._indexMap)); |
||
105 | |||
106 | for(var i = start_at; i <= stop; i++) |
||
107 | { |
||
108 | if(!nm.controller._indexMap[i] || !nm.controller._indexMap[i].uid) |
||
109 | { |
||
110 | // Returning instead of using IMAGE_DEFAULT means we stop as |
||
111 | // soon as a hole is found, instead of getting everything that is |
||
112 | // available. The gallery can't fill in the holes. |
||
113 | images[image_index++] = IMAGE_DEFAULT; |
||
114 | continue; |
||
115 | } |
||
116 | var uid = nm.controller._indexMap[i].uid; |
||
117 | if(!uid) continue; |
||
118 | var data = egw.dataGetUIDdata(uid); |
||
119 | if(data && data.data && data.data.mime && mime_regex.test(data.data.mime)) |
||
120 | { |
||
121 | var media = this.getMedia(data.data); |
||
122 | images[image_index++] = jQuery.extend({}, data.data, media[0]); |
||
123 | } |
||
124 | } |
||
125 | }; |
||
126 | |||
127 | /** |
||
128 | * Set a particular index/image in the gallery instead of just appending |
||
129 | * it to the end |
||
130 | * |
||
131 | * @param {integer} index |
||
132 | * @param {Object} image |
||
133 | * @returns {undefined} |
||
134 | */ |
||
135 | var set_slide = function(index, image) |
||
136 | { |
||
137 | var active = (index == gallery.index); |
||
138 | |||
139 | // Pad with blanks until length is right |
||
140 | while(index > gallery.getNumber()) |
||
141 | { |
||
142 | gallery.add([jQuery.extend({}, IMAGE_DEFAULT)]); |
||
143 | } |
||
144 | |||
145 | // Don't bother with adding a default, we just did that |
||
146 | if(image.loading) |
||
147 | { |
||
148 | //Add load class if it's really a slide with error |
||
149 | if (gallery.slidesContainer.find('[data-index="'+index+'"]').hasClass(gallery.options.slideErrorClass)) |
||
150 | jQuery(gallery.slides[index]) |
||
151 | .addClass(gallery.options.slideLoadingClass) |
||
152 | .removeClass(gallery.options.slideErrorClass); |
||
153 | return; |
||
154 | } |
||
155 | // Remove the loading class if the slide is loaded |
||
156 | else |
||
157 | { |
||
0 ignored issues
–
show
Comprehensibility
introduced
by
![]() |
|||
158 | jQuery(gallery.slides[index]).removeClass(gallery.options.slideLoadingClass); |
||
159 | } |
||
160 | |||
161 | // Just use add to let gallery create everything it needs |
||
162 | var new_index = gallery.num; |
||
163 | gallery.add([image]); |
||
164 | |||
165 | // Move it to where we want it. |
||
166 | // Gallery uses arrays and indexes and has several internal variables |
||
167 | // that need to be updated. |
||
168 | // |
||
169 | // list |
||
170 | gallery.list[index] = gallery.list[new_index]; |
||
171 | gallery.list.splice(new_index,1); |
||
172 | |||
173 | // indicators & slides |
||
174 | var dom_nodes = ['indicators','slides']; |
||
175 | for(var i in dom_nodes) |
||
176 | { |
||
177 | var var_name = dom_nodes[i]; |
||
178 | // Remove old one from DOM |
||
179 | jQuery(gallery[var_name][index]).remove(); |
||
180 | // Move new one into it's place in gallery |
||
181 | gallery[var_name][index] = gallery[var_name][new_index]; |
||
182 | // Move into place in DOM |
||
183 | var node = jQuery(gallery[var_name][index]); |
||
184 | node.attr('data-index', index) |
||
185 | .insertAfter(jQuery("[data-index='"+(index-1)+"']",node.parent())); |
||
186 | if(active) node.addClass(gallery.options.activeIndicatorClass); |
||
187 | gallery[var_name].splice(new_index,1); |
||
188 | } |
||
189 | if(active) |
||
190 | { |
||
191 | gallery.activeIndicator = jQuery(gallery.indicators[index]); |
||
192 | } |
||
193 | |||
194 | // positions |
||
195 | gallery.positions[index] = active ? 0 : (index > gallery.index ? gallery.slideWidth : -gallery.slideWidth); |
||
196 | gallery.positions.splice(new_index,1); |
||
197 | |||
198 | // elements - removing will allow to re-do the slide |
||
199 | if(gallery.elements[index]) |
||
200 | { |
||
201 | delete gallery.elements[index]; |
||
202 | gallery.loadElement(index); |
||
203 | } |
||
204 | |||
205 | // Remove the one we just added |
||
206 | gallery.num -= 1; |
||
207 | }; |
||
208 | |||
209 | return widget.extend([et2_IExposable],{ |
||
210 | |||
211 | /** |
||
212 | * Initialize the expose media gallery |
||
213 | */ |
||
214 | init: function() |
||
215 | { |
||
216 | this._super.apply(this, arguments); |
||
217 | this.mime_regexp = mime_regex; |
||
218 | this.mime_odf_regex = mime_odf_regex; |
||
219 | var self=this; |
||
220 | this.expose_options = { |
||
221 | // The Id, element or querySelector of the gallery widget: |
||
222 | container: '#blueimp-gallery', |
||
223 | // The tag name, Id, element or querySelector of the slides container: |
||
224 | slidesContainer: 'div', |
||
225 | // The tag name, Id, element or querySelector of the title element: |
||
226 | titleElement: 'h3', |
||
227 | // The class to add when the gallery is visible: |
||
228 | displayClass: 'blueimp-gallery-display', |
||
229 | // The class to add when the gallery controls are visible: |
||
230 | controlsClass: 'blueimp-gallery-controls', |
||
231 | // The class to add when the gallery only displays one element: |
||
232 | singleClass: 'blueimp-gallery-single', |
||
233 | // The class to add when the left edge has been reached: |
||
234 | leftEdgeClass: 'blueimp-gallery-left', |
||
235 | // The class to add when the right edge has been reached: |
||
236 | rightEdgeClass: 'blueimp-gallery-right', |
||
237 | // The class to add when the automatic slideshow is active: |
||
238 | playingClass: 'blueimp-gallery-playing', |
||
239 | // The class for all slides: |
||
240 | slideClass: 'slide', |
||
241 | // The slide class for loading elements: |
||
242 | slideLoadingClass: '', |
||
243 | // The slide class for elements that failed to load: |
||
244 | slideErrorClass: 'slide-error', |
||
245 | // The class for the content element loaded into each slide: |
||
246 | slideContentClass: 'slide-content', |
||
247 | // The class for the "toggle" control: |
||
248 | toggleClass: 'toggle', |
||
249 | // The class for the "prev" control: |
||
250 | prevClass: 'prev', |
||
251 | // The class for the "next" control: |
||
252 | nextClass: 'next', |
||
253 | // The class for the "close" control: |
||
254 | closeClass: 'close', |
||
255 | // The class for the "play-pause" toggle control: |
||
256 | playPauseClass: 'play-pause', |
||
257 | // The class to add for fullscreen button option |
||
258 | fullscreenClass:'fullscreen', |
||
259 | // The list object property (or data attribute) with the object type: |
||
260 | typeProperty: 'type', |
||
261 | // The list object property (or data attribute) with the object title: |
||
262 | titleProperty: 'title', |
||
263 | // The list object property (or data attribute) with the object URL: |
||
264 | urlProperty: 'href', |
||
265 | // The gallery listens for transitionend events before triggering the |
||
266 | // opened and closed events, unless the following option is set to false: |
||
267 | displayTransition: true, |
||
268 | // Defines if the gallery slides are cleared from the gallery modal, |
||
269 | // or reused for the next gallery initialization: |
||
270 | clearSlides: true, |
||
271 | // Defines if images should be stretched to fill the available space, |
||
272 | // while maintaining their aspect ratio (will only be enabled for browsers |
||
273 | // supporting background-size="contain", which excludes IE < 9). |
||
274 | // Set to "cover", to make images cover all available space (requires |
||
275 | // support for background-size="cover", which excludes IE < 9): |
||
276 | stretchImages: true, |
||
277 | // Toggle the controls on pressing the Return key: |
||
278 | toggleControlsOnReturn: true, |
||
279 | // Toggle the automatic slideshow interval on pressing the Space key: |
||
280 | toggleSlideshowOnSpace: true, |
||
281 | // Navigate the gallery by pressing left and right on the keyboard: |
||
282 | enableKeyboardNavigation: true, |
||
283 | // Close the gallery on pressing the ESC key: |
||
284 | closeOnEscape: true, |
||
285 | // Close the gallery when clicking on an empty slide area: |
||
286 | closeOnSlideClick: false, |
||
287 | // Close the gallery by swiping up or down: |
||
288 | closeOnSwipeUpOrDown: true, |
||
289 | // Emulate touch events on mouse-pointer devices such as desktop browsers: |
||
290 | emulateTouchEvents: true, |
||
291 | // Stop touch events from bubbling up to ancestor elements of the Gallery: |
||
292 | stopTouchEventsPropagation: false, |
||
293 | // Hide the page scrollbars: |
||
294 | hidePageScrollbars: true, |
||
295 | // Stops any touches on the container from scrolling the page: |
||
296 | disableScroll: true, |
||
297 | // Carousel mode (shortcut for carousel specific options): |
||
298 | carousel: true, |
||
299 | // Allow continuous navigation, moving from last to first |
||
300 | // and from first to last slide: |
||
301 | continuous: false, |
||
302 | // Remove elements outside of the preload range from the DOM: |
||
303 | unloadElements: true, |
||
304 | // Start with the automatic slideshow: |
||
305 | startSlideshow: false, |
||
306 | // Delay in milliseconds between slides for the automatic slideshow: |
||
307 | slideshowInterval: 3000, |
||
308 | // The starting index as integer. |
||
309 | // Can also be an object of the given list, |
||
310 | // or an equal object with the same url property: |
||
311 | index: 0, |
||
312 | // The number of elements to load around the current index: |
||
313 | preloadRange: 2, |
||
314 | // The transition speed between slide changes in milliseconds: |
||
315 | transitionSpeed: 400, |
||
316 | //Hide controls when the slideshow is playing |
||
317 | hideControlsOnSlideshow: true, |
||
318 | //Request fullscreen on slide show |
||
319 | toggleFullscreenOnSlideShow:true, |
||
320 | // The transition speed for automatic slide changes, set to an integer |
||
321 | // greater 0 to override the default transition speed: |
||
322 | slideshowTransitionSpeed: undefined, |
||
323 | // The tag name, Id, element or querySelector of the indicator container: |
||
324 | indicatorContainer: 'ol', |
||
325 | // The class for the active indicator: |
||
326 | activeIndicatorClass: 'active', |
||
327 | // The list object property (or data attribute) with the thumbnail URL, |
||
328 | // used as alternative to a thumbnail child element: |
||
329 | thumbnailProperty: 'thumbnail', |
||
330 | // Defines if the gallery indicators should display a thumbnail: |
||
331 | thumbnailIndicators: true, |
||
332 | //thumbnail with image tag |
||
333 | thumbnailWithImgTag: true, |
||
334 | // Callback function executed when the Gallery is initialized. |
||
335 | // Is called with the gallery instance as "this" object: |
||
336 | onopen: jQuery.proxy(this.expose_onopen,this), |
||
337 | // Callback function executed when the Gallery has been initialized |
||
338 | // and the initialization transition has been completed. |
||
339 | // Is called with the gallery instance as "this" object: |
||
340 | onopened: jQuery.proxy(this.expose_onopened,this), |
||
341 | // Callback function executed on slide change. |
||
342 | // Is called with the gallery instance as "this" object and the |
||
343 | // current index and slide as arguments: |
||
344 | onslide: function(index, slide) { |
||
345 | // Call our onslide method, and include gallery as an attribute |
||
346 | self.expose_onslide.apply(self, [this, index,slide]); |
||
347 | }, |
||
348 | // Callback function executed after the slide change transition. |
||
349 | // Is called with the gallery instance as "this" object and the |
||
350 | // current index and slide as arguments: |
||
351 | onslideend: function(index, slide) { |
||
352 | // Call our onslide method, and include gallery as an attribute |
||
353 | self.expose_onslideend.apply(self, [this, index,slide]); |
||
354 | }, |
||
355 | //// Callback function executed on slide content load. |
||
356 | // Is called with the gallery instance as "this" object and the |
||
357 | // slide index and slide element as arguments: |
||
358 | onslidecomplete: function(index, slide) { |
||
359 | // Call our onslide method, and include gallery as an attribute |
||
360 | self.expose_onslidecomplete.apply(self, [this, index,slide]); |
||
361 | }, |
||
362 | //// Callback function executed when the Gallery is about to be closed. |
||
363 | // Is called with the gallery instance as "this" object: |
||
364 | onclose:jQuery.proxy(this.expose_onclose,this), |
||
365 | // Callback function executed when the Gallery has been closed |
||
366 | // and the closing transition has been completed. |
||
367 | // Is called with the gallery instance as "this" object: |
||
368 | onclosed: jQuery.proxy(this.expose_onclosed,this) |
||
369 | }; |
||
370 | var $body = jQuery('body'); |
||
371 | if ($body.find('#blueimp-gallery').length == 0) |
||
372 | { |
||
373 | // Gallery Main DIV container |
||
374 | var $expose_node = jQuery(document.createElement('div')).attr({id:"blueimp-gallery", class:"blueimp-gallery"}); |
||
375 | // Create Gallery DOM NODE |
||
376 | $expose_node.append('<div class="slides"></div><h3 class="title"></h3><a class="prev">‹</a><a class="next">›</a><a title="'+ egw().lang('Close') + '" class="close">×</a><a title="'+ egw().lang('Play/Pause') + '" class="play-pause"></a><a title="'+ egw().lang('Fullscreen') + '" class="fullscreen"></a><a title="'+ egw().lang('Save') +'" class="download"></a><ol class="indicator"></ol>'); |
||
377 | // Append the gallery Node to DOM |
||
378 | $body.append($expose_node); |
||
379 | } |
||
380 | |||
381 | }, |
||
382 | |||
383 | set_value:function (_value) |
||
384 | { |
||
385 | if (typeof this._super == 'undefined') return; |
||
386 | |||
387 | this._super.apply(this,arguments); |
||
388 | // Do not run set value of expose if expose_view is not set |
||
389 | // it causes a wired error on nested image widgets which |
||
390 | // seems the expose is not its child widget |
||
391 | if (!this.options.expose_view ) |
||
392 | { |
||
393 | return; |
||
394 | } |
||
395 | |||
396 | var fe = egw_get_file_editor_prefered_mimes(); |
||
397 | var self=this; |
||
398 | // If the media type is not supported do not bind the click handler |
||
399 | if (!_value || typeof _value.mime != 'string' || (!_value.mime.match(mime_regex,'ig') |
||
400 | && (!fe || fe.mime && !fe.mime[_value.mime])) || typeof _value.download_url == 'undefined') |
||
401 | { |
||
402 | return; |
||
403 | } |
||
404 | if (typeof this.options.expose_view != 'undefined' && this.options.expose_view ) |
||
405 | { |
||
406 | jQuery(this.node).on('click', function(event){ |
||
407 | // Do not trigger expose view if one of the operator keys are held |
||
408 | if (!event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) |
||
409 | { |
||
410 | if (_value.mime.match(mime_regex,'ig')) |
||
411 | { |
||
412 | self._init_blueimp_gallery(event, _value); |
||
413 | } |
||
414 | else if(fe && fe.mime && fe.edit && fe.mime[_value.mime]) |
||
415 | { |
||
416 | egw.open_link(egw.link('/index.php', { |
||
417 | menuaction: fe.edit.menuaction, |
||
418 | path: _value.path, |
||
419 | cd: 'no' // needed to not reload framework in sharing |
||
420 | }), '', fe.edit_popup); |
||
421 | } |
||
422 | } |
||
423 | event.stopImmediatePropagation(); |
||
424 | }).addClass('et2_clickable'); |
||
425 | } |
||
426 | }, |
||
427 | |||
428 | _init_blueimp_gallery: function (event, _value) |
||
429 | { |
||
430 | var mediaContent = []; |
||
431 | var nm = find_nextmatch(this); |
||
432 | var current_index = 0; |
||
433 | if(nm && !this._is_target_indepth(nm,event.target)) |
||
434 | { |
||
435 | // Get the row that was clicked, find its index in the list |
||
436 | var current_entry = nm.controller.getRowByNode(event.target); |
||
437 | |||
438 | // But before it goes, we'll pull everything we can |
||
439 | read_from_nextmatch.call(this, nm, mediaContent); |
||
440 | // find current_entry in array and set it's array-index |
||
441 | for(var i=0; i < mediaContent.length; i++) |
||
442 | { |
||
443 | if ('filemanager::'+mediaContent[i].path == current_entry.uid) |
||
444 | { |
||
445 | current_index = i; |
||
446 | break; |
||
447 | } |
||
448 | } |
||
449 | |||
450 | // This will trigger nm to refresh and get just the ones we can handle |
||
451 | // but it might take a while, so do it later - make sure our current |
||
452 | // one is loaded first. |
||
453 | window.setTimeout(function() { |
||
454 | nm.applyFilters({col_filter: {mime: '/'+mime_regex.source+'/'}}); |
||
455 | },1); |
||
456 | } |
||
457 | else |
||
458 | { |
||
459 | mediaContent = this.getMedia(_value); |
||
460 | // Do not show thumbnail indicator on single expose view |
||
461 | this.expose_options.thumbnailIndicators = false; |
||
462 | } |
||
463 | this.expose_options.index = current_index; |
||
464 | gallery = blueimp.Gallery(mediaContent, this.expose_options); |
||
465 | }, |
||
466 | |||
467 | /** |
||
468 | * Check if clicked target from nm is in depth |
||
469 | * |
||
470 | * @param nm nextmatch widget |
||
471 | * @param target selected target dom node |
||
472 | * |
||
473 | * @return {boolean} returns false if target is not in depth otherwise True |
||
474 | */ |
||
475 | _is_target_indepth: function (nm, target){ |
||
476 | var res = false; |
||
477 | if (nm) |
||
478 | { |
||
479 | if (!target) |
||
480 | { |
||
481 | var target = this.getDOMNode(); |
||
482 | } |
||
483 | var entry = nm.controller.getRowByNode(target); |
||
484 | if (entry && entry.controller.getDepth()>0) |
||
485 | { |
||
486 | res = true; |
||
487 | } |
||
488 | } |
||
489 | return res; |
||
490 | }, |
||
491 | expose_onopen: function (event){}, |
||
492 | expose_onopened: function (event){ |
||
493 | // Check to see if we're in a nextmatch, do magic |
||
494 | var nm = find_nextmatch(this); |
||
495 | var self=this; |
||
496 | if(nm) |
||
497 | { |
||
498 | // Add scrolling to the indicator list |
||
499 | var total_count = nm.controller._grid.getTotalCount(); |
||
500 | if(total_count >= gallery.num) |
||
501 | { |
||
502 | var $indicator = gallery.container.find('.indicator'); |
||
503 | $indicator.off() |
||
504 | .addClass('paginating') |
||
505 | .swipe(function(event, direction, distance) { |
||
506 | if(direction == jQuery.fn.swipe.directions.LEFT) |
||
507 | { |
||
508 | distance *= -1; |
||
509 | } |
||
510 | else if(direction == jQuery.fn.swipe.directions.RIGHT) |
||
511 | { |
||
0 ignored issues
–
show
Comprehensibility
Documentation
Best Practice
introduced
by
|
|||
512 | // OK. |
||
513 | } |
||
514 | else |
||
515 | { |
||
516 | return; |
||
517 | } |
||
518 | jQuery(this).css('left',min(0,parseInt(jQuery(this).css('left'))-(distance*30))+'px'); |
||
519 | }); |
||
520 | // Bind the mousewheel handler for FF (DOMMousewheel), and other browsers (mousewheel) |
||
521 | $indicator.bind('mousewheel DOMMousewheel',function(event, _delta) { |
||
522 | var delta = _delta || event.originalEvent.wheelDelta / 120; |
||
523 | if(delta > 0 && parseInt(jQuery(this).css('left')) > gallery.container.width() / 2) return; |
||
524 | |||
525 | //Reload next pictures into the gallery by scrolling on thumbnails |
||
526 | if (delta<0 && jQuery(this).width() + parseInt(jQuery(this).css('left')) < gallery.container.width()) |
||
527 | { |
||
528 | var nextIndex = gallery.indicatorContainer.find('[title="loading"]')[0]; |
||
529 | if (nextIndex) self.expose_onslideend(gallery,nextIndex.dataset.index -1); |
||
530 | return; |
||
531 | } |
||
532 | // Move it about 5 indicators |
||
533 | jQuery(this).css('left',parseInt(jQuery(this).css('left'))-(-delta*gallery.activeIndicator.width()*5)+'px'); |
||
534 | |||
535 | event.preventDefault(); |
||
536 | }); |
||
537 | } |
||
538 | } |
||
539 | }, |
||
540 | /** |
||
541 | * Trigger on slide left/right |
||
542 | * @param {Gallery} gallery |
||
543 | * @param {integer} index |
||
544 | * @param {DOMNode} slide |
||
545 | */ |
||
546 | expose_onslide: function (gallery, index, slide){ |
||
547 | if (typeof this._super == 'undefined') return; |
||
548 | // First let parent try |
||
549 | this._super.apply(this, arguments); |
||
550 | var nm = find_nextmatch(this); |
||
551 | if(nm) |
||
552 | { |
||
553 | // See if we need to move the indicator |
||
554 | var indicator = gallery.container.find('.indicator'); |
||
555 | var current = jQuery('.active',indicator).position(); |
||
556 | |||
557 | if(current) |
||
558 | { |
||
559 | indicator.animate({left: (gallery.container.width() / 2)-current.left},10); |
||
560 | } |
||
561 | } |
||
562 | }, |
||
563 | expose_onslideend: function (gallery, index, slide){ |
||
564 | // Check to see if we're in a nextmatch, do magic |
||
565 | var nm = find_nextmatch(this); |
||
566 | if(nm) |
||
567 | { |
||
568 | // Check to see if we're near the end, or maybe some pagination |
||
569 | // would be good. |
||
570 | var total_count = nm.controller._grid.getTotalCount(); |
||
571 | |||
572 | // Already at the end, don't bother |
||
573 | if(index == total_count -1 || index == 0) return; |
||
574 | |||
575 | // Try to determine direction from state of next & previous slides |
||
576 | var direction = 1; |
||
577 | for(var i in gallery.elements) |
||
578 | { |
||
579 | // Loading or error |
||
580 | if(gallery.elements[i] == 1 || gallery.elements[i] == 3 || gallery.list[i].loading) |
||
581 | { |
||
582 | direction = i >= index ? 1 : -1; |
||
583 | break; |
||
584 | } |
||
585 | } |
||
586 | |||
587 | if(!gallery.list[index+direction] || gallery.list[index+direction].loading || |
||
588 | total_count > gallery.getNumber() && index + ET2_DATAVIEW_STEPSIZE > gallery.getNumber()) |
||
589 | { |
||
590 | // This will get the next batch of rows |
||
591 | var start = Math.max(0, direction > 0 ? index : index - ET2_DATAVIEW_STEPSIZE); |
||
592 | var end = Math.min(total_count - 1, start + ET2_DATAVIEW_STEPSIZE); |
||
593 | nm.controller._gridCallback(start, end); |
||
594 | var images = []; |
||
595 | read_from_nextmatch.call(this, nm, images, start); |
||
596 | |||
597 | // Gallery always adds to the end, causing problems with pagination |
||
598 | for(var i in images) |
||
599 | { |
||
600 | //if(i == index || i < gallery.num) continue; |
||
601 | set_slide(i, images[i]); |
||
602 | //gallery.add([images[i]]); |
||
603 | } |
||
604 | } |
||
605 | } |
||
606 | }, |
||
607 | expose_onslidecomplete:function (gallery, index, slide){}, |
||
608 | expose_onclose: function(event){ |
||
609 | // Check to see if we're in a nextmatch, remove magic |
||
610 | var nm = find_nextmatch(this); |
||
611 | if(nm && !this._is_target_indepth(nm)) |
||
612 | { |
||
613 | // Remove scrolling from thumbnails |
||
614 | gallery.container.find('.indicator') |
||
615 | .removeClass('paginating') |
||
616 | .off('mousewheel') |
||
617 | .off('swipe'); |
||
618 | |||
619 | // Remove applied mime filter |
||
620 | nm.applyFilters({col_filter: {mime: ''}}); |
||
621 | } |
||
622 | }, |
||
623 | expose_onclosed: function (event){}, |
||
624 | }); |
||
625 | } |
||
626 |