1 | window.PanZoom = (function(window, undefined) { |
2 | |
3 | var CURSOR = 'zoom-out'; |
4 | var DIMMING = false; |
5 | var MARGIN_COLOR = '#ffffff'; |
6 | var BORDER_RADIUS = 10; |
7 | var ZOOM_DURATION = 200; |
8 | var ZOOM_STEPS = 10; |
9 | var OPENED_POPUP_WINDOWS = []; |
10 | var SHADOW = { blur : 15, |
11 | spread : 5, |
12 | opacity : 0.5, |
13 | color : '#000000' }; |
14 | |
15 | |
16 | |
17 | |
18 | function s4 ( ) { |
19 | return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1); |
20 | } |
21 | |
22 | |
23 | var ie = (function() { |
24 | var undef, v = 3, div = document.createElement('div'), all = div.getElementsByTagName('i'); |
25 | while (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', all[0]) |
26 | ; |
27 | return v > 4 ? v : undef; |
28 | }()); |
29 | |
30 | |
31 | |
32 | |
33 | function hexToRgb ( hex ) { |
34 | |
35 | var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; |
36 | hex = hex.replace(shorthandRegex, function(m, r, g, b) { |
37 | return r + r + g + g + b + b; |
38 | }); |
39 | |
40 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); |
41 | return result ? { r : parseInt(result[1], 16), |
42 | g : parseInt(result[2], 16), |
43 | b : parseInt(result[3], 16) } : null; |
44 | } |
45 | |
46 | |
47 | |
48 | |
49 | function isNull ( obj, value ) { |
50 | return (typeof obj === 'undefined' || obj === null) ? value : obj; |
51 | } |
52 | |
53 | |
54 | |
55 | function _addEventListener ( object, type, listener, useCapture ) { |
56 | return 'function' == typeof object.addEventListener ? object.addEventListener(type, listener, useCapture) : object.attachEvent(type, listener); |
57 | } |
58 | |
59 | |
60 | |
61 | function removePopup ( popup ) { |
62 | if (popup) { |
63 | var id = popup.id; |
64 | document.body.removeChild(popup); |
65 | popup = null; |
66 | delete OPENED_POPUP_WINDOWS[id]; |
67 | } |
68 | } |
69 | |
70 | |
71 | |
72 | _addEventListener(document, (ie < 9 ? 'on' : '') + 'keydown', function(ev) { |
73 | ev = ev || window.event; |
74 | if (ev.keyCode == 27 && (divId = Object.keys(OPENED_POPUP_WINDOWS).pop()) && (top_div = document.getElementById(divId))) { |
75 | zoomOut(top_div); |
76 | if (ev.preventDefault) |
77 | ev.preventDefault(); |
78 | else |
79 | ev.returnValue = false; |
80 | return false; |
81 | } |
82 | }); |
83 | |
84 | |
85 | |
86 | |
87 | var popupCalcSize = function(id, hcentered, max_width, max_height) { |
88 | hcentered = isNull(hcentered, true); |
89 | var newdiv = document.getElementById(id); |
90 | if (!newdiv) |
91 | return false; |
92 | var WPadminBar = document.getElementById('wpadminbar'), WPadminMenu = document.getElementById('adminmenuback'), newdiv = document.getElementById(id); |
93 | var WPadminBarHeight = WPadminBar ? WPadminBar.clientHeight : 0, WPadminMenuWidth = WPadminMenu ? WPadminMenu.clientWidth : 0; |
94 | var style = 'width:100%;'; |
95 | window_height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; |
96 | window_width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; |
97 | if (newdiv.clientHeight > window_height - 100 - WPadminBarHeight) { |
98 | var h = window_height - WPadminBarHeight - 50; |
99 | style += 'overflow-y:auto;max-height:' + (h - WPadminBarHeight - 24) + 'px;'; |
100 | newdiv.style.maxHeight = h + 'px'; |
101 | } |
102 | if (newdiv.clientWidth > window_width - 100 - WPadminMenuWidth) { |
103 | var w = window_width - 50; |
104 | style += 'overflow:auto;max-width:' + (w - 10 - WPadminMenuWidth) + 'px;'; |
105 | newdiv.style.maxWidth = w + 'px'; |
106 | } |
107 | |
108 | if (hcentered) { |
109 | newdiv.style.left = (window_width - newdiv.clientWidth + WPadminMenuWidth) / 2 + 'px'; |
110 | newdiv.style.top = (window_height - newdiv.clientHeight + WPadminBarHeight) / 2 + 'px'; |
111 | } |
112 | |
113 | if (style.length > 0) |
114 | newdiv.innerHTML = newdiv.innerHTML.replace(/title=(['"]*)@INNER-STYLE@\1/, 'style="' + style + '"'); |
115 | if (null !== isNull(max_width, null)) |
116 | newdiv.style.maxWidth = isNull(max_width + 'px', newdiv.style.maxWidth); |
117 | if (null !== isNull(max_height, null)) |
118 | newdiv.style.maxHeight = isNull(max_height + 'px', newdiv.style.maxHeight); |
119 | }; |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | function initPanel ( url, caption, callback, width, height, zindex ) { |
126 | var uuid = s4() + s4() + s4() + s4(), divIdName = 'panZoom_' + uuid, inner_style = '', shadow_color = hexToRgb(PanZoom.SHADOW.color); |
127 | newdiv = document.createElement('div'); |
128 | newdiv.setAttribute('id', divIdName); |
129 | if (PanZoom.BORDER_RADIUS) |
130 | inner_style = 'border-radius:' + PanZoom.BORDER_RADIUS + 'px;'; |
131 | var prefix = '<div style="background-color:' + PanZoom.MARGIN_COLOR + ';box-shadow:' + ('0px 0px ' + SHADOW.blur + 'px ' + SHADOW.spread + 'px ' + 'rgb' + (ie < 9 ? '' : 'a') + '(' + shadow_color.r + ',' + shadow_color.g + ',' + shadow_color.b + (ie < 9 ? '' : ',' + SHADOW.opacity) + ')') + ';' + inner_style + '">'; |
132 | var sufix = '</div>'; |
133 | if (caption) |
134 | sufix = '<div style="text-align:center"></div>' + sufix; |
135 | if (url) |
136 | newdiv.innerHTML = prefix + '<img id="panimg_' + uuid + '" style="' + (PanZoom.CURSOR ? 'cursor:' + PanZoom.CURSOR + ';' : '') + 'border:10px;width:100%;height:100%;' + inner_style + '" src="' + url + '" onclick="PanZoom.zoomOut(this.parentElement.parentElement)">' + sufix; |
137 | else |
138 | newdiv.innerHTML = prefix + '<div id="div_' + uuid + '" style="' + (PanZoom.CURSOR ? 'cursor:' + PanZoom.CURSOR + ';' : '') + 'border:10px;width:100%;height:100%;' + inner_style + '">' + sufix + '</div>'; |
139 | newdiv.style.margin = 'auto'; |
140 | newdiv.style.position = 'absolute'; |
141 | newdiv.style.top = 0; |
142 | newdiv.style.left = 0; |
143 | newdiv.style.bottom = 0; |
144 | newdiv.style.right = 0; |
145 | newdiv.style.width = 0; |
146 | newdiv.style.height = 0; |
147 | newdiv.style.color = 'black'; |
148 | newdiv.style.select = 'none'; |
149 | newdiv.style.zIndex = zindex ? zindex : 1000; |
150 | |
151 | document.body.appendChild(newdiv); |
152 | |
153 | OPENED_POPUP_WINDOWS[divIdName] = false; |
154 | |
155 | popupCalcSize(divIdName, false, width, height); |
156 | |
157 | if (callback) { |
158 | btn_prev = document.createElement('div'); |
159 | btn_prev.className = 'previmg'; |
160 | btn_prev.onclick = function() { |
161 | shiftImage(this, callback); |
162 | }; |
163 | newdiv.firstChild.appendChild(btn_prev); |
164 | |
165 | btn_next = document.createElement('div'); |
166 | btn_next.className = 'nextimg'; |
167 | btn_next.onclick = function() { |
168 | shiftImage(this, callback); |
169 | }; |
170 | newdiv.firstChild.appendChild(btn_next); |
171 | |
172 | updateNavBtn(url, btn_prev, callback); |
173 | } |
174 | |
175 | return newdiv; |
176 | } |
177 | |
178 | |
179 | |
180 | |
181 | function updateNavBtn ( src, sender, callback ) { |
182 | var bname = src.substr(src.lastIndexOf('/') + 1), prev = callback(bname, -1), next = callback(bname, 1); |
183 | var btn_prev = sender.parentNode.getElementsByClassName('previmg')[0]; |
184 | var btn_next = sender.parentNode.getElementsByClassName('nextimg')[0]; |
185 | btn_prev.style.visibility = prev ? 'visible' : 'hidden'; |
186 | btn_next.style.visibility = next ? 'visible' : 'hidden'; |
187 | } |
188 | |
189 | |
190 | |
191 | |
192 | function shiftImage ( sender, callback ) { |
193 | if (!sender || !callback) |
194 | return false; |
195 | |
196 | var img = sender.parentNode.getElementsByTagName('img')[0]; |
197 | var caption = sender.parentNode.firstChild.nextSibling; |
198 | if (!img) |
199 | return false; |
200 | |
201 | var obj = callback(img.src.substr(img.src.lastIndexOf('/') + 1), 'previmg' == sender.className ? -1 : 1); |
202 | if (obj && obj.img) { |
203 | img.src = obj.img; |
204 | caption.innerHTML = obj.caption; |
205 | updateNavBtn(obj.img, sender, callback); |
206 | } |
207 | return true; |
208 | } |
209 | |
210 | |
211 | |
212 | |
213 | function addBackWall ( parent ) { |
214 | var uuid = s4() + s4() + s4() + s4(), divIdName = 'bakwall_' + uuid; |
215 | var newdiv = document.createElement('div'); |
216 | |
217 | parent = isNull(parent, document.body); |
218 | |
219 | newdiv.setAttribute('id', divIdName); |
220 | newdiv.style.margin = 0; |
221 | newdiv.style.padding = 0; |
222 | newdiv.style.padding = 0; |
223 | newdiv.style.border = 0; |
224 | newdiv.style.position = 'fixed'; |
225 | newdiv.style.width = '100%'; |
226 | newdiv.style.height = '100%'; |
227 | newdiv.style.left = 0; |
228 | newdiv.style.top = 0; |
229 | newdiv.style.backgroundColor = '#000'; |
230 | newdiv.style.zIndex = -1; |
231 | newdiv.style.opacity = 0.8; |
232 | |
233 | parent.appendChild(newdiv); |
234 | |
235 | return newdiv; |
236 | } |
237 | |
238 | |
239 | |
240 | function mangleStyle ( style_el, padding, position, top, left, transform ) { |
241 | if (!style_el) |
242 | return; |
243 | style_el.padding = padding; |
244 | style_el.position = position; |
245 | style_el.top = top; |
246 | style_el.left = left; |
247 | style_el.transform = transform; |
248 | } |
249 | |
250 | |
251 | |
252 | |
253 | |
254 | |
255 | |
256 | |
257 | |
258 | |
259 | |
260 | |
261 | |
262 | |
263 | |
264 | |
265 | |
266 | |
267 | |
268 | |
269 | |
270 | |
271 | |
272 | var zoomImage = function(url, caption, factor, div, dimming, callback) { |
273 | factor = isNull(factor, 1); |
274 | dimming = isNull(dimming, PanZoom.DIMMING); |
275 | var panzoom_div = div ? div : initPanel(url, caption, callback); |
276 | var img = document.getElementById(panzoom_div.id).firstChild.firstChild; |
277 | if (dimming) |
278 | var wall = addBackWall(panzoom_div); |
279 | |
280 | var child_style = panzoom_div.firstChild.style; |
281 | |
282 | |
283 | if (factor < 0) |
284 | mangleStyle(child_style, 0, 'absolute', 0, 0, ''); |
285 | |
286 | var img_obj = new Image(); |
287 | img_obj.onload = function() { |
288 | if (this.complete || this.readyState === 4) { |
289 | if (caption) |
290 | panzoom_div.firstChild.firstChild.nextSibling.innerHTML = caption; |
291 | var steps = PanZoom.ZOOM_STEPS, inc_x = factor * (factor > 0 ? this.width - img.clientWidth : this.width) / steps, inc_y = factor * (factor > 0 ? this.height - img.clientHeight : this.height) / steps; |
292 | var timer = setInterval(function() { |
293 | panzoom_div.style.width = (panzoom_div.clientWidth + inc_x) + 'px'; |
294 | panzoom_div.style.height = (panzoom_div.clientHeight + inc_y) + 'px'; |
295 | steps--; |
296 | if (steps < 1) { |
297 | clearInterval(timer); |
298 | if (factor < 0) |
299 | removePopup(panzoom_div); |
300 | else |
301 | |
302 | mangleStyle(child_style, '10px', 'fixed', '50%', '50%', 'translateX(-50%) translateY(-50%)'); |
303 | } |
304 | |
305 | }, PanZoom.ZOOM_DURATION / PanZoom.ZOOM_STEPS); |
306 | } |
307 | } |
308 | img_obj.src = img.src; |
309 | |
310 | return panzoom_div; |
311 | } |
312 | |
313 | |
314 | |
315 | |
316 | |
317 | |
318 | |
319 | |
320 | |
321 | |
322 | |
323 | |
324 | |
325 | |
326 | |
327 | |
328 | |
329 | |
330 | |
331 | |
332 | |
333 | var zoomGallery = function(base_url, img_list, caption_list, factor, div, dimming) { |
334 | if (!img_list || !img_list.length) |
335 | return; |
336 | base_url = base_url ? base_url + ('/' != base_url.substr(-1) ? '/' : '') : ''; |
337 | var ilist = img_list.split(','), clist = caption_list ? caption_list.split(',') : []; |
338 | |
339 | var callback = function(pos, offset) { |
340 | var i = ilist.indexOf(pos); |
341 | if ((-1 == i) || (i + offset >= ilist.length || i + offset < 0)) |
342 | return null; |
343 | return { img : base_url + ilist[i + offset], |
344 | caption : (i + offset >= clist.length) ? null : clist[i + offset] } |
345 | }; |
346 | |
347 | pos = ilist[0]; |
348 | caption = clist.length ? clist[0] : null; |
349 | var pz = zoomImage(base_url + pos, caption, factor, div, dimming, callback); |
350 | |
351 | } |
352 | |
353 | |
354 | |
355 | |
356 | |
357 | |
358 | |
359 | |
360 | |
361 | |
362 | |
363 | |
364 | |
365 | |
366 | |
367 | |
368 | |
369 | |
370 | |
371 | |
372 | |
373 | var zoomDiv = function(width, height, factor, div, dimming, callback) { |
374 | factor = isNull(factor, 1); |
375 | dimming = isNull(dimming, PanZoom.DIMMING); |
376 | var panzoom_div = div ? div : initPanel(); |
377 | var fc = panzoom_div.firstChild; |
378 | mangleStyle(fc.style, '10px', 'fixed', '50%', '50%', 'translateX(-50%) translateY(-50%)'); |
379 | var div = document.getElementById(panzoom_div.id).firstChild.firstChild; |
380 | if (factor > 0) { |
381 | fc.style.width = width + 'px'; |
382 | fc.style.height = height + 'px'; |
383 | fc.style.transform = 'translateX(-50%) translateY(-50%) scale(0)'; |
384 | if (dimming) |
385 | var wall = addBackWall(panzoom_div); |
386 | } |
387 | |
388 | var zoom_callback = function(xmlhttp) { |
389 | if (factor < 0 || 'object' != typeof xmlhttp || xmlhttp.readyState === 4) { |
390 | if (xmlhttp) { |
391 | var t = 'object' == typeof xmlhttp ? xmlhttp.responseText : xmlhttp; |
392 | if (callback) |
393 | t = callback(t); |
394 | div.innerHTML = t; |
395 | } |
396 | var i = 0, scale; |
397 | var timer = setInterval(function() { |
398 | scale = (factor < 0 ? 1 : 0) + factor * (i / PanZoom.ZOOM_STEPS); |
399 | fc.style.transform = 'translateX(-50%) translateY(-50%) scale(' + scale + ')'; |
400 | if (i > PanZoom.ZOOM_STEPS) { |
401 | clearInterval(timer); |
402 | if (factor < 0) |
403 | removePopup(panzoom_div); |
404 | else |
405 | |
406 | mangleStyle(fc.style, '10px', 'fixed', '50%', '50%', 'translateX(-50%) translateY(-50%)'); |
407 | } |
408 | i++; |
409 | }, PanZoom.ZOOM_DURATION / PanZoom.ZOOM_STEPS); |
410 | } |
411 | } |
412 | |
413 | |
414 | if (factor < 0) |
415 | return zoom_callback(); |
416 | |
417 | return { div : panzoom_div, |
418 | callback : zoom_callback }; |
419 | } |
420 | |
421 | |
422 | |
423 | |
424 | var zoomOut = function(div) { |
425 | var imgs = div.getElementsByTagName('img'), found = false, i; |
426 | for (i = 0; i < imgs.length; i += 1) |
427 | if (0 === imgs[i].id.indexOf('panimg_')) { |
428 | |
429 | |
430 | found = true; |
431 | break; |
432 | } |
433 | if (found) |
434 | zoomImage(null, null, -1, div, false); |
435 | else |
436 | zoomDiv(null, null, -1, div, false); |
437 | }; |
438 | |
439 | return { zoomImage : zoomImage, |
440 | zoomDiv : zoomDiv, |
441 | zoomOut : zoomOut, |
442 | zoomGallery : zoomGallery, |
443 | popupCalcSize : popupCalcSize, |
444 | DIMMING : DIMMING, |
445 | MARGIN_COLOR : MARGIN_COLOR, |
446 | BORDER_RADIUS : BORDER_RADIUS, |
447 | ZOOM_DURATION : ZOOM_DURATION, |
448 | ZOOM_STEPS : ZOOM_STEPS, |
449 | SHADOW : SHADOW, |
450 | CURSOR : CURSOR }; |
451 | })(this); |
452 | |