NextGEN Gallery – WordPress Gallery Plugin - Version 2.0.14

Version Description

  • 08.27.2013 =
  • NEW: Added the ability to override thumbnail settings for NextGEN Basic Albums
  • NEW: Shortcode Manager API, which ensures that shortcodes are outputted as intended
  • Changed: Re-added the ability to select the original image size for widgets
  • Fixed: Ensure that stylesheet url returned is correct for Windows hosts
  • Fixed: Broken links and lightbox effects with AJAX pagination
  • Fixed: Try to ensure that third party plugins don't add content to our dynamic JS
  • Fixed: Improved reliability of iframely.js
  • Fixed: Ensure that urls are generated correctly in HTTPs environments
  • Fixed: Datamapper works correctly in environments where temporary tables aren't supported
  • Fixed: Fixed an issue with thickbox loading animation when home url differs from site url
Download this release

Release Info

Developer photocrati
Plugin Icon 128x128 NextGEN Gallery – WordPress Gallery Plugin
Version 2.0.14
Comparing to
See all releases

Code changes from version 1.9.13 to 2.0.14

Files changed (193) hide show
  1. admin/about.php +0 -168
  2. admin/addgallery.php +0 -545
  3. admin/css/jquery.ui.css +0 -140
  4. admin/images/nextgen_16_color.png +0 -0
  5. admin/install.php +0 -282
  6. admin/js/swfupload.handler.js +0 -153
  7. admin/tinymce/editor_plugin.js +0 -77
  8. admin/tinymce/langs/de.js +0 -6
  9. admin/tinymce/langs/de_de.js +0 -6
  10. admin/tinymce/langs/en.js +0 -6
  11. admin/tinymce/langs/en_US.js +0 -6
  12. admin/tinymce/tinymce.js +0 -75
  13. admin/tinymce/tinymce.php +0 -102
  14. admin/tinymce/window.php +0 -152
  15. changelog.txt +76 -0
  16. css/Black_Minimalism.css +0 -375
  17. css/hovereffect.css +0 -425
  18. css/ngg_dkret3.css +0 -318
  19. css/ngg_k2.css +0 -330
  20. css/ngg_shadow.css +0 -371
  21. css/ngg_shadow2.css +0 -379
  22. css/nggallery.css +0 -403
  23. js/jquery.cycle.all.min.js +0 -1
  24. js/ngg.js +0 -188
  25. js/ngg.slideshow.js +0 -138
  26. js/ngg.slideshow.min.js +0 -1
  27. lib/image.php +0 -223
  28. lib/shortcodes.php +0 -395
  29. license.txt +340 -0
  30. nggallery.php +387 -492
  31. nggfunctions.php +0 -1141
  32. non_pope/class.nextgen_settings.php +31 -0
  33. non_pope/class.nextgen_shortcode_manager.php +125 -0
  34. non_pope/class.nextgen_style_manager.php +279 -0
  35. non_pope/class.photocrati_cache.php +179 -0
  36. non_pope/class.photocrati_installer.php +104 -0
  37. non_pope/class.photocrati_resource_manager.php +179 -0
  38. non_pope/class.photocrati_settings_manager.php +299 -0
  39. pope/README.txt +93 -0
  40. pope/lib/autoload.php +14 -0
  41. pope/lib/class.base_module.php +184 -0
  42. pope/lib/class.base_product.php +36 -0
  43. pope/lib/class.component.php +113 -0
  44. pope/lib/class.component_factory.php +35 -0
  45. pope/lib/class.component_registry.php +943 -0
  46. pope/lib/class.extensibleobject.php +1377 -0
  47. pope/lib/interface.component.php +10 -0
  48. pope/lib/interface.component_factory.php +6 -0
  49. pope/lib/interface.pope_module.php +6 -0
  50. products/photocrati_nextgen/class.nextgen_product_installer.php +13 -0
  51. products/photocrati_nextgen/modules/ajax/README.txt +30 -0
  52. products/photocrati_nextgen/modules/ajax/adapter.ajax_routes.php +21 -0
  53. products/photocrati_nextgen/modules/ajax/adapter.ajax_settings.php +15 -0
  54. products/photocrati_nextgen/modules/ajax/class.ajax_controller.php +55 -0
  55. products/photocrati_nextgen/modules/ajax/class.ajax_installer.php +13 -0
  56. products/photocrati_nextgen/modules/ajax/class.ajax_option_handler.php +29 -0
  57. products/photocrati_nextgen/modules/ajax/interface.ajax_controller.php +6 -0
  58. products/photocrati_nextgen/modules/ajax/module.ajax.php +88 -0
  59. products/photocrati_nextgen/modules/ajax/static/ajax.js +1 -0
  60. products/photocrati_nextgen/modules/attach_to_post/adapter.attach_to_post_ajax.php +235 -0
  61. products/photocrati_nextgen/modules/attach_to_post/adapter.attach_to_post_routes.php +24 -0
  62. products/photocrati_nextgen/modules/attach_to_post/adapter.gallery_storage_frame_event.php +39 -0
  63. products/photocrati_nextgen/modules/attach_to_post/class.attach_controller.php +295 -0
  64. products/photocrati_nextgen/modules/attach_to_post/class.attach_to_post_installer.php +13 -0
  65. products/photocrati_nextgen/modules/attach_to_post/class.attach_to_post_option_handler.php +28 -0
  66. products/photocrati_nextgen/modules/attach_to_post/class.attach_to_post_proxy_controller.php +62 -0
  67. products/photocrati_nextgen/modules/attach_to_post/interface.attach_to_post_controller.php +6 -0
  68. products/photocrati_nextgen/modules/attach_to_post/mixin.attach_to_post_display_tab.php +283 -0
  69. products/photocrati_nextgen/modules/attach_to_post/module.attach_to_post.php +382 -0
  70. products/photocrati_nextgen/modules/attach_to_post/static/attach_to_post.css +279 -0
  71. products/photocrati_nextgen/modules/attach_to_post/static/attach_to_post.js +124 -0
  72. products/photocrati_nextgen/modules/attach_to_post/static/attach_to_post_dialog.css +39 -0
  73. products/photocrati_nextgen/modules/attach_to_post/static/iframely.css +25 -0
  74. products/photocrati_nextgen/modules/attach_to_post/static/iframely.js +33 -0
  75. products/photocrati_nextgen/modules/attach_to_post/static/invalid_image.png +0 -0
  76. {admin/tinymce → products/photocrati_nextgen/modules/attach_to_post/static}/nextgen.gif +0 -0
  77. products/photocrati_nextgen/modules/attach_to_post/static/ngg_attach_to_post_tinymce_plugin.js +207 -0
  78. products/photocrati_nextgen/modules/attach_to_post/static/ngg_tabs.js +57 -0
  79. products/photocrati_nextgen/modules/attach_to_post/static/spinner.gif +0 -0
  80. products/photocrati_nextgen/modules/attach_to_post/static/underscore.string.js +600 -0
  81. products/photocrati_nextgen/modules/attach_to_post/static/uploader-icons-2x.png +0 -0
  82. products/photocrati_nextgen/modules/attach_to_post/static/uploader-icons.png +0 -0
  83. products/photocrati_nextgen/modules/attach_to_post/templates/accordion_tab.php +4 -0
  84. products/photocrati_nextgen/modules/attach_to_post/templates/attach_to_post.php +29 -0
  85. products/photocrati_nextgen/modules/attach_to_post/templates/display_settings_form.php +3 -0
  86. products/photocrati_nextgen/modules/attach_to_post/templates/display_tab.php +11 -0
  87. products/photocrati_nextgen/modules/attach_to_post/templates/display_tab_js.php +1654 -0
  88. products/photocrati_nextgen/modules/attach_to_post/templates/display_tab_source.php +2 -0
  89. products/photocrati_nextgen/modules/attach_to_post/templates/display_tab_type.php +3 -0
  90. products/photocrati_nextgen/modules/attach_to_post/templates/no_display_type_selected.php +3 -0
  91. products/photocrati_nextgen/modules/attach_to_post/templates/preview_tab.php +3 -0
  92. products/photocrati_nextgen/modules/cache/class.cache.php +85 -0
  93. products/photocrati_nextgen/modules/cache/interface.cache.php +7 -0
  94. products/photocrati_nextgen/modules/cache/module.cache.php +42 -0
  95. products/photocrati_nextgen/modules/datamapper/README.txt +1 -0
  96. products/photocrati_nextgen/modules/datamapper/adapter.datamapper_factory.php +24 -0
  97. products/photocrati_nextgen/modules/datamapper/class.custompost_datamapper_driver.php +547 -0
  98. products/photocrati_nextgen/modules/datamapper/class.customtable_datamapper_driver.php +486 -0
  99. products/photocrati_nextgen/modules/datamapper/class.datamapper_driver_base.php +603 -0
  100. products/photocrati_nextgen/modules/datamapper/class.datamapper_installer.php +14 -0
  101. products/photocrati_nextgen/modules/datamapper/class.datamapper_model.php +157 -0
  102. products/photocrati_nextgen/modules/datamapper/interface.custompost_datamapper.php +6 -0
  103. products/photocrati_nextgen/modules/datamapper/interface.customtable_datamapper.php +6 -0
  104. products/photocrati_nextgen/modules/datamapper/interface.datamapper_driver.php +29 -0
  105. products/photocrati_nextgen/modules/datamapper/interface.datamapper_model.php +9 -0
  106. products/photocrati_nextgen/modules/datamapper/module.datamapper.php +200 -0
  107. products/photocrati_nextgen/modules/dynamic_stylesheet/adapter.dynamic_stylesheet_routes.php +21 -0
  108. products/photocrati_nextgen/modules/dynamic_stylesheet/class.dynamic_stylesheet_controller.php +128 -0
  109. products/photocrati_nextgen/modules/dynamic_stylesheet/class.dynamic_stylesheet_installer.php +14 -0
  110. products/photocrati_nextgen/modules/dynamic_stylesheet/interface.dynamic_stylesheet.php +7 -0
  111. products/photocrati_nextgen/modules/dynamic_stylesheet/module.dynamic_stylesheet.php +53 -0
  112. products/photocrati_nextgen/modules/dynamic_thumbnails/adapter.dynamic_thumbnail_routes.php +28 -0
  113. products/photocrati_nextgen/modules/dynamic_thumbnails/adapter.dynamic_thumbnails_storage_driver.php +104 -0
  114. products/photocrati_nextgen/modules/dynamic_thumbnails/class.dynamic_thumbnails_controller.php +72 -0
  115. products/photocrati_nextgen/modules/dynamic_thumbnails/class.dynamic_thumbnails_installer.php +14 -0
  116. products/photocrati_nextgen/modules/dynamic_thumbnails/class.dynamic_thumbnails_manager.php +517 -0
  117. products/photocrati_nextgen/modules/dynamic_thumbnails/interface.dynamic_thumbnails_controller.php +5 -0
  118. products/photocrati_nextgen/modules/dynamic_thumbnails/interface.dynamic_thumbnails_manager.php +24 -0
  119. products/photocrati_nextgen/modules/dynamic_thumbnails/module.dynamic_thumbnails.php +53 -0
  120. products/photocrati_nextgen/modules/dynamic_thumbnails/static/invalid_image.png +0 -0
  121. products/photocrati_nextgen/modules/frame_communication/class.frame_communication_installer.php +14 -0
  122. products/photocrati_nextgen/modules/frame_communication/class.frame_event_publisher.php +71 -0
  123. products/photocrati_nextgen/modules/frame_communication/interface.frame_event_publisher.php +6 -0
  124. products/photocrati_nextgen/modules/frame_communication/module.frame_communication.php +64 -0
  125. products/photocrati_nextgen/modules/frame_communication/static/frame_event_publisher.js +162 -0
  126. products/photocrati_nextgen/modules/fs/class.fs.php +365 -0
  127. products/photocrati_nextgen/modules/fs/interface.fs.php +6 -0
  128. products/photocrati_nextgen/modules/fs/module.fs.php +36 -0
  129. products/photocrati_nextgen/modules/lightbox/adapter.lightbox_factory.php +14 -0
  130. products/photocrati_nextgen/modules/lightbox/adapter.lightbox_library_form.php +66 -0
  131. products/photocrati_nextgen/modules/lightbox/class.lightbox_installer.php +176 -0
  132. products/photocrati_nextgen/modules/lightbox/class.lightbox_library.php +31 -0
  133. products/photocrati_nextgen/modules/lightbox/class.lightbox_library_mapper.php +83 -0
  134. products/photocrati_nextgen/modules/lightbox/interface.lightbox_library.php +6 -0
  135. products/photocrati_nextgen/modules/lightbox/interface.lightbox_library_mapper.php +6 -0
  136. products/photocrati_nextgen/modules/lightbox/module.lightbox.php +82 -0
  137. products/photocrati_nextgen/modules/lightbox/static/fancybox/blank.gif +0 -0
  138. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_close.png +0 -0
  139. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_loading.png +0 -0
  140. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_nav_left.png +0 -0
  141. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_nav_right.png +0 -0
  142. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_e.png +0 -0
  143. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_n.png +0 -0
  144. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_ne.png +0 -0
  145. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_nw.png +0 -0
  146. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_s.png +0 -0
  147. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_se.png +0 -0
  148. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_sw.png +0 -0
  149. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_w.png +0 -0
  150. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_title_left.png +0 -0
  151. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_title_main.png +0 -0
  152. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_title_over.png +0 -0
  153. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_title_right.png +0 -0
  154. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancybox-x.png +0 -0
  155. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancybox-y.png +0 -0
  156. products/photocrati_nextgen/modules/lightbox/static/fancybox/fancybox.png +0 -0
  157. products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.easing-1.3.pack.js +72 -0
  158. products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.fancybox-1.3.4.css +366 -0
  159. products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.fancybox-1.3.4.js +1156 -0
  160. products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.fancybox-1.3.4.pack.js +46 -0
  161. products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.mousewheel-3.0.4.pack.js +14 -0
  162. products/photocrati_nextgen/modules/lightbox/static/fancybox/nextgen_fancybox_init.js +13 -0
  163. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/close.png +0 -0
  164. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/closeX.png +0 -0
  165. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar-black-border.gif +0 -0
  166. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar-text-buttons.png +0 -0
  167. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar-white-small.gif +0 -0
  168. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar-white.gif +0 -0
  169. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar2.gif +0 -0
  170. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar3.gif +0 -0
  171. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar4-hover.gif +0 -0
  172. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar4.gif +0 -0
  173. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/fullexpand.gif +0 -0
  174. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/geckodimmer.png +0 -0
  175. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/icon.gif +0 -0
  176. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/loader.gif +0 -0
  177. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/loader.white.gif +0 -0
  178. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/Outlines.psd +0 -0
  179. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/beveled.png +0 -0
  180. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/drop-shadow.png +0 -0
  181. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/glossy-dark.png +0 -0
  182. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/outer-glow.png +0 -0
  183. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/rounded-black.png +0 -0
  184. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/rounded-white.png +0 -0
  185. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/resize.gif +0 -0
  186. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/scrollarrows.png +0 -0
  187. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/zoomin.cur +0 -0
  188. products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/zoomout.cur +0 -0
  189. products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-full.js +3320 -0
  190. products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-full.min.js +9 -0
  191. products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-full.packed.js +9 -0
  192. products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-ie6.css +76 -0
  193. products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-with-gallery.js +1911 -0
admin/about.php DELETED
@@ -1,168 +0,0 @@
1
- <?php
2
- if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }
3
-
4
- function nggallery_admin_about() {
5
-
6
- ?>
7
-
8
- <div class="wrap">
9
- <?php include('templates/social_media_buttons.php'); ?>
10
- <?php screen_icon( 'nextgen-gallery' ); ?>
11
- <h2><?php _e('Copyright notes / Credits', 'nggallery') ;?></h2>
12
- <div id="poststuff">
13
- <div class="postbox">
14
- <h3 class="hndle"><span><?php _e('NextGEN DEV Team', 'nggallery'); ?></span></h3>
15
- <div class="inside">
16
- <p><?php _e('NextGEN Gallery is primarily developed, maintained, supported and documented by <a href="http://www.photocrati.com" target="_blank">Photocrati Media</a>. We\'d like to offer a special thanks to Alex Rabe, who first developed the plugin and maintained it through 2011. There are many others who have made contributions:', 'nggallery') ;?></p>
17
- <p><?php ngg_list_contributors(); ?></p>
18
- </div>
19
- </div>
20
- <div class="postbox">
21
- <h3 class="hndle"><span><?php _e('Contributors / Tribute to', 'nggallery'); ?></span></h3>
22
- <div class="inside">
23
- <p><?php _e('If you study the code of this plugin, you\'ll find we\'ve included a lot of good, existing code and ideas. We\'d like to thank the following people for their work:', 'nggallery') ;?></p>
24
- <ul class="ngg-list">
25
- <li><a href="http://wordpress.org" target="_blank">The WordPress Team</a> <?php _e('for their great documented code', 'nggallery') ;?></li>
26
- <li><a href="http://jquery.com" target="_blank">The jQuery Team</a> <?php _e('for jQuery, which is the best Web2.0 framework', 'nggallery') ;?></li>
27
- <li><a href="http://www.gen-x-design.com" target="_blank">Ian Selby</a> <?php _e('for the fantastic PHP Thumbnail Class', 'nggallery') ;?></li>
28
- <li><a href="http://www.lesterchan.net/" target="_blank">GaMerZ</a> <?php _e('for a lot of very useful plugins and ideas', 'nggallery') ;?></li>
29
- <li><a href="http://www.laptoptips.ca/" target="_blank">Andrew Ozz</a> <?php _e('for Shutter Reloaded, a real lightweight image effect', 'nggallery') ;?></li>
30
- <li><a href="http://www.jeroenwijering.com/" target="_blank">Jeroen Wijering</a> <?php _e('for the best Media Flash Scripts on earth', 'nggallery') ;?></li>
31
- <li><a href="http://field2.com" target="_blank">Ben Dunkle</a> <?php _e('for the Gallery Icon', 'nggallery') ;?></li>
32
- <li><a href="http://watermark.malcherek.com/" target="_blank">Marek Malcherek</a> <?php _e('for the Watermark plugin', 'nggallery') ;?></li>
33
- </ul>
34
- <p><?php _e('If you don\'t see your name on this list and we\'ve integrated some of your code into the plugin, don\'t hesitate to email us.', 'nggallery') ;?></p>
35
- </div>
36
- </div>
37
- <div class="postbox">
38
- <h3 class="hndle"><span><?php _e('How to support ?', 'nggallery'); ?></span></h3>
39
- <div class="inside">
40
- <p><?php _e('There are several ways to contribute:', 'nggallery') ;?></p>
41
- <ul class="ngg-list">
42
- <li><strong><?php _e('Send us bugfixes / code changes', 'nggallery') ;?></strong><br /><?php _e('The most motivated support for this plugin are your ideas and brain work.', 'nggallery') ;?></li>
43
- <li><strong><?php _e('Translate the plugin', 'nggallery') ;?></strong><br /><?php _e('To help people to work with this plugin, we would like to have it in all available languages.', 'nggallery') ;?></li>
44
- <li><strong><?php _e('Place a link to the plugin in your blog/webpage', 'nggallery') ;?></strong><br /><?php _e('Yes, sharing and linking are also supportive and helpful.', 'nggallery') ;?></li>
45
- </ul>
46
- </div>
47
- </div>
48
- <div class="postbox" id="donators">
49
- <h3 class="hndle"><span><?php _e('Thanks!', 'nggallery'); ?></span></h3>
50
- <div class="inside">
51
- <p><?php _e('We would like to thank the following people who have supported the NextGEN Gallery plugin:', 'nggallery'); ?></p>
52
- <p><a href="http://www.boelinger.com/heike/" target="_blank">HEIKE</a>, <?php ngg_list_support(); ?></p>
53
- </div>
54
- </div>
55
- </div>
56
- </div>
57
-
58
- <?php
59
- }
60
-
61
- function ngg_list_contributors() {
62
- /* The list of my contributors. Thanks to all of them !*/
63
-
64
- $contributors = array(
65
- 'Anty (Code contributor)' => 'http://www.anty.at/',
66
- 'Bjoern von Prollius (Code contributor)' => 'http://www.prollius.de/',
67
- 'Simone Fumagalli (Code contributor)' => 'http://www.iliveinperego.com/',
68
- 'Vincent Prat (Code contributor)' => 'http://www.vincentprat.info',
69
- 'Frederic De Ranter (AJAX code contributor)' => 'http://li.deranter.com/',
70
- 'Christian Arnold (Code contributor)' => 'http://blog.arctic-media.de/',
71
- 'Thomas Matzke (Album code contributor)' => 'http://mufuschnu.mu.funpic.de/',
72
- 'KeViN (Sidebar Widget developer)' => 'http://www.kev.hu/',
73
- 'Lazy (German Translation)' => 'http://www.lazychris.de/',
74
- 'Lise (French Translation)' => 'http://liseweb.fr/',
75
- 'Anja (Dutch Translation)' => 'http://www.werkgroepen.net/wordpress',
76
- 'Adrian (Indonesian Translation)' => 'http://adrian.web.id/',
77
- 'Gaspard Tseng / SillyCCSmile (Chinese Translation)' => '',
78
- 'Mika Pennanen (Finnish Translation)' => 'http://kapsi.fi/~penni',
79
- 'Wojciech Owczarek (Polish Translation)' => 'http://www.owczi.net',
80
- 'Dilip Ramirez (Spanish Translation)' => 'http://jmtd.110mb.com/blog',
81
- 'Oleinikov Vedmak Evgeny (Russian Translation)' => 'http://ka-2-03.mirea.org/',
82
- 'Sebastien MALHERBE (Logo design)' => 'http://www.7vision.com/',
83
- 'Claudia (German documentation)' => 'http://www.blog-werkstatt.de/',
84
- 'Robert (German documentation)' => 'http://www.curlyrob.de/',
85
- 'Pierpaolo Mannone (Italian Translation)' => 'http://www.interscambiocasa.com/',
86
- 'Mattias Tengblad (Swedish Translation)' => 'http://wp-support.se/',
87
- 'M&uuml;fit Kiper (Swedish Translation)' => 'http://www.kiper.se/',
88
- 'Gil Yaker (Documentation)' => 'http://bamboosoup.com/',
89
- 'Morten Johansen (Danish Translation)' => 'http://www.fr3ak.dk/',
90
- 'Vidar Seland (Norwegian Translation)' => 'http://www.viidar.net/',
91
- 'Emre G&uuml;ler (Turkish Translation)' => 'http://www.emreguler.com/',
92
- 'Emilio Lauretti (Italian Translation)' => '',
93
- 'Jan Angelovic (Czech Translation)' => 'http://www.angelovic.cz/',
94
- 'Laki (Slovak Translation)' => 'http://www.laki.sk/',
95
- 'Rowan Crane (WPMU support)' => 'http://blog.rowancrane.com/',
96
- 'Kuba Zwolinski (Polish Translation)' => 'http://kubazwolinski.com/',
97
- 'Rina Jiang (Chinese Translation)' => 'http://http://mysticecho.net/',
98
- 'Anthony (Chinese Translation)' => 'http://www.angryouth.com/',
99
- 'Milan Vasicek (Czech Translation)' => 'http://www.NoWorkTeam.cz/',
100
- 'Joo Gi-young (Korean Translation)' => 'http://lombric.linuxstudy.pe.kr/wp/',
101
- 'Oleg A. Safonov (Russian Translation)' => 'http://blog.olart.ru',
102
- 'AleXander Kirichev (Bulgarian Translation)' => 'http://xsakex.art-bg.org/',
103
- 'Richer Yang (Chinese Translation)' => 'http://fantasyworld.idv.tw/',
104
- 'Bill Jones (Forums contributor)' => 'http://jonesphoto.bluehorizoninternet.com/',
105
- 'TheDonSansone (Forums contributor)' => 'http://abseiling.200blogs.co.uk/',
106
- 'Komyshov (Russian Translation)' => 'http://kf-web.ru/',
107
- 'aleX Zhang (Chinese Translation)' => 'http://zhangfei.info/',
108
- 'TheSoloist (Chinese Translation)' => 'http://www.soloist-ic.cn/',
109
- 'Nica Luigi Cristian (Romanian Translation)' => 'http://www.cristiannica.com/',
110
- 'Zdenek Hatas (Czech Translation)' => '',
111
- 'David Potter (Documentation and Help)' => 'http://dpotter.net/',
112
- 'Carlale Chen (Chinese Translation)' => 'http://0-o-0.cc/',
113
- 'Nica Luigi Cristian (Romanian Translation)' => 'http://www.cristiannica.com/',
114
- 'Igor Shevkoplyas (Russian Translation)' => 'http://www.russian-translation-matters.com',
115
- 'Alexandr Kindras (Code contributor)' => 'http://www.fixdev.com',
116
- 'Manabu Togawa (Japanese Translation)' => 'http://www.churadesign.com/',
117
- 'Serhiy Tretyak (Ukrainian Translation)' => 'http://designpoint.com.ua/',
118
- 'Janis Grinvalds (Latvian Translation)' => 'http://riga.bmxrace.lv/',
119
- 'Kristoffer Th&oslash;ring (Norwegian Translation)' => '',
120
- 'Flactarus (Italian Translation)' => 'http://www.giroevago.it',
121
- 'Felip Alfred Galit&oacute; i Trilla (Catalan Translation)' => 'http://www.bratac.cat',
122
- 'Luka Komac (Slovenian Translation)' => 'http://www.komac.biz',
123
- 'Dimitris Ikonomou / Nikos Mouratidis (Greek Translation)' => 'http://www.kepik.gr'
124
- );
125
-
126
- ksort($contributors);
127
- $i = count($contributors);
128
- foreach ($contributors as $name => $url)
129
- {
130
- if ($url)
131
- echo "<a href=\"$url\" target=\"_blank\">$name</a>";
132
- else
133
- echo $name;
134
- $i--;
135
- if ($i == 1)
136
- echo " & ";
137
- elseif ($i)
138
- echo ", ";
139
- }
140
- }
141
-
142
- function ngg_list_support() {
143
- /* The list of my supporters. Thanks to all of them !*/
144
-
145
- global $ngg;
146
-
147
- $supporter = nggAdminPanel::get_remote_array($ngg->donators);
148
-
149
- // Ensure that this is a array
150
- if ( !is_array($supporter) )
151
- return _e('and all donators...', 'nggallery');
152
-
153
- ksort($supporter);
154
- $i = count($supporter);
155
- foreach ($supporter as $name => $url)
156
- {
157
- if ($url)
158
- echo "<a href=\"$url\" target=\"_blank\">$name</a>";
159
- else
160
- echo $name;
161
- $i--;
162
- if ($i == 1)
163
- echo " & ";
164
- elseif ($i)
165
- echo ", ";
166
- }
167
- }
168
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/addgallery.php DELETED
@@ -1,545 +0,0 @@
1
- <?php
2
- if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }
3
-
4
- class nggAddGallery {
5
-
6
- /**
7
- * PHP4 compatibility layer for calling the PHP5 constructor.
8
- *
9
- */
10
- function nggAddGallery() {
11
- return $this->__construct();
12
- }
13
-
14
- /**
15
- * nggAddGallery::__construct()
16
- *
17
- * @return void
18
- */
19
- function __construct() {
20
-
21
- // same as $_SERVER['REQUEST_URI'], but should work under IIS 6.0
22
- $this->filepath = admin_url() . 'admin.php?page=' . $_GET['page'];
23
-
24
- //Look for POST updates
25
- if ( !empty($_POST) )
26
- $this->processor();
27
- }
28
-
29
- /**
30
- * Perform the upload and add a new hook for plugins
31
- *
32
- * @return void
33
- */
34
- function processor() {
35
- global $wpdb, $ngg, $nggdb;
36
-
37
- $defaultpath = $ngg->options['gallerypath'];
38
-
39
- if ( isset($_POST['addgallery']) ){
40
- check_admin_referer('ngg_addgallery');
41
-
42
- if ( !nggGallery::current_user_can( 'NextGEN Add new gallery' ))
43
- wp_die(__('Cheatin&#8217; uh?'));
44
-
45
- $newgallery = esc_attr( $_POST['galleryname']);
46
- if ( !empty($newgallery) )
47
- nggAdmin::create_gallery($newgallery, $defaultpath);
48
- }
49
-
50
- if ( isset($_POST['zipupload']) ){
51
- check_admin_referer('ngg_addgallery');
52
-
53
- if ( !nggGallery::current_user_can( 'NextGEN Upload a zip' ))
54
- wp_die(__('Cheatin&#8217; uh?'));
55
-
56
- if ($_FILES['zipfile']['error'] == 0 || (!empty($_POST['zipurl'])))
57
- nggAdmin::import_zipfile( intval( $_POST['zipgalselect'] ) );
58
- else
59
- nggGallery::show_error( __('Upload failed!','nggallery') );
60
- }
61
-
62
- if ( isset($_POST['importfolder']) ){
63
- check_admin_referer('ngg_addgallery');
64
-
65
- if ( !nggGallery::current_user_can( 'NextGEN Import image folder' ))
66
- wp_die(__('Cheatin&#8217; uh?'));
67
-
68
- $galleryfolder = $_POST['galleryfolder'];
69
- if ( ( !empty($galleryfolder) ) AND ($defaultpath != $galleryfolder) )
70
- nggAdmin::import_gallery($galleryfolder);
71
- }
72
-
73
- if ( isset($_POST['uploadimage']) ){
74
- check_admin_referer('ngg_addgallery');
75
-
76
- if ( !nggGallery::current_user_can( 'NextGEN Upload in all galleries' ))
77
- wp_die(__('Cheatin&#8217; uh?'));
78
-
79
- if ( $_FILES['imagefiles']['error'][0] == 0 )
80
- $messagetext = nggAdmin::upload_images();
81
- else
82
- nggGallery::show_error( __('Upload failed! ' . nggAdmin::decode_upload_error( $_FILES['imagefiles']['error'][0]),'nggallery') );
83
- }
84
-
85
- if ( isset($_POST['swf_callback']) ){
86
- if ($_POST['galleryselect'] == '0' )
87
- nggGallery::show_error(__('No gallery selected !','nggallery'));
88
- else {
89
- if ($_POST['swf_callback'] == '-1' )
90
- nggGallery::show_error( __('Upload failed! ','nggallery') );
91
- else {
92
- $gallery = $nggdb->find_gallery( (int) $_POST['galleryselect'] );
93
- nggAdmin::import_gallery( $gallery->path );
94
- }
95
- }
96
- }
97
-
98
- if ( isset($_POST['disable_flash']) ){
99
- check_admin_referer('ngg_addgallery');
100
- $ngg->options['swfUpload'] = false;
101
- update_option('ngg_options', $ngg->options);
102
- }
103
-
104
- if ( isset($_POST['enable_flash']) ){
105
- check_admin_referer('ngg_addgallery');
106
- $ngg->options['swfUpload'] = true;
107
- update_option('ngg_options', $ngg->options);
108
- }
109
-
110
- do_action( 'ngg_update_addgallery_page' );
111
-
112
- }
113
-
114
- /**
115
- * Render the page content
116
- *
117
- * @return void
118
- */
119
- function controller() {
120
- global $ngg, $nggdb;
121
-
122
- // check for the max image size
123
- $this->maxsize = nggGallery::check_memory_limit();
124
-
125
- //get all galleries (after we added new ones)
126
- $this->gallerylist = $nggdb->find_all_galleries('gid', 'DESC');
127
-
128
- $this->defaultpath = $ngg->options['gallerypath'];
129
-
130
- // link for the flash file
131
- $swf_upload_link = admin_url('/?nggupload');
132
-
133
- // get list of tabs
134
- $tabs = $this->tabs_order();
135
-
136
- // with this filter you can add custom file types
137
- $file_types = apply_filters( 'ngg_swf_file_types', '*.jpg;*.jpeg;*.gif;*.png;*.JPG;*.JPEG;*.GIF;*.PNG' );
138
-
139
- // Set the post params, which plupload will post back with the file, and pass them through a filter.
140
- $post_params = array(
141
- "auth_cookie" => (is_ssl() ? $_COOKIE[SECURE_AUTH_COOKIE] : $_COOKIE[AUTH_COOKIE]),
142
- "logged_in_cookie" => $_COOKIE[LOGGED_IN_COOKIE],
143
- "_wpnonce" => wp_create_nonce('ngg_swfupload'),
144
- "galleryselect" => "0",
145
- );
146
- $p = array();
147
-
148
- foreach ( $post_params as $param => $val ) {
149
- $val = esc_js( $val );
150
- $p[] = "'$param' : '$val'";
151
- }
152
-
153
- $post_params_str = implode( ',', $p ). "\n";
154
- ?>
155
-
156
- <?php include('templates/social_media_buttons.php'); ?>
157
-
158
- <?php if($ngg->options['swfUpload'] && !empty ($this->gallerylist) ) { ?>
159
- <?php if ( defined('IS_WP_3_3') ) { ?>
160
- <!-- plupload script -->
161
- <script type="text/javascript">
162
- //<![CDATA[
163
- var resize_height = <?php echo (int) $ngg->options['imgHeight']; ?>,
164
- resize_width = <?php echo (int) $ngg->options['imgWidth']; ?>;
165
-
166
- jQuery(document).ready(function($) {
167
- window.uploader = new plupload.Uploader({
168
- runtimes: '<?php echo apply_filters('plupload_runtimes', 'html5,flash,silverlight,html4,'); ?>',
169
- browse_button: 'plupload-browse-button',
170
- container: 'plupload-upload-ui',
171
- drop_element: 'uploadimage',
172
- file_data_name: 'Filedata',
173
- max_file_size: '<?php echo round( (int) wp_max_upload_size() / 1024 ); ?>kb',
174
- url: '<?php echo esc_js( $swf_upload_link ); ?>',
175
- flash_swf_url: '<?php echo esc_js( includes_url('js/plupload/plupload.flash.swf') ); ?>',
176
- silverlight_xap_url: '<?php echo esc_js( includes_url('js/plupload/plupload.silverlight.xap') ); ?>',
177
- filters: [
178
- {title: '<?php echo esc_js( __('Image Files', 'nggallery') ); ?>', extensions: '<?php echo esc_js( str_replace( array('*.', ';'), array('', ','), $file_types) ); ?>'}
179
- ],
180
- multipart: true,
181
- urlstream_upload: true,
182
- multipart_params : {
183
- <?php echo $post_params_str; ?>
184
- },
185
- debug: false,
186
- preinit : {
187
- Init: function(up, info) {
188
- debug('[Init]', 'Info :', info, 'Features :', up.features);
189
- if (navigator.appVersion.indexOf("MSIE 10") > -1) {
190
- up.features.triggerDialog = true;
191
- }
192
- initUploader();
193
- }
194
- },
195
- i18n : {
196
- 'remove' : '<?php _e('remove', 'nggallery') ;?>',
197
- 'browse' : '<?php _e('Browse...', 'nggallery') ;?>',
198
- 'upload' : '<?php _e('Upload images', 'nggallery') ;?>'
199
- }
200
- });
201
-
202
- uploader.bind('FilesAdded', function(up, files) {
203
- $.each(files, function(i, file) {
204
- fileQueued(file);
205
- });
206
-
207
- up.refresh();
208
- });
209
-
210
- uploader.bind('BeforeUpload', function(up, file) {
211
- uploadStart(file);
212
- });
213
-
214
- uploader.bind('UploadProgress', function(up, file) {
215
- uploadProgress(file, file.loaded, file.size);
216
- });
217
-
218
- uploader.bind('Error', function(up, err) {
219
- uploadError(err.file, err.code, err.message);
220
-
221
- up.refresh();
222
- });
223
-
224
- uploader.bind('FileUploaded', function(up, file, response) {
225
- uploadSuccess(file, response);
226
- });
227
-
228
- uploader.bind('UploadComplete', function(up, file) {
229
- uploadComplete(file);
230
- });
231
-
232
- // on load change the upload to plupload
233
- uploader.init();
234
-
235
- nggAjaxOptions = {
236
- header: "<?php _e('Upload images', 'nggallery') ;?>",
237
- maxStep: 100
238
- };
239
-
240
- });
241
- //]]>
242
- </script>
243
- <?php } else { ?>
244
- <!-- SWFUpload script -->
245
- <script type="text/javascript">
246
- var ngg_swf_upload;
247
-
248
- window.onload = function () {
249
- ngg_swf_upload = new SWFUpload({
250
- // Backend settings
251
- upload_url : "<?php echo esc_js( $swf_upload_link ); ?>",
252
- flash_url : "<?php echo esc_js( includes_url('js/swfupload/swfupload.swf') ); ?>",
253
-
254
- // Button Settings
255
- button_placeholder_id : "spanButtonPlaceholder",
256
- button_width: 300,
257
- button_height: 27,
258
- button_text_top_padding: 3,
259
- button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT,
260
- button_cursor: SWFUpload.CURSOR.HAND,
261
-
262
- // File Upload Settings
263
- file_size_limit : "<?php echo wp_max_upload_size(); ?>b",
264
- file_types : "<?php echo $file_types; ?>",
265
- file_types_description : "<?php _e('Image Files', 'nggallery') ;?>",
266
-
267
- // Queue handler
268
- file_queued_handler : fileQueued,
269
-
270
- // Upload handler
271
- upload_start_handler : uploadStart,
272
- upload_progress_handler : uploadProgress,
273
- upload_error_handler : uploadError,
274
- upload_success_handler : uploadSuccess,
275
- upload_complete_handler : uploadComplete,
276
-
277
- post_params : {
278
- "auth_cookie" : "<?php echo (is_ssl() ? $_COOKIE[SECURE_AUTH_COOKIE] : $_COOKIE[AUTH_COOKIE]); ?>",
279
- "logged_in_cookie": "<?php echo $_COOKIE[LOGGED_IN_COOKIE]; ?>",
280
- "_wpnonce" : "<?php echo wp_create_nonce('ngg_swfupload'); ?>",
281
- "galleryselect" : "0"
282
- },
283
-
284
- // i18names
285
- custom_settings : {
286
- "remove" : "<?php _e('remove', 'nggallery') ;?>",
287
- "browse" : "<?php _e('Browse...', 'nggallery') ;?>",
288
- "upload" : "<?php _e('Upload images', 'nggallery') ;?>"
289
- },
290
-
291
- // Debug settings
292
- debug: false
293
-
294
- });
295
-
296
- // on load change the upload to swfupload
297
- initSWFUpload();
298
-
299
- nggAjaxOptions = {
300
- header: "<?php _e('Upload images', 'nggallery') ;?>",
301
- maxStep: 100
302
- };
303
-
304
- };
305
- </script>
306
- <?php } ?>
307
- <?php } else { ?>
308
- <!-- MultiFile script -->
309
- <script type="text/javascript">
310
- /* <![CDATA[ */
311
- jQuery(document).ready(function(){
312
- jQuery('#imagefiles').MultiFile({
313
- STRING: {
314
- remove:'[<?php _e('remove', 'nggallery') ;?>]'
315
- }
316
- });
317
- });
318
- /* ]]> */
319
- </script>
320
- <?php } ?>
321
- <!-- jQuery Tabs script -->
322
- <script type="text/javascript">
323
- /* <![CDATA[ */
324
- jQuery(document).ready(function(){
325
- jQuery('html,body').scrollTop(0);
326
- jQuery('#slider').tabs({ fxFade: true, fxSpeed: 'fast' });
327
- jQuery('#slider').css('display', 'block');
328
- });
329
-
330
- // File Tree implementation
331
- jQuery(function() {
332
- jQuery("span.browsefiles").show().click(function(){
333
- jQuery("#file_browser").fileTree({
334
- script: "admin-ajax.php?action=ngg_file_browser&nonce=<?php echo wp_create_nonce( 'ngg-ajax' ) ;?>",
335
- root: jQuery("#galleryfolder").val()
336
- }, function(folder) {
337
- jQuery("#galleryfolder").val( folder );
338
- });
339
- jQuery("#file_browser").show('slide');
340
- });
341
- });
342
- /* ]]> */
343
- </script>
344
- <div id="slider" class="wrap" style="display: none;">
345
- <ul id="tabs">
346
- <?php
347
- foreach($tabs as $tab_key => $tab_name) {
348
- echo "\n\t\t<li><a href='#$tab_key'>$tab_name</a></li>";
349
- }
350
- ?>
351
- </ul>
352
- <?php
353
- foreach($tabs as $tab_key => $tab_name) {
354
- echo "\n\t<div id='$tab_key'>\n";
355
- // Looks for the internal class function, otherwise enable a hook for plugins
356
- if ( method_exists( $this, "tab_$tab_key" ))
357
- call_user_func( array( &$this , "tab_$tab_key") );
358
- else
359
- do_action( 'ngg_tab_content_' . $tab_key );
360
- echo "\n\t</div>";
361
- }
362
- ?>
363
- </div>
364
- <?php
365
-
366
- }
367
-
368
- /**
369
- * Create array for tabs and add a filter for other plugins to inject more tabs
370
- *
371
- * @return array $tabs
372
- */
373
- function tabs_order() {
374
-
375
- $tabs = array();
376
-
377
- if ( !empty ($this->gallerylist) )
378
- $tabs['uploadimage'] = __( 'Upload Images', 'nggallery' );
379
-
380
- if ( nggGallery::current_user_can( 'NextGEN Add new gallery' ))
381
- $tabs['addgallery'] = __('Add new gallery', 'nggallery');
382
-
383
- if ( wpmu_enable_function('wpmuZipUpload') && nggGallery::current_user_can( 'NextGEN Upload a zip' ) )
384
- $tabs['zipupload'] = __('Upload a Zip-File', 'nggallery');
385
-
386
- if ( wpmu_enable_function('wpmuImportFolder') && nggGallery::current_user_can( 'NextGEN Import image folder' ) )
387
- $tabs['importfolder'] = __('Import image folder', 'nggallery');
388
-
389
- $tabs = apply_filters('ngg_addgallery_tabs', $tabs);
390
-
391
- return $tabs;
392
-
393
- }
394
-
395
- function tab_addgallery() {
396
- ?>
397
- <!-- create gallery -->
398
- <h2><?php _e('Add new gallery', 'nggallery') ;?></h2>
399
- <form name="addgallery" id="addgallery_form" method="POST" action="<?php echo $this->filepath; ?>" accept-charset="utf-8" >
400
- <?php wp_nonce_field('ngg_addgallery') ?>
401
- <table class="form-table">
402
- <tr valign="top">
403
- <th scope="row"><?php _e('New Gallery', 'nggallery') ;?>:</th>
404
- <td><input type="text" size="35" name="galleryname" value="" /><br />
405
- <?php if(!is_multisite()) { ?>
406
- <?php _e('Create a new , empty gallery below the folder', 'nggallery') ;?> <strong><?php echo $this->defaultpath ?></strong><br />
407
- <?php } ?>
408
- <i>( <?php _e('Allowed characters for file and folder names are', 'nggallery') ;?>: a-z, A-Z, 0-9, -, _ )</i></td>
409
- </tr>
410
- <?php do_action('ngg_add_new_gallery_form'); ?>
411
- </table>
412
- <div class="submit"><input class="button-primary" type="submit" name= "addgallery" value="<?php _e('Add gallery', 'nggallery') ;?>"/></div>
413
- </form>
414
- <?php
415
- }
416
-
417
- function tab_zipupload() {
418
- ?>
419
- <!-- zip-file operation -->
420
- <h2><?php _e('Upload a Zip-File', 'nggallery') ;?></h2>
421
- <form name="zipupload" id="zipupload_form" method="POST" enctype="multipart/form-data" action="<?php echo $this->filepath.'#zipupload'; ?>" accept-charset="utf-8" >
422
- <?php wp_nonce_field('ngg_addgallery') ?>
423
- <table class="form-table">
424
- <tr valign="top">
425
- <th scope="row"><?php _e('Select Zip-File', 'nggallery') ;?>:</th>
426
- <td><input type="file" name="zipfile" id="zipfile" size="35" class="uploadform"/><br />
427
- <?php _e('Upload a zip file with images', 'nggallery') ;?></td>
428
- </tr>
429
- <?php if (function_exists('curl_init')) : ?>
430
- <tr valign="top">
431
- <th scope="row"><?php _e('or enter a Zip-File URL', 'nggallery') ;?>:</th>
432
- <td><input type="text" name="zipurl" id="zipurl" size="35" class="uploadform"/><br />
433
- <?php _e('Import a zip file with images from a url', 'nggallery') ;?></td>
434
- </tr>
435
- <?php endif; ?>
436
- <tr valign="top">
437
- <th scope="row"><?php _e('in to', 'nggallery') ;?></th>
438
- <td><select name="zipgalselect">
439
- <option value="0" ><?php _e('a new gallery', 'nggallery') ?></option>
440
- <?php
441
- foreach($this->gallerylist as $gallery) {
442
- if ( !nggAdmin::can_manage_this_gallery($gallery->author) )
443
- continue;
444
- $name = ( empty($gallery->title) ) ? $gallery->name : $gallery->title;
445
- echo '<option value="' . $gallery->gid . '" >' . $gallery->gid . ' - ' . esc_attr( $name ). '</option>' . "\n";
446
- }
447
- ?>
448
- </select>
449
- <br /><?php echo $this->maxsize; ?>
450
- <br /><?php echo _e('Note : The upload limit on your server is ','nggallery') . "<strong>" . ini_get('upload_max_filesize') . "Byte</strong>\n"; ?>
451
- <br /><?php if ( (is_multisite()) && wpmu_enable_function('wpmuQuotaCheck') ) display_space_usage(); ?></td>
452
- </tr>
453
- </table>
454
- <div class="submit"><input class="button-primary" type="submit" name= "zipupload" value="<?php _e('Start upload', 'nggallery') ;?>"/></div>
455
- </form>
456
- <?php
457
- }
458
-
459
- function tab_importfolder() {
460
- ?>
461
- <!-- import folder -->
462
- <h2><?php _e('Import image folder', 'nggallery') ;?></h2>
463
- <form name="importfolder" id="importfolder_form" method="POST" action="<?php echo $this->filepath.'#importfolder'; ?>" accept-charset="utf-8" >
464
- <?php wp_nonce_field('ngg_addgallery') ?>
465
- <table class="form-table">
466
- <tr valign="top">
467
- <th scope="row"><?php _e('Import from Server path:', 'nggallery') ;?></th>
468
- <td><input type="text" size="35" id="galleryfolder" name="galleryfolder" value="<?php echo $this->defaultpath; ?>" /><span class="browsefiles button" style="display:none"><?php _e('Browse...', 'nggallery'); ?></span><br />
469
- <div id="file_browser"></div>
470
- <br /><i>( <?php _e('Note : Change the default path in the gallery settings', 'nggallery') ;?> )</i>
471
- <br /><?php echo $this->maxsize; ?>
472
- <?php if (SAFE_MODE) {?><br /><?php _e(' Please note : For safe-mode = ON you need to add the subfolder thumbs manually', 'nggallery') ;?><?php }; ?></td>
473
- </tr>
474
- </table>
475
- <div class="submit"><input class="button-primary" type="submit" name= "importfolder" value="<?php _e('Import folder', 'nggallery') ;?>"/></div>
476
- </form>
477
- <?php
478
- }
479
-
480
- function tab_uploadimage() {
481
- global $ngg;
482
- // check the cookie for the current setting
483
- $checked = get_user_setting('ngg_upload_resize') ? ' checked="true"' : '';
484
- ?>
485
- <!-- upload images -->
486
- <h2><?php _e('Upload Images', 'nggallery') ;?></h2>
487
- <form name="uploadimage" id="uploadimage_form" method="POST" enctype="multipart/form-data" action="<?php echo $this->filepath.'#uploadimage'; ?>" accept-charset="utf-8" >
488
- <?php wp_nonce_field('ngg_addgallery') ?>
489
- <table class="form-table">
490
-
491
- <tr valign="top">
492
- <th scope="row"><?php _e('Upload image', 'nggallery') ;?></th>
493
- <?php if ($ngg->options['swfUpload'] && defined('IS_WP_3_3') ) { ?>
494
- <td>
495
- <div id="plupload-upload-ui">
496
- <div>
497
- <?php _e( 'Choose files to upload' ); ?>
498
- <input id="plupload-browse-button" type="button" value="<?php esc_attr_e('Select Files'); ?>" class="button" />
499
- </div>
500
- <p class="ngg-dragdrop-info howto" style="display:none;" ><?php _e('Or you can drop the files into this window.'); ?></p>
501
- <div id='uploadQueue'></div>
502
- <p><label><input name="image_resize" type="checkbox" id="image_resize" value="true"<?php echo $checked; ?> />
503
- <?php printf( __( 'Scale images to max width %1$dpx or max height %2$dpx', 'nggallery' ), (int) $ngg->options['imgWidth' ], (int) $ngg->options[ 'imgHeight' ] ); ?>
504
- </label>
505
- </p>
506
-
507
- </div>
508
- </td>
509
- <?php } else { ?>
510
- <td><span id='spanButtonPlaceholder'></span><input type="file" name="imagefiles[]" id="imagefiles" size="35" class="imagefiles"/></td>
511
- <?php } ?>
512
- </tr>
513
- <tr valign="top">
514
- <th scope="row"><?php _e('in to', 'nggallery') ;?></th>
515
- <td><select name="galleryselect" id="galleryselect">
516
- <option value="0" ><?php _e('Choose gallery', 'nggallery') ?></option>
517
- <?php
518
- foreach($this->gallerylist as $gallery) {
519
-
520
- //special case : we check if a user has this cap, then we override the second cap check
521
- if ( !current_user_can( 'NextGEN Upload in all galleries' ) )
522
- if ( !nggAdmin::can_manage_this_gallery($gallery->author) )
523
- continue;
524
-
525
- $name = ( empty($gallery->title) ) ? $gallery->name : $gallery->title;
526
- echo '<option value="' . $gallery->gid . '" >' . $gallery->gid . ' - ' . esc_attr( $name ) . '</option>' . "\n";
527
- } ?>
528
- </select>
529
- <br /><?php echo $this->maxsize; ?>
530
- <br /><?php if ((is_multisite()) && wpmu_enable_function('wpmuQuotaCheck')) display_space_usage(); ?></td>
531
- </tr>
532
- </table>
533
- <div class="submit">
534
- <?php if ($ngg->options['swfUpload']) { ?>
535
- <input type="submit" name="disable_flash" id="disable_flash" title="<?php _e('The batch upload requires Adobe Flash 10, disable it if you have problems','nggallery') ?>" value="<?php _e('Disable flash upload', 'nggallery') ;?>" />
536
- <?php } else { ?>
537
- <input type="submit" name="enable_flash" id="enable_flash" title="<?php _e('Upload multiple files at once by ctrl/shift-selecting in dialog','nggallery') ?>" value="<?php _e('Enable flash based upload', 'nggallery') ;?>" />
538
- <?php } ?>
539
- <input class="button-primary" type="submit" name="uploadimage" id="uploadimage_btn" value="<?php _e('Upload images', 'nggallery') ;?>" />
540
- </div>
541
- </form>
542
- <?php
543
- }
544
- }
545
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/css/jquery.ui.css DELETED
@@ -1,140 +0,0 @@
1
- /*
2
- * jQuery UI CSS Framework @VERSION
3
- *
4
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
5
- * Dual licensed under the MIT or GPL Version 2 licenses.
6
- * http://jquery.org/license
7
- *
8
- * http://docs.jquery.com/UI/Theming/API
9
- */
10
-
11
- /* Layout helpers
12
- ----------------------------------*/
13
- .ui-helper-hidden { display: none; }
14
- .ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
15
- .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
16
- .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
17
- .ui-helper-clearfix { display: inline-block; }
18
- /* required comment for clearfix to work in Opera \*/
19
- * html .ui-helper-clearfix { height:1%; }
20
- .ui-helper-clearfix { display:block; }
21
- /* end clearfix */
22
- .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
23
-
24
- /* Interaction Cues
25
- ----------------------------------*/
26
- .ui-state-disabled { cursor: default !important; }
27
-
28
- /* Icons
29
- ----------------------------------*/
30
- .ui-icon-triangle-1-s { background-position: -64px -16px; }
31
-
32
- /* states and images */
33
- .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
34
-
35
- /* Misc visuals
36
- ----------------------------------*/
37
-
38
- /* Overlays */
39
- .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
40
-
41
- /* jQuery UI CSS Framework @VERSION */
42
-
43
- /* Component containers
44
- ----------------------------------*/
45
- .ui-widget-content { background: #fcfdfd 50% bottom repeat-x; color: #222222; }
46
- /* .ui-widget-content a { color: #222222; } */
47
- .ui-widget-header { background: #222222 50% 50% repeat-x; color: #CFCFCF; }
48
- .ui-widget-header a { color: #CFCFCF; }
49
-
50
- /* Interaction states
51
- ----------------------------------*/
52
- .ui-dialog-titlebar-close:hover { border: 1px solid #464646; background: #464646 50% 50% repeat-x; font-weight: normal; color: #ffffff; }
53
- .ui-widget :active { outline: none; }
54
-
55
- /* Icons
56
- ----------------------------------*/
57
-
58
- /* states and images */
59
- .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_cccccc_256x240.png); }
60
- .ui-widget-content .ui-icon {background-image: url(images/ui-icons_cccccc_256x240.png); }
61
- .ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
62
- .ui-state-default .ui-icon { background-image: url(images/ui-icons_cccccc_256x240.png); }
63
- .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
64
- .ui-state-active .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
65
-
66
- /* positioning */
67
- .ui-icon-close { background-position: -80px -128px; }
68
- .ui-icon-closethick { background-position: -96px -128px; }
69
- .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
70
- .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
71
-
72
- /* Misc visuals
73
- ----------------------------------*/
74
-
75
- /* Corner radius */
76
- .ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; }
77
- .ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; }
78
- .ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
79
- .ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
80
- .ui-corner-top { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; }
81
- .ui-corner-bottom { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
82
- .ui-corner-right { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
83
- .ui-corner-left { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
84
- .ui-corner-all { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }
85
-
86
- /* Overlays */
87
- .ui-widget-overlay { background: #000000 50% 50% repeat-x; opacity: .75;filter:Alpha(Opacity=75); }
88
- .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000 50% 50% repeat-x; opacity: .75;filter:Alpha(Opacity=75); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
89
-
90
- /* jQuery UI Resizable */
91
- .ui-resizable { position: relative;}
92
- .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
93
- .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
94
- .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
95
- .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
96
- .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
97
- .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
98
- .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
99
- .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
100
- .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
101
- .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
102
-
103
- /* jQuery UI Dialog */
104
- .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
105
- .ui-dialog { -moz-box-shadow: rgba(0,0,0,1) 0 4px 30px; -webkit-box-shadow: rgba(0,0,0,1) 0 4px 30px; -khtml-box-shadow: rgba(0,0,0,1) 0 4px 30px; box-shadow: rgba(0,0,0,1) 0 4px 30px; }
106
- .ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; }
107
- .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; }
108
- .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
109
- .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
110
- .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
111
- .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
112
- .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
113
- .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
114
- .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
115
- .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
116
- .ui-draggable .ui-dialog-titlebar { cursor: move; }
117
-
118
- /* jQuery UI Progressbar */
119
- .ui-progressbar { height:2em; text-align: left; }
120
- .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
121
-
122
- /* jQuery UI Dialog loading spinner */
123
- #spinner {display: none; width:100px; height: 100px; position: fixed; top: 50%; left: 50%; background:url(../../images/loader.gif) no-repeat center #fff; padding:10px; border:1px solid #666; margin-left: -50px; margin-top: -50px; z-index:2; overflow: auto; }
124
-
125
- /* jQuery Autocomplete */
126
- .ui-autocomplete { position: absolute; cursor: default; }
127
- .ui-autocomplete-start { background: white url('images/dropdown.png') right center no-repeat; }
128
- * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
129
- .ui-autocomplete-loading { background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; }
130
- /* this limit the height of the result list*/
131
- .ui-autocomplete { max-height: 90px; overflow-y: auto; }
132
- * html .ui-autocomplete { height: 90px; }
133
- .ui-autocomplete .ui-state-hover, .ui-autocomplete .ui-widget-content .ui-state-hover { background: #1e90ff; color: #FFFFFF !important; }
134
- .ui-widget-content { border: 1px solid #dddddd; border-style:outset; background: #FFFFFF; }
135
- .ui-autocomplete, .ui-autocomplete .ui-corner-all { -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; }
136
- .ui-menu { list-style:none; padding: 1px; margin: 0; display:block; float: left; }
137
- .ui-menu .ui-menu { margin-top: -3px; }
138
- .ui-menu .ui-menu-item { margin:0; padding:0; zoom:1; float:left; clear:left; width:100%; }
139
- .ui-menu .ui-menu-item a { text-decoration:none; display:block; zoom:1; color: black;}
140
- .ui-helper-hidden-accessible {display: none}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/images/nextgen_16_color.png DELETED
Binary file
admin/install.php DELETED
@@ -1,282 +0,0 @@
1
- <?php
2
- if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }
3
-
4
- /**
5
- * creates all tables for the gallery
6
- * called during register_activation hook
7
- *
8
- * @access internal
9
- * @return void
10
- */
11
- function nggallery_install () {
12
-
13
- global $wpdb , $wp_roles, $wp_version;
14
-
15
- // Check for capability
16
- if ( !current_user_can('activate_plugins') )
17
- return;
18
-
19
- // Set the capabilities for the administrator
20
- $role = get_role('administrator');
21
- // We need this role, no other chance
22
- if ( empty($role) ) {
23
- update_option( "ngg_init_check", __('Sorry, NextGEN Gallery works only with a role called administrator',"nggallery") );
24
- return;
25
- }
26
-
27
- $role->add_cap('NextGEN Gallery overview');
28
- $role->add_cap('NextGEN Use TinyMCE');
29
- $role->add_cap('NextGEN Upload images');
30
- $role->add_cap('NextGEN Manage gallery');
31
- $role->add_cap('NextGEN Manage tags');
32
- $role->add_cap('NextGEN Manage others gallery');
33
- $role->add_cap('NextGEN Edit album');
34
- $role->add_cap('NextGEN Change style');
35
- $role->add_cap('NextGEN Change options');
36
-
37
- // upgrade function changed in WordPress 2.3
38
- require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
39
-
40
- // add charset & collate like wp core
41
- $charset_collate = '';
42
-
43
- if ( version_compare(mysql_get_server_info(), '4.1.0', '>=') ) {
44
- if ( ! empty($wpdb->charset) )
45
- $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
46
- if ( ! empty($wpdb->collate) )
47
- $charset_collate .= " COLLATE $wpdb->collate";
48
- }
49
-
50
- $nggpictures = $wpdb->prefix . 'ngg_pictures';
51
- $nggallery = $wpdb->prefix . 'ngg_gallery';
52
- $nggalbum = $wpdb->prefix . 'ngg_album';
53
-
54
- // Create pictures table
55
- $sql = "CREATE TABLE " . $nggpictures . " (
56
- pid BIGINT(20) NOT NULL AUTO_INCREMENT ,
57
- image_slug VARCHAR(255) NOT NULL ,
58
- post_id BIGINT(20) DEFAULT '0' NOT NULL ,
59
- galleryid BIGINT(20) DEFAULT '0' NOT NULL ,
60
- filename VARCHAR(255) NOT NULL ,
61
- description MEDIUMTEXT NULL ,
62
- alttext MEDIUMTEXT NULL ,
63
- imagedate DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
64
- exclude TINYINT NULL DEFAULT '0' ,
65
- sortorder BIGINT(20) DEFAULT '0' NOT NULL ,
66
- meta_data LONGTEXT,
67
- PRIMARY KEY (pid),
68
- KEY post_id (post_id)
69
- ) $charset_collate;";
70
- dbDelta($sql);
71
-
72
- // Create gallery table
73
- $sql = "CREATE TABLE " . $nggallery . " (
74
- gid BIGINT(20) NOT NULL AUTO_INCREMENT ,
75
- name VARCHAR(255) NOT NULL ,
76
- slug VARCHAR(255) NOT NULL ,
77
- path MEDIUMTEXT NULL ,
78
- title MEDIUMTEXT NULL ,
79
- galdesc MEDIUMTEXT NULL ,
80
- pageid BIGINT(20) DEFAULT '0' NOT NULL ,
81
- previewpic BIGINT(20) DEFAULT '0' NOT NULL ,
82
- author BIGINT(20) DEFAULT '0' NOT NULL ,
83
- PRIMARY KEY (gid)
84
- ) $charset_collate;";
85
- dbDelta($sql);
86
-
87
- // Create albums table
88
- $sql = "CREATE TABLE " . $nggalbum . " (
89
- id BIGINT(20) NOT NULL AUTO_INCREMENT ,
90
- name VARCHAR(255) NOT NULL ,
91
- slug VARCHAR(255) NOT NULL ,
92
- previewpic BIGINT(20) DEFAULT '0' NOT NULL ,
93
- albumdesc MEDIUMTEXT NULL ,
94
- sortorder LONGTEXT NOT NULL,
95
- pageid BIGINT(20) DEFAULT '0' NOT NULL,
96
- PRIMARY KEY (id)
97
- ) $charset_collate;";
98
- dbDelta($sql);
99
-
100
- // check one table again, to be sure
101
- if( !$wpdb->get_var( "SHOW TABLES LIKE '$nggpictures'" ) ) {
102
- update_option( "ngg_init_check", __('NextGEN Gallery : Tables could not created, please check your database settings',"nggallery") );
103
- return;
104
- }
105
-
106
- $options = get_option('ngg_options');
107
- // set the default settings, if we didn't upgrade
108
- if ( empty( $options ) )
109
- ngg_default_options();
110
-
111
- // if all is passed , save the DBVERSION
112
- add_option("ngg_db_version", NGG_DBVERSION);
113
-
114
- }
115
-
116
- /**
117
- * Setup the default option array for the gallery
118
- *
119
- * @access internal
120
- * @since version 0.33
121
- * @return void
122
- */
123
- function ngg_default_options() {
124
-
125
- global $blog_id, $ngg;
126
-
127
- $ngg_options['gallerypath'] = 'wp-content/gallery/'; // set default path to the gallery
128
- $ngg_options['deleteImg'] = true; // delete Images
129
- $ngg_options['swfUpload'] = true; // activate the batch upload
130
- $ngg_options['usePermalinks'] = false; // use permalinks for parameters
131
- $ngg_options['permalinkSlug'] = 'nggallery'; // the default slug for permalinks
132
- $ngg_options['graphicLibrary'] = 'gd'; // default graphic library
133
- $ngg_options['imageMagickDir'] = '/usr/local/bin/'; // default path to ImageMagick
134
- $ngg_options['useMediaRSS'] = false; // activate the global Media RSS file
135
- $ngg_options['usePicLens'] = false; // activate the PicLens Link for galleries
136
-
137
- // Tags / categories
138
- $ngg_options['activateTags'] = false; // append related images
139
- $ngg_options['appendType'] = 'tags'; // look for category or tags
140
- $ngg_options['maxImages'] = 7; // number of images toshow
141
-
142
- // Thumbnail Settings
143
- $ngg_options['thumbwidth'] = 100; // Thumb Width
144
- $ngg_options['thumbheight'] = 75; // Thumb height
145
- $ngg_options['thumbfix'] = true; // Fix the dimension
146
- $ngg_options['thumbquality'] = 100; // Thumb Quality
147
-
148
- // Image Settings
149
- $ngg_options['imgWidth'] = 800; // Image Width
150
- $ngg_options['imgHeight'] = 600; // Image height
151
- $ngg_options['imgQuality'] = 85; // Image Quality
152
- $ngg_options['imgBackup'] = true; // Create a backup
153
- $ngg_options['imgAutoResize'] = false; // Resize after upload
154
-
155
- // Gallery Settings
156
- $ngg_options['galImages'] = '20'; // Number of images per page
157
- $ngg_options['galPagedGalleries'] = 0; // Number of galleries per page (in a album)
158
- $ngg_options['galColumns'] = 0; // Number of columns for the gallery
159
- $ngg_options['galShowSlide'] = true; // Show slideshow
160
- $ngg_options['galTextSlide'] = __('[Show as slideshow]','nggallery'); // Text for slideshow
161
- $ngg_options['galTextGallery'] = __('[Show picture list]','nggallery'); // Text for gallery
162
- $ngg_options['galShowOrder'] = 'gallery'; // Show order
163
- $ngg_options['galSort'] = 'sortorder'; // Sort order
164
- $ngg_options['galSortDir'] = 'ASC'; // Sort direction
165
- $ngg_options['galNoPages'] = true; // use no subpages for gallery
166
- $ngg_options['galImgBrowser'] = false; // Show ImageBrowser, instead effect
167
- $ngg_options['galHiddenImg'] = false; // For paged galleries we can hide image
168
- $ngg_options['galAjaxNav'] = false; // AJAX Navigation for Shutter effect
169
-
170
- // Thumbnail Effect
171
- $ngg_options['thumbEffect'] = 'shutter'; // select effect
172
- $ngg_options['thumbCode'] = 'class="shutterset_%GALLERY_NAME%"';
173
-
174
- // Watermark settings
175
- $ngg_options['wmPos'] = 'botRight'; // Postion
176
- $ngg_options['wmXpos'] = 5; // X Pos
177
- $ngg_options['wmYpos'] = 5; // Y Pos
178
- $ngg_options['wmType'] = 'text'; // Type : 'image' / 'text'
179
- $ngg_options['wmPath'] = ''; // Path to image
180
- $ngg_options['wmFont'] = 'arial.ttf'; // Font type
181
- $ngg_options['wmSize'] = 10; // Font Size
182
- $ngg_options['wmText'] = get_option('blogname'); // Text
183
- $ngg_options['wmColor'] = '000000'; // Font Color
184
- $ngg_options['wmOpaque'] = '100'; // Font Opaque
185
-
186
- // Image Rotator settings
187
- $ngg_options['enableIR'] = false;
188
- $ngg_options['slideFx'] = 'fade';
189
- $ngg_options['irURL'] = path_join(NGGALLERY_URLPATH, 'imagerotator.swf');
190
- $ngg_options['irXHTMLvalid'] = false;
191
- $ngg_options['irAudio'] = '';
192
- $ngg_options['irWidth'] = 320;
193
- $ngg_options['irHeight'] = 240;
194
- $ngg_options['irShuffle'] = true;
195
- $ngg_options['irLinkfromdisplay'] = true;
196
- $ngg_options['irShownavigation'] = false;
197
- $ngg_options['irShowicons'] = false;
198
- $ngg_options['irWatermark'] = false;
199
- $ngg_options['irOverstretch'] = 'true';
200
- $ngg_options['irRotatetime'] = 10;
201
- $ngg_options['irTransition'] = 'random';
202
- $ngg_options['irKenburns'] = false;
203
- $ngg_options['irBackcolor'] = '000000';
204
- $ngg_options['irFrontcolor'] = 'FFFFFF';
205
- $ngg_options['irLightcolor'] = 'CC0000';
206
- $ngg_options['irScreencolor'] = '000000';
207
-
208
- // CSS Style
209
- $ngg_options['activateCSS'] = true; // activate the CSS file
210
- $ngg_options['CSSfile'] = 'nggallery.css'; // set default css filename
211
-
212
- // special overrides for WPMU
213
- if (is_multisite()) {
214
- // get the site options
215
- $ngg_wpmu_options = get_site_option('ngg_options');
216
-
217
- // get the default value during first installation
218
- if (!is_array($ngg_wpmu_options)) {
219
- $ngg_wpmu_options['gallerypath'] = 'wp-content/blogs.dir/%BLOG_ID%/files/';
220
- $ngg_wpmu_options['wpmuCSSfile'] = 'nggallery.css';
221
- update_site_option('ngg_options', $ngg_wpmu_options);
222
- }
223
-
224
- $ngg_options['gallerypath'] = str_replace("%BLOG_ID%", $blog_id , $ngg_wpmu_options['gallerypath']);
225
- $ngg_options['CSSfile'] = $ngg_wpmu_options['wpmuCSSfile'];
226
- }
227
-
228
- update_option('ngg_options', $ngg_options);
229
-
230
- }
231
-
232
- /**
233
- * Deregister a capability from all classic roles
234
- *
235
- * @access internal
236
- * @param string $capability name of the capability which should be deregister
237
- * @return void
238
- */
239
- function ngg_remove_capability($capability){
240
- // this function remove the $capability only from the classic roles
241
- $check_order = array("subscriber", "contributor", "author", "editor", "administrator");
242
-
243
- foreach ($check_order as $role) {
244
-
245
- $role = get_role($role);
246
- $role->remove_cap($capability) ;
247
- }
248
-
249
- }
250
-
251
- /**
252
- * Uninstall all settings and tables
253
- * Called via Setup and register_unstall hook
254
- *
255
- * @access internal
256
- * @return void
257
- */
258
- function nggallery_uninstall() {
259
- global $wpdb;
260
-
261
- // first remove all tables
262
- $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}ngg_pictures");
263
- $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}ngg_gallery");
264
- $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}ngg_album");
265
-
266
- // then remove all options
267
- delete_option( 'ngg_options' );
268
- delete_option( 'ngg_db_version' );
269
- delete_option( 'ngg_update_exists' );
270
- delete_option( 'ngg_next_update' );
271
-
272
- // now remove the capability
273
- ngg_remove_capability("NextGEN Gallery overview");
274
- ngg_remove_capability("NextGEN Use TinyMCE");
275
- ngg_remove_capability("NextGEN Upload images");
276
- ngg_remove_capability("NextGEN Manage gallery");
277
- ngg_remove_capability("NextGEN Edit album");
278
- ngg_remove_capability("NextGEN Change style");
279
- ngg_remove_capability("NextGEN Change options");
280
- }
281
-
282
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/js/swfupload.handler.js DELETED
@@ -1,153 +0,0 @@
1
- /**
2
- * NextGEN Gallery - SWFUpload Handler
3
- * http://www.nextgen-gallery.com/
4
- *
5
- * Built on top of the swfupload library
6
- * http://swfupload.org version 2.2.0
7
- *
8
- * version 1.0.3
9
- */
10
-
11
- // on load change the upload to swfupload
12
- function initSWFUpload() {
13
- jQuery(function() {
14
- jQuery("#uploadimage_btn").after("<input class='button-primary' type='button' name='uploadimage' id='swfupload_btn' value='" + ngg_swf_upload.customSettings.upload + "' />")
15
- .remove();
16
- jQuery("#swfupload_btn").click( function() { submitFiles(); } );
17
- jQuery("#imagefiles")
18
- .after("<div id='uploadQueue'></div>")
19
- .after("<input id='imagefiles' type='button' class='button-secondary uploadform' value='" + ngg_swf_upload.customSettings.browse + "' />")
20
- .after("<input type='text' id='txtFileName' readonly='readonly' />")
21
- .remove();
22
- jQuery("#imagefiles").click( function() { fileBrowse(); } );
23
- });
24
- }
25
-
26
- // call the upload dialog
27
- function fileBrowse() {
28
- jQuery("#txtFileName").val("");
29
- ngg_swf_upload.cancelUpload();
30
- ngg_swf_upload.selectFiles();
31
- }
32
-
33
- // called when a file is added
34
- function fileQueued(fileObj) {
35
- filesize = " (" + Math.round(fileObj.size/1024) + " kB) ";
36
- jQuery("#txtFileName").val(fileObj.name);
37
- jQuery("#uploadQueue")
38
- .append("<div id='" + fileObj.id + "' class='nggUploadItem'> [<a href='javascript:removeFile(\"" + fileObj.id + "\");'>" + ngg_swf_upload.customSettings.remove + "</a>] " + fileObj.name + filesize + "</div>")
39
- .children("div:last").slideDown("slow")
40
- .end();
41
- }
42
-
43
- // start the upload
44
- function submitFiles() {
45
- // check if a gallery is selected
46
- if (jQuery('#galleryselect').val() > "0") {
47
- nggProgressBar.init(nggAjaxOptions);
48
- // get old post_params
49
- post_params = ngg_swf_upload.getSetting("post_params");
50
- // update the selected gallery in the post_params
51
- post_params['galleryselect'] = jQuery('#galleryselect').val();
52
- ngg_swf_upload.setPostParams(post_params);
53
- ngg_swf_upload.startUpload();
54
- } else {
55
- jQuery('#uploadimage_form').prepend("<input type=\"hidden\" name=\"swf_callback\" value=\"-1\">");
56
- jQuery("#uploadimage_form").submit();
57
- }
58
- }
59
-
60
- // called when a file will be removed
61
- function removeFile(fileID) {
62
- ngg_swf_upload.cancelUpload(fileID);
63
- jQuery("#" + fileID).hide("slow");
64
- jQuery("#" + fileID).remove();
65
- }
66
-
67
- // called before the uploads start
68
- function uploadStart(fileObj) {
69
- nggProgressBar.init(nggAjaxOptions);
70
- return true;
71
- }
72
-
73
- // called during the upload progress
74
- function uploadProgress(fileObj, bytesLoaded) {
75
- var percent = Math.ceil((bytesLoaded / fileObj.size) * 100);
76
- nggProgressBar.increase( percent );
77
- jQuery("#progressbar span").text(percent + "% - " + fileObj.name);
78
- }
79
-
80
- // called when the file is uploaded
81
- function uploadComplete(fileObj) {
82
- jQuery("#" + fileObj.id).hide("slow");
83
- jQuery("#" + fileObj.id).remove();
84
- if ( ngg_swf_upload.getStats().files_queued == 0) {
85
- nggProgressBar.finished();
86
- jQuery("#uploadimage_form").submit();
87
- }
88
- }
89
-
90
- // called when all files are uploaded
91
- function uploadSuccess(fileObj, server_data) {
92
- // Show any error message
93
- if (server_data != 0){
94
- nggProgressBar.addNote("<strong>ERROR</strong>: " + fileObj.name + " : " + server_data);
95
- }
96
- // Upload the next file until queue is empty
97
- if ( ngg_swf_upload.getStats().files_queued > 0) {
98
- ngg_swf_upload.startUpload();
99
- } else {
100
- // server_data could be add as hidden field
101
- jQuery('#uploadimage_form').prepend("<input type=\"hidden\" name=\"swf_callback\" value=\"" + server_data + "\">");
102
- }
103
- }
104
-
105
- // called on error
106
- function uploadError(fileObj, error_code, message) {
107
- var error_name = "";
108
- switch(error_code) {
109
- case SWFUpload.UPLOAD_ERROR.HTTP_ERROR:
110
- error_name = "HTTP ERROR";
111
- break;
112
- case SWFUpload.UPLOAD_ERROR.MISSING_UPLOAD_URL:
113
- error_name = "MISSING UPLOAD URL";
114
- break;
115
- case SWFUpload.UPLOAD_ERROR.IO_ERROR:
116
- error_name = "IO FAILURE";
117
- break;
118
- case SWFUpload.UPLOAD_ERROR.SECURITY_ERROR:
119
- error_name = "SECURITY ERROR";
120
- break;
121
- case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED:
122
- error_name = "UPLOAD LIMIT EXCEEDED";
123
- break;
124
- case SWFUpload.UPLOAD_ERROR.UPLOAD_FAILED:
125
- error_name = "UPLOAD FAILED";
126
- break;
127
- case SWFUpload.UPLOAD_ERROR.SPECIFIED_FILE_ID_NOT_FOUND:
128
- error_name = "SPECIFIED FILE ID NOT FOUND";
129
- break;
130
- case SWFUpload.UPLOAD_ERROR.FILE_VALIDATION_FAILED:
131
- error_name = "FILE VALIDATION FAILED";
132
- break;
133
- case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED:
134
- error_name = "FILE CANCELLED";
135
- return;
136
- break;
137
- case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED:
138
- error_name = "FILE STOPPED";
139
- break;
140
- default:
141
- error_name = "UNKNOWN";
142
- break;
143
- }
144
- nggProgressBar.addNote("<strong>ERROR " + error_name + " </strong>: " + fileObj.name + " : " + message);
145
- jQuery("#" + fileObj.id).hide("slow");
146
- jQuery("#" + fileObj.id).remove();
147
- if ( ngg_swf_upload.getStats().files_queued > 0) {
148
- ngg_swf_upload.startUpload();
149
- } else {
150
- jQuery('#uploadimage_form').prepend("<input type=\"hidden\" name=\"swf_callback\" value=\"" + error_name + "\">");
151
- jQuery("#uploadimage_form").submit();
152
- }
153
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/tinymce/editor_plugin.js DELETED
@@ -1,77 +0,0 @@
1
- // Docu : http://wiki.moxiecode.com/index.php/TinyMCE:Create_plugin/3.x#Creating_your_own_plugins
2
-
3
- (function() {
4
- // Load plugin specific language pack
5
- tinymce.PluginManager.requireLangPack('NextGEN');
6
-
7
- tinymce.create('tinymce.plugins.NextGEN', {
8
- /**
9
- * Initializes the plugin, this will be executed after the plugin has been created.
10
- * This call is done before the editor instance has finished it's initialization so use the onInit event
11
- * of the editor instance to intercept that event.
12
- *
13
- * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
14
- * @param {string} url Absolute URL to where the plugin is located.
15
- */
16
- init : function(ed, url) {
17
- // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample');
18
-
19
- ed.addCommand('mceNextGEN', function() {
20
- ed.windowManager.open({
21
- // call content via admin-ajax, no need to know the full plugin path
22
- file : ajaxurl + '?action=ngg_tinymce',
23
- width : 360 + ed.getLang('NextGEN.delta_width', 0),
24
- height : 210 + ed.getLang('NextGEN.delta_height', 0),
25
- inline : 1
26
- }, {
27
- plugin_url : url // Plugin absolute URL
28
- });
29
- });
30
-
31
- // Register example button
32
- ed.addButton('NextGEN', {
33
- title : 'NextGEN.desc',
34
- cmd : 'mceNextGEN',
35
- image : url + '/nextgen.gif'
36
- });
37
-
38
- // Add a node change handler, selects the button in the UI when a image is selected
39
- ed.onNodeChange.add(function(ed, cm, n) {
40
- cm.setActive('NextGEN', n.nodeName == 'IMG');
41
- });
42
- },
43
-
44
- /**
45
- * Creates control instances based in the incomming name. This method is normally not
46
- * needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons
47
- * but you sometimes need to create more complex controls like listboxes, split buttons etc then this
48
- * method can be used to create those.
49
- *
50
- * @param {String} n Name of the control to create.
51
- * @param {tinymce.ControlManager} cm Control manager to use inorder to create new control.
52
- * @return {tinymce.ui.Control} New control instance or null if no control was created.
53
- */
54
- createControl : function(n, cm) {
55
- return null;
56
- },
57
-
58
- /**
59
- * Returns information about the plugin as a name/value array.
60
- * The current keys are longname, author, authorurl, infourl and version.
61
- *
62
- * @return {Object} Name/value array containing information about the plugin.
63
- */
64
- getInfo : function() {
65
- return {
66
- longname : 'NextGEN',
67
- author : 'Photocrati',
68
- authorurl : 'http://www.photocrati.com/',
69
- infourl : 'http://www.nextgen-gallery.com/',
70
- version : "2.0"
71
- };
72
- }
73
- });
74
-
75
- // Register plugin
76
- tinymce.PluginManager.add('NextGEN', tinymce.plugins.NextGEN);
77
- })();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/tinymce/langs/de.js DELETED
@@ -1,6 +0,0 @@
1
- // German lang variables for WP2.5
2
-
3
- tinyMCE.addI18n({de:{
4
- NextGEN:{
5
- desc : 'NextGEN Gallery hinzufuegen'
6
- }}});
 
 
 
 
 
 
admin/tinymce/langs/de_de.js DELETED
@@ -1,6 +0,0 @@
1
- // German lang variables for WP2.5
2
-
3
- tinyMCE.addI18n({de:{
4
- NextGEN:{
5
- desc : 'NextGEN Gallery hinzufuegen'
6
- }}});
 
 
 
 
 
 
admin/tinymce/langs/en.js DELETED
@@ -1,6 +0,0 @@
1
- // English lang variables for WP2.5
2
-
3
- tinyMCE.addI18n({en:{
4
- NextGEN:{
5
- desc : 'Add NextGEN Gallery'
6
- }}});
 
 
 
 
 
 
admin/tinymce/langs/en_US.js DELETED
@@ -1,6 +0,0 @@
1
- // English lang variables for WP2.5
2
-
3
- tinyMCE.addI18n({en_US:{
4
- NextGEN:{
5
- desc : 'Add NextGEN Gallery'
6
- }}});
 
 
 
 
 
 
admin/tinymce/tinymce.js DELETED
@@ -1,75 +0,0 @@
1
- function init() {
2
- tinyMCEPopup.resizeToInnerSize();
3
- }
4
-
5
- function getCheckedValue(radioObj) {
6
- if(!radioObj)
7
- return "";
8
- var radioLength = radioObj.length;
9
- if(radioLength == undefined)
10
- if(radioObj.checked)
11
- return radioObj.value;
12
- else
13
- return "";
14
- for(var i = 0; i < radioLength; i++) {
15
- if(radioObj[i].checked) {
16
- return radioObj[i].value;
17
- }
18
- }
19
- return "";
20
- }
21
-
22
- function insertNGGLink() {
23
-
24
- var tagtext;
25
-
26
- var gallery = document.getElementById('gallery_panel');
27
- var album = document.getElementById('album_panel');
28
- var singlepic = document.getElementById('singlepic_panel');
29
-
30
- // who is active ?
31
- if (gallery.className.indexOf('current') != -1) {
32
- var galleryid = document.getElementById('gallerytag').value;
33
- var showtype = getCheckedValue(document.getElementsByName('showtype'));
34
- if (galleryid != 0 )
35
- tagtext = "["+ showtype + " id=" + galleryid + "]";
36
- else
37
- tinyMCEPopup.close();
38
- }
39
-
40
- if (album.className.indexOf('current') != -1) {
41
- var albumid = document.getElementById('albumtag').value;
42
- var showtype = getCheckedValue(document.getElementsByName('albumtype'));
43
- if (albumid != 0 )
44
- tagtext = "[nggalbum id=" + albumid + " template=" + showtype + "]";
45
- else
46
- tinyMCEPopup.close();
47
- }
48
-
49
- if (singlepic.className.indexOf('current') != -1) {
50
- var singlepicid = document.getElementById('singlepictag').value;
51
- var imgWidth = document.getElementById('imgWidth').value;
52
- var imgHeight = document.getElementById('imgHeight').value;
53
- var imgeffect = document.getElementById('imgeffect').value;
54
- var imgfloat = document.getElementById('imgfloat').value;
55
-
56
- if (singlepicid != 0 ) {
57
- if (imgeffect == "none")
58
- tagtext = "[singlepic id=" + singlepicid + " w=" + imgWidth + " h=" + imgHeight + " float=" + imgfloat + "]";
59
- else
60
- tagtext = "[singlepic id=" + singlepicid + " w=" + imgWidth + " h=" + imgHeight + " mode=" + imgeffect + " float=" + imgfloat + "]";
61
- } else {
62
- tinyMCEPopup.close();
63
- }
64
- }
65
-
66
- if(window.tinyMCE) {
67
- window.tinyMCE.execInstanceCommand(window.tinyMCE.activeEditor.id, 'mceInsertContent', false, tagtext);
68
- //Peforms a clean up of the current editor HTML.
69
- //tinyMCEPopup.editor.execCommand('mceCleanup');
70
- //Repaints the editor. Sometimes the browser has graphic glitches.
71
- tinyMCEPopup.editor.execCommand('mceRepaint');
72
- tinyMCEPopup.close();
73
- }
74
- return;
75
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/tinymce/tinymce.php DELETED
@@ -1,102 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * add_nextgen_button
5
- *
6
- * @package NextGEN Gallery
7
- * @title TinyMCE V3 Button Integration (for WP2.5 and higher)
8
- * @author Alex Rabe
9
- *
10
- * @access public
11
- */
12
- class add_nextgen_button {
13
-
14
- var $pluginname = 'NextGEN';
15
- var $path = '';
16
- var $internalVersion = 200;
17
-
18
- /**
19
- * add_nextgen_button::add_nextgen_button()
20
- * the constructor
21
- *
22
- * @return void
23
- */
24
- function add_nextgen_button() {
25
-
26
- // Set path to editor_plugin.js
27
- $this->path = NGGALLERY_URLPATH . 'admin/tinymce/';
28
-
29
- // Modify the version when tinyMCE plugins are changed.
30
- add_filter('tiny_mce_version', array (&$this, 'change_tinymce_version') );
31
-
32
- // init process for button control
33
- add_action('init', array (&$this, 'addbuttons') );
34
- }
35
-
36
- /**
37
- * add_nextgen_button::addbuttons()
38
- *
39
- * @return void
40
- */
41
- function addbuttons() {
42
-
43
- // Don't bother doing this stuff if the current user lacks permissions
44
- if ( !current_user_can('edit_posts') && !current_user_can('edit_pages') )
45
- return;
46
-
47
- // Check for NextGEN capability
48
- if ( !current_user_can('NextGEN Use TinyMCE') )
49
- return;
50
-
51
- // Add only in Rich Editor mode
52
- if ( get_user_option('rich_editing') == 'true') {
53
-
54
- // add the button for wp2.5 in a new way
55
- add_filter("mce_external_plugins", array (&$this, 'add_tinymce_plugin' ), 5);
56
- add_filter('mce_buttons', array (&$this, 'register_button' ), 5);
57
- }
58
- }
59
-
60
- /**
61
- * add_nextgen_button::register_button()
62
- * used to insert button in wordpress 2.5x editor
63
- *
64
- * @return $buttons
65
- */
66
- function register_button($buttons) {
67
-
68
- array_push($buttons, 'separator', $this->pluginname );
69
-
70
- return $buttons;
71
- }
72
-
73
- /**
74
- * add_nextgen_button::add_tinymce_plugin()
75
- * Load the TinyMCE plugin : editor_plugin.js
76
- *
77
- * @return $plugin_array
78
- */
79
- function add_tinymce_plugin($plugin_array) {
80
-
81
- $plugin_array[$this->pluginname] = $this->path . 'editor_plugin.js';
82
-
83
- return $plugin_array;
84
- }
85
-
86
- /**
87
- * add_nextgen_button::change_tinymce_version()
88
- * A different version will rebuild the cache
89
- *
90
- * @return $versio
91
- */
92
- function change_tinymce_version($version) {
93
- $version = $version + $this->internalVersion;
94
- return $version;
95
- }
96
-
97
- }
98
-
99
- // Call it now
100
- $tinymce_button = new add_nextgen_button ();
101
-
102
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/tinymce/window.php DELETED
@@ -1,152 +0,0 @@
1
- <?php
2
-
3
- if ( !defined('ABSPATH') )
4
- die('You are not allowed to call this page directly.');
5
-
6
- global $wpdb, $nggdb;
7
-
8
- @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
9
-
10
- // Get WordPress scripts and styles
11
- wp_enqueue_script('jquery-ui-core');
12
- wp_enqueue_script('jquery-ui-widget');
13
- wp_enqueue_script('jquery-ui-position');
14
- global $wp_scripts;
15
- if (!isset($wp_scripts->registered['jquery-ui-autocomplete'])) {
16
- wp_register_script( 'jquery-ui-autocomplete', NGGALLERY_URLPATH .'admin/js/jquery.ui.autocomplete.min.js', array('jquery-ui-core'), '1.8.15');
17
- }
18
- wp_enqueue_script('jquery-ui-autocomplete');
19
- ?>
20
- <html xmlns="http://www.w3.org/1999/xhtml">
21
- <head>
22
- <title>NextGEN Gallery</title>
23
- <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
24
- <script language="javascript" type="text/javascript" src="<?php echo site_url(); ?>/wp-includes/js/tinymce/tiny_mce_popup.js"></script>
25
- <script language="javascript" type="text/javascript" src="<?php echo site_url(); ?>/wp-includes/js/tinymce/utils/mctabs.js"></script>
26
- <script language="javascript" type="text/javascript" src="<?php echo site_url(); ?>/wp-includes/js/tinymce/utils/form_utils.js"></script>
27
- <?php wp_print_scripts() ?>
28
- <script language="javascript" type="text/javascript" src="<?php echo NGGALLERY_URLPATH ?>admin/js/ngg.autocomplete.js"></script>
29
- <script language="javascript" type="text/javascript" src="<?php echo NGGALLERY_URLPATH ?>admin/tinymce/tinymce.js"></script>
30
- <link rel="stylesheet" type="text/css" href="<?php echo NGGALLERY_URLPATH ?>admin/css/jquery.ui.css" media="all" />
31
- <base target="_self" />
32
- </head>
33
- <script type="text/javascript">
34
- jQuery(document).ready(function(){
35
- jQuery("#gallerytag").nggAutocomplete( {
36
- type: 'gallery',domain: "<?php echo home_url('index.php', is_ssl() ? 'https' : 'http'); ?>"
37
- });
38
- jQuery("#albumtag").nggAutocomplete( {
39
- type: 'album',domain: "<?php echo home_url('index.php', is_ssl() ? 'https' : 'http'); ?>"
40
- });
41
- jQuery("#singlepictag").nggAutocomplete( {
42
- type: 'image',domain: "<?php echo home_url('index.php', is_ssl() ? 'https' : 'http'); ?>"
43
- });
44
- });
45
- </script>
46
- <body class="nextgen_tinymce_window" id="link" onload="tinyMCEPopup.executeOnLoad('init();');document.body.style.display='';" style="display: none">
47
- <!-- <form onsubmit="insertLink();return false;" action="#"> -->
48
- <form name="NextGEN" action="#">
49
- <div class="tabs">
50
- <ul>
51
- <li id="gallery_tab" class="current"><span><a href="javascript:mcTabs.displayTab('gallery_tab','gallery_panel');" onmousedown="return false;"><?php echo _n( 'Gallery', 'Galleries', 1, 'nggallery' ) ?></a></span></li>
52
- <li id="album_tab"><span><a href="javascript:mcTabs.displayTab('album_tab','album_panel');" onmousedown="return false;"><?php echo _n( 'Album', 'Albums', 1, 'nggallery' ) ?></a></span></li>
53
- <li id="singlepic_tab"><span><a href="javascript:mcTabs.displayTab('singlepic_tab','singlepic_panel');" onmousedown="return false;"><?php _e('Picture', 'nggallery'); ?></a></span></li>
54
- </ul>
55
- </div>
56
-
57
- <div class="panel_wrapper">
58
- <!-- gallery panel -->
59
- <div id="gallery_panel" class="panel current">
60
- <br />
61
- <table border="0" cellpadding="4" cellspacing="0">
62
- <tr>
63
- <td nowrap="nowrap"><label for="gallerytag"><?php _e("Gallery", 'nggallery'); ?></label></td>
64
- <td><select id="gallerytag" name="gallerytag" style="width: 200px">
65
- <option value="0" selected="selected"><?php _e("Select or enter gallery", 'nggallery'); ?></option>
66
- </select>
67
- </td>
68
- </tr>
69
- <tr>
70
- <td nowrap="nowrap" valign="top"><label for="showtype"><?php _e("Show as", 'nggallery'); ?></label></td>
71
- <td><label><input name="showtype" type="radio" value="nggallery" checked="checked" /> <?php _e('Image list', 'nggallery') ;?></label><br />
72
- <label><input name="showtype" type="radio" value="slideshow" /> <?php _e('Slideshow', 'nggallery') ;?></label><br />
73
- <label><input name="showtype" type="radio" value="imagebrowser" /> <?php _e('Imagebrowser', 'nggallery') ;?></label></td>
74
- </tr>
75
- </table>
76
- </div>
77
- <!-- gallery panel -->
78
-
79
- <!-- album panel -->
80
- <div id="album_panel" class="panel">
81
- <br />
82
- <table border="0" cellpadding="4" cellspacing="0">
83
- <tr>
84
- <td nowrap="nowrap"><label for="albumtag"><?php _e("Album", 'nggallery'); ?></label></td>
85
- <td><select id="albumtag" name="albumtag" style="width: 200px">
86
- <option value="0" selected="selected"><?php _e("Select or enter album", 'nggallery'); ?></option>
87
- </select>
88
- </td>
89
- </tr>
90
- <tr>
91
- <td nowrap="nowrap" valign="top"><label for="showtype"><?php _e("Show as", 'nggallery'); ?></label></td>
92
- <td><label><input name="albumtype" type="radio" value="extend" checked="checked" /> <?php _e('Extended version', 'nggallery') ;?></label><br />
93
- <label><input name="albumtype" type="radio" value="compact" /> <?php _e('Compact version', 'nggallery') ;?></label></td>
94
- </tr>
95
- </table>
96
- </div>
97
- <!-- album panel -->
98
-
99
- <!-- single pic panel -->
100
- <div id="singlepic_panel" class="panel">
101
- <br />
102
- <table border="0" cellpadding="4" cellspacing="0">
103
- <tr>
104
- <td nowrap="nowrap"><label for="singlepictag"><?php _e("Picture", 'nggallery'); ?></label></td>
105
- <td><select id="singlepictag" name="singlepictag" style="width: 200px">
106
- <option value="0" selected="selected"><?php _e("Select or enter picture", 'nggallery'); ?></option>
107
- </select>
108
- </td>
109
- </tr>
110
- <tr>
111
- <td nowrap="nowrap"><?php _e("Width x Height", 'nggallery'); ?></td>
112
- <td><input type="text" size="5" id="imgWidth" name="imgWidth" value="320" /> x <input type="text" size="5" id="imgHeight" name="imgHeight" value="240" /></td>
113
- </tr>
114
- <tr>
115
- <td nowrap="nowrap" valign="top"><?php _e("Effect", 'nggallery'); ?></td>
116
- <td>
117
- <label><select id="imgeffect" name="imgeffect">
118
- <option value="none"><?php _e("No effect", 'nggallery'); ?></option>
119
- <option value="watermark"><?php _e("Watermark", 'nggallery'); ?></option>
120
- <option value="web20"><?php _e("Web 2.0", 'nggallery'); ?></option>
121
- </select></label>
122
- </td>
123
- </tr>
124
- <tr>
125
- <td nowrap="nowrap" valign="top"><?php _e("Float", 'nggallery'); ?></td>
126
- <td>
127
- <label><select id="imgfloat" name="imgfloat">
128
- <option value=""><?php _e("No float", 'nggallery'); ?></option>
129
- <option value="left"><?php _e("Left", 'nggallery'); ?></option>
130
- <option value="center"><?php _e("Center", 'nggallery'); ?></option>
131
- <option value="right"><?php _e("Right", 'nggallery'); ?></option>
132
- </select></label>
133
- </td>
134
- </tr>
135
-
136
- </table>
137
- </div>
138
- <!-- single pic panel -->
139
- </div>
140
-
141
- <div class="mceActionPanel">
142
- <div style="float: left">
143
- <input type="button" id="cancel" name="cancel" value="<?php _e("Cancel", 'nggallery'); ?>" onclick="tinyMCEPopup.close();" />
144
- </div>
145
-
146
- <div style="float: right">
147
- <input type="submit" id="insert" name="insert" value="<?php _e("Insert", 'nggallery'); ?>" onclick="insertNGGLink();" />
148
- </div>
149
- </div>
150
- </form>
151
- </body>
152
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
changelog.txt CHANGED
@@ -1,6 +1,81 @@
1
  NextGEN Gallery
2
  by Photocrati Media
3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  = V1.9.13 - 06.11.2013 =
5
  * NEW: Slideshows are now centered to their content area
6
  * Secured: Ensure that only logged in users can upload images
@@ -31,6 +106,7 @@ by Photocrati Media
31
  * Fixed: Deleted galleries within an album are handed gracefully without warning messages
32
  * Fixed: Correct use of register_uninstall_hook
33
  * Fixed: CSS and usability issues with the TinyMCE window used to display galleries
 
34
 
35
  = V1.9.9 - 12.14.2012 =
36
  * NEW: JW ImageRotator v3.17 is now bundled with the plugin and used by default.
1
  NextGEN Gallery
2
  by Photocrati Media
3
 
4
+ = V2.0.14 - 08.27.2013 =
5
+ * NEW: Added the ability to override thumbnail settings for NextGEN Basic Albums
6
+ * NEW: Shortcode Manager API, which ensures that shortcodes are outputted as intended
7
+ * Changed: Re-added the ability to select the original image size for widgets
8
+ * Fixed: Ensure that stylesheet url returned is correct for Windows hosts
9
+ * Fixed: Broken links and lightbox effects with AJAX pagination
10
+ * Fixed: Try to ensure that third party plugins don't add content to our dynamic JS
11
+ * Fixed: Improved reliability of iframely.js
12
+ * Fixed: Ensure that urls are generated correctly in HTTPs environments
13
+ * Fixed: Datamapper works correctly in environments where temporary tables aren't supported
14
+ * Fixed: Fixed an issue with thickbox loading animation when home url differs from site url
15
+
16
+ = V2.0.11 - 08.19.2013 =
17
+ * NEW: Added "run_ngg_resource_manager" hook to by-pass our resource manager
18
+ * Changed: Removed "Reset & Uninstall" tab, for now
19
+ * Fixed: Compatibility with W3 Total Cache. Please flush cache after updating.
20
+ * Fixed: Conflicts with Photocrati Theme Galleries
21
+ * Fixed: Blank Attach to Post interface window
22
+ * Fixed: Fixed ability to change Lightbox Effect settings
23
+ * Fixed: Implemented techniques to ensure WP_Query variables aren't overwritten
24
+ * Fixed: Enqueuing AJAX JS libraries twice in wp-admin
25
+ * Fixed: Encoding issues
26
+ * Fixed: PHP warnings caused by accessing unserialized data as array
27
+ * Fixed: Fixed installer issues
28
+
29
+ = V2.0.7 - 08.09.2013 =
30
+ * NEW: New resource manager that fixes many plugin and theme incompatibilities
31
+ * NEW: Styles (custom stylesheets) should reside in wp-content/ngg_styles
32
+ * NEW: Added option to "Other Options -> Misc" to control maximum images returned
33
+ * Secured: Removed default connector for jQuery FileTree library
34
+ * Changed: Updated the simplehtmldom library to version 1.5
35
+ * Changed: jQuery is now enqueued at the beginning of every request
36
+ * Fixed: Incompatibilities with BuddyPress
37
+ * Fixed: Incompatibilities with Events+, bbPress, Custom Permalinks, and many other plugins
38
+ * Fixed: Incompcatibilities with Member Access, AMember, Magic Fields, and More Fields
39
+ * Fixed: Incompatibilities with Elegant Themes, Oxygen, Responsive, and many other themes
40
+ * Fixed: Ensure that gallery images don't have a border by default
41
+ * Fixed: Conflict between imagebrowser and album urls
42
+ * Fixed: Reverted default gallerypath to wp-content/gallery/
43
+ * Fixed: Upgrade-safe way of overriding Styles
44
+ * Fixed: Generation of AJAX url is now based on slug
45
+ * Fixed: Restore nggShowGallery and nggShowSlideshow as wrappers to new API
46
+ * Fixed: Always use domain as specified by WordPress Site URL
47
+ * Fixed: Use WordPress Home URL over Site URL when appropriate
48
+ * Fixed: Numerous pagination issues
49
+ * Fixed: Adjusted our forms to comply with WordPress Firewalls
50
+ * Fixed: Correct use of select2 DOM selector for maximum compatibility
51
+ * Fixed: Path and URL calculations for Windows and UNIX environments
52
+ * Fixed: Ensure that pluggable.php is loaded at the start of every request
53
+ * Fixed: Fancybox: adjust CSS for further box-sizing protection from themes
54
+ * Fixed: Use PHP 5.2.1 compatible named pattern matching syntax
55
+ * Fixed: Remove usage of __DIR__ constant not supported by PHP 5.2.x
56
+ * Fixed: Removed dependency on mb_string PHP module
57
+ * Fixed: Allow "No Lightbox" as an option for Lightbox Effects
58
+ * Fixed: Warning: "Invalid CRT parameters detected" for Windows environments
59
+
60
+ = V2.0 - 07.30.2013 =
61
+ * NEW: Improved user experience throughout the plugin, settings and usage.
62
+ * NEW: Plupload queue uploader that allows for bulk and zip uploads within the same interface.
63
+ * NEW: Complete redesign of the NextGEN options panel
64
+ * NEW: Added new interface for adding galleries from pages and posts.
65
+ * NEW: Galleries are now mobile friendly and responsive, which is most noticeable with a responsive theme.
66
+ * NEW: Streamlined functionality for displaying galleries based on tags.
67
+ * NEW: Architecture based on Pope Framework (http://bitbucket.org/photocrati/pope-framework)
68
+ * NEW: New shortcode, “ngg_images”, and corresponding Attach to Post interface
69
+ * NEW: Galleries have now global and instance settings
70
+ * NEW: Support for FastCGI environments
71
+ * Changed: Replaces shortcodes with placeholder images, however still supports legacy shortcodes.
72
+ * Changed: Introduced new Growl-like notifications
73
+ * Changed: The container and it’s images are centered for slideshows
74
+ * Changed: NextGEN styles now override vs replace default styles
75
+ * Changed: NextGEN legacy templates have been deprecated (but still function)
76
+ * FIXED: The ability to use NextGEN image as a Featured Image.
77
+ * FIXED: Many bugs and annoyances, such as PHP warnings, errors, etc.
78
+
79
  = V1.9.13 - 06.11.2013 =
80
  * NEW: Slideshows are now centered to their content area
81
  * Secured: Ensure that only logged in users can upload images
106
  * Fixed: Deleted galleries within an album are handed gracefully without warning messages
107
  * Fixed: Correct use of register_uninstall_hook
108
  * Fixed: CSS and usability issues with the TinyMCE window used to display galleries
109
+ * Fixed: Inability to generate new image slugs
110
 
111
  = V1.9.9 - 12.14.2012 =
112
  * NEW: JW ImageRotator v3.17 is now bundled with the plugin and used by default.
css/Black_Minimalism.css DELETED
@@ -1,375 +0,0 @@
1
- /*
2
- CSS Name: Black Minimalism Theme
3
- Description: For Black Minimalism Theme
4
- Author: Alex Rabe
5
- Version: 1.60
6
-
7
- This is a template stylesheet that can be used with NextGEN Gallery. I tested the
8
- styles with a default theme Kubrick. Modify it when your theme struggle with it,
9
- it's only a template design
10
-
11
- */
12
-
13
- /* ----------- Album Styles Extend -------------*/
14
-
15
- .ngg-albumoverview {
16
- margin-top: 10px;
17
- width: 100%;
18
- clear:both;
19
- display:block !important;
20
- }
21
-
22
- .ngg-album {
23
- /*height: 130px;*/
24
- overflow:hidden;
25
- padding: 5px;
26
- margin-bottom: 5px;
27
- border: 1px solid #cccccc;
28
- }
29
-
30
- .ngg-albumtitle {
31
- text-align: left;
32
- font-weight: bold;
33
- margin:0px;
34
- padding:0px;
35
- font-size: 1.4em;
36
- margin-bottom: 10px;
37
- }
38
-
39
- .ngg-thumbnail {
40
- float: left;
41
- margin: 0pt !important;
42
- margin-right: 12px !important;
43
- }
44
-
45
- .ngg-thumbnail img {
46
- background-color:#FFFFFF;
47
- border:1px solid #A9A9A9;
48
- margin:4px 0px 4px 5px;
49
- padding:4px;
50
- position:relative;
51
- }
52
-
53
- .ngg-thumbnail img:hover {
54
- background-color: #A9A9A9;
55
- }
56
-
57
- .ngg-description {
58
- text-align: left;
59
- }
60
-
61
- /* ----------- Album Styles Compact -------------*/
62
-
63
- .ngg-album-compact {
64
- float:left;
65
- height:180px;
66
- padding-right:6px !important;
67
- margin:0px !important;
68
- text-align:left;
69
- width:120px;
70
- }
71
-
72
- .ngg-album-compactbox {
73
- background:transparent url(albumset.gif) no-repeat scroll 0%;
74
- height:86px;
75
- margin:0pt 0pt 6px !important;
76
- padding:12px 0pt 0pt 7px !important;
77
- width:120px;
78
- }
79
-
80
-
81
- .ngg-album-compactbox .Thumb {
82
- border:1px solid #000000;
83
- margin:0px !important;
84
- padding:0px !important;
85
- width:91px;
86
- height:68px;
87
- }
88
-
89
- .ngg-album-compact h4 {
90
- font-size:15px;
91
- font-weight:bold;
92
- margin-bottom:0px;
93
- margin-top:0px;
94
- width:110px;
95
- }
96
-
97
- .ngg-album-compact p {
98
- font-size:11px;
99
- margin-top:2px;
100
- }
101
-
102
- /* ----------- Gallery style -------------*/
103
-
104
- .ngg-galleryoverview {
105
- overflow: hidden;
106
- margin-top: 10px;
107
- width: 100%;
108
- clear:both;
109
- display:block !important;
110
- }
111
-
112
- .ngg-gallery-thumbnail-box {
113
- float: left;
114
- width: 20%;
115
- }
116
-
117
- .ngg-gallery-thumbnail {
118
- float: left;
119
- background: url(shadowAlpha.png) no-repeat bottom right !important;
120
- background: url(shadow.gif) no-repeat bottom right;
121
- margin: 10px 0 0 10px !important;
122
- }
123
-
124
- .ngg-gallery-thumbnail img {
125
- margin: -6px 6px 6px -6px;
126
- background-color:#FFFFFF;
127
- border:1px solid #A9A9A9;
128
- display:block;
129
- padding:4px;
130
- position:relative;
131
- }
132
-
133
- .ngg-gallery-thumbnail img:hover {
134
- background-color: #A9A9A9;
135
- }
136
-
137
- .ngg-gallery-thumbnail span {
138
- /* Images description */
139
- font-size:90%;
140
- padding-left:5px;
141
- display:block;
142
- }
143
-
144
- .ngg-clear {
145
- clear: both;
146
- }
147
-
148
- /* ----------- Gallery navigation -------------*/
149
-
150
- .ngg-navigation {
151
- font-size:0.9em !important;
152
- clear:both !important;
153
- display:block !important;
154
- padding-top:15px;
155
- text-align:center;
156
- }
157
-
158
- .ngg-navigation span {
159
- font-weight:bold;
160
- margin:0pt 6px;
161
- }
162
-
163
- .ngg-navigation a.page-numbers,
164
- .ngg-navigation a.next,
165
- .ngg-navigation a.prev,
166
- .ngg-navigation span.page-numbers,
167
- .ngg-navigation span.next,
168
- .ngg-navigation span.prev {
169
- border:1px solid #660000;
170
- margin-right:3px;
171
- padding:3px 7px;
172
- }
173
-
174
- .ngg-navigation a.page-numbers:hover,
175
- .ngg-navigation a.next:hover,
176
- .ngg-navigation a.prev:hover,
177
- .ngg-navigation span.page-numbers:hover,
178
- .ngg-navigation span.next:hover,
179
- .ngg-navigation span.prev:hover {
180
- background-color: #660000;
181
- color: #FFFFFF;
182
- text-decoration: none;
183
- }
184
-
185
- /* ----------- Image browser style -------------*/
186
-
187
- .ngg-imagebrowser {
188
-
189
- }
190
-
191
- .ngg-imagebrowser h3 {
192
- text-align:center;
193
- }
194
-
195
- .ngg-imagebrowser img {
196
- border:1px solid #A9A9A9;
197
- margin-top: 10px;
198
- margin-bottom: 10px;
199
- width: 100%;
200
- display:block !important;
201
- padding:5px;
202
- }
203
-
204
- .ngg-imagebrowser-nav {
205
- padding:5px;
206
- margin-left:10px;
207
- }
208
-
209
- .ngg-imagebrowser-nav .back {
210
- float:left;
211
- border:1px solid #DDDDDD;
212
- margin-right:3px;
213
- padding:3px 7px;
214
- }
215
-
216
- .ngg-imagebrowser-nav .next {
217
- float:right;
218
- border:1px solid #DDDDDD;
219
- margin-right:3px;
220
- padding:3px 7px;
221
- }
222
-
223
- .ngg-imagebrowser-nav .counter {
224
- text-align:center;
225
- font-size:0.9em !important;
226
- }
227
-
228
- .exif-data {
229
- margin-left: auto !important;
230
- margin-right: auto !important;
231
- }
232
-
233
- /* ----------- Slideshow -------------*/
234
- .slideshow {
235
- margin-left: auto;
236
- margin-right: auto;
237
- text-align:center;
238
- outline: none;
239
- }
240
-
241
- .slideshowlink {
242
-
243
- }
244
-
245
- /* ----------- JS Slideshow -------------*/
246
- .ngg-slideshow {
247
- overflow:hidden;
248
- position: relative;
249
- }
250
-
251
- .ngg-slideshow * {
252
- vertical-align:middle;
253
- }
254
-
255
- /* See also : http://www.brunildo.org/test/img_center.html */
256
- .ngg-slideshow-loader{
257
- display: table-cell;
258
- text-align: center;
259
- vertical-align:middle;
260
- }
261
-
262
- .ngg-slideshow-loader img{
263
- background: none !important;
264
- border: 0 none !important;
265
- margin:auto !important;
266
- }
267
-
268
- /* ----------- Single picture -------------*/
269
- .ngg-singlepic {
270
- display:block;
271
- padding:4px;
272
- }
273
-
274
- .ngg-left {
275
- float: left;
276
- margin-right:10px;
277
- }
278
-
279
- .ngg-right {
280
- float: right;
281
- margin-left:10px;
282
- }
283
-
284
- .ngg-center {
285
- margin-left: auto !important;
286
- margin-right: auto !important;
287
- }
288
-
289
- /* ----------- Sidebar widget -------------*/
290
- .ngg-widget,
291
- .ngg-widget-slideshow {
292
- overflow: hidden;
293
- margin:0pt;
294
- padding:5px 0px 0px 0pt;
295
- }
296
-
297
- .ngg-widget img {
298
- border:2px solid #A9A9A9;
299
- margin:0pt 2px 2px 0px;
300
- padding:1px;
301
- }
302
-
303
- /* ----------- Related images -------------*/
304
- .ngg-related-gallery {
305
- background:#F9F9F9;
306
- border:1px solid #E0E0E0;
307
- overflow:hidden;
308
- margin-bottom:1em;
309
- margin-top:1em;
310
- padding:5px;
311
- }
312
- .ngg-related-gallery img {
313
- border: 1px solid #DDDDDD;
314
- float: left;
315
- margin: 0pt 2px;
316
- padding: 2px;
317
- height: 50px;
318
- width: 50px;
319
- }
320
-
321
- .ngg-related-gallery img:hover {
322
- border: 1px solid #000000;
323
- }
324
-
325
- /* ----------- Gallery list -------------*/
326
-
327
- .ngg-galleryoverview ul li:before {
328
- content: '' !important;
329
- }
330
-
331
- .ngg-gallery-list {
332
- list-style-type:none;
333
- padding: 0px !important;
334
- text-indent:0px !important;
335
- }
336
-
337
- .ngg-galleryoverview div.pic img{
338
- width: 100%;
339
- }
340
-
341
- .ngg-gallery-list li {
342
- float:left;
343
- margin:0 2px 0px 2px !important;
344
- overflow:hidden;
345
- }
346
-
347
- .ngg-gallery-list li a {
348
- border:1px solid #CCCCCC;
349
- display:block;
350
- padding:2px;
351
- }
352
-
353
- .ngg-gallery-list li.selected a{
354
- -moz-background-clip:border;
355
- -moz-background-inline-policy:continuous;
356
- -moz-background-origin:padding;
357
- background:#000000 none repeat scroll 0 0;
358
- }
359
-
360
- .ngg-gallery-list li img {
361
- height:40px;
362
- width:40px;
363
- }
364
-
365
- li.ngg-next, li.ngg-prev {
366
- height:40px;
367
- width:40px;
368
- font-size:3.5em;
369
- }
370
-
371
- li.ngg-next a, li.ngg-prev a {
372
- padding-top: 10px;
373
- border: none;
374
- text-decoration: none;
375
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/hovereffect.css DELETED
@@ -1,425 +0,0 @@
1
- /*
2
- CSS Name: Hovereffect Styles
3
- Description: Hover Stylesheet based on the idea of Hoverbox from http://host.sonspring.com/hoverbox/
4
- Author: Alex Rabe - Orginal by Nathan Smith
5
- Version: 1.60
6
-
7
- This is a template stylesheet which doesn't support description below the thumbnails. It's a experimental version.
8
-
9
- */
10
-
11
- /* ----------- Album Styles Extend -------------*/
12
-
13
- .ngg-albumoverview {
14
- margin-top: 10px;
15
- width: 100%;
16
- clear:both;
17
- display:block !important;
18
- }
19
-
20
- .ngg-album {
21
- overflow: hidden;
22
- padding: 5px;
23
- margin-bottom: 5px;
24
- }
25
-
26
- .ngg-albumtitle {
27
- border-bottom:1px dashed #AAAAAA;
28
- text-align: left;
29
- font-weight: bold;
30
- margin:0px;
31
- padding-bottom: 3px;
32
- font-size: 1.4em;
33
- margin-bottom: 10px;
34
- }
35
-
36
- .ngg-thumbnail {
37
- float: left;
38
- margin-right: 12px;
39
- background:#EEEEEE none repeat scroll 0% 50%;
40
- border-color:#DDDDDD rgb(187, 187, 187) rgb(170, 170, 170) rgb(204, 204, 204);
41
- border-style:solid;
42
- border-width:1px;
43
- color:inherit;
44
- margin-right: 5px;
45
- padding:5px;
46
- }
47
-
48
- .ngg-thumbnail img {
49
- filter: alpha(opacity=100);
50
- -moz-opacity: .99;
51
- opacity: .99;
52
- background:#FFFFFF none repeat scroll 0%;
53
- border-color:#AAAAAA rgb(204, 204, 204) rgb(221, 221, 221) rgb(187, 187, 187);
54
- border-style:solid;
55
- border-width:1px;
56
- color:inherit;
57
- padding:2px;
58
- vertical-align:top;
59
- }
60
-
61
- .ngg-thumbnail img:hover {
62
- filter: alpha(opacity=90);
63
- -moz-opacity: .9;
64
- opacity: .9;
65
- border-color:#000000;
66
- }
67
-
68
- .ngg-description {
69
- text-align: left;
70
- }
71
-
72
- /* ----------- Album Styles Compact -------------*/
73
-
74
- .ngg-album-compact {
75
- float:left;
76
- height:180px;
77
- padding-right:6px !important;
78
- margin:0px !important;
79
- text-align:left;
80
- width:120px;
81
- }
82
-
83
- .ngg-album-compactbox {
84
- background:transparent url(albumset.gif) no-repeat scroll 0%;
85
- height:86px;
86
- margin:0pt 0pt 6px !important;
87
- padding:12px 0pt 0pt 7px !important;
88
- width:120px;
89
- }
90
-
91
-
92
- .ngg-album-compactbox .Thumb {
93
- border:1px solid #000000;
94
- margin:0px !important;
95
- padding:0px !important;
96
- width:91px;
97
- height:68px;
98
- }
99
-
100
- .ngg-album-compact h4 {
101
- font-size:15px;
102
- font-weight:bold;
103
- margin-bottom:0px;
104
- margin-top:0px;
105
- width:110px;
106
- }
107
-
108
- .ngg-album-compact p {
109
- font-size:11px;
110
- margin-top:2px;
111
- }
112
-
113
- /* ----------- Gallery style -------------*/
114
-
115
- .ngg-galleryoverview {
116
- overflow: hidden;
117
- margin-top: 10px;
118
- width: 100%;
119
- clear:both;
120
- display:block !important;
121
- }
122
-
123
- .ngg-gallery-thumbnail-box {
124
- float: left;
125
- background:#EEEEEE none repeat scroll 0% 50%;
126
- border-color:#DDDDDD rgb(187, 187, 187) rgb(170, 170, 170) rgb(204, 204, 204);
127
- border-style:solid;
128
- border-width:1px;
129
- color:inherit;
130
- display:inline;
131
- margin:3px;
132
- padding:5px;
133
- position:relative;
134
- }
135
-
136
- .ngg-gallery-thumbnail {
137
- float: left;
138
- }
139
-
140
- .ngg-gallery-thumbnail img {
141
- filter: alpha(opacity=100);
142
- -moz-opacity: .99;
143
- opacity: .99;
144
- background:#FFFFFF none repeat scroll 0%;
145
- border-color:#AAAAAA rgb(204, 204, 204) rgb(221, 221, 221) rgb(187, 187, 187);
146
- border-style:solid;
147
- border-width:1px;
148
- color:inherit;
149
- padding:2px;
150
- vertical-align:top;
151
- }
152
-
153
- .ngg-gallery-thumbnail img:hover {
154
- filter: alpha(opacity=90);
155
- -moz-opacity: .9;
156
- opacity: .9;
157
- border-color:#000000;
158
- }
159
-
160
- .ngg-gallery-thumbnail span {
161
- /* Images description */
162
- font-size:90%;
163
- padding-left:5px;
164
- display:block;
165
- }
166
-
167
- .ngg-clear {
168
- clear: both;
169
- }
170
-
171
- /* ----------- Gallery navigation -------------*/
172
-
173
- .ngg-navigation {
174
- font-size:0.9em !important;
175
- clear:both !important;
176
- display:block !important;
177
- padding-top:15px;
178
- text-align:center;
179
-
180
- }
181
-
182
- .ngg-navigation span {
183
- font-weight:bold;
184
- margin:0pt 6px;
185
- }
186
-
187
- .ngg-navigation a.page-numbers,
188
- .ngg-navigation a.next,
189
- .ngg-navigation a.prev,
190
- .ngg-navigation span.page-numbers,
191
- .ngg-navigation span.next,
192
- .ngg-navigation span.prev {
193
- border:1px solid #DDDDDD;
194
- margin-right:3px;
195
- padding:3px 7px;
196
- }
197
-
198
- .ngg-navigation a.page-numbers:hover,
199
- .ngg-navigation a.next:hover,
200
- .ngg-navigation a.prev:hover,
201
- .ngg-navigation span.page-numbers:hover,
202
- .ngg-navigation span.next:hover,
203
- .ngg-navigation span.prev:hover {
204
- background-color: #0066CC;
205
- color: #FFFFFF !important;
206
- text-decoration: none !important;
207
- }
208
-
209
- /* ----------- Image browser style -------------*/
210
-
211
- .ngg-imagebrowser {
212
-
213
- }
214
-
215
- .ngg-imagebrowser h3 {
216
- text-align:center;
217
- padding-bottom:10px;
218
- }
219
-
220
- .ngg-imagebrowser .pic {
221
- background:#EEEEEE none repeat scroll 0% 50%;
222
- border-color:#DDDDDD rgb(187, 187, 187) rgb(170, 170, 170) rgb(204, 204, 204);
223
- border-style:solid;
224
- border-width:1px;
225
- color:inherit;
226
- display:block;
227
- padding:10px;
228
- }
229
-
230
- .ngg-imagebrowser img {
231
- width: 100%;
232
- margin: -3px;
233
- background:#FFFFFF none repeat scroll 0%;
234
- border-color:#AAAAAA rgb(204, 204, 204) rgb(221, 221, 221) rgb(187, 187, 187);
235
- border-style:solid;
236
- border-width:1px;
237
- color:inherit;
238
- padding:2px;
239
- vertical-align:top;
240
- }
241
-
242
- .ngg-imagebrowser-nav {
243
- padding:10px;
244
- margin-left:10px;
245
-
246
- }
247
-
248
- .ngg-imagebrowser-nav .back {
249
- float:left;
250
- border:1px solid #DDDDDD;
251
- margin-right:3px;
252
- padding:3px 7px;
253
- }
254
-
255
- .ngg-imagebrowser-nav .next {
256
- float:right;
257
- border:1px solid #DDDDDD;
258
- margin-right:3px;
259
- padding:3px 7px;
260
- }
261
-
262
- .ngg-imagebrowser-nav .back:hover,
263
- .ngg-imagebrowser-nav .next:hover {
264
- border:1px solid #000000;
265
- }
266
-
267
- .ngg-imagebrowser-nav .back a:hover,
268
- .ngg-imagebrowser-nav .next a:hover {
269
- text-decoration: none !important;
270
- }
271
-
272
- .ngg-imagebrowser-nav .counter {
273
- text-align:center;
274
- font-size:0.9em !important;
275
- }
276
-
277
- .exif-data {
278
- margin-left: auto !important;
279
- margin-right: auto !important;
280
- }
281
-
282
- /* ----------- Slideshow -------------*/
283
- .slideshow {
284
- margin-left: auto;
285
- margin-right: auto;
286
- text-align:center;
287
- outline: none;
288
- }
289
-
290
- .slideshowlink {
291
-
292
- }
293
-
294
- /* ----------- JS Slideshow -------------*/
295
- .ngg-slideshow {
296
- overflow:hidden;
297
- position: relative;
298
- }
299
-
300
- .ngg-slideshow * {
301
- vertical-align:middle;
302
- }
303
-
304
- /* See also : http://www.brunildo.org/test/img_center.html */
305
- .ngg-slideshow-loader{
306
- display: table-cell;
307
- text-align: center;
308
- vertical-align:middle;
309
- }
310
-
311
- .ngg-slideshow-loader img{
312
- background: none !important;
313
- border: 0 none !important;
314
- margin:auto !important;
315
- }
316
-
317
- /* ----------- Single picture -------------*/
318
- .ngg-singlepic {
319
- background-color:#FFFFFF;
320
- display:block;
321
- padding:4px;
322
- }
323
-
324
- .ngg-left {
325
- float: left;
326
- margin-right:10px;
327
- }
328
-
329
- .ngg-right {
330
- float: right;
331
- margin-left:10px;
332
- }
333
-
334
- .ngg-center {
335
- margin-left: auto !important;
336
- margin-right: auto !important;
337
- }
338
-
339
- /* ----------- Sidebar widget -------------*/
340
- .ngg-widget,
341
- .ngg-widget-slideshow {
342
- overflow: hidden;
343
- margin:0pt;
344
- padding:5px 0px 0px 0pt;
345
- }
346
-
347
- .ngg-widget img {
348
- border:2px solid #A9A9A9;
349
- margin:0pt 2px 2px 0px;
350
- padding:1px;
351
- }
352
-
353
- /* ----------- Related images -------------*/
354
- .ngg-related-gallery {
355
- background:#F9F9F9;
356
- border:1px solid #E0E0E0;
357
- overflow:hidden;
358
- margin-bottom:1em;
359
- margin-top:1em;
360
- padding:5px;
361
- }
362
- .ngg-related-gallery img {
363
- border: 1px solid #DDDDDD;
364
- float: left;
365
- margin: 0pt 3px;
366
- padding: 2px;
367
- height: 50px;
368
- width: 50px;
369
- }
370
-
371
- .ngg-related-gallery img:hover {
372
- border: 1px solid #000000;
373
- }
374
-
375
- /* ----------- Gallery list -------------*/
376
-
377
- .ngg-galleryoverview ul li:before {
378
- content: '' !important;
379
- }
380
-
381
- .ngg-gallery-list {
382
- list-style-type:none;
383
- padding: 0px !important;
384
- text-indent:0px !important;
385
- }
386
-
387
- .ngg-galleryoverview div.pic img{
388
- width: 100%;
389
- }
390
-
391
- .ngg-gallery-list li {
392
- float:left;
393
- margin:0 2px 0px 2px !important;
394
- overflow:hidden;
395
- }
396
-
397
- .ngg-gallery-list li a {
398
- border:1px solid #CCCCCC;
399
- display:block;
400
- padding:2px;
401
- }
402
-
403
- .ngg-gallery-list li.selected a{
404
- -moz-background-clip:border;
405
- -moz-background-inline-policy:continuous;
406
- -moz-background-origin:padding;
407
- background:#000000 none repeat scroll 0 0;
408
- }
409
-
410
- .ngg-gallery-list li img {
411
- height:40px;
412
- width:40px;
413
- }
414
-
415
- li.ngg-next, li.ngg-prev {
416
- height:40px;
417
- width:40px;
418
- font-size:3.5em;
419
- }
420
-
421
- li.ngg-next a, li.ngg-prev a {
422
- padding-top: 10px;
423
- border: none;
424
- text-decoration: none;
425
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/ngg_dkret3.css DELETED
@@ -1,318 +0,0 @@
1
- /*
2
- CSS Name: dkret3 Theme
3
- Description: NextGEN dkret3 style with a shadow effect
4
- Author: Jörn Kretzschmar (based on Alex Rabes Default Style)
5
- Version: 1.3
6
-
7
- This is a template stylesheet that can be used with NextGEN Gallery. I tested the
8
- styles with the theme dkret3. Modify it when your theme struggle with it,
9
- it's only a template design
10
-
11
- */
12
-
13
- /* ----------- Album Styles Extend -------------*/
14
-
15
- .ngg-albumoverview {
16
- margin-top: 10px;
17
- width: 100%;
18
- clear:both;
19
- display:block !important;
20
- }
21
-
22
- .ngg-album {
23
- height: 100%;
24
- padding: 5px;
25
- margin-bottom: 5px;
26
- border: 1px solid #cccccc;
27
- overflow:hidden;
28
- }
29
-
30
- .ngg-albumtitle {
31
- text-align: left;
32
- font-weight: bold;
33
- margin:0px;
34
- padding:0px;
35
- font-size: 1.4em;
36
- margin-bottom: 10px;
37
- }
38
-
39
- .ngg-thumbnail {
40
- float: left;
41
- margin-right: 12px;
42
- }
43
-
44
- .ngg-thumbnail img {
45
- background-color:#FFFFFF;
46
- border:1px solid #A9A9A9;
47
- margin:4px 0px 4px 5px;
48
- padding:4px;
49
- position:relative;
50
- }
51
-
52
- .ngg-thumbnail img:hover {
53
- background-color: #A9A9A9;
54
- }
55
-
56
- .ngg-description {
57
- text-align: left;
58
- }
59
-
60
- /* ----------- Album Styles Compact -------------*/
61
-
62
- .ngg-album-compact {
63
- float:left;
64
- height:180px;
65
- padding-right:6px !important;
66
- margin:0px !important;
67
- text-align:left;
68
- width:120px;
69
- }
70
-
71
- .ngg-album-compactbox {
72
- background:transparent url(albumset.gif) no-repeat scroll 0%;
73
- height:86px;
74
- margin:0pt 0pt 6px !important;
75
- padding:12px 0pt 0pt 7px !important;
76
- width:120px;
77
- }
78
-
79
-
80
- .ngg-album-compactbox .Thumb {
81
- border:1px solid #000000;
82
- margin:0px !important;
83
- padding:0px !important;
84
- width:91px;
85
- height:68px;
86
- }
87
-
88
- .ngg-album-compact h4 {
89
- font-size:15px;
90
- font-weight:bold;
91
- margin-bottom:0px;
92
- margin-top:0px;
93
- width:110px;
94
- }
95
-
96
- .ngg-album-compact p {
97
- font-size:11px;
98
- margin-top:2px;
99
- }
100
-
101
- /* ----------- Gallery style -------------*/
102
-
103
- .ngg-galleryoverview {
104
- margin-top: 10px;
105
- width: 100%;
106
- clear:both;
107
- display:block !important;
108
- }
109
-
110
- .ngg-gallery-thumbnail-box {
111
- float: left;
112
- }
113
-
114
- .ngg-gallery-thumbnail {
115
- float: left;
116
- background: url(shadowAlpha.png) no-repeat bottom right !important;
117
- background: url(shadow.gif) no-repeat bottom right;
118
- margin: 10px 0 0 10px !important;
119
- }
120
-
121
- .ngg-gallery-thumbnail img {
122
- margin: -6px 6px 6px -6px;
123
- background-color:#FFFFFF;
124
- border:1px solid #A9A9A9;
125
- display:block;
126
- padding:4px;
127
- position:relative;
128
- }
129
-
130
- .ngg-gallery-thumbnail img:hover {
131
- background-color: #A9A9A9;
132
- }
133
-
134
- .ngg-gallery-thumbnail span {
135
- display:none;
136
- }
137
-
138
- .ngg-clear {
139
- clear: both;
140
- }
141
-
142
- /* ----------- Gallery navigation -------------*/
143
-
144
- .ngg-navigation {
145
- font-size:0.9em !important;
146
- clear:both !important;
147
- display:block !important;
148
- padding-top:15px;
149
- text-align:center;
150
- }
151
-
152
- .ngg-navigation span {
153
- font-weight:bold;
154
- margin:0pt 6px;
155
- }
156
-
157
- .ngg-navigation a.page-numbers,
158
- .ngg-navigation a.next,
159
- .ngg-navigation a.prev,
160
- .ngg-navigation span.page-numbers,
161
- .ngg-navigation span.next,
162
- .ngg-navigation span.prev {
163
- border:1px solid #DDDDDD;
164
- margin-right:3px;
165
- padding:3px 7px;
166
- }
167
-
168
- .ngg-navigation a.page-numbers:hover,
169
- .ngg-navigation a.next:hover,
170
- .ngg-navigation a.prev:hover,
171
- .ngg-navigation span.page-numbers:hover,
172
- .ngg-navigation span.next:hover,
173
- .ngg-navigation span.prev:hover {
174
- background-color: #0066CC;
175
- color: #FFFFFF !important;
176
- text-decoration: none !important;
177
- }
178
-
179
- /* ----------- Image browser style -------------*/
180
-
181
- .ngg-imagebrowser {
182
-
183
- }
184
-
185
- .ngg-imagebrowser h3 {
186
- text-align:center;
187
- }
188
-
189
- .ngg-imagebrowser img {
190
- border:1px solid #A9A9A9;
191
- margin-top: 10px;
192
- margin-bottom: 10px;
193
- width: 100%;
194
- display:block !important;
195
- padding:5px;
196
- }
197
-
198
- .ngg-imagebrowser-nav {
199
- padding:5px;
200
- margin-left:10px;
201
- }
202
-
203
- .ngg-imagebrowser-nav .back {
204
- float:left;
205
- border:1px solid #DDDDDD;
206
- margin-right:3px;
207
- padding:3px 7px;
208
- }
209
-
210
- .ngg-imagebrowser-nav .next {
211
- float:right;
212
- border:1px solid #DDDDDD;
213
- margin-right:3px;
214
- padding:3px 7px;
215
- }
216
-
217
- .ngg-imagebrowser-nav .counter {
218
- text-align:center;
219
- font-size:0.9em !important;
220
- }
221
-
222
- .exif-data {
223
- margin-left: auto !important;
224
- margin-right: auto !important;
225
- }
226
-
227
- /* ----------- Slideshow -------------*/
228
- .slideshow {
229
- margin-left: auto;
230
- margin-right: auto;
231
- text-align:center;
232
- outline: none;
233
- }
234
-
235
- .slideshowlink {
236
-
237
- }
238
-
239
- /* ----------- JS Slideshow -------------*/
240
- .ngg-slideshow {
241
- overflow:hidden;
242
- position: relative;
243
- }
244
-
245
- .ngg-slideshow * {
246
- vertical-align:middle;
247
- }
248
-
249
- /* See also : http://www.brunildo.org/test/img_center.html */
250
- .ngg-slideshow-loader{
251
- display: table-cell;
252
- text-align: center;
253
- vertical-align:middle;
254
- }
255
-
256
- .ngg-slideshow-loader img{
257
- background: none !important;
258
- border: 0 none !important;
259
- margin:auto !important;
260
- }
261
-
262
- /* ----------- Single picture -------------*/
263
- .ngg-singlepic {
264
- background-color:#FFFFFF;
265
- display:block;
266
- padding:4px;
267
- }
268
-
269
- .ngg-left {
270
- float: left;
271
- }
272
-
273
- .ngg-right {
274
- float: right;
275
- }
276
-
277
- .ngg-center {
278
- margin-left: auto;
279
- margin-right: auto;
280
- }
281
-
282
- /* ----------- Sidebar widget -------------*/
283
-
284
- .ngg-widget,
285
- .ngg-widget-slideshow {
286
- overflow: hidden;
287
- margin:0pt;
288
- padding:5px 0px 0px 0pt;
289
- text-align: center;
290
- }
291
-
292
- .ngg-widget img {
293
- border:2px solid #A9A9A9;
294
- margin:0pt 2px 2px 0px;
295
- padding:1px;
296
- }
297
-
298
- /* ----------- Related images -------------*/
299
- .ngg-related-gallery {
300
- background:#F9F9F9;
301
- border:1px solid #E0E0E0;
302
- overflow:hidden;
303
- margin-bottom:1em;
304
- margin-top:1em;
305
- padding:5px;
306
- }
307
- .ngg-related-gallery img {
308
- border: 1px solid #DDDDDD;
309
- float: left;
310
- margin: 0pt 3px;
311
- padding: 2px;
312
- height: 50px;
313
- width: 50px;
314
- }
315
-
316
- .ngg-related-gallery img:hover {
317
- border: 1px solid #000000;
318
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/ngg_k2.css DELETED
@@ -1,330 +0,0 @@
1
- /*
2
- CSS Name: K2 Theme
3
- Description: NextGEN Style for K2 Theme
4
- Author: Alex Rabe
5
- Version: 1.60
6
-
7
- This is a template stylesheet that can be used with NextGEN Gallery. I tested the
8
- styles with a default theme Kubrick. Modify it when your theme struggle with it,
9
- it's only a template design
10
-
11
- */
12
-
13
- /* ----------- Album Styles Extend -------------*/
14
-
15
- .ngg-albumoverview {
16
- margin: 10px 0px 0px 0px !important;
17
- width: 100%;
18
- clear:both;
19
- display:block !important;
20
- }
21
-
22
- .ngg-album {
23
- /*height: 130px;*/
24
- overflow:hidden;
25
- margin: 0px 0px 5px !important;
26
- padding: 5px;
27
- border: 1px solid #cccccc;
28
- }
29
-
30
- .ngg-albumtitle {
31
- text-align: left;
32
- font-weight: bold;
33
- padding:0px;
34
- font-size: 1.4em;
35
- margin: 0px 0px 10px 0px !important;
36
- }
37
-
38
- .ngg-albumcontent {
39
- margin: 0px !important;
40
- }
41
-
42
- .ngg-thumbnail {
43
- margin:0px 12px 0px 0px !important;
44
- float: left;
45
- }
46
-
47
- .ngg-thumbnail img {
48
- background-color:#FFFFFF;
49
- border:1px solid #A9A9A9;
50
- margin:4px 0px 4px 5px !important;
51
- padding:4px;
52
- position:relative;
53
- }
54
-
55
- .ngg-thumbnail img:hover {
56
- background-color: #A9A9A9;
57
- }
58
-
59
- .ngg-description {
60
- text-align: left;
61
- }
62
-
63
- /* ----------- Album Styles Compact -------------*/
64
-
65
- .ngg-album-compact {
66
- float:left;
67
- height:180px;
68
- padding-right:6px !important;
69
- margin:0px !important;
70
- text-align:left;
71
- width:120px;
72
- }
73
-
74
- .ngg-album-compactbox {
75
- background:transparent url(albumset.gif) no-repeat scroll 0%;
76
- height:86px;
77
- margin:0pt 0pt 6px !important;
78
- padding:12px 0pt 0pt 7px !important;
79
- width:120px;
80
- }
81
-
82
- .ngg-album-link {
83
- margin:0px !important;
84
- }
85
-
86
- .ngg-album-compactbox .Thumb {
87
- border:1px solid #000000;
88
- margin:0px !important;
89
- padding:0px !important;
90
- width:91px;
91
- height:68px;
92
- }
93
-
94
- .ngg-album-compact h4 {
95
- font-size:15px;
96
- font-weight:bold;
97
- margin-bottom:0px !important;
98
- margin-top:0px !important;
99
- width:110px;
100
- padding:0px !important;
101
- }
102
-
103
- .ngg-album-compact p {
104
- font-size:11px;
105
- margin-top:2px;
106
- }
107
-
108
- /* ----------- Gallery style -------------*/
109
-
110
- .ngg-galleryoverview {
111
- margin-top: 10px;
112
- width: 100%;
113
- clear:both;
114
- display:block !important;
115
- }
116
-
117
- .ngg-gallery-thumbnail-box {
118
- margin:0px !important;
119
- float: left;
120
- }
121
-
122
- .ngg-gallery-thumbnail {
123
- float: left;
124
- background: url(shadowAlpha.png) no-repeat bottom right !important;
125
- background: url(shadow.gif) no-repeat bottom right;
126
- margin: 10px 0 0 10px !important;
127
- }
128
-
129
- .ngg-gallery-thumbnail img {
130
- margin: -6px 6px 6px -6px !important;
131
- background-color:#FFFFFF;
132
- border:1px solid #A9A9A9;
133
- display:block;
134
- padding:4px;
135
- position:relative;
136
- }
137
-
138
- .ngg-gallery-thumbnail img:hover {
139
- background-color: #A9A9A9;
140
- }
141
-
142
- .ngg-gallery-thumbnail span {
143
- /* Images description */
144
- font-size:90%;
145
- padding-left:5px;
146
- display:block;
147
- }
148
-
149
- .ngg-clear {
150
- clear: both;
151
- }
152
-
153
- /* ----------- Gallery navigation -------------*/
154
-
155
- .ngg-navigation {
156
- font-size:0.9em !important;
157
- clear:both !important;
158
- display:block !important;
159
- padding-top:15px;
160
- text-align:center;
161
- }
162
-
163
- .ngg-navigation span {
164
- font-weight:bold;
165
- margin:0pt 6px;
166
- }
167
-
168
- .ngg-navigation a.page-numbers,
169
- .ngg-navigation a.next,
170
- .ngg-navigation a.prev,
171
- .ngg-navigation span.page-numbers,
172
- .ngg-navigation span.next,
173
- .ngg-navigation span.prev {
174
- border:1px solid #DDDDDD;
175
- margin-right:3px;
176
- padding:3px 7px;
177
- }
178
-
179
- .ngg-navigation a.page-numbers:hover,
180
- .ngg-navigation a.next:hover,
181
- .ngg-navigation a.prev:hover,
182
- .ngg-navigation span.page-numbers:hover,
183
- .ngg-navigation span.next:hover,
184
- .ngg-navigation span.prev:hover {
185
- background-color: #0066CC;
186
- color: #FFFFFF;
187
- text-decoration: none;
188
- }
189
-
190
- /* ----------- Image browser style -------------*/
191
-
192
- .ngg-imagebrowser {
193
-
194
- }
195
-
196
- .ngg-imagebrowser h3 {
197
- text-align:center;
198
- }
199
-
200
- .ngg-imagebrowser img {
201
- border:1px solid #A9A9A9;
202
- margin-top: 10px;
203
- margin-bottom: 10px;
204
- width: 100%;
205
- display:block !important;
206
- padding:5px;
207
- }
208
-
209
- .ngg-imagebrowser-nav {
210
- padding:5px;
211
- margin-left:10px;
212
- }
213
-
214
- .ngg-imagebrowser-nav .back {
215
- float:left;
216
- border:1px solid #DDDDDD;
217
- margin-right:3px;
218
- padding:3px 7px;
219
- }
220
-
221
- .ngg-imagebrowser-nav .next {
222
- float:right;
223
- border:1px solid #DDDDDD;
224
- margin-right:3px;
225
- padding:3px 7px;
226
- }
227
-
228
- .ngg-imagebrowser-nav .counter {
229
- text-align:center;
230
- font-size:0.9em !important;
231
- }
232
-
233
- .exif-data {
234
- margin-left: auto !important;
235
- margin-right: auto !important;
236
- }
237
-
238
- /* ----------- Slideshow -------------*/
239
- .slideshow {
240
- margin-left: auto;
241
- margin-right: auto;
242
- text-align:center;
243
- outline: none;
244
- }
245
-
246
- .slideshowlink {
247
-
248
- }
249
-
250
- /* ----------- JS Slideshow -------------*/
251
- .ngg-slideshow {
252
- overflow:hidden;
253
- position: relative;
254
- }
255
-
256
- .ngg-slideshow * {
257
- vertical-align:middle;
258
- }
259
-
260
- /* See also : http://www.brunildo.org/test/img_center.html */
261
- .ngg-slideshow-loader{
262
- display: table-cell;
263
- text-align: center;
264
- vertical-align:middle;
265
- }
266
-
267
- .ngg-slideshow-loader img{
268
- background: none !important;
269
- border: 0 none !important;
270
- margin:auto !important;
271
- }
272
-
273
- /* ----------- Single picture -------------*/
274
- .ngg-singlepic {
275
- background-color:#FFFFFF;
276
- display:block;
277
- padding:4px;
278
- }
279
-
280
- .ngg-left {
281
- float: left;
282
- margin-right:10px;
283
- }
284
-
285
- .ngg-right {
286
- float: right;
287
- margin-left:10px;
288
- }
289
-
290
- .ngg-center {
291
- margin-left: auto !important;
292
- margin-right: auto !important;
293
- }
294
-
295
- /* ----------- Sidebar widget -------------*/
296
- .ngg-widget,
297
- .ngg-widget-slideshow {
298
- overflow: hidden;
299
- margin:0pt;
300
- padding:5px 0px 0px 0pt;
301
- text-align:left;
302
- }
303
-
304
- .ngg-widget img {
305
- border:2px solid #A9A9A9;
306
- margin:0pt 2px 2px 0px;
307
- padding:1px;
308
- }
309
-
310
- /* ----------- Related images -------------*/
311
- .ngg-related-gallery {
312
- background:#F9F9F9;
313
- border:1px solid #E0E0E0;
314
- overflow:hidden;
315
- margin-bottom:1em;
316
- margin-top:1em;
317
- padding:5px;
318
- }
319
- .ngg-related-gallery img {
320
- border: 1px solid #DDDDDD;
321
- float: left;
322
- margin: 0pt 2px;
323
- padding: 2px;
324
- height: 50px;
325
- width: 50px;
326
- }
327
-
328
- .ngg-related-gallery img:hover {
329
- border: 1px solid #000000;
330
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/ngg_shadow.css DELETED
@@ -1,371 +0,0 @@
1
- /*
2
- CSS Name: Shadow Effect
3
- Description: NextGEN Default Style with a Shadow effect
4
- Author: Alex Rabe
5
- Version: 1.60
6
-
7
- This is a template stylesheet that can be used with NextGEN Gallery. I tested the
8
- styles with a default theme Kubrick. Modify it when your theme struggle with it,
9
- it's only a template design
10
-
11
- */
12
-
13
- /* ----------- Album Styles Extend -------------*/
14
-
15
- .ngg-albumoverview {
16
- margin-top: 10px;
17
- width: 100%;
18
- clear:both;
19
- display:block !important;
20
- }
21
-
22
- .ngg-album {
23
- /*height: 130px;*/
24
- padding: 5px;
25
- margin-bottom: 5px;
26
- border: 1px solid #cccccc;
27
- overflow:hidden;
28
- }
29
-
30
- .ngg-albumtitle {
31
- text-align: left;
32
- font-weight: bold;
33
- margin:0px;
34
- padding:0px;
35
- font-size: 1.4em;
36
- margin-bottom: 10px;
37
- }
38
-
39
- .ngg-thumbnail {
40
- float: left;
41
- margin-right: 12px;
42
- }
43
-
44
- .ngg-thumbnail img {
45
- background-color:#FFFFFF;
46
- border:1px solid #A9A9A9;
47
- margin:4px 0px 4px 5px;
48
- padding:4px;
49
- position:relative;
50
- }
51
-
52
- .ngg-thumbnail img:hover {
53
- background-color: #A9A9A9;
54
- }
55
-
56
- .ngg-description {
57
- text-align: left;
58
- }
59
-
60
- /* ----------- Album Styles Compact -------------*/
61
-
62
- .ngg-album-compact {
63
- float:left;
64
- height:180px;
65
- padding-right:6px !important;
66
- margin:0px !important;
67
- text-align:left;
68
- width:120px;
69
- }
70
-
71
- .ngg-album-compactbox {
72
- background:transparent url(albumset.gif) no-repeat scroll 0%;
73
- height:86px;
74
- margin:0pt 0pt 6px !important;
75
- padding:12px 0pt 0pt 7px !important;
76
- width:120px;
77
- }
78
-
79
-
80
- .ngg-album-compactbox .Thumb {
81
- border:1px solid #000000;
82
- margin:0px !important;
83
- padding:0px !important;
84
- width:91px;
85
- height:68px;
86
- }
87
-
88
- .ngg-album-compact h4 {
89
- font-size:15px;
90
- font-weight:bold;
91
- margin-bottom:0px;
92
- margin-top:0px;
93
- width:110px;
94
- }
95
-
96
- .ngg-album-compact p {
97
- font-size:11px;
98
- margin-top:2px;
99
- }
100
-
101
- /* ----------- Gallery style -------------*/
102
-
103
- .ngg-galleryoverview {
104
- margin-top: 10px;
105
- width: 100%;
106
- clear:both;
107
- display:block !important;
108
- }
109
-
110
- .ngg-gallery-thumbnail-box {
111
- float: left;
112
- }
113
-
114
- .ngg-gallery-thumbnail {
115
- float: left;
116
- background: url(shadowAlpha.png) no-repeat bottom right !important;
117
- background: url(shadow.gif) no-repeat bottom right;
118
- margin: 10px 0 0 10px !important;
119
- }
120
-
121
- .ngg-gallery-thumbnail img {
122
- margin: -6px 6px 6px -6px;
123
- background-color:#FFFFFF;
124
- border:1px solid #A9A9A9;
125
- display:block;
126
- padding:4px;
127
- position:relative;
128
- }
129
-
130
- .ngg-gallery-thumbnail img:hover {
131
- background-color: #A9A9A9;
132
- }
133
-
134
- .ngg-gallery-thumbnail span {
135
- display:none;
136
- }
137
-
138
- .ngg-clear {
139
- clear: both;
140
- }
141
-
142
- /* ----------- Gallery navigation -------------*/
143
-
144
- .ngg-navigation {
145
- font-size:0.9em !important;
146
- clear:both !important;
147
- display:block !important;
148
- padding-top:15px;
149
- text-align:center;
150
- }
151
-
152
- .ngg-navigation span {
153
- font-weight:bold;
154
- margin:0pt 6px;
155
- }
156
-
157
- .ngg-navigation a.page-numbers,
158
- .ngg-navigation a.next,
159
- .ngg-navigation a.prev,
160
- .ngg-navigation span.page-numbers,
161
- .ngg-navigation span.next,
162
- .ngg-navigation span.prev {
163
- border:1px solid #DDDDDD;
164
- margin-right:3px;
165
- padding:3px 7px;
166
- }
167
-
168
- .ngg-navigation a.page-numbers:hover,
169
- .ngg-navigation a.next:hover,
170
- .ngg-navigation a.prev:hover,
171
- .ngg-navigation span.page-numbers:hover,
172
- .ngg-navigation span.next:hover,
173
- .ngg-navigation span.prev:hover {
174
- background-color: #0066CC;
175
- color: #FFFFFF !important;
176
- text-decoration: none !important;
177
- }
178
-
179
- /* ----------- Image browser style -------------*/
180
-
181
- .ngg-imagebrowser {
182
-
183
- }
184
-
185
- .ngg-imagebrowser h3 {
186
- text-align:center;
187
- }
188
-
189
- .ngg-imagebrowser img {
190
- border:1px solid #A9A9A9;
191
- margin-top: 10px;
192
- margin-bottom: 10px;
193
- width: 100%;
194
- display:block !important;
195
- padding:5px;
196
- }
197
-
198
- .ngg-imagebrowser-nav {
199
- padding:5px;
200
- margin-left:10px;
201
- }
202
-
203
- .ngg-imagebrowser-nav .back {
204
- float:left;
205
- border:1px solid #DDDDDD;
206
- margin-right:3px;
207
- padding:3px 7px;
208
- }
209
-
210
- .ngg-imagebrowser-nav .next {
211
- float:right;
212
- border:1px solid #DDDDDD;
213
- margin-right:3px;
214
- padding:3px 7px;
215
- }
216
-
217
- .ngg-imagebrowser-nav .counter {
218
- text-align:center;
219
- font-size:0.9em !important;
220
- }
221
-
222
- .exif-data {
223
- margin-left: auto !important;
224
- margin-right: auto !important;
225
- }
226
-
227
- /* ----------- Slideshow -------------*/
228
- .slideshow {
229
- margin-left: auto;
230
- margin-right: auto;
231
- text-align:center;
232
- outline: none;
233
- }
234
-
235
- .slideshowlink {
236
-
237
- }
238
-
239
- /* ----------- JS Slideshow -------------*/
240
- .ngg-slideshow {
241
- overflow:hidden;
242
- position: relative;
243
- }
244
-
245
- .ngg-slideshow * {
246
- vertical-align:middle;
247
- }
248
-
249
- /* See also : http://www.brunildo.org/test/img_center.html */
250
- .ngg-slideshow-loader{
251
- display: table-cell;
252
- text-align: center;
253
- vertical-align:middle;
254
- }
255
-
256
- .ngg-slideshow-loader img{
257
- background: none !important;
258
- border: 0 none !important;
259
- margin:auto !important;
260
- }
261
-
262
- /* ----------- Single picture -------------*/
263
- .ngg-singlepic {
264
- background-color:#FFFFFF;
265
- display:block;
266
- padding:4px;
267
- }
268
-
269
- .ngg-left {
270
- float: left;
271
- margin-right:10px;
272
- }
273
-
274
- .ngg-right {
275
- float: right;
276
- margin-left:10px;
277
- }
278
-
279
- .ngg-center {
280
- margin-left: auto !important;
281
- margin-right: auto !important;
282
- }
283
-
284
- /* ----------- Sidebar widget -------------*/
285
-
286
- .ngg-widget,
287
- .ngg-widget-slideshow {
288
- overflow: hidden;
289
- margin:0pt;
290
- padding:5px 0px 0px 0pt;
291
- }
292
-
293
- .ngg-widget img {
294
- border:2px solid #A9A9A9;
295
- margin:0pt 2px 2px 0px;
296
- padding:1px;
297
- }
298
-
299
- /* ----------- Related images -------------*/
300
- .ngg-related-gallery {
301
- background:#F9F9F9;
302
- border:1px solid #E0E0E0;
303
- overflow:hidden;
304
- margin-bottom:1em;
305
- margin-top:1em;
306
- padding:5px;
307
- }
308
- .ngg-related-gallery img {
309
- border: 1px solid #DDDDDD;
310
- float: left;
311
- margin: 0pt 3px;
312
- padding: 2px;
313
- height: 50px;
314
- width: 50px;
315
- }
316
-
317
- .ngg-related-gallery img:hover {
318
- border: 1px solid #000000;
319
- }
320
-
321
- /* ----------- Gallery list -------------*/
322
-
323
- .ngg-galleryoverview ul li:before {
324
- content: '' !important;
325
- }
326
-
327
- .ngg-gallery-list {
328
- list-style-type:none;
329
- padding: 0px !important;
330
- text-indent:0px !important;
331
- }
332
-
333
- .ngg-galleryoverview div.pic img{
334
- width: 100%;
335
- }
336
-
337
- .ngg-gallery-list li {
338
- float:left;
339
- margin:0 2px 0px 2px !important;
340
- overflow:hidden;
341
- }
342
-
343
- .ngg-gallery-list li a {
344
- border:1px solid #CCCCCC;
345
- display:block;
346
- padding:2px;
347
- }
348
-
349
- .ngg-gallery-list li.selected a{
350
- -moz-background-clip:border;
351
- -moz-background-inline-policy:continuous;
352
- -moz-background-origin:padding;
353
- background:#000000 none repeat scroll 0 0;
354
- }
355
-
356
- .ngg-gallery-list li img {
357
- height:40px;
358
- width:40px;
359
- }
360
-
361
- li.ngg-next, li.ngg-prev {
362
- height:40px;
363
- width:40px;
364
- font-size:3.5em;
365
- }
366
-
367
- li.ngg-next a, li.ngg-prev a {
368
- padding-top: 10px;
369
- border: none;
370
- text-decoration: none;
371
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/ngg_shadow2.css DELETED
@@ -1,379 +0,0 @@
1
- /*
2
- CSS Name: Shadow Effect with Description text
3
- Description: NextGEN Default Style with a Shadow effect and description text below the thumbnail
4
- Author: Alex Rabe
5
- Version: 1.60
6
-
7
- This is a template stylesheet that can be used with NextGEN Gallery. I tested the
8
- styles with a default theme Kubrick. Modify it when your theme struggle with it,
9
- it's only a template design
10
-
11
- */
12
-
13
- /* ----------- Album Styles Extend -------------*/
14
-
15
- .ngg-albumoverview {
16
- margin-top: 10px;
17
- width: 100%;
18
- clear:both;
19
- display:block !important;
20
- }
21
-
22
- .ngg-album {
23
- /*height: 130px;*/
24
- padding: 5px;
25
- margin-bottom: 5px;
26
- border: 1px solid #cccccc;
27
- overflow:hidden;
28
- }
29
-
30
- .ngg-albumtitle {
31
- text-align: left;
32
- font-weight: bold;
33
- margin:0px;
34
- padding:0px;
35
- font-size: 1.4em;
36
- margin-bottom: 10px;
37
- }
38
-
39
- .ngg-thumbnail {
40
- float: left;
41
- margin-right: 12px;
42
- }
43
-
44
- .ngg-thumbnail img {
45
- background-color:#FFFFFF;
46
- border:1px solid #A9A9A9;
47
- margin:4px 0px 4px 5px;
48
- padding:4px;
49
- position:relative;
50
- }
51
-
52
- .ngg-thumbnail img:hover {
53
- background-color: #A9A9A9;
54
- }
55
-
56
- .ngg-description {
57
- text-align: left;
58
- }
59
-
60
- /* ----------- Album Styles Compact -------------*/
61
-
62
- .ngg-album-compact {
63
- float:left;
64
- height:180px;
65
- padding-right:6px !important;
66
- margin:0px !important;
67
- text-align:left;
68
- width:120px;
69
- }
70
-
71
- .ngg-album-compactbox {
72
- background:transparent url(albumset.gif) no-repeat scroll 0%;
73
- height:86px;
74
- margin:0pt 0pt 6px !important;
75
- padding:12px 0pt 0pt 7px !important;
76
- width:120px;
77
- }
78
-
79
-
80
- .ngg-album-compactbox .Thumb {
81
- border:1px solid #000000;
82
- margin:0px !important;
83
- padding:0px !important;
84
- width:91px;
85
- height:68px;
86
- }
87
-
88
- .ngg-album-compact h4 {
89
- font-size:15px;
90
- font-weight:bold;
91
- margin-bottom:0px;
92
- margin-top:0px;
93
- width:110px;
94
- }
95
-
96
- .ngg-album-compact p {
97
- font-size:11px;
98
- margin-top:2px;
99
- }
100
-
101
- /* ----------- Gallery style -------------*/
102
-
103
- .ngg-galleryoverview {
104
- margin-top: 10px;
105
- width: 100%;
106
- clear:both;
107
- display:block !important;
108
- }
109
-
110
- .ngg-gallery-thumbnail-box {
111
- float: left;
112
- }
113
-
114
- .ngg-gallery-thumbnail {
115
- float: left;
116
- background: url(shadowAlpha.png) no-repeat bottom right !important;
117
- background: url(shadow.gif) no-repeat bottom right;
118
- margin: 10px 0 0 10px !important;
119
- padding:10px 15px 10px 15px;
120
- border-color:#EEEEEE;
121
- border-style:solid none none solid;
122
- border-width:1px medium medium 1px;
123
- }
124
-
125
- .ngg-gallery-thumbnail img {
126
- margin: -6px 6px 6px -6px;
127
- background-color:#FFFFFF;
128
- border:1px solid #A9A9A9;
129
- display:block;
130
- padding:4px;
131
- position:relative;
132
- }
133
-
134
- .ngg-gallery-thumbnail img:hover {
135
- background-color: #A9A9A9;
136
- }
137
-
138
- .ngg-gallery-thumbnail span {
139
- margin: -6px 6px 6px -6px;
140
- text-align:center;
141
- font-size:90%;
142
- color:#808080;
143
- display:block;
144
- }
145
-
146
- .ngg-clear {
147
- clear: both;
148
- }
149
-
150
- /* ----------- Gallery navigation -------------*/
151
-
152
- .ngg-navigation {
153
- font-size:0.9em !important;
154
- clear:both !important;
155
- display:block !important;
156
- padding-top:15px;
157
- text-align:center;
158
- }
159
-
160
- .ngg-navigation span {
161
- font-weight:bold;
162
- margin:0pt 6px;
163
- }
164
-
165
- .ngg-navigation a.page-numbers,
166
- .ngg-navigation a.next,
167
- .ngg-navigation a.prev,
168
- .ngg-navigation span.page-numbers,
169
- .ngg-navigation span.next,
170
- .ngg-navigation span.prev {
171
- border:1px solid #DDDDDD;
172
- margin-right:3px;
173
- padding:3px 7px;
174
- }
175
-
176
- .ngg-navigation a.page-numbers:hover,
177
- .ngg-navigation a.next:hover,
178
- .ngg-navigation a.prev:hover,
179
- .ngg-navigation span.page-numbers:hover,
180
- .ngg-navigation span.next:hover,
181
- .ngg-navigation span.prev:hover {
182
- background-color: #0066CC;
183
- color: #FFFFFF !important;
184
- text-decoration: none !important;
185
- }
186
-
187
- /* ----------- Image browser style -------------*/
188
-
189
- .ngg-imagebrowser {
190
-
191
- }
192
-
193
- .ngg-imagebrowser h3 {
194
- text-align:center;
195
- }
196
-
197
- .ngg-imagebrowser img {
198
- border:1px solid #A9A9A9;
199
- margin-top: 10px;
200
- margin-bottom: 10px;
201
- width: 100%;
202
- display:block !important;
203
- padding:5px;
204
- }
205
-
206
- .ngg-imagebrowser-nav {
207
- padding:5px;
208
- margin-left:10px;
209
- }
210
-
211
- .ngg-imagebrowser-nav .back {
212
- float:left;
213
- border:1px solid #DDDDDD;
214
- margin-right:3px;
215
- padding:3px 7px;
216
- }
217
-
218
- .ngg-imagebrowser-nav .next {
219
- float:right;
220
- border:1px solid #DDDDDD;
221
- margin-right:3px;
222
- padding:3px 7px;
223
- }
224
-
225
- .ngg-imagebrowser-nav .counter {
226
- text-align:center;
227
- font-size:0.9em !important;
228
- }
229
-
230
- .exif-data {
231
- margin-left: auto !important;
232
- margin-right: auto !important;
233
- }
234
-
235
- /* ----------- Slideshow -------------*/
236
- .slideshow {
237
- margin-left: auto;
238
- margin-right: auto;
239
- text-align:center;
240
- outline: none;
241
- }
242
-
243
- .slideshowlink {
244
-
245
- }
246
-
247
- /* ----------- JS Slideshow -------------*/
248
- .ngg-slideshow {
249
- overflow:hidden;
250
- position: relative;
251
- }
252
-
253
- .ngg-slideshow * {
254
- vertical-align:middle;
255
- }
256
-
257
- /* See also : http://www.brunildo.org/test/img_center.html */
258
- .ngg-slideshow-loader{
259
- display: table-cell;
260
- text-align: center;
261
- vertical-align:middle;
262
- }
263
-
264
- .ngg-slideshow-loader img{
265
- background: none !important;
266
- border: 0 none !important;
267
- margin:auto !important;
268
- }
269
-
270
- /* ----------- Single picture -------------*/
271
- .ngg-singlepic {
272
- background-color:#FFFFFF;
273
- display:block;
274
- padding:4px;
275
- }
276
-
277
- .ngg-left {
278
- float: left;
279
- margin-right:10px;
280
- }
281
-
282
- .ngg-right {
283
- float: right;
284
- margin-left:10px;
285
- }
286
-
287
- .ngg-center {
288
- margin-left: auto !important;
289
- margin-right: auto !important;
290
- }
291
-
292
- /* ----------- Sidebar widget -------------*/
293
-
294
- .ngg-widget,
295
- .ngg-widget-slideshow {
296
- overflow: hidden;
297
- margin:0pt;
298
- padding:5px 0px 0px 0pt;
299
- }
300
-
301
- .ngg-widget img {
302
- border:2px solid #A9A9A9;
303
- margin:0pt 2px 2px 0px;
304
- padding:1px;
305
- }
306
-
307
- /* ----------- Related images -------------*/
308
- .ngg-related-gallery {
309
- background:#F9F9F9;
310
- border:1px solid #E0E0E0;
311
- overflow:hidden;
312
- margin-bottom:1em;
313
- margin-top:1em;
314
- padding:5px;
315
- }
316
- .ngg-related-gallery img {
317
- border: 1px solid #DDDDDD;
318
- float: left;
319
- margin: 0pt 3px;
320
- padding: 2px;
321
- height: 50px;
322
- width: 50px;
323
- }
324
-
325
- .ngg-related-gallery img:hover {
326
- border: 1px solid #000000;
327
- }
328
-
329
- /* ----------- Gallery list -------------*/
330
-
331
- .ngg-galleryoverview ul li:before {
332
- content: '' !important;
333
- }
334
-
335
- .ngg-gallery-list {
336
- list-style-type:none;
337
- padding: 0px !important;
338
- text-indent:0px !important;
339
- }
340
-
341
- .ngg-galleryoverview div.pic img{
342
- width: 100%;
343
- }
344
-
345
- .ngg-gallery-list li {
346
- float:left;
347
- margin:0 2px 0px 2px !important;
348
- overflow:hidden;
349
- }
350
-
351
- .ngg-gallery-list li a {
352
- border:1px solid #CCCCCC;
353
- display:block;
354
- padding:2px;
355
- }
356
-
357
- .ngg-gallery-list li.selected a{
358
- -moz-background-clip:border;
359
- -moz-background-inline-policy:continuous;
360
- -moz-background-origin:padding;
361
- background:#000000 none repeat scroll 0 0;
362
- }
363
-
364
- .ngg-gallery-list li img {
365
- height:40px;
366
- width:40px;
367
- }
368
-
369
- li.ngg-next, li.ngg-prev {
370
- height:40px;
371
- width:40px;
372
- font-size:3.5em;
373
- }
374
-
375
- li.ngg-next a, li.ngg-prev a {
376
- padding-top: 10px;
377
- border: none;
378
- text-decoration: none;
379
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/nggallery.css DELETED
@@ -1,403 +0,0 @@
1
- /*
2
- CSS Name: Default Styles
3
- Description: NextGEN Default Gallery Stylesheet
4
- Author: Alex Rabe
5
- Version: 2.11
6
-
7
- This is a template stylesheet that can be used with NextGEN Gallery. I tested the
8
- styles with a default theme Kubrick. Modify it when your theme struggle with it,
9
- it's only a template design
10
-
11
- */
12
-
13
- /* ----------- Album Styles Extend -------------*/
14
-
15
- .ngg-albumoverview {
16
- margin-top: 10px;
17
- width: 100%;
18
- clear:both;
19
- display:block !important;
20
- }
21
-
22
- .ngg-album {
23
- height: 100%;
24
- padding: 5px;
25
- margin-bottom: 5px;
26
- border: 1px solid #fff;
27
- }
28
-
29
- /* IE6 will ignore this , again I hate IE6 */
30
- /* See also http://www.sitepoint.com/article/browser-specific-css-hacks */
31
- html>body .ngg-album {
32
- overflow:hidden;
33
- padding: 5px;
34
- margin-bottom: 5px;
35
- border: 1px solid #cccccc;
36
- }
37
-
38
- .ngg-album {
39
- overflow: hidden;
40
- padding: 5px;
41
- margin-bottom: 5px;
42
- border: 1px solid #cccccc;
43
- }
44
-
45
- .ngg-albumtitle {
46
- text-align: left;
47
- font-weight: bold;
48
- margin:0px;
49
- padding:0px;
50
- font-size: 1.4em;
51
- margin-bottom: 10px;
52
- }
53
-
54
- .ngg-thumbnail {
55
- float: left;
56
- margin-right: 12px;
57
- }
58
-
59
- .ngg-thumbnail img {
60
- background-color:#FFFFFF;
61
- border:1px solid #A9A9A9;
62
- margin:4px 0px 4px 5px;
63
- padding:4px;
64
- position:relative;
65
- }
66
-
67
- .ngg-thumbnail img:hover {
68
- background-color: #A9A9A9;
69
- }
70
-
71
- .ngg-description {
72
- text-align: left;
73
- }
74
-
75
- /* ----------- Album Styles Compact -------------*/
76
-
77
- .ngg-album-compact {
78
- float:left;
79
- padding-right:6px !important;
80
- margin:0px !important;
81
- text-align:left;
82
- width:120px;
83
- }
84
-
85
- .ngg-album-compactbox {
86
- background:transparent url(albumset.gif) no-repeat scroll 0%;
87
- height:86px;
88
- margin:0pt 0pt 6px !important;
89
- padding:12px 0pt 0pt 7px !important;
90
- width:120px;
91
- }
92
-
93
-
94
- .ngg-album-compactbox .Thumb {
95
- border:1px solid #000000;
96
- margin:0px !important;
97
- padding:0px !important;
98
- width:91px;
99
- height:68px;
100
- }
101
-
102
- .ngg-album-compact h4 {
103
- font-size:15px;
104
- font-weight:bold;
105
- margin-bottom:0px;
106
- margin-top:0px;
107
- width:110px;
108
- }
109
-
110
- .ngg-album-compact p {
111
- font-size:11px;
112
- margin-top:2px;
113
- }
114
-
115
- /* ----------- Gallery style -------------*/
116
-
117
- .ngg-galleryoverview {
118
- overflow: hidden;
119
- margin-top: 10px;
120
- width: 100%;
121
- clear:both;
122
- display:block !important;
123
- }
124
-
125
- .ngg-galleryoverview .desc {
126
- /* required for description */
127
- margin:0px 10px 10px 0px;
128
- padding:5px;
129
- }
130
-
131
- .ngg-gallery-thumbnail-box {
132
- float: left;
133
- }
134
-
135
- .ngg-gallery-thumbnail {
136
- float: left;
137
- margin-right: 5px;
138
- text-align: center;
139
- }
140
-
141
- .ngg-gallery-thumbnail img {
142
- background-color:#FFFFFF;
143
- border:1px solid #A9A9A9;
144
- display:block;
145
- margin:4px 0px 4px 5px;
146
- padding:4px;
147
- position:relative;
148
- }
149
-
150
- .ngg-gallery-thumbnail img:hover {
151
- background-color: #A9A9A9;
152
- }
153
-
154
- .ngg-gallery-thumbnail span {
155
- /* Images description */
156
- font-size:90%;
157
- padding-left:5px;
158
- display:block;
159
- }
160
-
161
- .ngg-clear {
162
- clear: both;
163
- float: none;
164
- }
165
-
166
- /* ----------- Gallery navigation -------------*/
167
-
168
- .ngg-navigation {
169
- font-size:0.9em !important;
170
- clear:both !important;
171
- display:block !important;
172
- padding-top: 15px;
173
- padding-bottom: 2px;
174
- text-align:center;
175
- }
176
-
177
- .ngg-navigation span {
178
- font-weight:bold;
179
- margin:0pt 6px;
180
- }
181
-
182
- .ngg-navigation a.page-numbers,
183
- .ngg-navigation a.next,
184
- .ngg-navigation a.prev,
185
- .ngg-navigation span.page-numbers,
186
- .ngg-navigation span.next,
187
- .ngg-navigation span.prev {
188
- border:1px solid #DDDDDD;
189
- margin-right:3px;
190
- padding:3px 8px;
191
- text-decoration: none;
192
- }
193
-
194
- .ngg-navigation a.page-numbers:hover,
195
- .ngg-navigation a.next:hover,
196
- .ngg-navigation a.prev:hover,
197
- .ngg-navigation span.page-numbers:hover,
198
- .ngg-navigation span.next:hover,
199
- .ngg-navigation span.prev:hover {
200
- background-color: #0066CC;
201
- color: #FFFFFF !important;
202
- text-decoration: none !important;
203
- }
204
-
205
- /* ----------- Image browser style -------------*/
206
-
207
- .ngg-imagebrowser {
208
-
209
- }
210
-
211
- .ngg-imagebrowser h3 {
212
- text-align:center;
213
- }
214
-
215
- .ngg-imagebrowser img {
216
- border:1px solid #A9A9A9;
217
- margin-top: 10px;
218
- margin-bottom: 10px;
219
- width: 100%;
220
- display:block !important;
221
- padding:5px;
222
- }
223
-
224
- .ngg-imagebrowser-nav {
225
- padding:5px;
226
- margin-left:10px;
227
- }
228
-
229
- .ngg-imagebrowser-nav .back {
230
- float:left;
231
- border:1px solid #DDDDDD;
232
- margin-right:3px;
233
- padding:3px 7px;
234
- }
235
-
236
- .ngg-imagebrowser-nav .next {
237
- float:right;
238
- border:1px solid #DDDDDD;
239
- margin-right:3px;
240
- padding:3px 7px;
241
- }
242
-
243
- .ngg-imagebrowser-nav .counter {
244
- text-align:center;
245
- font-size:0.9em !important;
246
- }
247
-
248
- .exif-data {
249
- margin-left: auto !important;
250
- margin-right: auto !important;
251
- }
252
-
253
- /* ----------- Slideshow -------------*/
254
- .slideshow {
255
- margin-left: auto;
256
- margin-right: auto;
257
- text-align:center;
258
- outline: none;
259
- }
260
-
261
- .slideshowlink {
262
-
263
- }
264
-
265
- /* ----------- JS Slideshow -------------*/
266
- .ngg-slideshow {
267
- overflow:hidden;
268
- position: relative;
269
- margin-left: auto;
270
- margin-right: auto;
271
- }
272
-
273
- .ngg-slideshow * {
274
- vertical-align:middle;
275
- }
276
-
277
- /* See also : http://www.brunildo.org/test/img_center.html */
278
- .ngg-slideshow-loader{
279
- display: table-cell;
280
- text-align: center;
281
- vertical-align:middle;
282
- }
283
-
284
- .ngg-slideshow-loader img{
285
- background: none !important;
286
- border: 0 none !important;
287
- margin:auto !important;
288
- }
289
-
290
- /* ----------- Single picture -------------*/
291
- .ngg-singlepic {
292
- background-color:#FFFFFF;
293
- display:block;
294
- padding:4px;
295
- }
296
-
297
- .ngg-left {
298
- float: left;
299
- margin-right:10px;
300
- }
301
-
302
- .ngg-right {
303
- float: right;
304
- margin-left:10px;
305
- }
306
-
307
- .ngg-center {
308
- margin-left: auto !important;
309
- margin-right: auto !important;
310
- }
311
-
312
- /* ----------- Sidebar widget -------------*/
313
- .ngg-widget,
314
- .ngg-widget-slideshow {
315
- overflow: hidden;
316
- margin:0pt;
317
- padding:5px 0px 0px 0pt;
318
- text-align:left;
319
- }
320
-
321
- .ngg-widget img {
322
- border:2px solid #A9A9A9;
323
- margin:0pt 2px 2px 0px;
324
- padding:1px;
325
- }
326
-
327
- /* ----------- Related images -------------*/
328
- .ngg-related-gallery {
329
- background:#F9F9F9;
330
- border:1px solid #E0E0E0;
331
- overflow:hidden;
332
- margin-bottom:1em;
333
- margin-top:1em;
334
- padding:5px;
335
- }
336
- .ngg-related-gallery img {
337
- border: 1px solid #DDDDDD;
338
- float: left;
339
- margin: 0pt 3px;
340
- padding: 2px;
341
- height: 50px;
342
- width: 50px;
343
- }
344
-
345
- .ngg-related-gallery img:hover {
346
- border: 1px solid #000000;
347
- }
348
-
349
- /* ----------- Gallery list -------------*/
350
-
351
- .ngg-galleryoverview ul li:before {
352
- content: '' !important;
353
- }
354
-
355
- .ngg-gallery-list {
356
- list-style-type:none;
357
- padding: 0px !important;
358
- text-indent:0px !important;
359
- }
360
-
361
- .ngg-galleryoverview div.pic img{
362
- width: 100%;
363
- }
364
-
365
- .ngg-gallery-list li {
366
- float:left;
367
- margin:0 2px 0px 2px !important;
368
- overflow:hidden;
369
- }
370
-
371
- .ngg-gallery-list li a {
372
- border:1px solid #CCCCCC;
373
- display:block;
374
- padding:2px;
375
- }
376
-
377
- .ngg-gallery-list li.selected a{
378
- -moz-background-clip:border;
379
- -moz-background-inline-policy:continuous;
380
- -moz-background-origin:padding;
381
- background:#000000 none repeat scroll 0 0;
382
- }
383
-
384
- .ngg-gallery-list li img {
385
- height:40px;
386
- width:40px;
387
- }
388
-
389
- li.ngg-next, li.ngg-prev {
390
- height:40px;
391
- width:40px;
392
- font-size:3.5em;
393
- }
394
-
395
- li.ngg-next a, li.ngg-prev a {
396
- padding-top: 10px;
397
- border: none;
398
- text-decoration: none;
399
- }
400
-
401
- #TB_window {
402
- z-index: 9999 !important;
403
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/jquery.cycle.all.min.js DELETED
@@ -1 +0,0 @@
1
- (function(a){function r(b){function e(b){for(;b&&b.nodeName.toLowerCase()!="html";b=b.parentNode){var c=a.css(b,"background-color");if(c&&c.indexOf("rgb")>=0){var e=c.match(/\d+/g);return"#"+d(e[0])+d(e[1])+d(e[2])}if(c&&c!="transparent")return c}return"#ffffff"}function d(a){a=parseInt(a,10).toString(16);return a.length<2?"0"+a:a}c("applying clearType background-color hack");b.each(function(){a(this).css("background-color",e(this))})}function q(b,c){var d=a(c.pager);a.each(b,function(e,f){a.fn.cycle.createPagerAnchor(e,f,d,b,c)});c.updateActivePagerLink(c.pager,c.startingSlide,c.activePagerClass)}function o(b,c){var d=c?1:-1;var e=b.elements;var f=b.$cont[0],g=f.cycleTimeout;if(g){clearTimeout(g);f.cycleTimeout=0}if(b.random&&d<0){b.randomIndex--;if(--b.randomIndex==-2)b.randomIndex=e.length-2;else if(b.randomIndex==-1)b.randomIndex=e.length-1;b.nextSlide=b.randomMap[b.randomIndex]}else if(b.random){b.nextSlide=b.randomMap[b.randomIndex]}else{b.nextSlide=b.currSlide+d;if(b.nextSlide<0){if(b.nowrap)return false;b.nextSlide=e.length-1}else if(b.nextSlide>=e.length){if(b.nowrap)return false;b.nextSlide=0}}var h=b.onPrevNextEvent||b.prevNextClick;if(a.isFunction(h))h(d>0,b.nextSlide,e[b.nextSlide]);m(e,b,1,c);return false}function n(a,b,d,e){if(d.timeoutFn){var f=d.timeoutFn.call(a,a,b,d,e);while(d.fx!="none"&&f-d.speed<250)f+=d.speed;c("calculated timeout: "+f+"; speed: "+d.speed);if(f!==false)return f}return d.timeout}function m(b,d,e,f){if(e&&d.busy&&d.manualTrump){c("manualTrump in go(), stopping active transition");a(b).stop(true,true);d.busy=0}if(d.busy){c("transition active, ignoring new tx request");return}var g=d.$cont[0],h=b[d.currSlide],i=b[d.nextSlide];if(g.cycleStop!=d.stopCount||g.cycleTimeout===0&&!e)return;if(!e&&!g.cyclePause&&!d.bounce&&(d.autostop&&--d.countdown<=0||d.nowrap&&!d.random&&d.nextSlide<d.currSlide)){if(d.end)d.end(d);return}var j=false;if((e||!g.cyclePause)&&d.nextSlide!=d.currSlide){j=true;var k=d.fx;h.cycleH=h.cycleH||a(h).height();h.cycleW=h.cycleW||a(h).width();i.cycleH=i.cycleH||a(i).height();i.cycleW=i.cycleW||a(i).width();if(d.multiFx){if(f&&(d.lastFx==undefined||++d.lastFx>=d.fxs.length))d.lastFx=0;else if(!f&&(d.lastFx==undefined||--d.lastFx<0))d.lastFx=d.fxs.length-1;k=d.fxs[d.lastFx]}if(d.oneTimeFx){k=d.oneTimeFx;d.oneTimeFx=null}a.fn.cycle.resetState(d,k);if(d.before.length)a.each(d.before,function(a,b){if(g.cycleStop!=d.stopCount)return;b.apply(i,[h,i,d,f])});var l=function(){d.busy=0;a.each(d.after,function(a,b){if(g.cycleStop!=d.stopCount)return;b.apply(i,[h,i,d,f])})};c("tx firing("+k+"); currSlide: "+d.currSlide+"; nextSlide: "+d.nextSlide);d.busy=1;if(d.fxFn)d.fxFn(h,i,d,l,f,e&&d.fastOnEvent);else if(a.isFunction(a.fn.cycle[d.fx]))a.fn.cycle[d.fx](h,i,d,l,f,e&&d.fastOnEvent);else a.fn.cycle.custom(h,i,d,l,f,e&&d.fastOnEvent)}if(j||d.nextSlide==d.currSlide){d.lastSlide=d.currSlide;if(d.random){d.currSlide=d.nextSlide;if(++d.randomIndex==b.length)d.randomIndex=0;d.nextSlide=d.randomMap[d.randomIndex];if(d.nextSlide==d.currSlide)d.nextSlide=d.currSlide==d.slideCount-1?0:d.currSlide+1}else if(d.backwards){var o=d.nextSlide-1<0;if(o&&d.bounce){d.backwards=!d.backwards;d.nextSlide=1;d.currSlide=0}else{d.nextSlide=o?b.length-1:d.nextSlide-1;d.currSlide=o?0:d.nextSlide+1}}else{var o=d.nextSlide+1==b.length;if(o&&d.bounce){d.backwards=!d.backwards;d.nextSlide=b.length-2;d.currSlide=b.length-1}else{d.nextSlide=o?0:d.nextSlide+1;d.currSlide=o?b.length-1:d.nextSlide-1}}}if(j&&d.pager)d.updateActivePagerLink(d.pager,d.currSlide,d.activePagerClass);var p=0;if(d.timeout&&!d.continuous)p=n(b[d.currSlide],b[d.nextSlide],d,f);else if(d.continuous&&g.cyclePause)p=10;if(p>0)g.cycleTimeout=setTimeout(function(){m(b,d,0,!d.backwards)},p)}function l(b,c){b.addSlide=function(d,e){var f=a(d),g=f[0];if(!b.autostopCount)b.countdown++;c[e?"unshift":"push"](g);if(b.els)b.els[e?"unshift":"push"](g);b.slideCount=c.length;f.css("position","absolute");f[e?"prependTo":"appendTo"](b.$cont);if(e){b.currSlide++;b.nextSlide++}if(!a.support.opacity&&b.cleartype&&!b.cleartypeNoBg)r(f);if(b.fit&&b.width)f.width(b.width);if(b.fit&&b.height&&b.height!="auto")f.height(b.height);g.cycleH=b.fit&&b.height?b.height:f.height();g.cycleW=b.fit&&b.width?b.width:f.width();f.css(b.cssBefore);if(b.pager||b.pagerAnchorBuilder)a.fn.cycle.createPagerAnchor(c.length-1,g,a(b.pager),c,b);if(a.isFunction(b.onAddSlide))b.onAddSlide(f);else f.hide()}}function k(b){var e,f,g=a.fn.cycle.transitions;if(b.fx.indexOf(",")>0){b.multiFx=true;b.fxs=b.fx.replace(/\s*/g,"").split(",");for(e=0;e<b.fxs.length;e++){var h=b.fxs[e];f=g[h];if(!f||!g.hasOwnProperty(h)||!a.isFunction(f)){d("discarding unknown transition: ",h);b.fxs.splice(e,1);e--}}if(!b.fxs.length){d("No valid transitions named; slideshow terminating.");return false}}else if(b.fx=="all"){b.multiFx=true;b.fxs=[];for(p in g){f=g[p];if(g.hasOwnProperty(p)&&a.isFunction(f))b.fxs.push(p)}}if(b.multiFx&&b.randomizeEffects){var i=Math.floor(Math.random()*20)+30;for(e=0;e<i;e++){var j=Math.floor(Math.random()*b.fxs.length);b.fxs.push(b.fxs.splice(j,1)[0])}c("randomized fx sequence: ",b.fxs)}return true}function j(b){b.original={before:[],after:[]};b.original.cssBefore=a.extend({},b.cssBefore);b.original.cssAfter=a.extend({},b.cssAfter);b.original.animIn=a.extend({},b.animIn);b.original.animOut=a.extend({},b.animOut);a.each(b.before,function(){b.original.before.push(this)});a.each(b.after,function(){b.original.after.push(this)})}function i(b,c,f,h,i){var n=a.extend({},a.fn.cycle.defaults,h||{},a.metadata?b.metadata():a.meta?b.data():{});var p=a.isFunction(b.data)?b.data(n.metaAttr):null;if(p)n=a.extend(n,p);if(n.autostop)n.countdown=n.autostopCount||f.length;var s=b[0];b.data("cycle.opts",n);n.$cont=b;n.stopCount=s.cycleStop;n.elements=f;n.before=n.before?[n.before]:[];n.after=n.after?[n.after]:[];if(!a.support.opacity&&n.cleartype)n.after.push(function(){g(this,n)});if(n.continuous)n.after.push(function(){m(f,n,0,!n.backwards)});j(n);if(!a.support.opacity&&n.cleartype&&!n.cleartypeNoBg)r(c);if(b.css("position")=="static")b.css("position","relative");if(n.width)b.width(n.width);if(n.height&&n.height!="auto")b.height(n.height);if(n.startingSlide)n.startingSlide=parseInt(n.startingSlide,10);else if(n.backwards)n.startingSlide=f.length-1;if(n.random){n.randomMap=[];for(var t=0;t<f.length;t++)n.randomMap.push(t);n.randomMap.sort(function(a,b){return Math.random()-.5});n.randomIndex=1;n.startingSlide=n.randomMap[1]}else if(n.startingSlide>=f.length)n.startingSlide=0;n.currSlide=n.startingSlide||0;var u=n.startingSlide;c.css({position:"absolute",top:0,left:0}).hide().each(function(b){var c;if(n.backwards)c=u?b<=u?f.length+(b-u):u-b:f.length-b;else c=u?b>=u?f.length-(b-u):u-b:f.length-b;a(this).css("z-index",c)});a(f[u]).css("opacity",1).show();g(f[u],n);if(n.fit){if(!n.aspect){if(n.width)c.width(n.width);if(n.height&&n.height!="auto")c.height(n.height)}else{c.each(function(){var b=a(this);var c=n.aspect===true?b.width()/b.height():n.aspect;if(n.width&&b.width()!=n.width){b.width(n.width);b.height(n.width/c)}if(n.height&&b.height()<n.height){b.height(n.height);b.width(n.height*c)}})}}if(n.center&&(!n.fit||n.aspect)){c.each(function(){var b=a(this);b.css({"margin-left":n.width?(n.width-b.width())/2+"px":0,"margin-top":n.height?(n.height-b.height())/2+"px":0})})}if(n.center&&!n.fit&&!n.slideResize){c.each(function(){var b=a(this);b.css({"margin-left":n.width?(n.width-b.width())/2+"px":0,"margin-top":n.height?(n.height-b.height())/2+"px":0})})}var v=n.containerResize&&!b.innerHeight();if(v){var w=0,x=0;for(var y=0;y<f.length;y++){var z=a(f[y]),A=z[0],B=z.outerWidth(),C=z.outerHeight();if(!B)B=A.offsetWidth||A.width||z.attr("width");if(!C)C=A.offsetHeight||A.height||z.attr("height");w=B>w?B:w;x=C>x?C:x}if(w>0&&x>0)b.css({width:w+"px",height:x+"px"})}var D=false;if(n.pause)b.hover(function(){D=true;this.cyclePause++;e(s,true)},function(){D&&this.cyclePause--;e(s,true)});if(k(n)===false)return false;var E=false;h.requeueAttempts=h.requeueAttempts||0;c.each(function(){var b=a(this);this.cycleH=n.fit&&n.height?n.height:b.height()||this.offsetHeight||this.height||b.attr("height")||0;this.cycleW=n.fit&&n.width?n.width:b.width()||this.offsetWidth||this.width||b.attr("width")||0;if(b.is("img")){var c=a.browser.msie&&this.cycleW==28&&this.cycleH==30&&!this.complete;var e=a.browser.mozilla&&this.cycleW==34&&this.cycleH==19&&!this.complete;var f=a.browser.opera&&(this.cycleW==42&&this.cycleH==19||this.cycleW==37&&this.cycleH==17)&&!this.complete;var g=this.cycleH==0&&this.cycleW==0&&!this.complete;if(c||e||f||g){if(i.s&&n.requeueOnImageNotLoaded&&++h.requeueAttempts<100){d(h.requeueAttempts," - img slide not loaded, requeuing slideshow: ",this.src,this.cycleW,this.cycleH);setTimeout(function(){a(i.s,i.c).cycle(h)},n.requeueTimeout);E=true;return false}else{d("could not determine size of image: "+this.src,this.cycleW,this.cycleH)}}}return true});if(E)return false;n.cssBefore=n.cssBefore||{};n.cssAfter=n.cssAfter||{};n.cssFirst=n.cssFirst||{};n.animIn=n.animIn||{};n.animOut=n.animOut||{};c.not(":eq("+u+")").css(n.cssBefore);a(c[u]).css(n.cssFirst);if(n.timeout){n.timeout=parseInt(n.timeout,10);if(n.speed.constructor==String)n.speed=a.fx.speeds[n.speed]||parseInt(n.speed,10);if(!n.sync)n.speed=n.speed/2;var F=n.fx=="none"?0:n.fx=="shuffle"?500:250;while(n.timeout-n.speed<F)n.timeout+=n.speed}if(n.easing)n.easeIn=n.easeOut=n.easing;if(!n.speedIn)n.speedIn=n.speed;if(!n.speedOut)n.speedOut=n.speed;n.slideCount=f.length;n.currSlide=n.lastSlide=u;if(n.random){if(++n.randomIndex==f.length)n.randomIndex=0;n.nextSlide=n.randomMap[n.randomIndex]}else if(n.backwards)n.nextSlide=n.startingSlide==0?f.length-1:n.startingSlide-1;else n.nextSlide=n.startingSlide>=f.length-1?0:n.startingSlide+1;if(!n.multiFx){var G=a.fn.cycle.transitions[n.fx];if(a.isFunction(G))G(b,c,n);else if(n.fx!="custom"&&!n.multiFx){d("unknown transition: "+n.fx,"; slideshow terminating");return false}}var H=c[u];if(!n.skipInitializationCallbacks){if(n.before.length)n.before[0].apply(H,[H,H,n,true]);if(n.after.length)n.after[0].apply(H,[H,H,n,true])}if(n.next)a(n.next).bind(n.prevNextEvent,function(){return o(n,1)});if(n.prev)a(n.prev).bind(n.prevNextEvent,function(){return o(n,0)});if(n.pager||n.pagerAnchorBuilder)q(f,n);l(n,f);return n}function h(b){if(b.next)a(b.next).unbind(b.prevNextEvent);if(b.prev)a(b.prev).unbind(b.prevNextEvent);if(b.pager||b.pagerAnchorBuilder)a.each(b.pagerAnchors||[],function(){this.unbind().remove()});b.pagerAnchors=null;if(b.destroy)b.destroy(b)}function g(b,c){if(!a.support.opacity&&c.cleartype&&b.style.filter){try{b.style.removeAttribute("filter")}catch(d){}}}function f(b,c,f){function j(b,c,e){if(!b&&c===true){var f=a(e).data("cycle.opts");if(!f){d("options not found, can not resume");return false}if(e.cycleTimeout){clearTimeout(e.cycleTimeout);e.cycleTimeout=0}m(f.elements,f,1,!f.backwards)}}if(b.cycleStop==undefined)b.cycleStop=0;if(c===undefined||c===null)c={};if(c.constructor==String){switch(c){case"destroy":case"stop":var g=a(b).data("cycle.opts");if(!g)return false;b.cycleStop++;if(b.cycleTimeout)clearTimeout(b.cycleTimeout);b.cycleTimeout=0;g.elements&&a(g.elements).stop();a(b).removeData("cycle.opts");if(c=="destroy")h(g);return false;case"toggle":b.cyclePause=b.cyclePause===1?0:1;j(b.cyclePause,f,b);e(b);return false;case"pause":b.cyclePause=1;e(b);return false;case"resume":b.cyclePause=0;j(false,f,b);e(b);return false;case"prev":case"next":var g=a(b).data("cycle.opts");if(!g){d('options not found, "prev/next" ignored');return false}a.fn.cycle[c](g);return false;default:c={fx:c}}return c}else if(c.constructor==Number){var i=c;c=a(b).data("cycle.opts");if(!c){d("options not found, can not advance slide");return false}if(i<0||i>=c.elements.length){d("invalid slide index: "+i);return false}c.nextSlide=i;if(b.cycleTimeout){clearTimeout(b.cycleTimeout);b.cycleTimeout=0}if(typeof f=="string")c.oneTimeFx=f;m(c.elements,c,1,i>=c.currSlide);return false}return c}function e(b,c,d){var e=a(b).data("cycle.opts");var f=!!b.cyclePause;if(f&&e.paused)e.paused(b,e,c,d);else if(!f&&e.resumed)e.resumed(b,e,c,d)}function d(){window.console&&console.log&&console.log("[cycle] "+Array.prototype.join.call(arguments," "))}function c(b){a.fn.cycle.debug&&d(b)}var b="2.9995";if(a.support==undefined){a.support={opacity:!a.browser.msie}}a.expr[":"].paused=function(a){return a.cyclePause};a.fn.cycle=function(b,e){var g={s:this.selector,c:this.context};if(this.length===0&&b!="stop"){if(!a.isReady&&g.s){d("DOM not ready, queuing slideshow");a(function(){a(g.s,g.c).cycle(b,e)});return this}d("terminating; zero elements found by selector"+(a.isReady?"":" (DOM not ready)"));return this}return this.each(function(){var h=f(this,b,e);if(h===false)return;h.updateActivePagerLink=h.updateActivePagerLink||a.fn.cycle.updateActivePagerLink;if(this.cycleTimeout)clearTimeout(this.cycleTimeout);this.cycleTimeout=this.cyclePause=0;var j=a(this);var k=h.slideExpr?a(h.slideExpr,this):j.children();var l=k.get();var o=i(j,k,l,h,g);if(o===false)return;if(l.length<2){d("terminating; too few slides: "+l.length);return}var p=o.continuous?10:n(l[o.currSlide],l[o.nextSlide],o,!o.backwards);if(p){p+=o.delay||0;if(p<10)p=10;c("first timeout: "+p);this.cycleTimeout=setTimeout(function(){m(l,o,0,!h.backwards)},p)}})};a.fn.cycle.resetState=function(b,c){c=c||b.fx;b.before=[];b.after=[];b.cssBefore=a.extend({},b.original.cssBefore);b.cssAfter=a.extend({},b.original.cssAfter);b.animIn=a.extend({},b.original.animIn);b.animOut=a.extend({},b.original.animOut);b.fxFn=null;a.each(b.original.before,function(){b.before.push(this)});a.each(b.original.after,function(){b.after.push(this)});var d=a.fn.cycle.transitions[c];if(a.isFunction(d))d(b.$cont,a(b.elements),b)};a.fn.cycle.updateActivePagerLink=function(b,c,d){a(b).each(function(){a(this).children().removeClass(d).eq(c).addClass(d)})};a.fn.cycle.next=function(a){o(a,1)};a.fn.cycle.prev=function(a){o(a,0)};a.fn.cycle.createPagerAnchor=function(b,d,f,g,h){var i;if(a.isFunction(h.pagerAnchorBuilder)){i=h.pagerAnchorBuilder(b,d);c("pagerAnchorBuilder("+b+", el) returned: "+i)}else i='<a href="#">'+(b+1)+"</a>";if(!i)return;var j=a(i);if(j.parents("body").length===0){var k=[];if(f.length>1){f.each(function(){var b=j.clone(true);a(this).append(b);k.push(b[0])});j=a(k)}else{j.appendTo(f)}}h.pagerAnchors=h.pagerAnchors||[];h.pagerAnchors.push(j);var l=function(c){c.preventDefault();h.nextSlide=b;var d=h.$cont[0],e=d.cycleTimeout;if(e){clearTimeout(e);d.cycleTimeout=0}var f=h.onPagerEvent||h.pagerClick;if(a.isFunction(f))f(h.nextSlide,g[h.nextSlide]);m(g,h,1,h.currSlide<b)};if(/mouseenter|mouseover/i.test(h.pagerEvent)){j.hover(l,function(){})}else{j.bind(h.pagerEvent,l)}if(!/^click/.test(h.pagerEvent)&&!h.allowPagerClickBubble)j.bind("click.cycle",function(){return false});var n=h.$cont[0];var o=false;if(h.pauseOnPagerHover){j.hover(function(){o=true;n.cyclePause++;e(n,true,true)},function(){o&&n.cyclePause--;e(n,true,true)})}};a.fn.cycle.hopsFromLast=function(a,b){var c,d=a.lastSlide,e=a.currSlide;if(b)c=e>d?e-d:a.slideCount-d;else c=e<d?d-e:d+a.slideCount-e;return c};a.fn.cycle.commonReset=function(b,c,d,e,f,g){a(d.elements).not(b).hide();if(typeof d.cssBefore.opacity=="undefined")d.cssBefore.opacity=1;d.cssBefore.display="block";if(d.slideResize&&e!==false&&c.cycleW>0)d.cssBefore.width=c.cycleW;if(d.slideResize&&f!==false&&c.cycleH>0)d.cssBefore.height=c.cycleH;d.cssAfter=d.cssAfter||{};d.cssAfter.display="none";a(b).css("zIndex",d.slideCount+(g===true?1:0));a(c).css("zIndex",d.slideCount+(g===true?0:1))};a.fn.cycle.custom=function(b,c,d,e,f,g){var h=a(b),i=a(c);var j=d.speedIn,k=d.speedOut,l=d.easeIn,m=d.easeOut;i.css(d.cssBefore);if(g){if(typeof g=="number")j=k=g;else j=k=1;l=m=null}var n=function(){i.animate(d.animIn,j,l,function(){e()})};h.animate(d.animOut,k,m,function(){h.css(d.cssAfter);if(!d.sync)n()});if(d.sync)n()};a.fn.cycle.transitions={fade:function(b,c,d){c.not(":eq("+d.currSlide+")").css("opacity",0);d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d);d.cssBefore.opacity=0});d.animIn={opacity:1};d.animOut={opacity:0};d.cssBefore={top:0,left:0}}};a.fn.cycle.ver=function(){return b};a.fn.cycle.defaults={activePagerClass:"activeSlide",after:null,allowPagerClickBubble:false,animIn:null,animOut:null,aspect:false,autostop:0,autostopCount:0,backwards:false,before:null,center:null,cleartype:!a.support.opacity,cleartypeNoBg:false,containerResize:1,continuous:0,cssAfter:null,cssBefore:null,delay:0,easeIn:null,easeOut:null,easing:null,end:null,fastOnEvent:0,fit:0,fx:"fade",fxFn:null,height:"auto",manualTrump:true,metaAttr:"cycle",next:null,nowrap:0,onPagerEvent:null,onPrevNextEvent:null,pager:null,pagerAnchorBuilder:null,pagerEvent:"click.cycle",pause:0,pauseOnPagerHover:0,prev:null,prevNextEvent:"click.cycle",random:0,randomizeEffects:1,requeueOnImageNotLoaded:true,requeueTimeout:250,rev:0,shuffle:null,skipInitializationCallbacks:false,slideExpr:null,slideResize:1,speed:1e3,speedIn:null,speedOut:null,startingSlide:0,sync:1,timeout:4e3,timeoutFn:null,updateActivePagerLink:null,width:null}})(jQuery);(function(a){a.fn.cycle.transitions.none=function(b,c,d){d.fxFn=function(b,c,d,e){a(c).show();a(b).hide();e()}};a.fn.cycle.transitions.fadeout=function(b,c,d){c.not(":eq("+d.currSlide+")").css({display:"block",opacity:1});d.before.push(function(b,c,d,e,f,g){a(b).css("zIndex",d.slideCount+(!g===true?1:0));a(c).css("zIndex",d.slideCount+(!g===true?0:1))});d.animIn.opacity=1;d.animOut.opacity=0;d.cssBefore.opacity=1;d.cssBefore.display="block";d.cssAfter.zIndex=0};a.fn.cycle.transitions.scrollUp=function(b,c,d){b.css("overflow","hidden");d.before.push(a.fn.cycle.commonReset);var e=b.height();d.cssBefore.top=e;d.cssBefore.left=0;d.cssFirst.top=0;d.animIn.top=0;d.animOut.top=-e};a.fn.cycle.transitions.scrollDown=function(b,c,d){b.css("overflow","hidden");d.before.push(a.fn.cycle.commonReset);var e=b.height();d.cssFirst.top=0;d.cssBefore.top=-e;d.cssBefore.left=0;d.animIn.top=0;d.animOut.top=e};a.fn.cycle.transitions.scrollLeft=function(b,c,d){b.css("overflow","hidden");d.before.push(a.fn.cycle.commonReset);var e=b.width();d.cssFirst.left=0;d.cssBefore.left=e;d.cssBefore.top=0;d.animIn.left=0;d.animOut.left=0-e};a.fn.cycle.transitions.scrollRight=function(b,c,d){b.css("overflow","hidden");d.before.push(a.fn.cycle.commonReset);var e=b.width();d.cssFirst.left=0;d.cssBefore.left=-e;d.cssBefore.top=0;d.animIn.left=0;d.animOut.left=e};a.fn.cycle.transitions.scrollHorz=function(b,c,d){b.css("overflow","hidden").width();d.before.push(function(b,c,d,e){if(d.rev)e=!e;a.fn.cycle.commonReset(b,c,d);d.cssBefore.left=e?c.cycleW-1:1-c.cycleW;d.animOut.left=e?-b.cycleW:b.cycleW});d.cssFirst.left=0;d.cssBefore.top=0;d.animIn.left=0;d.animOut.top=0};a.fn.cycle.transitions.scrollVert=function(b,c,d){b.css("overflow","hidden");d.before.push(function(b,c,d,e){if(d.rev)e=!e;a.fn.cycle.commonReset(b,c,d);d.cssBefore.top=e?1-c.cycleH:c.cycleH-1;d.animOut.top=e?b.cycleH:-b.cycleH});d.cssFirst.top=0;d.cssBefore.left=0;d.animIn.top=0;d.animOut.left=0};a.fn.cycle.transitions.slideX=function(b,c,d){d.before.push(function(b,c,d){a(d.elements).not(b).hide();a.fn.cycle.commonReset(b,c,d,false,true);d.animIn.width=c.cycleW});d.cssBefore.left=0;d.cssBefore.top=0;d.cssBefore.width=0;d.animIn.width="show";d.animOut.width=0};a.fn.cycle.transitions.slideY=function(b,c,d){d.before.push(function(b,c,d){a(d.elements).not(b).hide();a.fn.cycle.commonReset(b,c,d,true,false);d.animIn.height=c.cycleH});d.cssBefore.left=0;d.cssBefore.top=0;d.cssBefore.height=0;d.animIn.height="show";d.animOut.height=0};a.fn.cycle.transitions.shuffle=function(b,c,d){var e,f=b.css("overflow","visible").width();c.css({left:0,top:0});d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,true,true,true)});if(!d.speedAdjusted){d.speed=d.speed/2;d.speedAdjusted=true}d.random=0;d.shuffle=d.shuffle||{left:-f,top:15};d.els=[];for(e=0;e<c.length;e++)d.els.push(c[e]);for(e=0;e<d.currSlide;e++)d.els.push(d.els.shift());d.fxFn=function(b,c,d,e,f){if(d.rev)f=!f;var g=f?a(b):a(c);a(c).css(d.cssBefore);var h=d.slideCount;g.animate(d.shuffle,d.speedIn,d.easeIn,function(){var c=a.fn.cycle.hopsFromLast(d,f);for(var i=0;i<c;i++)f?d.els.push(d.els.shift()):d.els.unshift(d.els.pop());if(f){for(var j=0,k=d.els.length;j<k;j++)a(d.els[j]).css("z-index",k-j+h)}else{var l=a(b).css("z-index");g.css("z-index",parseInt(l,10)+1+h)}g.animate({left:0,top:0},d.speedOut,d.easeOut,function(){a(f?this:b).hide();if(e)e()})})};a.extend(d.cssBefore,{display:"block",opacity:1,top:0,left:0})};a.fn.cycle.transitions.turnUp=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,true,false);d.cssBefore.top=c.cycleH;d.animIn.height=c.cycleH;d.animOut.width=c.cycleW});d.cssFirst.top=0;d.cssBefore.left=0;d.cssBefore.height=0;d.animIn.top=0;d.animOut.height=0};a.fn.cycle.transitions.turnDown=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,true,false);d.animIn.height=c.cycleH;d.animOut.top=b.cycleH});d.cssFirst.top=0;d.cssBefore.left=0;d.cssBefore.top=0;d.cssBefore.height=0;d.animOut.height=0};a.fn.cycle.transitions.turnLeft=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,false,true);d.cssBefore.left=c.cycleW;d.animIn.width=c.cycleW});d.cssBefore.top=0;d.cssBefore.width=0;d.animIn.left=0;d.animOut.width=0};a.fn.cycle.transitions.turnRight=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,false,true);d.animIn.width=c.cycleW;d.animOut.left=b.cycleW});a.extend(d.cssBefore,{top:0,left:0,width:0});d.animIn.left=0;d.animOut.width=0};a.fn.cycle.transitions.zoom=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,false,false,true);d.cssBefore.top=c.cycleH/2;d.cssBefore.left=c.cycleW/2;a.extend(d.animIn,{top:0,left:0,width:c.cycleW,height:c.cycleH});a.extend(d.animOut,{width:0,height:0,top:b.cycleH/2,left:b.cycleW/2})});d.cssFirst.top=0;d.cssFirst.left=0;d.cssBefore.width=0;d.cssBefore.height=0};a.fn.cycle.transitions.fadeZoom=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,false,false);d.cssBefore.left=c.cycleW/2;d.cssBefore.top=c.cycleH/2;a.extend(d.animIn,{top:0,left:0,width:c.cycleW,height:c.cycleH})});d.cssBefore.width=0;d.cssBefore.height=0;d.animOut.opacity=0};a.fn.cycle.transitions.blindX=function(b,c,d){var e=b.css("overflow","hidden").width();d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d);d.animIn.width=c.cycleW;d.animOut.left=b.cycleW});d.cssBefore.left=e;d.cssBefore.top=0;d.animIn.left=0;d.animOut.left=e};a.fn.cycle.transitions.blindY=function(b,c,d){var e=b.css("overflow","hidden").height();d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d);d.animIn.height=c.cycleH;d.animOut.top=b.cycleH});d.cssBefore.top=e;d.cssBefore.left=0;d.animIn.top=0;d.animOut.top=e};a.fn.cycle.transitions.blindZ=function(b,c,d){var e=b.css("overflow","hidden").height();var f=b.width();d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d);d.animIn.height=c.cycleH;d.animOut.top=b.cycleH});d.cssBefore.top=e;d.cssBefore.left=f;d.animIn.top=0;d.animIn.left=0;d.animOut.top=e;d.animOut.left=f};a.fn.cycle.transitions.growX=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,false,true);d.cssBefore.left=this.cycleW/2;d.animIn.left=0;d.animIn.width=this.cycleW;d.animOut.left=0});d.cssBefore.top=0;d.cssBefore.width=0};a.fn.cycle.transitions.growY=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,true,false);d.cssBefore.top=this.cycleH/2;d.animIn.top=0;d.animIn.height=this.cycleH;d.animOut.top=0});d.cssBefore.height=0;d.cssBefore.left=0};a.fn.cycle.transitions.curtainX=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,false,true,true);d.cssBefore.left=c.cycleW/2;d.animIn.left=0;d.animIn.width=this.cycleW;d.animOut.left=b.cycleW/2;d.animOut.width=0});d.cssBefore.top=0;d.cssBefore.width=0};a.fn.cycle.transitions.curtainY=function(b,c,d){d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,true,false,true);d.cssBefore.top=c.cycleH/2;d.animIn.top=0;d.animIn.height=c.cycleH;d.animOut.top=b.cycleH/2;d.animOut.height=0});d.cssBefore.height=0;d.cssBefore.left=0};a.fn.cycle.transitions.cover=function(b,c,d){var e=d.direction||"left";var f=b.css("overflow","hidden").width();var g=b.height();d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d);if(e=="right")d.cssBefore.left=-f;else if(e=="up")d.cssBefore.top=g;else if(e=="down")d.cssBefore.top=-g;else d.cssBefore.left=f});d.animIn.left=0;d.animIn.top=0;d.cssBefore.top=0;d.cssBefore.left=0};a.fn.cycle.transitions.uncover=function(b,c,d){var e=d.direction||"left";var f=b.css("overflow","hidden").width();var g=b.height();d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,true,true,true);if(e=="right")d.animOut.left=f;else if(e=="up")d.animOut.top=-g;else if(e=="down")d.animOut.top=g;else d.animOut.left=-f});d.animIn.left=0;d.animIn.top=0;d.cssBefore.top=0;d.cssBefore.left=0};a.fn.cycle.transitions.toss=function(b,c,d){var e=b.css("overflow","visible").width();var f=b.height();d.before.push(function(b,c,d){a.fn.cycle.commonReset(b,c,d,true,true,true);if(!d.animOut.left&&!d.animOut.top)a.extend(d.animOut,{left:e*2,top:-f/2,opacity:0});else d.animOut.opacity=0});d.cssBefore.left=0;d.cssBefore.top=0;d.animIn.left=0};a.fn.cycle.transitions.wipe=function(b,c,d){var e=b.css("overflow","hidden").width();var f=b.height();d.cssBefore=d.cssBefore||{};var g;if(d.clip){if(/l2r/.test(d.clip))g="rect(0px 0px "+f+"px 0px)";else if(/r2l/.test(d.clip))g="rect(0px "+e+"px "+f+"px "+e+"px)";else if(/t2b/.test(d.clip))g="rect(0px "+e+"px 0px 0px)";else if(/b2t/.test(d.clip))g="rect("+f+"px "+e+"px "+f+"px 0px)";else if(/zoom/.test(d.clip)){var h=parseInt(f/2,10);var i=parseInt(e/2,10);g="rect("+h+"px "+i+"px "+h+"px "+i+"px)"}}d.cssBefore.clip=d.cssBefore.clip||g||"rect(0px 0px 0px 0px)";var j=d.cssBefore.clip.match(/(\d+)/g);var k=parseInt(j[0],10),l=parseInt(j[1],10),m=parseInt(j[2],10),n=parseInt(j[3],10);d.before.push(function(b,c,d){if(b==c)return;var g=a(b),h=a(c);a.fn.cycle.commonReset(b,c,d,true,true,false);d.cssAfter.display="block";var i=1,j=parseInt(d.speedIn/13,10)-1;(function o(){var a=k?k-parseInt(i*(k/j),10):0;var b=n?n-parseInt(i*(n/j),10):0;var c=m<f?m+parseInt(i*((f-m)/j||1),10):f;var d=l<e?l+parseInt(i*((e-l)/j||1),10):e;h.css({clip:"rect("+a+"px "+d+"px "+c+"px "+b+"px)"});i++<=j?setTimeout(o,13):g.css("display","none")})()});a.extend(d.cssBefore,{display:"block",opacity:1,top:0,left:0});d.animIn={left:0};d.animOut={left:0}}})(jQuery)
 
js/ngg.js DELETED
@@ -1,188 +0,0 @@
1
- jQuery("document").ready(function(){
2
- // register ajax gallery-navigation listeners
3
- jQuery("a.page-numbers").click(function(e) {
4
- return ngg_ajax_navigation(e, this);
5
- });
6
- jQuery("a.prev").click(function(e) {
7
- return ngg_ajax_navigation(e, this);
8
- });
9
- jQuery("a.next").click(function(e) {
10
- return ngg_ajax_navigation(e, this);
11
- });
12
-
13
- // register ajax browser-navigation listeners
14
- jQuery("a.ngg-browser-next").click(function(e) {
15
- return ngg_ajax_browser_navigation(e, this);
16
- });
17
- jQuery("a.ngg-browser-prev").click(function(e) {
18
- return ngg_ajax_browser_navigation(e, this);
19
- });
20
- });
21
-
22
- function ngg_ajax_navigation(e, obj) {
23
- // try to find page number
24
- var pageNumber = 0;
25
- if (jQuery(obj).hasClass("page-numbers")) {
26
- pageNumber = jQuery(obj).contents()[0].data;
27
- } else if (jQuery(obj).hasClass("prev")) {
28
- pageNumber = jQuery(obj).attr("id").substr(9);
29
- } else if (jQuery(obj).hasClass("next")) {
30
- pageNumber = jQuery(obj).attr("id").substr(9);
31
- }
32
-
33
- // try to find gallery number by checking the parents ID until we find a matching one
34
- var currentNode = obj.parentNode;
35
- while (null != currentNode.parentNode && !jQuery.nodeName(currentNode.parentNode, "body") && "ngg-gallery-" != jQuery(currentNode.parentNode).attr("id").substring(0, 12)) {
36
- currentNode = currentNode.parentNode;
37
- }
38
-
39
- if (jQuery(currentNode.parentNode).attr("id")) {
40
- var gallery = jQuery(currentNode.parentNode);
41
-
42
- // we found a gallery, let's extract the post id & gallery id
43
- var payload = gallery.attr("id").substring(12);
44
- var separatorPosition = parseInt(payload.indexOf("-"));
45
-
46
- var galleryId = payload.substr(0, separatorPosition);
47
- var postId = payload.substr(separatorPosition + 1);
48
-
49
- if ( (galleryId.length == 0) || (postId.length == 0) ) {
50
- return true;
51
- }
52
-
53
- ngg_show_loading(e);
54
-
55
- // load gallery content
56
- jQuery.get(ngg_ajax.callback, {p: postId, galleryid: galleryId, nggpage: pageNumber, type: "gallery"}, function (data, textStatus) {
57
-
58
- // delete old content
59
- gallery.children().remove();
60
-
61
- // add new content
62
- gallery.replaceWith(data);
63
-
64
- // add ajax-navigation, again
65
- jQuery("document").ready(function(){
66
- // remove old listeners to avoid double-clicks
67
- jQuery("a.page-numbers").unbind("click");
68
- jQuery("a.prev").unbind("click");
69
- jQuery("a.next").unbind("click");
70
-
71
- // add shutter-listeners again
72
- shutterReloaded.init('sh');
73
-
74
- jQuery("a.page-numbers").click(function(e) {
75
- return ngg_ajax_navigation(e, this);
76
- });
77
- jQuery("a.prev").click(function(e) {
78
- return ngg_ajax_navigation(e, this);
79
- });
80
- jQuery("a.next").click(function(e) {
81
- return ngg_ajax_navigation(e, this);
82
- });
83
-
84
- ngg_remove_loading();
85
- });
86
- });
87
-
88
- // deactivate HTML link
89
- return false;
90
- }
91
-
92
- // an error occurred, use traditional HTML link
93
- return true;
94
- };
95
-
96
- function ngg_ajax_browser_navigation(e, obj) {
97
-
98
-
99
- // try to find gallery number
100
- if ("ngg-prev-" == jQuery(obj).attr("id").substr(0, 9) || "ngg-next-" == jQuery(obj).attr("id").substr(0, 9)) {
101
-
102
- // extract the image-id
103
- var imageNumber = jQuery(obj).attr("id").substr(9);
104
-
105
- // find the image-browser-container
106
- var currentNode = obj;
107
- while (null != currentNode.parentNode && !jQuery.nodeName(currentNode.parentNode, "body") && !jQuery(currentNode.parentNode).hasClass("ngg-imagebrowser")) {
108
- currentNode = currentNode.parentNode;
109
- }
110
-
111
- if (jQuery(currentNode.parentNode).hasClass("ngg-imagebrowser")) {
112
- var gallery = jQuery(currentNode.parentNode);
113
-
114
- // let's extract the post id & gallery id
115
- var payload = gallery.attr("id").substring(17);
116
- var separatorPosition = parseInt(payload.indexOf("-"));
117
-
118
- var galleryId = payload.substr(0, separatorPosition);
119
- var postId = payload.substr(separatorPosition + 1);
120
-
121
- if ( (galleryId.length == 0) || (postId.length == 0) ) {
122
- return true;
123
- }
124
-
125
- ngg_show_loading(e);
126
-
127
- // get content
128
- jQuery.get(ngg_ajax.callback, {p: postId, galleryid: galleryId, pid: imageNumber, type: "browser"}, function (data, textStatus) {
129
- // delete old content
130
- gallery.children().remove();
131
-
132
- // add new content
133
- gallery.replaceWith(data);
134
-
135
- // add ajax-navigation, again
136
- jQuery("document").ready(function(){
137
- // remove old listeners to avoid double-clicks
138
- jQuery("a.ngg-browser-next").unbind("click");
139
- jQuery("a.ngg-browser-prev").unbind("click");
140
-
141
- // add shutter-listeners again
142
- shutterReloaded.init('sh');
143
-
144
- // register ajax browser-navigation listeners
145
- jQuery("a.ngg-browser-next").click(function(e) {
146
- return ngg_ajax_browser_navigation(e, this);
147
- });
148
- jQuery("a.ngg-browser-prev").click(function(e) {
149
- return ngg_ajax_browser_navigation(e, this);
150
- });
151
-
152
- ngg_remove_loading();
153
- });
154
- });
155
-
156
- // deactivate HTML link
157
- return false;
158
- }
159
- }
160
-
161
- return true;
162
- }
163
-
164
- var loadingImage;
165
- function ngg_show_loading(obj) {
166
- loadingImage = jQuery(document.createElement("img")).attr("src", ngg_ajax.path + "images/ajax-loader.gif").attr("alt", ngg_ajax.loading);
167
-
168
- jQuery("body").append(loadingImage);
169
-
170
- jQuery(loadingImage).css({
171
- position: "absolute",
172
- top: (obj.pageY + 15) + "px",
173
- left: (obj.pageX + 15) + "px"
174
- });
175
-
176
- jQuery(document).mousemove(function(e) {
177
- loadingImage.css({
178
- top: (e.pageY + 15) + "px",
179
- left: (e.pageX + 15) + "px"
180
- });
181
- });
182
- }
183
-
184
- function ngg_remove_loading() {
185
- jQuery(document).unbind("mousemove");
186
-
187
- jQuery(loadingImage).remove();
188
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/ngg.slideshow.js DELETED
@@ -1,138 +0,0 @@
1
- /*!
2
- * NextGEN Slideshow based on jQuery Cycle Plugin
3
- * Copyright (c) 2010-2012 Alex Rabe
4
- * Version: 1.0.6
5
- * Requires: jQuery v1.2.6 or later
6
- */
7
- jQuery.fn.nggSlideshow = function ( args ) {
8
-
9
- var defaults = { id: 1,
10
- width: 320,
11
- height: 240,
12
- fx: 'fade',
13
- domain: '',
14
- timeout: 5000 };
15
-
16
- var s = jQuery.extend( {}, defaults, args);
17
-
18
- var obj = this.selector;
19
- var stack = [];
20
- var url = s.domain + 'index.php?callback=json&api_key=true&format=json&method=gallery&id=' + s.id;
21
- /*
22
- the stackLength var will store stack length for ref - it is quicker to ref memory than make a call to find an obj property
23
- stack length is first collected in jQuery.getJSON(); stack length is auto-decremented in loadImage() + jCycle_onBefore()
24
- */
25
- var stackLength = 0;
26
-
27
- jQuery.getJSON(url, function(r){
28
-
29
- if (r.stat == "ok"){
30
-
31
- for (img in r.images) {
32
- var photo = r.images[img];
33
- //populate images into an array
34
- stack.push( decodeURI( photo['imageURL'] ) );
35
- }
36
- stackLength = stack.length;
37
- // init loading first 3 images (param 1 in func is first pass)
38
- loadImage(1);
39
- }
40
- });
41
-
42
- // load image and bind appendImage() to the img load - here we are making sure the loads do not get displaced
43
- function loadImage(num){
44
- // check that stack is not empty and we haven't alreay loaded 3 images
45
- if(stackLength > 0 && num <= 3) {
46
- var img = new Image();
47
- img.src = stack.shift();
48
- stackLength--;
49
- // wait to append image until the load is complete
50
- jQuery( img ).one('load', function() { appendImage(img, num); }).each(function(){
51
- // IE browser : in case it's already cached
52
- if(this.complete) jQuery(this).trigger('load');
53
- });
54
- }
55
- }
56
-
57
- // append image to obj
58
- function appendImage(img, num){
59
- // Hide them first, Cycle plugin will show them
60
- jQuery( img ).hide();
61
- // Add the image now and resize after loaded
62
- jQuery( obj ).append( imageResize(img, s.width , s.height) );
63
- // start slideshow with third image, load next image if not
64
- if (num == 3 || stackLength == 0 ) {
65
- startSlideshow();
66
- } else {
67
- loadImage(++num); // increase index and load next image
68
- }
69
-
70
- }
71
-
72
- function startSlideshow() {
73
-
74
- // hide the loader icon
75
- jQuery( obj + '-loader' ).empty().remove();
76
- // Start the slideshow
77
- jQuery(obj + ' img:first').fadeIn(1000, function() {
78
- // Start the cycle plugin
79
- jQuery( obj ).cycle( {
80
- fx: s.fx,
81
- containerResize: 1,
82
- fit: 1,
83
- timeout: s.timeout,
84
- next: obj,
85
- before: jCycle_onBefore
86
- });
87
- });
88
-
89
- }
90
-
91
- //Resize Image and keep ratio on client side, better move to server side later
92
- function imageResize(img, maxWidth , maxHeight) {
93
-
94
- // we need to wait until the image is loaded
95
- if ( !img.complete )
96
- jQuery( img ).bind('load', function() { imageResize(img, maxWidth , maxHeight) });
97
-
98
- // in some cases the image is not loaded, we can't resize them
99
- if (img.height == 0 || img.width == 0)
100
- return img;
101
-
102
- var width, height;
103
-
104
- if (img.width * maxHeight > img.height * maxWidth) {
105
- // img has a wider ratio than target size, make width fit
106
- if (img.width > maxWidth) {
107
- width = maxWidth;
108
- height = Math.round(img.height / img.width * maxWidth);
109
- }
110
- } else {
111
- // img has a less wide ratio than target size, make height fit
112
- if (img.height > maxHeight) {
113
- height = maxHeight;
114
- width = Math.round(img.width / img.height * maxHeight);
115
- }
116
- }
117
-
118
- jQuery( img ).css({
119
- 'height': height,
120
- 'width': width
121
- });
122
-
123
- return img;
124
- };
125
-
126
- // add images to slideshow step by step
127
- function jCycle_onBefore(curr, next, opts) {
128
- if (opts.addSlide)
129
- if (stackLength > 0){ // check that stack is not empty
130
- var img = new Image();
131
- img.src = stack.shift();
132
- stackLength--;
133
- jQuery( img ).bind('load', function() {
134
- opts.addSlide( imageResize(this, s.width , s.height) );
135
- });
136
- }
137
- };
138
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/ngg.slideshow.min.js DELETED
@@ -1 +0,0 @@
1
- jQuery.fn.nggSlideshow=function(args){var defaults={id:1,width:320,height:240,fx:'fade',domain:'',timeout:5000};var s=jQuery.extend({},defaults,args);var obj=this.selector;var stack=[];var url=s.domain+'index.php?callback=json&api_key=true&format=json&method=gallery&id='+s.id;var stackLength=0;jQuery.getJSON(url,function(r){if(r.stat=="ok"){for(img in r.images){var photo=r.images[img];stack.push(decodeURI(photo['imageURL']))}stackLength=stack.length;loadImage(1)}});function loadImage(num){if(stackLength>0&&num<=3){var img=new Image();img.src=stack.shift();stackLength--;jQuery(img).one('load',function(){appendImage(img,num)}).each(function(){if(this.complete)jQuery(this).trigger('load')})}}function appendImage(img,num){jQuery(img).hide();jQuery(obj).append(imageResize(img,s.width,s.height));if(num==3||stackLength==0){startSlideshow()}else{loadImage(++num)}}function startSlideshow(){jQuery(obj+'-loader').empty().remove();jQuery(obj+' img:first').fadeIn(1000,function(){jQuery(obj).cycle({fx:s.fx,containerResize:1,fit:1,timeout:s.timeout,next:obj,before:jCycle_onBefore})})}function imageResize(img,maxWidth,maxHeight){if(!img.complete)jQuery(img).bind('load',function(){imageResize(img,maxWidth,maxHeight)});if(img.height==0||img.width==0)return img;var width,height;if(img.width*maxHeight>img.height*maxWidth){if(img.width>maxWidth){width=maxWidth;height=Math.round(img.height/img.width*maxWidth)}}else{if(img.height>maxHeight){height=maxHeight;width=Math.round(img.width/img.height*maxHeight)}}jQuery(img).css({'height':height,'width':width});return img};function jCycle_onBefore(curr,next,opts){if(opts.addSlide)if(stackLength>0){var img=new Image();img.src=stack.shift();stackLength--;jQuery(img).bind('load',function(){opts.addSlide(imageResize(this,s.width,s.height))})}}}
 
lib/image.php DELETED
@@ -1,223 +0,0 @@
1
- <?php
2
- if ( !class_exists('nggImage') ) :
3
- /**
4
- * Image PHP class for the WordPress plugin NextGEN Gallery
5
- *
6
- * @author Alex Rabe
7
- *
8
- */
9
- class nggImage{
10
-
11
- /**** Public variables ****/
12
- var $errmsg = ''; // Error message to display, if any
13
- var $error = FALSE; // Error state
14
- var $imageURL = ''; // URL Path to the image
15
- var $thumbURL = ''; // URL Path to the thumbnail
16
- var $imagePath = ''; // Server Path to the image
17
- var $thumbPath = ''; // Server Path to the thumbnail
18
- var $href = ''; // A href link code
19
-
20
- // TODO: remove thumbPrefix and thumbFolder (constants)
21
- var $thumbPrefix = 'thumbs_'; // FolderPrefix to the thumbnail
22
- var $thumbFolder = '/thumbs/'; // Foldername to the thumbnail
23
-
24
- /**** Image Data ****/
25
- var $galleryid = 0; // Gallery ID
26
- var $pid = 0; // Image ID
27
- var $filename = ''; // Image filename
28
- var $description = ''; // Image description
29
- var $alttext = ''; // Image alttext
30
- var $imagedate = ''; // Image date/time
31
- var $exclude = ''; // Image exclude
32
- var $thumbcode = ''; // Image effect code
33
-
34
- /**** Gallery Data ****/
35
- var $name = ''; // Gallery name
36
- var $path = ''; // Gallery path
37
- var $title = ''; // Gallery title
38
- var $pageid = 0; // Gallery page ID
39
- var $previewpic = 0; // Gallery preview pic
40
-
41
- var $permalink = '';
42
- var $tags = '';
43
-
44
- /**
45
- * Constructor
46
- *
47
- * @param object $gallery The nggGallery object representing the gallery containing this image
48
- * @return void
49
- */
50
- function nggImage($gallery) {
51
-
52
- //This must be an object
53
- $gallery = (object) $gallery;
54
-
55
- // Build up the object
56
- foreach ($gallery as $key => $value)
57
- $this->$key = $value ;
58
-
59
- // Finish initialisation
60
- $this->name = $gallery->name;
61
- $this->path = $gallery->path;
62
- $this->title = stripslashes($gallery->title);
63
- $this->pageid = $gallery->pageid;
64
- $this->previewpic = $gallery->previewpic;
65
-
66
- // set urls and paths
67
- $this->imageURL = site_url() . '/' . $this->path . '/' . $this->filename;
68
- $this->thumbURL = site_url() . '/' . $this->path . '/thumbs/thumbs_' . $this->filename;
69
- $this->imagePath = WINABSPATH.$this->path . '/' . $this->filename;
70
- $this->thumbPath = WINABSPATH.$this->path . '/thumbs/thumbs_' . $this->filename;
71
- $this->meta_data = unserialize($this->meta_data);
72
- $this->imageHTML = $this->get_href_link();
73
- $this->thumbHTML = $this->get_href_thumb_link();
74
-
75
- do_action_ref_array('ngg_get_image', array(&$this));
76
-
77
- // Note wp_cache_add will increase memory needs (4-8 kb)
78
- //wp_cache_add($this->pid, $this, 'ngg_image');
79
- // Get tags only if necessary
80
- unset($this->tags);
81
- }
82
-
83
- /**
84
- * Get the thumbnail code (to add effects on thumbnail click)
85
- *
86
- * Applies the filter 'ngg_get_thumbcode'
87
- */
88
- function get_thumbcode($galleryname = '') {
89
-
90
- // clean up the name
91
- $galleryname = sanitize_title( $galleryname );
92
-
93
- // read the option setting
94
- $ngg_options = get_option('ngg_options');
95
-
96
- // get the effect code
97
- if ($ngg_options['thumbEffect'] != "none")
98
- $this->thumbcode = stripslashes($ngg_options['thumbCode']);
99
-
100
- // for highslide to a different approach
101
- if ($ngg_options['thumbEffect'] == "highslide")
102
- $this->thumbcode = str_replace("%GALLERY_NAME%", "'".$galleryname."'", $this->thumbcode);
103
- else
104
- $this->thumbcode = str_replace("%GALLERY_NAME%", $galleryname, $this->thumbcode);
105
-
106
- return apply_filters('ngg_get_thumbcode', $this->thumbcode, $this);
107
- }
108
-
109
- function get_href_link() {
110
- // create the a href link from the picture
111
- $this->href = "\n".'<a href="'.$this->imageURL.'" title="'.htmlspecialchars( stripslashes( nggGallery::i18n($this->description, 'pic_' . $this->pid . '_description') ) ).'" '.$this->get_thumbcode($this->name).'>'."\n\t";
112
- $this->href .= '<img alt="'.$this->alttext.'" src="'.$this->imageURL.'"/>'."\n".'</a>'."\n";
113
-
114
- return $this->href;
115
- }
116
-
117
- function get_href_thumb_link() {
118
- // create the a href link with the thumbanil
119
- $this->href = "\n".'<a href="'.$this->imageURL.'" title="'.htmlspecialchars( stripslashes( nggGallery::i18n($this->description, 'pic_' . $this->pid . '_description') ) ).'" '.$this->get_thumbcode($this->name).'>'."\n\t";
120
- $this->href .= '<img alt="'.$this->alttext.'" src="'.$this->thumbURL.'"/>'."\n".'</a>'."\n";
121
-
122
- return $this->href;
123
- }
124
-
125
- /**
126
- * This function creates a cache for all singlepics to reduce the CPU load
127
- *
128
- * @param int $width
129
- * @param int $height
130
- * @param string $mode could be watermark | web20 | crop
131
- * @return the url for the image or false if failed
132
- */
133
- function cached_singlepic_file($width = '', $height = '', $mode = '' ) {
134
-
135
- $ngg_options = get_option('ngg_options');
136
-
137
- include_once( nggGallery::graphic_library() );
138
-
139
- // cache filename should be unique
140
- $cachename = $this->pid . '_' . $mode . '_'. $width . 'x' . $height . '_' . $this->filename;
141
- $cachefolder = WINABSPATH .$ngg_options['gallerypath'] . 'cache/';
142
- $cached_url = site_url() . '/' . $ngg_options['gallerypath'] . 'cache/' . $cachename;
143
- $cached_file = $cachefolder . $cachename;
144
-
145
- // check first for the file
146
- if ( file_exists($cached_file) )
147
- return $cached_url;
148
-
149
- // create folder if needed
150
- if ( !file_exists($cachefolder) )
151
- if ( !wp_mkdir_p($cachefolder) )
152
- return false;
153
-
154
- $thumb = new ngg_Thumbnail($this->imagePath, TRUE);
155
- // echo $thumb->errmsg;
156
-
157
- if (!$thumb->error) {
158
- if ($mode == 'crop') {
159
- // calculates the new dimentions for a downsampled image
160
- list ( $ratio_w, $ratio_h ) = wp_constrain_dimensions($thumb->currentDimensions['width'], $thumb->currentDimensions['height'], $width, $height);
161
- // check ratio to decide which side should be resized
162
- ( $ratio_h < $height || $ratio_w == $width ) ? $thumb->resize(0, $height) : $thumb->resize($width, 0);
163
- // get the best start postion to crop from the middle
164
- $ypos = ($thumb->currentDimensions['height'] - $height) / 2;
165
- $thumb->crop(0, $ypos, $width, $height);
166
- } else
167
- $thumb->resize($width , $height);
168
-
169
- if ($mode == 'watermark') {
170
- if ($ngg_options['wmType'] == 'image') {
171
- $thumb->watermarkImgPath = $ngg_options['wmPath'];
172
- $thumb->watermarkImage($ngg_options['wmPos'], $ngg_options['wmXpos'], $ngg_options['wmYpos']);
173
- }
174
- if ($ngg_options['wmType'] == 'text') {
175
- $thumb->watermarkText = $ngg_options['wmText'];
176
- $thumb->watermarkCreateText($ngg_options['wmColor'], $ngg_options['wmFont'], $ngg_options['wmSize'], $ngg_options['wmOpaque']);
177
- $thumb->watermarkImage($ngg_options['wmPos'], $ngg_options['wmXpos'], $ngg_options['wmYpos']);
178
- }
179
- }
180
-
181
- if ($mode == 'web20') {
182
- $thumb->createReflection(40,40,50,false,'#a4a4a4');
183
- }
184
-
185
- // save the new cache picture
186
- $thumb->save($cached_file,$ngg_options['imgQuality']);
187
- }
188
- $thumb->destruct();
189
-
190
- // check again for the file
191
- if (file_exists($cached_file))
192
- return $cached_url;
193
-
194
- return false;
195
- }
196
-
197
- /**
198
- * Get the tags associated to this image
199
- */
200
- function get_tags() {
201
- if ( !isset($this->tags) )
202
- $this->tags = wp_get_object_terms($this->pid, 'ngg_tag', 'fields=all');
203
-
204
- return $this->tags;
205
- }
206
-
207
- /**
208
- * Get the permalink to the image
209
- * TODO Get a permalink to a page presenting the image
210
- */
211
- function get_permalink() {
212
- if ($this->permalink == '')
213
- $this->permalink = $this->imageURL;
214
-
215
- return $this->permalink;
216
- }
217
-
218
- function __destruct() {
219
-
220
- }
221
- }
222
- endif;
223
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/shortcodes.php DELETED
@@ -1,395 +0,0 @@
1
- <?php
2
- /**
3
- * @author Alex Rabe, Vincent Prat
4
- *
5
- * @since 1.0.0
6
- * @description Use WordPress Shortcode API for more features
7
- * @Docs http://codex.wordpress.org/Shortcode_API
8
- */
9
-
10
- class NextGEN_shortcodes {
11
-
12
- function __construct()
13
- {
14
- //Long posts should require a higher limit, see http://core.trac.wordpress.org/ticket/8553
15
- @ini_set('pcre.backtrack_limit', 500000);
16
-
17
- // convert the old shortcode
18
- add_filter('the_content', array(&$this, 'convert_shortcode'));
19
- add_filter('loop_start', array(&$this, 'reset_globals'));
20
-
21
- // do_shortcode on the_excerpt could causes several unwanted output. Uncomment it on your own risk
22
- // add_filter('the_excerpt', array(&$this, 'convert_shortcode'));
23
- // add_filter('the_excerpt', 'do_shortcode', 11);
24
-
25
- add_shortcode( 'singlepic', array(&$this, 'show_singlepic' ) );
26
- add_shortcode( 'album', array(&$this, 'show_album' ) );
27
- add_shortcode( 'nggalbum', array(&$this, 'show_album' ) );
28
- add_shortcode( 'nggallery', array(&$this, 'show_gallery') );
29
- add_shortcode( 'imagebrowser', array(&$this, 'show_imagebrowser' ) );
30
- add_shortcode( 'slideshow', array(&$this, 'show_slideshow' ) );
31
- add_shortcode( 'nggtags', array(&$this, 'show_tags' ) );
32
- add_shortcode( 'thumb', array(&$this, 'show_thumbs' ) );
33
- add_shortcode( 'random', array(&$this, 'show_random' ) );
34
- add_shortcode( 'recent', array(&$this, 'show_recent' ) );
35
- add_shortcode( 'tagcloud', array(&$this, 'show_tagcloud' ) );
36
- }
37
-
38
- function reset_globals()
39
- {
40
- unset($GLOBALS['subalbum']);
41
- unset($GLOBALS['nggShowGallery']);
42
- }
43
-
44
- /**
45
- * NextGEN_shortcodes::convert_shortcode()
46
- * convert old shortcodes to the new WordPress core style
47
- * [gallery=1] ->> [nggallery id=1]
48
- *
49
- * @param string $content Content to search for shortcodes
50
- * @return string Content with new shortcodes.
51
- */
52
- function convert_shortcode($content) {
53
-
54
- $ngg_options = nggGallery::get_option('ngg_options');
55
-
56
- if ( stristr( $content, '[singlepic' )) {
57
- $search = "@\[singlepic=(\d+)(|,\d+|,)(|,\d+|,)(|,watermark|,web20|,)(|,right|,center|,left|,)\]@i";
58
- if (preg_match_all($search, $content, $matches, PREG_SET_ORDER)) {
59
-
60
- foreach ($matches as $match) {
61
- // remove the comma
62
- $match[2] = ltrim($match[2], ',');
63
- $match[3] = ltrim($match[3], ',');
64
- $match[4] = ltrim($match[4], ',');
65
- $match[5] = ltrim($match[5], ',');
66
- $replace = "[singlepic id=\"{$match[1]}\" w=\"{$match[2]}\" h=\"{$match[3]}\" mode=\"{$match[4]}\" float=\"{$match[5]}\" ]";
67
- $content = str_replace ($match[0], $replace, $content);
68
- }
69
- }
70
- }
71
-
72
- if ( stristr( $content, '[album' )) {
73
- $search = "@(?:<p>)*\s*\[album\s*=\s*(\w+|^\+)(|,extend|,compact)\]\s*(?:</p>)*@i";
74
- if (preg_match_all($search, $content, $matches, PREG_SET_ORDER)) {
75
-
76
- foreach ($matches as $match) {
77
- // remove the comma
78
- $match[2] = ltrim($match[2],',');
79
- $replace = "[album id=\"{$match[1]}\" template=\"{$match[2]}\"]";
80
- $content = str_replace ($match[0], $replace, $content);
81
- }
82
- }
83
- }
84
-
85
- if ( stristr( $content, '[gallery' )) {
86
- $search = "@(?:<p>)*\s*\[gallery\s*=\s*(\w+|^\+)\]\s*(?:</p>)*@i";
87
- if (preg_match_all($search, $content, $matches, PREG_SET_ORDER)) {
88
-
89
- foreach ($matches as $match) {
90
- $replace = "[nggallery id=\"{$match[1]}\"]";
91
- $content = str_replace ($match[0], $replace, $content);
92
- }
93
- }
94
- }
95
-
96
- if ( stristr( $content, '[imagebrowser' )) {
97
- $search = "@(?:<p>)*\s*\[imagebrowser\s*=\s*(\w+|^\+)\]\s*(?:</p>)*@i";
98
- if (preg_match_all($search, $content, $matches, PREG_SET_ORDER)) {
99
-
100
- foreach ($matches as $match) {
101
- $replace = "[imagebrowser id=\"{$match[1]}\"]";
102
- $content = str_replace ($match[0], $replace, $content);
103
- }
104
- }
105
- }
106
-
107
- if ( stristr( $content, '[slideshow' )) {
108
- $search = "@(?:<p>)*\s*\[slideshow\s*=\s*(\w+|^\+)(|,(\d+)|,)(|,(\d+))\]\s*(?:</p>)*@i";
109
- if (preg_match_all($search, $content, $matches, PREG_SET_ORDER)) {
110
-
111
- foreach ($matches as $match) {
112
- // remove the comma
113
- $match[3] = ltrim($match[3],',');
114
- $match[5] = ltrim($match[5],',');
115
- $replace = "[slideshow id=\"{$match[1]}\" w=\"{$match[3]}\" h=\"{$match[5]}\"]";
116
- $content = str_replace ($match[0], $replace, $content);
117
- }
118
- }
119
- }
120
-
121
- if ( stristr( $content, '[tags' )) {
122
- $search = "@(?:<p>)*\s*\[tags\s*=\s*(.*?)\s*\]\s*(?:</p>)*@i";
123
- if (preg_match_all($search, $content, $matches, PREG_SET_ORDER)) {
124
-
125
- foreach ($matches as $match) {
126
- $replace = "[nggtags gallery=\"{$match[1]}\"]";
127
- $content = str_replace ($match[0], $replace, $content);
128
- }
129
- }
130
- }
131
-
132
- if ( stristr( $content, '[albumtags' )) {
133
- $search = "@(?:<p>)*\s*\[albumtags\s*=\s*(.*?)\s*\]\s*(?:</p>)*@i";
134
- if (preg_match_all($search, $content, $matches, PREG_SET_ORDER)) {
135
-
136
- foreach ($matches as $match) {
137
- $replace = "[nggtags album=\"{$match[1]}\"]";
138
- $content = str_replace ($match[0], $replace, $content);
139
- }
140
- }
141
- }
142
-
143
- // attach related images based on category or tags
144
- if ($ngg_options['activateTags'])
145
- $content .= nggShowRelatedImages();
146
-
147
- return $content;
148
- }
149
-
150
- /**
151
- * Function to show a single picture:
152
- *
153
- * [singlepic id="10" float="none|left|right" width="" height="" mode="none|watermark|web20" link="url" "template="filename" /]
154
- *
155
- * where
156
- * - id is one picture id
157
- * - float is the CSS float property to apply to the thumbnail
158
- * - width is width of the single picture you want to show (original width if this parameter is missing)
159
- * - height is height of the single picture you want to show (original height if this parameter is missing)
160
- * - mode is one of none, watermark or web20 (transformation applied to the picture)
161
- * - link is optional and could link to a other url instead the full image
162
- * - template is a name for a gallery template, which is located in themefolder/nggallery or plugins/nextgen-gallery/view
163
- *
164
- * If the tag contains some text, this will be inserted as an additional caption to the picture too. Example:
165
- * [singlepic id="10"]This is an additional caption[/singlepic]
166
- * This tag will show a picture with under it two HTML span elements containing respectively the alttext of the picture
167
- * and the additional caption specified in the tag.
168
- *
169
- * @param array $atts
170
- * @param string $caption text
171
- * @return the content
172
- */
173
- function show_singlepic( $atts, $content = '' ) {
174
-
175
- extract(shortcode_atts(array(
176
- 'id' => 0,
177
- 'w' => '',
178
- 'h' => '',
179
- 'mode' => '',
180
- 'float' => '',
181
- 'link' => '',
182
- 'template' => ''
183
- ), $atts ));
184
-
185
- $out = nggSinglePicture($id, $w, $h, $mode, $float, $template, $content, $link);
186
-
187
- return $out;
188
- }
189
-
190
- /**
191
- * Function to show a collection of galleries:
192
- *
193
- * [album id="1,2,4,5,..." template="filename" gallery="filename" /]
194
- * where
195
- * - id of a album
196
- * - template is a name for a album template, which is located in themefolder/nggallery or plugins/nextgen-gallery/view
197
- * - template is a name for a gallery template, which is located in themefolder/nggallery or plugins/nextgen-gallery/view
198
- *
199
- * @param array $atts
200
- * @return the_content
201
- */
202
- function show_album( $atts ) {
203
-
204
- extract(shortcode_atts(array(
205
- 'id' => 0,
206
- 'template' => 'extend',
207
- 'gallery' => ''
208
- ), $atts ));
209
-
210
- $out = nggShowAlbum($id, $template, $gallery);
211
-
212
- return $out;
213
- }
214
- /**
215
- * Function to show a thumbnail or a set of thumbnails with shortcode of type:
216
- *
217
- * [gallery id="1,2,4,5,..." template="filename" images="number of images per page" /]
218
- * where
219
- * - id of a gallery
220
- * - images is the number of images per page (optional), 0 will show all images
221
- * - template is a name for a gallery template, which is located in themefolder/nggallery or plugins/nextgen-gallery/view
222
- *
223
- * @param array $atts
224
- * @return the_content
225
- */
226
- function show_gallery( $atts ) {
227
-
228
- global $wpdb;
229
-
230
- extract(shortcode_atts(array(
231
- 'id' => 0,
232
- 'template' => '',
233
- 'images' => false
234
- ), $atts ));
235
-
236
- // backward compat for user which uses the name instead, still deprecated
237
- if( !is_numeric($id) )
238
- $id = $wpdb->get_var( $wpdb->prepare ("SELECT gid FROM $wpdb->nggallery WHERE name = '%s' ", $id) );
239
-
240
- $out = nggShowGallery( $id, $template, $images );
241
-
242
- return $out;
243
- }
244
-
245
- function show_imagebrowser( $atts ) {
246
-
247
- global $wpdb;
248
-
249
- extract(shortcode_atts(array(
250
- 'id' => 0,
251
- 'template' => ''
252
- ), $atts ));
253
-
254
- $out = nggShowImageBrowser($id, $template);
255
-
256
- return $out;
257
- }
258
-
259
- function show_slideshow( $atts ) {
260
-
261
- global $wpdb;
262
-
263
- extract(shortcode_atts(array(
264
- 'id' => 0,
265
- 'w' => '',
266
- 'h' => ''
267
- ), $atts ));
268
-
269
- if( !is_numeric($id) )
270
- $id = $wpdb->get_var( $wpdb->prepare ("SELECT gid FROM $wpdb->nggallery WHERE name = '%s' ", $id) );
271
-
272
- if( !empty( $id ) )
273
- $out = nggShowSlideshow($id, $w, $h);
274
- else
275
- $out = __('[Gallery not found]','nggallery');
276
-
277
- return $out;
278
- }
279
-
280
- function show_tags( $atts ) {
281
-
282
- extract(shortcode_atts(array(
283
- 'gallery' => '',
284
- 'album' => ''
285
- ), $atts ));
286
-
287
- if ( !empty($album) )
288
- $out = nggShowAlbumTags($album);
289
- else
290
- $out = nggShowGalleryTags($gallery);
291
-
292
- return $out;
293
- }
294
-
295
- /**
296
- * Function to show a thumbnail or a set of thumbnails with shortcode of type:
297
- *
298
- * [thumb id="1,2,4,5,..." template="filename" /]
299
- * where
300
- * - id is one or more picture ids
301
- * - template is a name for a gallery template, which is located in themefolder/nggallery or plugins/nextgen-gallery/view
302
- *
303
- * @param array $atts
304
- * @return the_content
305
- */
306
- function show_thumbs( $atts ) {
307
-
308
- extract(shortcode_atts(array(
309
- 'id' => '',
310
- 'template' => ''
311
- ), $atts));
312
-
313
- // make an array out of the ids
314
- $pids = explode( ',', $id );
315
-
316
- // Some error checks
317
- if ( count($pids) == 0 )
318
- return __('[Pictures not found]','nggallery');
319
-
320
- $picturelist = nggdb::find_images_in_list( $pids );
321
-
322
- // show gallery
323
- if ( is_array($picturelist) )
324
- $out = nggCreateGallery($picturelist, false, $template);
325
-
326
- return $out;
327
- }
328
-
329
- /**
330
- * Function to show a gallery of random or the most recent images with shortcode of type:
331
- *
332
- * [random max="7" template="filename" id="2" /]
333
- * [recent max="7" template="filename" id="3" mode="date" /]
334
- * where
335
- * - max is the maximum number of random or recent images to show
336
- * - template is a name for a gallery template, which is located in themefolder/nggallery or plugins/nextgen-gallery/view
337
- * - id is the gallery id, if the recent/random pictures shall be taken from a specific gallery only
338
- * - mode is either "id" (which takes the latest additions to the databse, default)
339
- * or "date" (which takes the latest pictures by EXIF date)
340
- * or "sort" (which takes the pictures by user sort order)
341
- *
342
- * @param array $atts
343
- * @return the_content
344
- */
345
- function show_random( $atts ) {
346
-
347
- extract(shortcode_atts(array(
348
- 'max' => '',
349
- 'template' => '',
350
- 'id' => 0
351
- ), $atts));
352
-
353
- $out = nggShowRandomRecent('random', $max, $template, $id);
354
-
355
- return $out;
356
- }
357
-
358
- function show_recent( $atts ) {
359
-
360
- extract(shortcode_atts(array(
361
- 'max' => '',
362
- 'template' => '',
363
- 'id' => 0,
364
- 'mode' => 'id'
365
- ), $atts));
366
-
367
- $out = nggShowRandomRecent($mode, $max, $template, $id);
368
-
369
- return $out;
370
- }
371
-
372
- /**
373
- * Shortcode for the Image tag cloud
374
- * Usage : [tagcloud template="filename" /]
375
- *
376
- * @param array $atts
377
- * @return the content
378
- */
379
- function show_tagcloud( $atts ) {
380
-
381
- extract(shortcode_atts(array(
382
- 'template' => ''
383
- ), $atts));
384
-
385
- $out = nggTagCloud( '', $template );
386
-
387
- return $out;
388
- }
389
-
390
- }
391
-
392
- // let's use it
393
- $nggShortcodes = new NextGEN_Shortcodes;
394
-
395
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
license.txt ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ <one line to give the program's name and a brief idea of what it does.>
294
+ Copyright (C) <year> <name of author>
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ <signature of Ty Coon>, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
340
+
nggallery.php CHANGED
@@ -1,593 +1,488 @@
1
  <?php
2
- /*
3
- Plugin Name: NextGEN Gallery
4
- Plugin URI: http://www.nextgen-gallery.com/
5
- Description: A NextGENeration Photo Gallery for WordPress
6
- Author: Photocrati
7
- Author URI: http://www.photocrati.com/
8
- Version: 1.9.13
9
-
10
- Copyright (c) 2007-2011 by Alex Rabe & NextGEN DEV-Team
11
- Copyright (c) 2012 Photocrati Media
12
-
13
- This program is free software; you can redistribute it and/or modify
14
- it under the terms of the GNU General Public License as published by
15
- the Free Software Foundation; either version 2 of the License, or
16
- (at your option) any later version.
17
-
18
- This program is distributed in the hope that it will be useful,
19
- but WITHOUT ANY WARRANTY; without even the implied warranty of
20
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
- GNU General Public License for more details.
22
-
23
- You should have received a copy of the GNU General Public License
24
- along with this program; if not, write to the Free Software
25
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
- */
27
-
28
- // Stop direct call
29
  if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }
30
 
31
  /**
32
- * Indicates that a clean exit occured. Handled by set_exception_handler
 
 
 
 
 
 
33
  */
34
- if (!class_exists('E_Clean_Exit')) {
35
- class E_Clean_Exit extends RuntimeException
36
- {
37
-
38
- }
39
- }
40
 
 
41
 
42
  /**
43
- * Loads the NextGEN plugin
 
 
 
 
 
 
 
 
 
 
 
 
44
  */
45
- if (!class_exists('nggLoader')) {
46
- class nggLoader {
47
-
48
- var $version = '1.9.13';
49
- var $dbversion = '1.8.1';
50
- var $minimum_WP = '3.5';
51
- var $donators = 'http://www.nextgen-gallery.com/donators.php';
52
- var $options = '';
53
- var $manage_page;
54
- var $add_PHP5_notice = false;
55
-
56
- function nggLoader() {
57
-
58
- // Stop the plugin if we missed the requirements
59
- if ( ( !$this->required_version() ) || ( !$this->check_memory_limit() ) )
60
- return;
61
-
62
- // Set error handler
63
- set_exception_handler(array(&$this, 'exception_handler'));
64
-
65
- // Get some constants first
66
- $this->load_options();
67
- $this->define_constant();
68
- $this->define_tables();
69
- $this->load_dependencies();
70
- $this->start_rewrite_module();
71
-
72
- $this->plugin_name = basename(dirname(__FILE__)).'/'.basename(__FILE__);
73
-
74
- // Init options & tables during activation & deregister init option
75
- register_activation_hook( $this->plugin_name, array(&$this, 'activate') );
76
- register_deactivation_hook( $this->plugin_name, array(&$this, 'deactivate') );
77
-
78
- // Register a uninstall hook to remove all tables & option automatic
79
- register_uninstall_hook( $this->plugin_name, array(__CLASS__, 'uninstall') );
80
-
81
- // Start this plugin once all other plugins are fully loaded
82
- add_action( 'plugins_loaded', array(&$this, 'start_plugin') );
83
-
84
- // Register_taxonomy must be used during the init
85
- add_action( 'init', array(&$this, 'register_taxonomy') );
86
- add_action( 'wpmu_new_blog', array(&$this, 'multisite_new_blog'), 10, 6);
87
-
88
- // Add a message for PHP4 Users, can disable the update message later on
89
- if (version_compare(PHP_VERSION, '5.0.0', '<'))
90
- add_filter('transient_update_plugins', array(&$this, 'disable_upgrade'));
91
-
92
- //Add some links on the plugin page
93
- add_filter('plugin_row_meta', array(&$this, 'add_plugin_links'), 10, 2);
94
-
95
- // Check for the header / footer
96
- add_action( 'init', array(&$this, 'test_head_footer_init' ) );
97
-
98
- // Show NextGEN version in header
99
- add_action('wp_head', array('nggGallery', 'nextgen_version') );
100
-
101
- // Handle upload requests
102
- add_action('init', array(&$this, 'handle_upload_request'));
103
  }
104
 
105
- function start_plugin() {
106
-
107
- global $nggRewrite;
108
-
109
- // Load the language file
110
- $this->load_textdomain();
111
-
112
- // All credits to the tranlator
113
- $this->translator = '<p class="hint">'. __('<strong>Translation by : </strong><a target="_blank" href="http://alexrabe.de/wordpress-plugins/nextgen-gallery/languages/">See here</a>', 'nggallery') . '</p>';
114
- $this->translator .= '<p class="hint">'. __('<strong>This translation is not yet updated for Version 1.9.0</strong>. If you would like to help with translation, download the current po from the plugin folder and read <a href="http://alexrabe.de/wordpress-plugins/wordtube/translation-of-plugins/">here</a> how you can translate the plugin.', 'nggallery') . '</p>';
115
-
116
- // Content Filters
117
- add_filter('ngg_gallery_name', 'sanitize_title');
118
-
119
- // Check if we are in the admin area
120
- if ( is_admin() ) {
121
-
122
- // Pass the init check or show a message
123
- if (get_option( 'ngg_init_check' ) != false )
124
- add_action( 'admin_notices', create_function('', 'echo \'<div id="message" class="error"><p><strong>' . get_option( "ngg_init_check" ) . '</strong></p></div>\';') );
125
-
126
- } else {
127
-
128
- // Add MRSS to wp_head
129
- if ( $this->options['useMediaRSS'] )
130
- add_action('wp_head', array('nggMediaRss', 'add_mrss_alternate_link'));
131
-
132
- // Look for XML request, before page is render
133
- add_action('parse_request', array(&$this, 'check_request') );
134
-
135
- // Add the script and style files
136
- add_action('wp_enqueue_scripts', array(&$this, 'load_scripts') );
137
- add_action('wp_enqueue_scripts', array(&$this, 'load_styles') );
138
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  }
140
  }
 
141
 
142
- function check_request( $wp ) {
143
-
144
- if ( !array_key_exists('callback', $wp->query_vars) )
145
- return;
146
 
147
- if ( $wp->query_vars['callback'] == 'imagerotator') {
148
- require_once (dirname (__FILE__) . '/xml/imagerotator.php');
149
- exit();
150
- }
151
 
152
- if ( $wp->query_vars['callback'] == 'json') {
153
- require_once (dirname (__FILE__) . '/xml/json.php');
154
- exit();
155
- }
156
 
157
- if ( $wp->query_vars['callback'] == 'image') {
158
- require_once (dirname (__FILE__) . '/nggshow.php');
159
- exit();
160
- }
161
 
162
- //TODO:see trac #12400 could be an option for WP3.0
163
- if ( $wp->query_vars['callback'] == 'ngg-ajax') {
164
- require_once (dirname (__FILE__) . '/xml/ajax.php');
165
- exit();
166
- }
167
 
 
 
 
 
 
 
 
 
168
  }
169
 
170
- function required_version() {
 
 
 
 
171
 
172
- global $wp_version;
 
173
 
174
- // Check for WP version installation
175
- $wp_ok = version_compare($wp_version, $this->minimum_WP, '>=');
 
176
 
177
- if ( ($wp_ok == FALSE) ) {
178
- add_action(
179
- 'admin_notices',
180
- create_function(
181
- '',
182
- 'global $ngg; printf (\'<div id="message" class="error"><p><strong>\' . __(\'Sorry, NextGEN Gallery works only under WordPress %s or higher\', "nggallery" ) . \'</strong></p></div>\', $ngg->minimum_WP );'
183
- )
184
- );
185
- return false;
186
- }
187
 
188
- return true;
 
 
189
 
190
- }
 
 
 
 
 
 
191
 
192
- function check_memory_limit() {
 
 
193
 
194
- // get the real memory limit before some increase it
195
- $this->memory_limit = ini_get('memory_limit');
 
 
196
 
197
- // PHP docs : Note that to have no memory limit, set this directive to -1.
198
- if ($this->memory_limit == -1 ) return true;
199
 
200
- // Yes, we reached Gigabyte limits, so check if it's a megabyte limit
201
- if (strtolower( substr($this->memory_limit, -1) ) == 'm') {
202
 
203
- $this->memory_limit = (int) substr( $this->memory_limit, 0, -1);
 
 
 
204
 
205
- //This works only with enough memory, 16MB is silly, wordpress requires already 16MB :-)
206
- if ( ($this->memory_limit != 0) && ($this->memory_limit < 16 ) ) {
207
- add_action(
208
- 'admin_notices',
209
- create_function(
210
- '',
211
- 'echo \'<div id="message" class="error"><p><strong>' . __('Sorry, NextGEN Gallery works only with a Memory Limit of 16 MB or higher', 'nggallery') . '</strong></p></div>\';'
212
- )
213
- );
214
- return false;
215
- }
216
- }
217
 
218
- return true;
 
219
 
220
- }
 
221
 
222
- function define_tables() {
223
- global $wpdb;
224
 
225
- // add database pointer
226
- $wpdb->nggpictures = $wpdb->prefix . 'ngg_pictures';
227
- $wpdb->nggallery = $wpdb->prefix . 'ngg_gallery';
228
- $wpdb->nggalbum = $wpdb->prefix . 'ngg_album';
229
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  }
231
 
232
- function register_taxonomy() {
233
- global $wp_rewrite;
234
 
235
- // Register the NextGEN taxonomy
236
- $args = array(
237
- 'label' => __('Picture tag', 'nggallery'),
238
- 'template' => __('Picture tag: %2$l.', 'nggallery'),
239
- 'helps' => __('Separate picture tags with commas.', 'nggallery'),
240
- 'sort' => true,
241
- 'args' => array('orderby' => 'term_order')
242
- );
243
 
244
- register_taxonomy( 'ngg_tag', 'nggallery', $args );
 
 
 
 
 
 
 
 
245
  }
 
 
246
 
247
- function define_constant() {
248
-
249
- global $wp_version;
250
-
251
- //TODO:SHOULD BE REMOVED LATER
252
- define('NGGVERSION', $this->version);
253
- // Minimum required database version
254
- define('NGG_DBVERSION', $this->dbversion);
255
-
256
- // required for Windows & XAMPP
257
- define('WINABSPATH', str_replace("\\", "/", ABSPATH) );
258
-
259
- // define URL
260
- define('NGGFOLDER', basename( dirname(__FILE__) ) );
261
-
262
- define('NGGALLERY_ABSPATH', trailingslashit( str_replace("\\","/", WP_PLUGIN_DIR . '/' . NGGFOLDER ) ) );
263
- define('NGGALLERY_URLPATH', trailingslashit( plugins_url( NGGFOLDER ) ) );
264
-
265
- // look for imagerotator
266
- define('NGGALLERY_IREXIST', !empty( $this->options['irURL'] ));
267
-
268
- // get value for safe mode
269
- if ( (gettype( ini_get('safe_mode') ) == 'string') ) {
270
- // if sever did in in a other way
271
- if ( ini_get('safe_mode') == 'off' ) define('SAFE_MODE', FALSE);
272
- else define( 'SAFE_MODE', ini_get('safe_mode') );
273
- } else
274
- define( 'SAFE_MODE', ini_get('safe_mode') );
275
-
276
- if ( version_compare($wp_version, '3.2.999', '>') )
277
- define('IS_WP_3_3', TRUE);
278
-
279
- }
280
 
281
- function load_dependencies() {
282
-
283
- // Load global libraries // average memory usage (in bytes)
284
- require_once (dirname (__FILE__) . '/lib/core.php'); // 94.840
285
- require_once (dirname (__FILE__) . '/lib/ngg-db.php'); // 132.400
286
- require_once (dirname (__FILE__) . '/lib/image.php'); // 59.424
287
- require_once (dirname (__FILE__) . '/lib/tags.php'); // 117.136
288
- require_once (dirname (__FILE__) . '/lib/post-thumbnail.php'); // n.a.
289
- require_once (dirname (__FILE__) . '/widgets/widgets.php'); // 298.792
290
- require_once (dirname (__FILE__) . '/lib/multisite.php');
291
- require_once (dirname (__FILE__) . '/lib/sitemap.php');
292
-
293
- // Load frontend libraries
294
- require_once (dirname (__FILE__) . '/lib/navigation.php'); // 242.016
295
- require_once (dirname (__FILE__) . '/nggfunctions.php'); // n.a.
296
- require_once (dirname (__FILE__) . '/lib/shortcodes.php'); // 92.664
297
-
298
- //Just needed if you access remote to WordPress
299
- if ( defined('XMLRPC_REQUEST') )
300
- require_once (dirname (__FILE__) . '/lib/xmlrpc.php');
301
-
302
- // We didn't need all stuff during a AJAX operation
303
- if ( defined('DOING_AJAX') )
304
- require_once (dirname (__FILE__) . '/admin/ajax.php');
305
- else {
306
- require_once (dirname (__FILE__) . '/lib/meta.php'); // 131.856
307
- require_once (dirname (__FILE__) . '/lib/media-rss.php'); // 82.768
308
- require_once (dirname (__FILE__) . '/lib/rewrite.php'); // 71.936
309
- include_once (dirname (__FILE__) . '/admin/tinymce/tinymce.php'); // 22.408
310
-
311
- // Load backend libraries
312
- if ( is_admin() ) {
313
- require_once (dirname (__FILE__) . '/admin/admin.php');
314
- require_once (dirname (__FILE__) . '/admin/media-upload.php');
315
- $this->nggAdminPanel = new nggAdminPanel();
316
- }
317
  }
318
  }
 
 
 
 
319
 
320
- function load_textdomain() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
 
322
- load_plugin_textdomain('nggallery', false, NGGFOLDER . '/lang');
 
 
 
 
 
 
 
323
 
 
 
 
 
 
 
 
 
 
 
324
  }
 
325
 
326
- function load_scripts() {
 
 
 
 
 
 
327
 
328
- // if you don't want that NGG load the scripts, add this constant
329
- if ( defined('NGG_SKIP_LOAD_SCRIPTS') )
330
- return;
 
 
 
 
331
 
332
- // activate Thickbox
333
- if ($this->options['thumbEffect'] == 'thickbox') {
334
- wp_enqueue_script( 'thickbox' );
335
- // Load the thickbox images after all other scripts
336
- add_action( 'wp_footer', array(&$this, 'load_thickbox_images'), 11 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
 
338
- }
339
 
340
- // activate jquery.lightbox
341
- if ($this->options['thumbEffect'] == 'lightbox') {
342
- wp_enqueue_script('jquery');
343
- }
 
 
 
 
344
 
345
- // activate modified Shutter reloaded if not use the Shutter plugin
346
- if ( ($this->options['thumbEffect'] == "shutter") && !function_exists('srel_makeshutter') ) {
347
- wp_register_script('shutter', NGGALLERY_URLPATH .'shutter/shutter-reloaded.js', false ,'1.3.3');
348
- wp_localize_script('shutter', 'shutterSettings', array(
349
- 'msgLoading' => __('L O A D I N G', 'nggallery'),
350
- 'msgClose' => __('Click to Close', 'nggallery'),
351
- 'imageCount' => '1'
352
- ) );
353
- wp_enqueue_script( 'shutter' );
354
- }
355
 
356
- // required for the slideshow
357
- if ( NGGALLERY_IREXIST == true && $this->options['enableIR'] == '1' && nggGallery::detect_mobile_phone() === false )
358
- wp_enqueue_script('swfobject');
359
- else {
360
- wp_register_script('jquery-cycle', NGGALLERY_URLPATH .'js/jquery.cycle.all.min.js', array('jquery'), '2.9995');
361
- wp_enqueue_script('ngg-slideshow', NGGALLERY_URLPATH .'js/ngg.slideshow.min.js', array('jquery-cycle'), '1.06');
362
 
363
- }
 
 
 
 
 
 
 
364
 
365
- // Load AJAX navigation script, works only with shutter script as we need to add the listener
366
- if ( $this->options['galAjaxNav'] ) {
367
- if ( ($this->options['thumbEffect'] == "shutter") || function_exists('srel_makeshutter') ) {
368
- wp_enqueue_script ( 'ngg_script', NGGALLERY_URLPATH . 'js/ngg.js', array('jquery'), '2.1');
369
- wp_localize_script( 'ngg_script', 'ngg_ajax', array('path' => NGGALLERY_URLPATH,
370
- 'callback' => trailingslashit( home_url() ) . 'index.php?callback=ngg-ajax',
371
- 'loading' => __('loading', 'nggallery'),
372
- ) );
373
- }
374
- }
375
 
376
- // If activated, add PicLens/Cooliris javascript to footer
377
- if ( $this->options['usePicLens'] )
378
- nggMediaRss::add_piclens_javascript();
379
 
380
- }
 
 
 
 
 
 
 
381
 
382
- function load_thickbox_images() {
383
- // WP core reference relative to the images. Bad idea
384
- echo "\n" . '<script type="text/javascript">tb_pathToImage = "' . site_url() . '/wp-includes/js/thickbox/loadingAnimation.gif";tb_closeImage = "' . site_url() . '/wp-includes/js/thickbox/tb-close.png";</script>'. "\n";
385
  }
386
 
387
- function load_styles() {
388
-
389
- // check first the theme folder for a nggallery.css
390
- if ( nggGallery::get_theme_css_file() )
391
- wp_enqueue_style('NextGEN', nggGallery::get_theme_css_file() , false, '1.0.0', 'screen');
392
- else if ($this->options['activateCSS'])
393
- wp_enqueue_style('NextGEN', NGGALLERY_URLPATH . 'css/' . $this->options['CSSfile'], false, '1.0.0', 'screen');
394
-
395
- // activate Thickbox
396
- if ($this->options['thumbEffect'] == 'thickbox')
397
- wp_enqueue_style( 'thickbox');
398
 
399
- // activate modified Shutter reloaded if not use the Shutter plugin
400
- if ( ($this->options['thumbEffect'] == 'shutter') && !function_exists('srel_makeshutter') )
401
- wp_enqueue_style('shutter', NGGALLERY_URLPATH .'shutter/shutter-reloaded.css', false, '1.3.4', 'screen');
402
 
403
- }
 
 
 
 
 
 
 
404
 
405
- function load_options() {
406
- // Load the options
407
- $this->options = get_option('ngg_options');
408
- }
409
 
410
- // Add rewrite rules
411
- function start_rewrite_module() {
412
- global $nggRewrite;
 
 
 
 
 
 
413
 
414
- if ( class_exists('nggRewrite') )
415
- $nggRewrite = new nggRewrite();
416
- }
417
 
418
- // THX to Shiba for the code
419
- // See: http://shibashake.com/wordpress-theme/write-a-plugin-for-wordpress-multi-site
420
- function multisite_new_blog($blog_id, $user_id, $domain, $path, $site_id, $meta ) {
421
- global $wpdb;
422
 
423
- include_once (dirname (__FILE__) . '/admin/install.php');
 
424
 
425
- if (is_plugin_active_for_network( $this->plugin_name )) {
426
- $current_blog = $wpdb->blogid;
427
- switch_to_blog($blog_id);
428
- nggallery_install();
429
- switch_to_blog($current_blog);
430
- }
431
  }
432
 
433
- /**
434
- * Removes all transients created by NextGEN. Called during activation
435
- * and deactivation routines
436
- */
437
- static function remove_transients()
438
  {
439
- global $wpdb, $_wp_using_ext_object_cache;
440
-
441
- // Fetch all transients
442
- $query = "
443
- SELECT option_name FROM {$wpdb->options}
444
- WHERE option_name LIKE '%ngg_request%'
445
- ";
446
- $transient_names = $wpdb->get_col($query);;
447
-
448
- // Delete all transients in the database
449
- $query = "
450
- DELETE FROM {$wpdb->options}
451
- WHERE option_name LIKE '%ngg_request%'
452
- ";
453
- $wpdb->query($query);
454
-
455
- // If using an external caching mechanism, delete the cached items
456
- if ($_wp_using_ext_object_cache) {
457
- foreach ($transient_names as $transient) {
458
- wp_cache_delete($transient, 'transient');
459
- wp_cache_delete(substr($transient, 11), 'transient');
460
- }
461
- }
462
  }
463
 
464
- function activate() {
465
- global $wpdb;
466
- //Starting from version 1.8.0 it's works only with PHP5.2
467
- if (version_compare(PHP_VERSION, '5.2.0', '<')) {
468
- deactivate_plugins($this->plugin_name); // Deactivate ourself
469
- wp_die("Sorry, but you can't run this plugin, it requires PHP 5.2 or higher.");
470
- return;
471
- }
472
 
473
- // Clean up transients
474
- self::remove_transients();
475
-
476
- include_once (dirname (__FILE__) . '/admin/install.php');
477
-
478
- if (is_multisite()) {
479
- $network=isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:"";
480
- $activate=isset($_GET['action'])?$_GET['action']:"";
481
- $isNetwork=($network=='/wp-admin/network/plugins.php')?true:false;
482
- $isActivation=($activate=='deactivate')?false:true;
483
-
484
- if ($isNetwork and $isActivation){
485
- $old_blog = $wpdb->blogid;
486
- $blogids = $wpdb->get_col($wpdb->prepare("SELECT blog_id FROM $wpdb->blogs", NULL));
487
- foreach ($blogids as $blog_id) {
488
- switch_to_blog($blog_id);
489
- nggallery_install();
490
- }
491
- switch_to_blog($old_blog);
492
- return;
493
- }
494
- }
495
 
496
- // check for tables
497
- nggallery_install();
498
- // remove the update message
499
- delete_option( 'ngg_update_exists' );
500
 
501
- }
502
 
503
- function deactivate() {
 
 
 
 
 
 
 
 
 
504
 
505
- // remove & reset the init check option
506
- delete_option( 'ngg_init_check' );
507
- delete_option( 'ngg_update_exists' );
508
 
509
- // Clean up transients
510
- self::remove_transients();
511
- }
512
 
513
- function uninstall() {
514
- // Clean up transients
515
- self::remove_transients();
 
516
 
517
- include_once (dirname (__FILE__) . '/admin/install.php');
518
- nggallery_uninstall();
519
  }
520
 
521
- function disable_upgrade($option){
522
-
523
- // PHP5.2 is required for NGG V1.4.0
524
- if ( version_compare($option->response[ $this->plugin_name ]->new_version, '1.4.0', '>=') )
525
- return $option;
526
 
527
- if( isset($option->response[ $this->plugin_name ]) ){
528
- //Clear it''s download link
529
- $option->response[ $this->plugin_name ]->package = '';
530
 
531
- //Add a notice message
532
- if ($this->add_PHP5_notice == false){
533
- add_action( "in_plugin_update_message-$this->plugin_name", create_function('', 'echo \'<br /><span style="color:red">Please update to PHP5.2 as soon as possible, the plugin is not tested under PHP4 anymore</span>\';') );
534
- $this->add_PHP5_notice = true;
535
- }
536
  }
537
- return $option;
538
  }
 
 
 
 
539
 
540
- // Add links to Plugins page
541
- function add_plugin_links($links, $file) {
542
-
543
- if ( $file == $this->plugin_name ) {
544
- $plugin_name = plugin_basename(NGGALLERY_ABSPATH);
545
- $links[] = "<a href='admin.php?page={$plugin_name}'>" . __('Overview', 'nggallery') . '</a>';
546
- $links[] = '<a href="http://wordpress.org/tags/nextgen-gallery?forum_id=10">' . __('Get help', 'nggallery') . '</a>';
547
- $links[] = '<a href="https://bitbucket.org/photocrati/nextgen-gallery">' . __('Contribute', 'nggallery') . '</a>';
548
  }
549
- return $links;
550
- }
551
-
552
- // Check for the header / footer, parts taken from Matt Martz (http://sivel.net/)
553
- function test_head_footer_init() {
554
-
555
- // If test-head query var exists hook into wp_head
556
- if ( isset( $_GET['test-head'] ) )
557
- add_action( 'wp_head', create_function('', 'echo \'<!--wp_head-->\';'), 99999 );
558
-
559
- // If test-footer query var exists hook into wp_footer
560
- if ( isset( $_GET['test-footer'] ) )
561
- add_action( 'wp_footer', create_function('', 'echo \'<!--wp_footer-->\';'), 99999 );
562
- }
563
 
564
- /**
565
- * Handles upload requests
566
- */
567
- function handle_upload_request()
568
- {
569
- if (isset($_GET['nggupload'])) {
570
- require_once(implode(DIRECTORY_SEPARATOR, array(
571
- NGGALLERY_ABSPATH,
572
- 'admin',
573
- 'upload.php'
574
- )));
575
- throw new E_Clean_Exit();
576
  }
577
- }
578
 
579
- /**
580
- * Handles clean exits gracefully. Re-raises anything else
581
- * @param Exception $ex
582
- */
583
- function exception_handler($ex)
584
- {
585
- if (get_class($ex) != 'E_Clean_Exit') throw $ex;
586
  }
 
 
587
  }
588
 
589
- // Let's start the holy plugin
590
- global $ngg;
591
- $ngg = new nggLoader();
 
 
 
 
 
 
592
  }
593
- ?>
 
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }
3
 
4
  /**
5
+ * Plugin Name: NextGEN Gallery by Photocrati
6
+ * Description: The most popular gallery plugin for WordPress and one of the most popular plugins of all time with over 7 million downloads.
7
+ * Version: 2.0.14
8
+ * Author: Photocrati Media
9
+ * Plugin URI: http://www.nextgen-gallery.com
10
+ * Author URI: http://www.photocrati.com
11
+ * License: GPLv2
12
  */
 
 
 
 
 
 
13
 
14
+ if (!class_exists('E_Clean_Exit')) { class E_Clean_Exit extends RuntimeException {} }
15
 
16
  /**
17
+ * NextGEN Gallery is built on top of the Photocrati Pope Framework:
18
+ * https://bitbucket.org/photocrati/pope-framework
19
+ *
20
+ * Pope constructs applications by assembling modules.
21
+ *
22
+ * The Bootstrapper. This class performs the following:
23
+ * 1) Loads the Pope Framework
24
+ * 2) Adds a path to the C_Component_Registry instance to search for products
25
+ * 3) Loads all found Products. A Product is a collection of modules with some
26
+ * additional meta data. A Product is responsible for loading any modules it
27
+ * requires.
28
+ * 4) Once all Products (and their associated modules) have been loaded (or in
29
+ * otherwords, "included"), the modules are initialized.
30
  */
31
+ class C_NextGEN_Bootstrap
32
+ {
33
+ var $_registry = NULL;
34
+ var $_settings_option_name = 'ngg_options';
35
+ var $_pope_loaded = FALSE;
36
+ static $debug = FALSE;
37
+
38
+ static function shutdown($exception=NULL)
39
+ {
40
+ if (is_null($exception)) {
41
+ throw new E_Clean_Exit;
42
+ }
43
+ elseif (!($exception instanceof E_Clean_Exit)) {
44
+ ob_end_clean();
45
+ self::print_exception($exception);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
 
48
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
+ static function print_exception($exception)
51
+ {
52
+ $klass = get_class($exception);
53
+ echo "<h1>{$klass} thrown</h1>";
54
+ echo "<p>{$exception->getMessage()}</p>";
55
+ if (self::$debug OR (defined('NEXTGEN_GALLERY_DEBUG') AND NEXTGEN_GALLERY_DEBUG == TRUE)) {
56
+ echo "<h3>Where:</h3>";
57
+ echo "<p>On line <strong>{$exception->getLine()}</strong> of <strong>{$exception->getFile()}</strong></p>";
58
+ echo "<h3>Trace:</h3>";
59
+ echo "<pre>{$exception->getTraceAsString()}</pre>";
60
+ while (($previous = $exception->getPrevious())) {
61
+ self::print_exception($previous);
62
  }
63
  }
64
+ }
65
 
66
+ function __construct()
67
+ {
68
+ // Boostrap
69
+ set_exception_handler(__CLASS__.'::shutdown');
70
 
71
+ $this->_define_constants();
72
+ $this->_load_non_pope();
73
+ $this->_register_hooks();
74
+ $this->_load_pope();
75
 
76
+ }
 
 
 
77
 
78
+ function _load_non_pope()
79
+ {
80
+ // Load WordPress pluggables for plugin compatibility
81
+ include_once(path_join(ABSPATH, 'wp-includes/pluggable.php'));
82
 
83
+ // Load caching component
84
+ include_once('non_pope/class.photocrati_cache.php');
85
+ C_Photocrati_Cache::$enabled = TRUE;
 
 
86
 
87
+ if (isset($_REQUEST['ngg_flush'])) {
88
+ C_Photocrati_Cache::flush('all');
89
+ $_SERVER['QUERY_STRING'] = str_replace('ngg_flush=1', '', $_SERVER['QUERY_STRING']);
90
+ }
91
+ elseif (isset($_REQUEST['ngg_force_update'])) {
92
+ C_Photocrati_Cache::$do_not_lookup = TRUE;
93
+ C_Photocrati_Cache::$force_update = TRUE;
94
+ $_SERVER['QUERY_STRING'] = str_replace('ngg_force_update=1', '', $_SERVER['QUERY_STRING']);
95
  }
96
 
97
+ // Load Settings Manager
98
+ include_once('non_pope/class.photocrati_settings_manager.php');
99
+ include_once('non_pope/class.nextgen_settings.php');
100
+ C_Photocrati_Global_Settings_Manager::$option_name = $this->_settings_option_name;
101
+ C_Photocrati_Settings_Manager::$option_name = $this->_settings_option_name;
102
 
103
+ // Load the installer
104
+ include_once('non_pope/class.photocrati_installer.php');
105
 
106
+ // Load the resource manager
107
+ include_once('non_pope/class.photocrati_resource_manager.php');
108
+ C_Photocrati_Resource_Manager::init();
109
 
110
+ // Load the style manager
111
+ include_once('non_pope/class.nextgen_style_manager.php');
 
 
 
 
 
 
 
 
112
 
113
+ // Load the shortcode manager
114
+ include_once('non_pope/class.nextgen_shortcode_manager.php');
115
+ }
116
 
117
+ /**
118
+ * Loads the Pope Framework
119
+ */
120
+ function _load_pope()
121
+ {
122
+ // No need to initialize pope again
123
+ if ($this->_pope_loaded) return;
124
 
125
+ // Pope requires a a higher limit
126
+ $tmp = ini_get('xdebug.max_nesting_level');
127
+ if ($tmp && (int)$tmp <= 300) @ini_set('xdebug.max_nesting_level', 300);
128
 
129
+ // Include pope framework
130
+ require_once(path_join(NEXTGEN_GALLERY_PLUGIN_DIR, implode(
131
+ DIRECTORY_SEPARATOR, array('pope','lib','autoload.php')
132
+ )));
133
 
134
+ // Get the component registry
135
+ $this->_registry = C_Component_Registry::get_instance();
136
 
137
+ // Add the default Pope factory utility, C_Component_Factory
138
+ $this->_registry->add_utility('I_Component_Factory', 'C_Component_Factory');
139
 
140
+ // Load embedded products. Each product is expected to load any
141
+ // modules required
142
+ $this->_registry->add_module_path(NEXTGEN_GALLERY_PRODUCT_DIR, true, false);
143
+ $this->_registry->load_all_products();
144
 
145
+ // Give third-party plugins that opportunity to include their own products
146
+ // and modules
147
+ do_action('load_nextgen_gallery_modules', $this->_registry);
 
 
 
 
 
 
 
 
 
148
 
149
+ // Initializes all loaded modules
150
+ $this->_registry->initialize_all_modules();
151
 
152
+ // Set the document root
153
+ $this->_registry->get_utility('I_Fs')->set_document_root(ABSPATH);
154
 
155
+ $this->_pope_loaded = TRUE;
156
+ }
157
 
 
 
 
 
158
 
159
+ /**
160
+ * Registers hooks for the WordPress framework necessary for instantiating
161
+ * the plugin
162
+ */
163
+ function _register_hooks()
164
+ {
165
+ // Load text domain
166
+ load_plugin_textdomain(
167
+ NEXTGEN_GALLERY_I8N_DOMAIN,
168
+ false,
169
+ $this->directory_path('lang')
170
+ );
171
+
172
+ // Register the activation routines
173
+ add_action('activate_'.NEXTGEN_GALLERY_PLUGIN_BASENAME, array(get_class(), 'activate'));
174
+
175
+ // Register the deactivation routines
176
+ add_action('deactivate_'.NEXTGEN_GALLERY_PLUGIN_BASENAME, array(get_class(), 'deactivate'));
177
+
178
+ // Register our test suite
179
+ add_filter('simpletest_suites', array(&$this, 'add_testsuite'));
180
+
181
+ // Ensure that settings manager is saved as an array
182
+ add_filter('pre_update_option_'.$this->_settings_option_name, array(&$this, 'persist_settings'));
183
+ add_filter('pre_update_site_option_'.$this->_settings_option_name, array(&$this, 'persist_settings'));
184
+
185
+ // This plugin uses jQuery extensively
186
+ add_action('init', array(&$this, 'enqueue_jquery'), 1);
187
+ add_action('wp_print_scripts', array(&$this, 'fix_jquery'));
188
+ add_action('admin_print_scripts', array(&$this, 'fix_jquery'));
189
+
190
+ // If the selected stylesheet is using an unsafe path, then notify the user
191
+ if (C_NextGen_Style_Manager::get_instance()->is_directory_unsafe()) {
192
+ add_action('all_admin_notices', array(&$this, 'display_stylesheet_notice'));
193
  }
194
 
195
+ // Update modules
196
+ add_action('init', array(&$this, 'update'), PHP_INT_MAX);
197
 
198
+ // Start the plugin!
199
+ add_action('init', array(&$this, 'route'), PHP_INT_MAX);
200
+ }
 
 
 
 
 
201
 
202
+ /**
203
+ * Ensure that C_Photocrati_Settings_Manager gets persisted as an array
204
+ * @param $settings
205
+ * @return array
206
+ */
207
+ function persist_settings($settings)
208
+ {
209
+ if (is_object($settings) && $settings instanceof C_Photocrati_Settings_Manager_Base) {
210
+ $settings = $settings->to_array();
211
  }
212
+ return $settings;
213
+ }
214
 
215
+ /**
216
+ * Enqueues jQuery
217
+ */
218
+ function enqueue_jquery()
219
+ {
220
+ wp_enqueue_script('jquery');
221
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
 
223
+ /**
224
+ * Ensures that the latest version of jQuery bundled with WordPress is used
225
+ */
226
+ function fix_jquery()
227
+ {
228
+ global $wp_scripts;
229
+
230
+ if (isset($wp_scripts->registered['jquery'])) {
231
+ $jquery = $wp_scripts->registered['jquery'];
232
+ if (!isset($jquery->ver) OR version_compare('1.8', $jquery->ver) == 1) {
233
+ ob_start();
234
+ wp_deregister_script('jquery');
235
+ ob_end_clean();
236
+ wp_register_script('jquery', false, array( 'jquery-core', 'jquery-migrate' ), '1.10.0' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  }
238
  }
239
+ else wp_register_script( 'jquery', false, array( 'jquery-core', 'jquery-migrate' ), '1.10.0' );
240
+
241
+ wp_enqueue_script('jquery');
242
+ }
243
 
244
+ /**
245
+ * Displays a notice to the user that the current stylesheet location is unsafe
246
+ */
247
+ function display_stylesheet_notice()
248
+ {
249
+ $styles = C_NextGen_Style_Manager::get_instance();
250
+ $filename = $styles->get_selected_stylesheet();
251
+ $abspath = $styles->find_selected_stylesheet_abspath();
252
+ $newpath = $styles->new_dir;
253
+
254
+ echo "<div class='updated error'>
255
+ <h3>WARNING: NextGEN Gallery Stylesheet NOT Upgrade-safe</h3>
256
+ <p>
257
+ <strong>{$filename}</strong> is currently stored in <strong>{$abspath}</strong>, which isn't upgrade-safe. Please move the stylesheet to
258
+ <strong>{$newpath}</strong> to ensure that your customizations persist after updates.
259
+ </p></div>";
260
+ }
261
 
262
+ /**
263
+ * Updates all modules
264
+ */
265
+ function update()
266
+ {
267
+ $this->_load_pope();
268
+ C_Photocrati_Installer::update();
269
+ }
270
 
271
+ /**
272
+ * Routes access points using the Pope Router
273
+ * @return boolean
274
+ */
275
+ function route()
276
+ {
277
+ $this->_load_pope();
278
+ $router = $this->_registry->get_utility('I_Router');
279
+ if (!$router->serve_request() && $router->has_parameter_segments()) {
280
+ return $router->passthru();
281
  }
282
+ }
283
 
284
+ /**
285
+ * Run the installer
286
+ */
287
+ static function activate($network=FALSE)
288
+ {
289
+ C_Photocrati_Installer::update();
290
+ }
291
 
292
+ /**
293
+ * Run the uninstaller
294
+ */
295
+ static function deactivate()
296
+ {
297
+ C_Photocrati_Installer::uninstall(NEXTGEN_GALLERY_PLUGIN_BASENAME);
298
+ }
299
 
300
+ /**
301
+ * Defines necessary plugins for the plugin to load correctly
302
+ */
303
+ function _define_constants()
304
+ {
305
+ // NextGEN by Photocrati Constants
306
+ define('NEXTGEN_GALLERY_PLUGIN', basename($this->directory_path()));
307
+ define('NEXTGEN_GALLERY_PLUGIN_BASENAME', plugin_basename(__FILE__));
308
+ define('NEXTGEN_GALLERY_PLUGIN_DIR', $this->directory_path());
309
+ define('NEXTGEN_GALLERY_PLUGIN_URL', $this->path_uri());
310
+ define('NEXTGEN_GALLERY_I8N_DOMAIN', 'nggallery');
311
+ define('NEXTGEN_GALLERY_TESTS_DIR', path_join(NEXTGEN_GALLERY_PLUGIN_DIR, 'tests'));
312
+ define('NEXTGEN_GALLERY_PRODUCT_DIR', path_join(NEXTGEN_GALLERY_PLUGIN_DIR, 'products'));
313
+ define('NEXTGEN_GALLERY_PRODUCT_URL', path_join(NEXTGEN_GALLERY_PLUGIN_URL, 'products'));
314
+ define('NEXTGEN_GALLERY_MODULE_DIR', path_join(NEXTGEN_GALLERY_PRODUCT_DIR, 'photocrati_nextgen/modules'));
315
+ define('NEXTGEN_GALLERY_MODULE_URL', path_join(NEXTGEN_GALLERY_PRODUCT_URL, 'photocrati_nextgen/modules'));
316
+ define('NEXTGEN_GALLERY_PLUGIN_CLASS', path_join(NEXTGEN_GALLERY_PLUGIN_DIR, 'module.NEXTGEN_GALLERY_PLUGIN.php'));
317
+ define('NEXTGEN_GALLERY_PLUGIN_STARTED_AT', microtime());
318
+ define('NEXTGEN_GALLERY_PLUGIN_VERSION', '2.0.14');
319
+ }
320
 
 
321
 
322
+ /**
323
+ * Defines the NextGEN Test Suite
324
+ * @param array $suites
325
+ * @return array
326
+ */
327
+ function add_testsuite($suites=array())
328
+ {
329
+ $tests_dir = NEXTGEN_GALLERY_TESTS_DIR;
330
 
331
+ if (file_exists($tests_dir)) {
 
 
 
 
 
 
 
 
 
332
 
333
+ // Include mock objects
334
+ // TODO: These mock objects should be moved to the appropriate
335
+ // test folder
336
+ require_once(path_join($tests_dir, 'mocks.php'));
 
 
337
 
338
+ // Define the NextGEN Test Suite
339
+ $suites['nextgen'] = array(
340
+ // path_join($tests_dir, 'mvc'),
341
+ path_join($tests_dir, 'datamapper'),
342
+ path_join($tests_dir, 'nextgen_data'),
343
+ path_join($tests_dir, 'gallery_display')
344
+ );
345
+ }
346
 
347
+ return $suites;
348
+ }
 
 
 
 
 
 
 
 
349
 
 
 
 
350
 
351
+ /**
352
+ * Returns the path to a file within the plugin root folder
353
+ * @param type $file_name
354
+ * @return type
355
+ */
356
+ function file_path($file_name=NULL)
357
+ {
358
+ $path = dirname(__FILE__);
359
 
360
+ if ($file_name != null)
361
+ {
362
+ $path .= '/' . $file_name;
363
  }
364
 
365
+ return str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
366
+ }
 
 
 
 
 
 
 
 
 
367
 
 
 
 
368
 
369
+ /**
370
+ * Gets the directory path used by the plugin
371
+ * @return string
372
+ */
373
+ function directory_path($dir=NULL)
374
+ {
375
+ return $this->file_path($dir);
376
+ }
377
 
 
 
 
 
378
 
379
+ /**
380
+ * Determines the location of the plugin - within a theme or plugin
381
+ * @return string
382
+ */
383
+ function get_plugin_location()
384
+ {
385
+ $path = dirname(__FILE__);
386
+ $gallery_dir = strtolower($path);
387
+ $gallery_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $gallery_dir);
388
 
389
+ $theme_dir = strtolower(get_stylesheet_directory());
390
+ $theme_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $theme_dir);
 
391
 
392
+ $plugin_dir = strtolower(WP_PLUGIN_DIR);
393
+ $plugin_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $plugin_dir);
 
 
394
 
395
+ $common_dir_theme = substr($gallery_dir, 0, strlen($theme_dir));
396
+ $common_dir_plugin = substr($gallery_dir, 0, strlen($plugin_dir));
397
 
398
+ if ($common_dir_theme == $theme_dir)
399
+ {
400
+ return 'theme';
 
 
 
401
  }
402
 
403
+ if ($common_dir_plugin == $plugin_dir)
 
 
 
 
404
  {
405
+ return 'plugin';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  }
407
 
408
+ $parent_dir = dirname($path);
 
 
 
 
 
 
 
409
 
410
+ if (file_exists($parent_dir . DIRECTORY_SEPARATOR . 'style.css'))
411
+ {
412
+ return 'theme';
413
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
 
415
+ return 'plugin';
416
+ }
 
 
417
 
 
418
 
419
+ /**
420
+ * Gets the URI for a particular path
421
+ * @param string $path
422
+ * @param boolean $url_encode
423
+ * @return string
424
+ */
425
+ function path_uri($path = null, $url_encode = false)
426
+ {
427
+ $location = $this->get_plugin_location();
428
+ $uri = null;
429
 
430
+ $path = str_replace(array('/', '\\'), '/', $path);
 
 
431
 
432
+ if ($url_encode)
433
+ {
434
+ $path_list = explode('/', $path);
435
 
436
+ foreach ($path_list as $index => $path_item)
437
+ {
438
+ $path_list[$index] = urlencode($path_item);
439
+ }
440
 
441
+ $path = implode('/', $path_list);
 
442
  }
443
 
444
+ if ($location == 'theme')
445
+ {
446
+ $theme_uri = get_stylesheet_directory_uri();
 
 
447
 
448
+ $uri = $theme_uri . 'nextgen-gallery';
 
 
449
 
450
+ if ($path != null)
451
+ {
452
+ $uri .= '/' . $path;
 
 
453
  }
 
454
  }
455
+ else
456
+ {
457
+ // XXX Note, paths could not match but STILL being contained in the theme (i.e. WordPress returns the wrong path for the theme directory, either with wrong formatting or wrong encoding)
458
+ $base = basename(dirname(__FILE__));
459
 
460
+ if ($base != 'nextgen-gallery')
461
+ {
462
+ // XXX this is needed when using symlinks, if the user renames the plugin folder everything will break though
463
+ $base = 'nextgen-gallery';
 
 
 
 
464
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
465
 
466
+ if ($path != null)
467
+ {
468
+ $base .= '/' . $path;
 
 
 
 
 
 
 
 
 
469
  }
 
470
 
471
+ $uri = plugins_url($base);
 
 
 
 
 
 
472
  }
473
+
474
+ return $uri;
475
  }
476
 
477
+ /**
478
+ * Returns the URI for a particular file
479
+ * @param string $file_name
480
+ * @return string
481
+ */
482
+ function file_uri($file_name = NULL)
483
+ {
484
+ return $this->path($file_name);
485
+ }
486
  }
487
+
488
+ new C_NextGEN_Bootstrap();
nggfunctions.php DELETED
@@ -1,1141 +0,0 @@
1
- <?php
2
-
3
- if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }
4
-
5
- /**
6
- * Return a script for the Imagerotator flash slideshow. Can be used in any template with <?php echo nggShowSlideshow($galleryID, $width, $height) ?>
7
- * Require the script swfobject.js in the header or footer
8
- *
9
- * @access public
10
- * @param integer $galleryID ID of the gallery
11
- * @param integer $irWidth Width of the flash container
12
- * @param integer $irHeight Height of the flash container
13
- * @return the content
14
- */
15
- function nggShowSlideshow($galleryID, $width, $height) {
16
-
17
- require_once (dirname (__FILE__).'/lib/swfobject.php');
18
-
19
- $ngg_options = nggGallery::get_option('ngg_options');
20
-
21
- // remove media file from RSS feed
22
- if ( is_feed() ) {
23
- $out = '[' . nggGallery::i18n($ngg_options['galTextSlide']) . ']';
24
- return $out;
25
- }
26
-
27
- //Redirect all calls to the JavaScript slideshow if wanted
28
- if ( $ngg_options['enableIR'] !== '1' || nggGallery::detect_mobile_phone() === true )
29
- return nggShow_JS_Slideshow($galleryID, $width, $height);
30
-
31
- // If the Imagerotator didn't exist, skip the output
32
- if ( NGGALLERY_IREXIST == false )
33
- return;
34
-
35
- if (empty($width) ) $width = (int) $ngg_options['irWidth'];
36
- if (empty($height)) $height = (int) $ngg_options['irHeight'];
37
- // Doesn't work fine with zero
38
- $ngg_options['irRotatetime'] = ($ngg_options['irRotatetime'] == 0) ? 5 : $ngg_options['irRotatetime'];
39
- // init the flash output
40
- $swfobject = new swfobject( $ngg_options['irURL'] , 'so' . $galleryID, $width, $height, '7.0.0', 'false');
41
-
42
- $swfobject->message = '<p>'. __('The <a href="http://www.macromedia.com/go/getflashplayer">Flash Player</a> and <a href="http://www.mozilla.com/firefox/">a browser with Javascript support</a> are needed.', 'nggallery').'</p>';
43
- $swfobject->add_params('wmode', 'opaque');
44
- $swfobject->add_params('allowfullscreen', 'true');
45
- $swfobject->add_params('bgcolor', $ngg_options['irScreencolor'], 'FFFFFF', 'string', '#');
46
- $swfobject->add_attributes('styleclass', 'slideshow');
47
- $swfobject->add_attributes('name', 'so' . $galleryID);
48
-
49
- // adding the flash parameter
50
- $swfobject->add_flashvars( 'file', urlencode ( trailingslashit ( home_url() ) . 'index.php?callback=imagerotator&gid=' . $galleryID ) );
51
- $swfobject->add_flashvars( 'shuffle', $ngg_options['irShuffle'], 'true', 'bool');
52
- // option has oposite meaning : true should switch to next image
53
- $swfobject->add_flashvars( 'linkfromdisplay', !$ngg_options['irLinkfromdisplay'], 'false', 'bool');
54
- $swfobject->add_flashvars( 'shownavigation', $ngg_options['irShownavigation'], 'true', 'bool');
55
- $swfobject->add_flashvars( 'showicons', $ngg_options['irShowicons'], 'true', 'bool');
56
- $swfobject->add_flashvars( 'kenburns', $ngg_options['irKenburns'], 'false', 'bool');
57
- $swfobject->add_flashvars( 'overstretch', $ngg_options['irOverstretch'], 'false', 'string');
58
- $swfobject->add_flashvars( 'rotatetime', $ngg_options['irRotatetime'], 5, 'int');
59
- $swfobject->add_flashvars( 'transition', $ngg_options['irTransition'], 'random', 'string');
60
- $swfobject->add_flashvars( 'backcolor', $ngg_options['irBackcolor'], 'FFFFFF', 'string', '0x');
61
- $swfobject->add_flashvars( 'frontcolor', $ngg_options['irFrontcolor'], '000000', 'string', '0x');
62
- $swfobject->add_flashvars( 'lightcolor', $ngg_options['irLightcolor'], '000000', 'string', '0x');
63
- $swfobject->add_flashvars( 'screencolor', $ngg_options['irScreencolor'], '000000', 'string', '0x');
64
- if ($ngg_options['irWatermark'])
65
- $swfobject->add_flashvars( 'logo', $ngg_options['wmPath'], '', 'string');
66
- $swfobject->add_flashvars( 'audio', $ngg_options['irAudio'], '', 'string');
67
- $swfobject->add_flashvars( 'width', $width, '260');
68
- $swfobject->add_flashvars( 'height', $height, '320');
69
- // create the output
70
- $out = '<div class="slideshow">' . $swfobject->output() . '</div>';
71
- // add now the script code
72
- $out .= "\n".'<script type="text/javascript" defer="defer">';
73
- // load script via jQuery afterwards
74
- // $out .= "\n".'jQuery.getScript( "' . esc_js( includes_url('js/swfobject.js') ) . '", function() {} );';
75
- if ($ngg_options['irXHTMLvalid']) $out .= "\n".'<!--';
76
- if ($ngg_options['irXHTMLvalid']) $out .= "\n".'//<![CDATA[';
77
- $out .= $swfobject->javascript();
78
- if ($ngg_options['irXHTMLvalid']) $out .= "\n".'//]]>';
79
- if ($ngg_options['irXHTMLvalid']) $out .= "\n".'-->';
80
- $out .= "\n".'</script>';
81
-
82
- $out = apply_filters('ngg_show_slideshow_content', $out, $galleryID, $width, $height);
83
-
84
- return $out;
85
- }
86
-
87
- /**
88
- * Return a script for the jQuery based slideshow. Can be used in any template with <?php echo nggShow_JS_Slideshow($galleryID, $width, $height) ?>
89
- * Require the script jquery.cycle.all.js
90
- *
91
- * @since 1.6.0
92
- * @access public
93
- * @param integer $galleryID ID of the gallery
94
- * @param integer $width Width of the slideshow container
95
- * @param integer $height Height of the slideshow container
96
- * @param string $class Classname of the div container
97
- * @return the content
98
- */
99
- function nggShow_JS_Slideshow($galleryID, $width, $height, $class = 'ngg-slideshow') {
100
-
101
- global $slideCounter;
102
-
103
- $ngg_options = nggGallery::get_option('ngg_options');
104
-
105
- // we need to know the current page id
106
- $current_page = (get_the_ID() == false) ? rand(5, 15) : get_the_ID();
107
- // look for a other slideshow instance
108
- if ( !isset($slideCounter) ) $slideCounter = 1;
109
- // create unique anchor
110
- $anchor = 'ngg-slideshow-' . $galleryID . '-' . $current_page . '-' . $slideCounter++;
111
-
112
- if (empty($width) ) $width = (int) $ngg_options['irWidth'];
113
- if (empty($height)) $height = (int) $ngg_options['irHeight'];
114
-
115
- //filter to resize images for mobile browser
116
- list($width, $height) = apply_filters('ngg_slideshow_size', array( $width, $height ) );
117
-
118
- $width = (int) $width;
119
- $height = (int) $height;
120
-
121
- $out = '<div id="' . $anchor . '" class="' . $class . '" style="height:' . $height . 'px;width:' . $width . 'px;">';
122
- $out .= "\n". '<div id="' . $anchor . '-loader" class="ngg-slideshow-loader" style="height:' . $height . 'px;width:' . $width . 'px;">';
123
- $out .= "\n". '<img src="'. NGGALLERY_URLPATH . 'images/loader.gif" alt="" />';
124
- $out .= "\n". '</div>';
125
- $out .= '</div>'."\n";
126
- $out .= "\n".'<script type="text/javascript" defer="defer">';
127
- $out .= "\n" . 'jQuery(document).ready(function(){ ' . "\n" . 'jQuery("#' . $anchor . '").nggSlideshow( {' .
128
- 'id: ' . $galleryID . ',' .
129
- 'fx:"' . $ngg_options['slideFx'] . '",' .
130
- 'width:' . $width . ',' .
131
- 'height:' . $height . ',' .
132
- 'domain: "' . trailingslashit ( home_url() ) . '",' .
133
- 'timeout:' . $ngg_options['irRotatetime'] * 1000 .
134
- '});' . "\n" . '});';
135
- $out .= "\n".'</script>';
136
-
137
- return $out;
138
- }
139
-
140
- /**
141
- * nggShowGallery() - return a gallery
142
- *
143
- * @access public
144
- * @param int | string ID or slug from a gallery
145
- * @param string $template (optional) name for a template file, look for gallery-$template
146
- * @param int $images (optional) number of images per page
147
- * @return the content
148
- */
149
- function nggShowGallery( $galleryID, $template = '', $images = false ) {
150
-
151
- global $nggRewrite;
152
-
153
- $ngg_options = nggGallery::get_option('ngg_options');
154
-
155
- //Set sort order value, if not used (upgrade issue)
156
- $ngg_options['galSort'] = ($ngg_options['galSort']) ? $ngg_options['galSort'] : 'pid';
157
- $ngg_options['galSortDir'] = ($ngg_options['galSortDir'] == 'DESC') ? 'DESC' : 'ASC';
158
-
159
- // get gallery values
160
- //TODO: Use pagination limits here to reduce memory needs
161
- $picturelist = nggdb::get_gallery($galleryID, $ngg_options['galSort'], $ngg_options['galSortDir']);
162
-
163
- if ( !$picturelist )
164
- return __('[Gallery not found]','nggallery');
165
-
166
- // If we have we slug instead the id, we should extract the ID from the first image
167
- if ( !is_numeric($galleryID) ) {
168
- $first_image = current($picturelist);
169
- $galleryID = intval($first_image->gid);
170
- }
171
-
172
- // $_GET from wp_query
173
- $show = get_query_var('show');
174
- $pid = get_query_var('pid');
175
- $pageid = get_query_var('pageid');
176
-
177
- // set $show if slideshow first
178
- if ( empty( $show ) AND ($ngg_options['galShowOrder'] == 'slide')) {
179
- if ( is_home() )
180
- $pageid = get_the_ID();
181
-
182
- $show = 'slide';
183
- }
184
-
185
- // filter to call up the imagebrowser instead of the gallery
186
- // use in your theme : add_action( 'ngg_show_imagebrowser_first', create_function('', 'return true;') );
187
- if ( apply_filters('ngg_show_imagebrowser_first', false, $galleryID ) && $show != 'thumbnails' ) {
188
- $out = nggShowImageBrowser( $galleryID, $template );
189
- return $out;
190
- }
191
-
192
- // go on only on this page
193
- if ( !is_home() || $pageid == get_the_ID() ) {
194
-
195
- // 1st look for ImageBrowser link
196
- if ( !empty($pid) && $ngg_options['galImgBrowser'] && ($template != 'carousel') ) {
197
- $out = nggShowImageBrowser( $galleryID, $template );
198
- return $out;
199
- }
200
-
201
- // 2nd look for slideshow
202
- if ( $show == 'slide' ) {
203
- $args['show'] = "gallery";
204
- $out = '<div class="ngg-galleryoverview">';
205
- $out .= '<div class="slideshowlink"><a class="slideshowlink" href="' . $nggRewrite->get_permalink($args) . '">'.nggGallery::i18n($ngg_options['galTextGallery']).'</a></div>';
206
- $out .= nggShowSlideshow($galleryID, $ngg_options['irWidth'], $ngg_options['irHeight']);
207
- $out .= '</div>'."\n";
208
- $out .= '<div class="ngg-clear"></div>'."\n";
209
- return $out;
210
- }
211
- }
212
-
213
- // get all picture with this galleryid
214
- if ( is_array($picturelist) )
215
- $out = nggCreateGallery($picturelist, $galleryID, $template, $images);
216
-
217
- $out = apply_filters('ngg_show_gallery_content', $out, intval($galleryID));
218
- return $out;
219
- }
220
-
221
- /**
222
- * Build a gallery output
223
- *
224
- * @access internal
225
- * @param array $picturelist
226
- * @param bool $galleryID, if you supply a gallery ID, you can add a slideshow link
227
- * @param string $template (optional) name for a template file, look for gallery-$template
228
- * @param int $images (optional) number of images per page
229
- * @return the content
230
- */
231
- function nggCreateGallery($picturelist, $galleryID = false, $template = '', $images = false) {
232
- global $nggRewrite;
233
-
234
- require_once (dirname (__FILE__) . '/lib/media-rss.php');
235
-
236
- $ngg_options = nggGallery::get_option('ngg_options');
237
-
238
- //the shortcode parameter will override global settings, TODO: rewrite this to a class
239
- $ngg_options['galImages'] = ( $images === false ) ? $ngg_options['galImages'] : (int) $images;
240
-
241
- $current_pid = false;
242
-
243
- // $_GET from wp_query
244
- $nggpage = get_query_var('nggpage');
245
- $pageid = get_query_var('pageid');
246
- $pid = get_query_var('pid');
247
-
248
- // in case of permalinks the pid is a slug, we need the id
249
- if( !is_numeric($pid) && !empty($pid) ) {
250
- $picture = nggdb::find_image($pid);
251
- $pid = $picture->pid;
252
- }
253
-
254
- // we need to know the current page id
255
- $current_page = (get_the_ID() == false) ? 0 : get_the_ID();
256
-
257
- if ( !is_array($picturelist) )
258
- $picturelist = array($picturelist);
259
-
260
- // Populate galleries values from the first image
261
- $first_image = current($picturelist);
262
- $gallery = new stdclass;
263
- $gallery->ID = (int) $galleryID;
264
- $gallery->show_slideshow = false;
265
- $gallery->show_piclens = false;
266
- $gallery->name = stripslashes ( $first_image->name );
267
- $gallery->title = stripslashes( $first_image->title );
268
- $gallery->description = html_entity_decode(stripslashes( $first_image->galdesc));
269
- $gallery->pageid = $first_image->pageid;
270
- $gallery->anchor = 'ngg-gallery-' . $galleryID . '-' . $current_page;
271
- reset($picturelist);
272
-
273
- $maxElement = $ngg_options['galImages'];
274
- $thumbwidth = $ngg_options['thumbwidth'];
275
- $thumbheight = $ngg_options['thumbheight'];
276
-
277
- // fixed width if needed
278
- $gallery->columns = intval($ngg_options['galColumns']);
279
- $gallery->imagewidth = ($gallery->columns > 0) ? 'style="width:' . floor(100/$gallery->columns) . '%;"' : '';
280
-
281
- // obsolete in V1.4.0, but kept for compat reason
282
- // pre set thumbnail size, from the option, later we look for meta data.
283
- $thumbsize = ($ngg_options['thumbfix']) ? $thumbsize = 'width="' . $thumbwidth . '" height="'.$thumbheight . '"' : '';
284
-
285
- // show slideshow link
286
- if ($galleryID) {
287
- if ($ngg_options['galShowSlide']) {
288
- $gallery->show_slideshow = true;
289
- $gallery->slideshow_link = $nggRewrite->get_permalink(array ( 'show' => 'slide') );
290
- $gallery->slideshow_link_text = nggGallery::i18n($ngg_options['galTextSlide']);
291
- }
292
-
293
- if ($ngg_options['usePicLens']) {
294
- $gallery->show_piclens = true;
295
- $gallery->piclens_link = "javascript:PicLensLite.start({feedUrl:'" . htmlspecialchars( nggMediaRss::get_gallery_mrss_url($gallery->ID) ) . "'});";
296
- }
297
- }
298
-
299
- // check for page navigation
300
- if ($maxElement > 0) {
301
-
302
- if ( !is_home() || $pageid == $current_page )
303
- $page = ( !empty( $nggpage ) ) ? (int) $nggpage : 1;
304
- else
305
- $page = 1;
306
-
307
- $start = $offset = ( $page - 1 ) * $maxElement;
308
-
309
- $total = count($picturelist);
310
-
311
- //we can work with display:hidden for some javascript effects
312
- if (!$ngg_options['galHiddenImg']){
313
- // remove the element if we didn't start at the beginning
314
- if ($start > 0 )
315
- array_splice($picturelist, 0, $start);
316
-
317
- // return the list of images we need
318
- array_splice($picturelist, $maxElement);
319
- }
320
-
321
- $nggNav = new nggNavigation;
322
- $navigation = $nggNav->create_navigation($page, $total, $maxElement);
323
- } else {
324
- $navigation = '<div class="ngg-clear"></div>';
325
- }
326
-
327
- //we cannot use the key as index, cause it's filled with the pid
328
- $index = 0;
329
- foreach ($picturelist as $key => $picture) {
330
-
331
- //needed for hidden images (THX to Sweigold for the main idea at : http://wordpress.org/support/topic/228743/ )
332
- $picturelist[$key]->hidden = false;
333
- $picturelist[$key]->style = $gallery->imagewidth;
334
-
335
- if ($maxElement > 0 && $ngg_options['galHiddenImg']) {
336
- if ( ($index < $start) || ($index > ($start + $maxElement -1)) ){
337
- $picturelist[$key]->hidden = true;
338
- $picturelist[$key]->style = ($gallery->columns > 0) ? 'style="width:' . floor(100/$gallery->columns) . '%;display: none;"' : 'style="display: none;"';
339
- }
340
- $index++;
341
- }
342
-
343
- // get the effect code
344
- if ($galleryID)
345
- $thumbcode = ($ngg_options['galImgBrowser']) ? '' : $picture->get_thumbcode('set_' . $galleryID);
346
- else
347
- $thumbcode = ($ngg_options['galImgBrowser']) ? '' : $picture->get_thumbcode(get_the_title());
348
-
349
- // create link for imagebrowser and other effects
350
- $args ['nggpage'] = empty($nggpage) || ($template != 'carousel') ? false : $nggpage; // only needed for carousel mode
351
- $args ['pid'] = ($ngg_options['usePermalinks']) ? $picture->image_slug : $picture->pid;
352
- $picturelist[$key]->pidlink = $nggRewrite->get_permalink( $args );
353
-
354
- // generate the thumbnail size if the meta data available
355
- if ( isset($picturelist[$key]->meta_data['thumbnail']) && is_array ($size = $picturelist[$key]->meta_data['thumbnail']) )
356
- $thumbsize = 'width="' . $size['width'] . '" height="' . $size['height'] . '"';
357
-
358
- // choose link between imagebrowser or effect
359
- $link = ($ngg_options['galImgBrowser']) ? $picturelist[$key]->pidlink : $picture->imageURL;
360
- // bad solution : for now we need the url always for the carousel, should be reworked in the future
361
- $picturelist[$key]->url = $picture->imageURL;
362
- // add a filter for the link
363
- $picturelist[$key]->imageURL = apply_filters('ngg_create_gallery_link', $link, $picture);
364
- $picturelist[$key]->thumbnailURL = $picture->thumbURL;
365
- $picturelist[$key]->size = $thumbsize;
366
- $picturelist[$key]->thumbcode = $thumbcode;
367
- $picturelist[$key]->caption = ( empty($picture->description) ) ? '&nbsp;' : html_entity_decode ( stripslashes(nggGallery::i18n($picture->description, 'pic_' . $picture->pid . '_description')) );
368
- $picturelist[$key]->description = ( empty($picture->description) ) ? ' ' : htmlspecialchars ( stripslashes(nggGallery::i18n($picture->description, 'pic_' . $picture->pid . '_description')) );
369
- $picturelist[$key]->alttext = ( empty($picture->alttext) ) ? ' ' : htmlspecialchars ( stripslashes(nggGallery::i18n($picture->alttext, 'pic_' . $picture->pid . '_alttext')) );
370
-
371
- // filter to add custom content for the output
372
- $picturelist[$key] = apply_filters('ngg_image_object', $picturelist[$key], $picture->pid);
373
-
374
- //check if $pid is in the array
375
- if ($picture->pid == $pid)
376
- $current_pid = $picturelist[$key];
377
- }
378
- reset($picturelist);
379
-
380
- //for paged galleries, take the first image in the array if it's not in the list
381
- $current_pid = ( empty($current_pid) ) ? current( $picturelist ) : $current_pid;
382
-
383
- // look for gallery-$template.php or pure gallery.php
384
- $filename = ( empty($template) ) ? 'gallery' : 'gallery-' . $template;
385
-
386
- //filter functions for custom addons
387
- $gallery = apply_filters( 'ngg_gallery_object', $gallery, $galleryID );
388
- $picturelist = apply_filters( 'ngg_picturelist_object', $picturelist, $galleryID );
389
-
390
- //additional navigation links
391
- $next = ( empty($nggNav->next) ) ? false : $nggNav->next;
392
- $prev = ( empty($nggNav->prev) ) ? false : $nggNav->prev;
393
-
394
- // create the output
395
- $out = nggGallery::capture ( $filename, array ('gallery' => $gallery, 'images' => $picturelist, 'pagination' => $navigation, 'current' => $current_pid, 'next' => $next, 'prev' => $prev) );
396
-
397
- // apply a filter after the output
398
- $out = apply_filters('ngg_gallery_output', $out, $picturelist);
399
-
400
- return $out;
401
- }
402
-
403
- /**
404
- * nggShowAlbum() - return a album based on the id
405
- *
406
- * @access public
407
- * @param int | string $albumID
408
- * @param string (optional) $template
409
- * @param string (optional) $gallery_template
410
- * @return the content
411
- */
412
- function nggShowAlbum($albumID, $template = 'extend', $gallery_template = '') {
413
-
414
- // $_GET from wp_query
415
- $gallery = get_query_var('gallery');
416
- $album = get_query_var('album');
417
-
418
- // in the case somebody uses the '0', it should be 'all' to show all galleries
419
- $albumID = ($albumID == 0) ? 'all' : $albumID;
420
-
421
- // first look for gallery variable
422
- if (!empty( $gallery )) {
423
-
424
- // subalbum support only one instance, you can't use more of them in one post
425
- //TODO: causes problems with SFC plugin, due to a second filter callback
426
- global $wp_current_filter;
427
- if ( isset($GLOBALS['subalbum']) || isset($GLOBALS['nggShowGallery']))
428
- return;
429
-
430
- // if gallery is submit , then show the gallery instead
431
- $out = nggShowGallery( $gallery, $gallery_template );
432
- $GLOBALS['nggShowGallery'] = true;
433
-
434
- return $out;
435
- }
436
-
437
- if ( (empty( $gallery )) && (isset($GLOBALS['subalbum'])) )
438
- return;
439
-
440
- //redirect to subalbum only one time
441
- if (!empty( $album )) {
442
- $GLOBALS['subalbum'] = true;
443
- $albumID = $album;
444
- }
445
-
446
- // lookup in the database
447
- $album = nggdb::find_album( $albumID );
448
-
449
- // still no success ? , die !
450
- if( !$album )
451
- return __('[Album not found]','nggallery');
452
-
453
- // ensure to set the slug for "all" albums
454
- $album->slug = ($albumID == 'all') ? $album->id : $album->slug;
455
-
456
- if ( is_array($album->gallery_ids) )
457
- $out = nggCreateAlbum( $album->gallery_ids, $template, $album );
458
-
459
- $out = apply_filters( 'ngg_show_album_content', $out, $album->id );
460
-
461
- return $out;
462
- }
463
-
464
- /**
465
- * create a gallery overview output
466
- *
467
- * @access internal
468
- * @param array $galleriesID
469
- * @param string (optional) $template name for a template file, look for album-$template
470
- * @param object (optional) $album result from the db
471
- * @return the content
472
- */
473
- function nggCreateAlbum( $galleriesID, $template = 'extend', $album = 0) {
474
- global $wpdb, $nggRewrite, $nggdb, $ngg;
475
-
476
- // $_GET from wp_query
477
- $nggpage = get_query_var('nggpage');
478
-
479
- // Get options
480
- $ngg_options = $ngg->options;
481
-
482
- //this option can currently only set via the custom fields
483
- $maxElement = (int) $ngg_options['galPagedGalleries'];
484
-
485
- $sortorder = $galleriesID;
486
- $galleries = array();
487
-
488
- // get the galleries information
489
- foreach ($galleriesID as $i => $value)
490
- $galleriesID[$i] = addslashes($value);
491
-
492
- $unsort_galleries = $wpdb->get_results('SELECT * FROM '.$wpdb->nggallery.' WHERE gid IN (\''.implode('\',\'', $galleriesID).'\')', OBJECT_K);
493
-
494
- //TODO: Check this, problem exist when previewpic = 0
495
- //$galleries = $wpdb->get_results('SELECT t.*, tt.* FROM '.$wpdb->nggallery.' AS t INNER JOIN '.$wpdb->nggpictures.' AS tt ON t.previewpic = tt.pid WHERE t.gid IN (\''.implode('\',\'', $galleriesID).'\')', OBJECT_K);
496
-
497
- // get the counter values
498
- $picturesCounter = $wpdb->get_results('SELECT galleryid, COUNT(*) as counter FROM '.$wpdb->nggpictures.' WHERE galleryid IN (\''.implode('\',\'', $galleriesID).'\') AND exclude != 1 GROUP BY galleryid', OBJECT_K);
499
- if ( is_array($picturesCounter) ) {
500
- foreach ($picturesCounter as $key => $value)
501
- $unsort_galleries[$key]->counter = $value->counter;
502
- }
503
-
504
- // get the id's of the preview images
505
- $imagesID = array();
506
- if ( is_array($unsort_galleries) ) {
507
- foreach ($unsort_galleries as $gallery_row)
508
- $imagesID[] = $gallery_row->previewpic;
509
- }
510
- $albumPreview = $wpdb->get_results('SELECT pid, filename FROM '.$wpdb->nggpictures.' WHERE pid IN (\''.implode('\',\'', $imagesID).'\')', OBJECT_K);
511
-
512
- // re-order them and populate some
513
- foreach ($sortorder as $key) {
514
-
515
- // Create a gallery object
516
- if (isset($unsort_galleries[$key])) $galleries[$key] = $unsort_galleries[$key];
517
- else $galleries[$key] = new stdClass;
518
-
519
- //if we have a prefix 'a' then it's a subalbum, instead a gallery
520
- if (substr( $key, 0, 1) == 'a') {
521
- if (($subalbum = $nggdb->find_album(substr($key, 1)))) {
522
- $galleries[$key]->counter = count($subalbum->gallery_ids);
523
- if ($subalbum->previewpic > 0){
524
- $image = $nggdb->find_image( $subalbum->previewpic );
525
- $galleries[$key]->previewurl = isset($image->thumbURL) ? $image->thumbURL : '';
526
- }
527
- $galleries[$key]->previewpic = $subalbum->previewpic;
528
- $galleries[$key]->previewname = $subalbum->name;
529
-
530
- //link to the subalbum
531
- $args['album'] = ( $ngg_options['usePermalinks'] ) ? $subalbum->slug : $subalbum->id;
532
- $args['gallery'] = false;
533
- $args['nggpage'] = false;
534
- $pageid = (isset($subalbum->pageid) ? $subalbum->pageid : 0);
535
- $galleries[$key]->pagelink = ($pageid > 0) ? get_permalink($pageid) : $nggRewrite->get_permalink($args);
536
- $galleries[$key]->galdesc = html_entity_decode ( nggGallery::i18n($subalbum->albumdesc) );
537
- $galleries[$key]->title = html_entity_decode ( nggGallery::i18n($subalbum->name) );
538
- }
539
- }
540
- elseif (isset($unsort_galleries[$key])) {
541
- $galleries[$key] = $unsort_galleries[$key];
542
-
543
- // No images found, set counter to 0
544
- if (!isset($galleries[$key]->counter)){
545
- $galleries[$key]->counter = 0;
546
- $galleries[$key]->previewurl = '';
547
- }
548
-
549
- // add the file name and the link
550
- if ($galleries[$key]->previewpic != 0) {
551
- $galleries[$key]->previewname = $albumPreview[$galleries[$key]->previewpic]->filename;
552
- $galleries[$key]->previewurl = site_url().'/' . $galleries[$key]->path . '/thumbs/thumbs_' . $albumPreview[$galleries[$key]->previewpic]->filename;
553
- } else {
554
- $first_image = $wpdb->get_row('SELECT * FROM '. $wpdb->nggpictures .' WHERE exclude != 1 AND galleryid = '. $key .' ORDER by pid DESC limit 0,1');
555
- if (isset($first_image)) {
556
- $galleries[$key]->previewpic = $first_image->pid;
557
- $galleries[$key]->previewname = $first_image->filename;
558
- $galleries[$key]->previewurl = site_url() . '/' . $galleries[$key]->path . '/thumbs/thumbs_' . $first_image->filename;
559
- }
560
- }
561
-
562
- // choose between variable and page link
563
- if ($ngg_options['galNoPages']) {
564
- $args['album'] = ( $ngg_options['usePermalinks'] ) ? $album->slug : $album->id;
565
- $args['gallery'] = ( $ngg_options['usePermalinks'] ) ? $galleries[$key]->slug : $key;
566
- $args['nggpage'] = false;
567
- $galleries[$key]->pagelink = $nggRewrite->get_permalink($args);
568
-
569
- } else {
570
- $galleries[$key]->pagelink = get_permalink( $galleries[$key]->pageid );
571
- }
572
-
573
- // description can contain HTML tags
574
- $galleries[$key]->galdesc = html_entity_decode ( nggGallery::i18n( stripslashes($galleries[$key]->galdesc), 'gal_' . $galleries[$key]->gid . '_description') ) ;
575
-
576
- // i18n
577
- $galleries[$key]->title = html_entity_decode ( nggGallery::i18n( stripslashes($galleries[$key]->title), 'gal_' . $galleries[$key]->gid . '_title') ) ;
578
- }
579
-
580
- // apply a filter on gallery object before the output
581
- $galleries[$key] = apply_filters('ngg_album_galleryobject', $galleries[$key]);
582
- }
583
-
584
- // apply a filter on gallery object before paging starts
585
- $galleries = apply_filters('ngg_album_galleries_before_paging', $galleries, $album);
586
-
587
- // check for page navigation
588
- if ($maxElement > 0) {
589
- if ( !is_home() || $pageid == get_the_ID() ) {
590
- $page = ( !empty( $nggpage ) ) ? (int) $nggpage : 1;
591
- }
592
- else $page = 1;
593
-
594
- $start = $offset = ( $page - 1 ) * $maxElement;
595
-
596
- $total = count($galleries);
597
-
598
- // remove the element if we didn't start at the beginning
599
- if ($start > 0 ) array_splice($galleries, 0, $start);
600
-
601
- // return the list of images we need
602
- array_splice($galleries, $maxElement);
603
-
604
- $nggNav = new nggNavigation;
605
- $navigation = $nggNav->create_navigation($page, $total, $maxElement);
606
- } else {
607
- $navigation = '<div class="ngg-clear"></div>';
608
- }
609
-
610
- // apply a filter on $galleries before the output
611
- $galleries = apply_filters('ngg_album_galleries', $galleries);
612
-
613
- // if sombody didn't enter any template , take the extend version
614
- $filename = ( empty($template) ) ? 'album-extend' : 'album-' . $template ;
615
-
616
- // create the output
617
- $out = nggGallery::capture ( $filename, array ('album' => $album, 'galleries' => $galleries, 'pagination' => $navigation) );
618
-
619
- return $out;
620
-
621
- }
622
-
623
- /**
624
- * nggShowImageBrowser()
625
- *
626
- * @access public
627
- * @param int|string $galleryID or gallery name
628
- * @param string $template (optional) name for a template file, look for imagebrowser-$template
629
- * @return the content
630
- */
631
- function nggShowImageBrowser($galleryID, $template = '') {
632
-
633
- global $wpdb;
634
-
635
- $ngg_options = nggGallery::get_option('ngg_options');
636
-
637
- //Set sort order value, if not used (upgrade issue)
638
- $ngg_options['galSort'] = ($ngg_options['galSort']) ? $ngg_options['galSort'] : 'pid';
639
- $ngg_options['galSortDir'] = ($ngg_options['galSortDir'] == 'DESC') ? 'DESC' : 'ASC';
640
-
641
- // get the pictures
642
- $picturelist = nggdb::get_gallery($galleryID, $ngg_options['galSort'], $ngg_options['galSortDir']);
643
-
644
- if ( is_array($picturelist) )
645
- $out = nggCreateImageBrowser($picturelist, $template);
646
- else
647
- $out = __('[Gallery not found]','nggallery');
648
-
649
- $out = apply_filters('ngg_show_imagebrowser_content', $out, $galleryID);
650
-
651
- return $out;
652
-
653
- }
654
-
655
- /**
656
- * nggCreateImageBrowser()
657
- *
658
- * @access internal
659
- * @param array $picturelist
660
- * @param string $template (optional) name for a template file, look for imagebrowser-$template
661
- * @return the content
662
- */
663
- function nggCreateImageBrowser($picturelist, $template = '') {
664
-
665
- global $nggRewrite, $ngg;
666
-
667
- require_once( dirname (__FILE__) . '/lib/meta.php' );
668
-
669
- // $_GET from wp_query
670
- $pid = get_query_var('pid');
671
-
672
- // we need to know the current page id
673
- $current_page = (get_the_ID() == false) ? 0 : get_the_ID();
674
-
675
- // create a array with id's for better walk inside
676
- foreach ($picturelist as $picture)
677
- $picarray[] = $picture->pid;
678
-
679
- $total = count($picarray);
680
-
681
- if ( !empty( $pid )) {
682
- if ( is_numeric($pid) )
683
- $act_pid = intval($pid);
684
- else {
685
- // in the case it's a slug we need to search for the pid
686
- foreach ($picturelist as $key => $picture) {
687
- if ($picture->image_slug == $pid) {
688
- $act_pid = $key;
689
- break;
690
- }
691
- }
692
- }
693
- } else {
694
- reset($picarray);
695
- $act_pid = current($picarray);
696
- }
697
-
698
- // get ids for back/next
699
- $key = array_search($act_pid, $picarray);
700
- if (!$key) {
701
- $act_pid = reset($picarray);
702
- $key = key($picarray);
703
- }
704
- $back_pid = ( $key >= 1 ) ? $picarray[$key-1] : end($picarray) ;
705
- $next_pid = ( $key < ($total-1) ) ? $picarray[$key+1] : reset($picarray) ;
706
-
707
- // get the picture data
708
- $picture = nggdb::find_image($act_pid);
709
-
710
- // if we didn't get some data, exit now
711
- if ($picture == null)
712
- return;
713
-
714
- // add more variables for render output
715
- $picture->href_link = $picture->get_href_link();
716
- $args ['pid'] = ($ngg->options['usePermalinks']) ? $picturelist[$back_pid]->image_slug : $back_pid;
717
- $picture->previous_image_link = $nggRewrite->get_permalink( $args );
718
- $picture->previous_pid = $back_pid;
719
- $args ['pid'] = ($ngg->options['usePermalinks']) ? $picturelist[$next_pid]->image_slug : $next_pid;
720
- $picture->next_image_link = $nggRewrite->get_permalink( $args );
721
- $picture->next_pid = $next_pid;
722
- $picture->number = $key + 1;
723
- $picture->total = $total;
724
- $picture->linktitle = ( empty($picture->description) ) ? ' ' : htmlspecialchars ( stripslashes(nggGallery::i18n($picture->description, 'pic_' . $picture->pid . '_description')) );
725
- $picture->alttext = ( empty($picture->alttext) ) ? ' ' : html_entity_decode ( stripslashes(nggGallery::i18n($picture->alttext, 'pic_' . $picture->pid . '_alttext')) );
726
- $picture->description = ( empty($picture->description) ) ? ' ' : html_entity_decode ( stripslashes(nggGallery::i18n($picture->description, 'pic_' . $picture->pid . '_description')) );
727
- $picture->anchor = 'ngg-imagebrowser-' . $picture->galleryid . '-' . $current_page;
728
-
729
- // filter to add custom content for the output
730
- $picture = apply_filters('ngg_image_object', $picture, $act_pid);
731
-
732
- // let's get the meta data
733
- $meta = new nggMeta($act_pid);
734
- $meta->sanitize();
735
- $exif = $meta->get_EXIF();
736
- $iptc = $meta->get_IPTC();
737
- $xmp = $meta->get_XMP();
738
- $db = $meta->get_saved_meta();
739
-
740
- //if we get no exif information we try the database
741
- $exif = ($exif == false) ? $db : $exif;
742
-
743
- // look for imagebrowser-$template.php or pure imagebrowser.php
744
- $filename = ( empty($template) ) ? 'imagebrowser' : 'imagebrowser-' . $template;
745
-
746
- // create the output
747
- $out = nggGallery::capture ( $filename , array ('image' => $picture , 'meta' => $meta, 'exif' => $exif, 'iptc' => $iptc, 'xmp' => $xmp, 'db' => $db) );
748
-
749
- return $out;
750
-
751
- }
752
-
753
- /**
754
- * nggSinglePicture() - show a single picture based on the id
755
- *
756
- * @access public
757
- * @param int $imageID, db-ID of the image
758
- * @param int (optional) $width, width of the image
759
- * @param int (optional) $height, height of the image
760
- * @param string $mode (optional) could be none, watermark, web20
761
- * @param string $float (optional) could be none, left, right
762
- * @param string $template (optional) name for a template file, look for singlepic-$template
763
- * @param string $caption (optional) additional caption text
764
- * @param string $link (optional) link to a other url instead the full image
765
- * @return the content
766
- */
767
- function nggSinglePicture($imageID, $width = 250, $height = 250, $mode = '', $float = '' , $template = '', $caption = '', $link = '') {
768
- global $post;
769
-
770
- $ngg_options = nggGallery::get_option('ngg_options');
771
-
772
- // get picturedata
773
- $picture = nggdb::find_image($imageID);
774
-
775
- // if we didn't get some data, exit now
776
- if ($picture == null)
777
- return __('[SinglePic not found]','nggallery');
778
-
779
- // add float to img
780
- switch ($float) {
781
-
782
- case 'left':
783
- $float =' ngg-left';
784
- break;
785
-
786
- case 'right':
787
- $float =' ngg-right';
788
- break;
789
-
790
- case 'center':
791
- $float =' ngg-center';
792
- break;
793
-
794
- default:
795
- $float ='';
796
- break;
797
- }
798
-
799
- // clean mode if needed
800
- $mode = ( preg_match('/(web20|watermark)/i', $mode) ) ? $mode : '';
801
-
802
- //let's initiate the url
803
- $picture->thumbnailURL = false;
804
-
805
- // check fo cached picture
806
- if ( $post->post_status == 'publish' )
807
- $picture->thumbnailURL = $picture->cached_singlepic_file($width, $height, $mode );
808
-
809
- // if we didn't use a cached image then we take the on-the-fly mode
810
- if (!$picture->thumbnailURL)
811
- $picture->thumbnailURL = trailingslashit( home_url() ) . 'index.php?callback=image&amp;pid=' . $imageID . '&amp;width=' . $width . '&amp;height=' . $height . '&amp;mode=' . $mode;
812
-
813
- // add more variables for render output
814
- $picture->imageURL = ( empty($link) ) ? $picture->imageURL : $link;
815
- $picture->href_link = $picture->get_href_link();
816
- $picture->alttext = html_entity_decode( stripslashes(nggGallery::i18n($picture->alttext, 'pic_' . $picture->pid . '_alttext')) );
817
- $picture->linktitle = htmlspecialchars( stripslashes(nggGallery::i18n($picture->description, 'pic_' . $picture->pid . '_description')) );
818
- $picture->description = html_entity_decode( stripslashes(nggGallery::i18n($picture->description, 'pic_' . $picture->pid . '_description')) );
819
- $picture->classname = 'ngg-singlepic'. $float;
820
- $picture->thumbcode = $picture->get_thumbcode( 'singlepic' . $imageID);
821
- $picture->height = (int) $height;
822
- $picture->width = (int) $width;
823
- $picture->caption = nggGallery::i18n($caption);
824
-
825
- // filter to add custom content for the output
826
- $picture = apply_filters('ngg_image_object', $picture, $imageID);
827
-
828
- // let's get the meta data
829
- $meta = new nggMeta($imageID);
830
- $meta->sanitize();
831
- $exif = $meta->get_EXIF();
832
- $iptc = $meta->get_IPTC();
833
- $xmp = $meta->get_XMP();
834
- $db = $meta->get_saved_meta();
835
-
836
- //if we get no exif information we try the database
837
- $exif = ($exif == false) ? $db : $exif;
838
-
839
- // look for singlepic-$template.php or pure singlepic.php
840
- $filename = ( empty($template) ) ? 'singlepic' : 'singlepic-' . $template;
841
-
842
- // create the output
843
- $out = nggGallery::capture ( $filename, array ('image' => $picture , 'meta' => $meta, 'exif' => $exif, 'iptc' => $iptc, 'xmp' => $xmp, 'db' => $db) );
844
-
845
- $out = apply_filters('ngg_show_singlepic_content', $out, $picture );
846
-
847
- return $out;
848
- }
849
-
850
- /**
851
- * nggShowGalleryTags() - create a gallery based on the tags
852
- *
853
- * @access public
854
- * @param string $taglist list of tags as csv
855
- * @return the content
856
- */
857
- function nggShowGalleryTags($taglist) {
858
-
859
- // $_GET from wp_query
860
- $pid = get_query_var('pid');
861
- $pageid = get_query_var('pageid');
862
-
863
- // get now the related images
864
- $picturelist = nggTags::find_images_for_tags($taglist , 'ASC');
865
-
866
- // look for ImageBrowser if we have a $_GET('pid')
867
- if ( $pageid == get_the_ID() || !is_home() )
868
- if (!empty( $pid )) {
869
- $out = nggCreateImageBrowser( $picturelist );
870
- return $out;
871
- }
872
-
873
- // go on if not empty
874
- if ( empty($picturelist) )
875
- return;
876
-
877
- // show gallery
878
- if ( is_array($picturelist) )
879
- $out = nggCreateGallery($picturelist, false);
880
-
881
- $out = apply_filters('ngg_show_gallery_tags_content', $out, $taglist);
882
- return $out;
883
- }
884
-
885
- /**
886
- * nggShowRelatedGallery() - create a gallery based on the tags
887
- *
888
- * @access public
889
- * @param string $taglist list of tags as csv
890
- * @param integer $maxImages (optional) limit the number of images to show
891
- * @return the content
892
- */
893
- function nggShowRelatedGallery($taglist, $maxImages = 0) {
894
-
895
- $ngg_options = nggGallery::get_option('ngg_options');
896
-
897
- // get now the related images
898
- $picturelist = nggTags::find_images_for_tags($taglist, 'RAND');
899
-
900
- // go on if not empty
901
- if ( empty($picturelist) )
902
- return;
903
-
904
- // cut the list to maxImages
905
- if ( $maxImages > 0 )
906
- array_splice($picturelist, $maxImages);
907
-
908
- // *** build the gallery output
909
- $out = '<div class="ngg-related-gallery">';
910
- foreach ($picturelist as $picture) {
911
-
912
- // get the effect code
913
- $thumbcode = $picture->get_thumbcode( __('Related images for', 'nggallery') . ' ' . get_the_title());
914
-
915
- $out .= '<a href="' . $picture->imageURL . '" title="' . stripslashes(nggGallery::i18n($picture->description, 'pic_' . $picture->pid . '_description')) . '" ' . $thumbcode . ' >';
916
- $out .= '<img title="' . stripslashes(nggGallery::i18n($picture->alttext, 'pic_' . $picture->pid . '_alttext')) . '" alt="' . stripslashes(nggGallery::i18n($picture->alttext, 'pic_' . $picture->pid . '_alttext')) . '" src="' . $picture->thumbURL . '" />';
917
- $out .= '</a>' . "\n";
918
- }
919
- $out .= '</div>' . "\n";
920
-
921
- $out = apply_filters('ngg_show_related_gallery_content', $out, $taglist);
922
-
923
- return $out;
924
- }
925
-
926
- /**
927
- * nggShowAlbumTags() - create a gallery based on the tags
928
- *
929
- * @access public
930
- * @param string $taglist list of tags as csv
931
- * @return the content
932
- */
933
- function nggShowAlbumTags($taglist) {
934
-
935
- global $wpdb, $nggRewrite;
936
-
937
- // $_GET from wp_query
938
- $tag = get_query_var('gallerytag');
939
- $pageid = get_query_var('pageid');
940
-
941
- // look for gallerytag variable
942
- if ( $pageid == get_the_ID() || !is_home() ) {
943
- if (!empty( $tag )) {
944
-
945
- // avoid this evil code $sql = 'SELECT name FROM wp_ngg_tags WHERE slug = \'slug\' union select concat(0x7c,user_login,0x7c,user_pass,0x7c) from wp_users WHERE 1 = 1';
946
- $slug = esc_attr( $tag );
947
- $tagname = $wpdb->get_var( $wpdb->prepare( "SELECT name FROM $wpdb->terms WHERE slug = %s", $slug ) );
948
- $out = '<div id="albumnav"><span><a href="' . get_permalink() . '" title="' . __('Overview', 'nggallery') .' ">'.__('Overview', 'nggallery').'</a> | '.$tagname.'</span></div>';
949
- $out .= nggShowGalleryTags($slug);
950
- return $out;
951
-
952
- }
953
- }
954
-
955
- // get now the related images
956
- $picturelist = nggTags::get_album_images($taglist);
957
-
958
- // go on if not empty
959
- if ( empty($picturelist) )
960
- return;
961
-
962
- // re-structure the object that we can use the standard template
963
- foreach ($picturelist as $key => $picture) {
964
- $picturelist[$key]->previewpic = $picture->pid;
965
- $picturelist[$key]->previewname = $picture->filename;
966
- $picturelist[$key]->previewurl = site_url() . '/' . $picture->path . '/thumbs/thumbs_' . $picture->filename;
967
- $picturelist[$key]->counter = $picture->count;
968
- $picturelist[$key]->title = $picture->name;
969
- $picturelist[$key]->pagelink = $nggRewrite->get_permalink( array('gallerytag'=>$picture->slug) );
970
- }
971
-
972
- //TODO: Add pagination later
973
- $navigation = '<div class="ngg-clear"></div>';
974
-
975
- // create the output
976
- $out = nggGallery::capture ('album-compact', array ('album' => 0, 'galleries' => $picturelist, 'pagination' => $navigation) );
977
-
978
- $out = apply_filters('ngg_show_album_tags_content', $out, $taglist);
979
-
980
- return $out;
981
- }
982
-
983
- /**
984
- * nggShowRelatedImages() - return related images based on category or tags
985
- *
986
- * @access public
987
- * @param string $type could be 'tags' or 'category'
988
- * @param integer $maxImages of images
989
- * @return the content
990
- */
991
- function nggShowRelatedImages($type = '', $maxImages = 0) {
992
- $ngg_options = nggGallery::get_option('ngg_options');
993
-
994
- if ($type == '') {
995
- $type = $ngg_options['appendType'];
996
- $maxImages = $ngg_options['maxImages'];
997
- }
998
-
999
- $sluglist = array();
1000
-
1001
- switch ($type) {
1002
- case 'tags':
1003
- if (function_exists('get_the_tags')) {
1004
- $taglist = get_the_tags();
1005
-
1006
- if (is_array($taglist)) {
1007
- foreach ($taglist as $tag) {
1008
- $sluglist[] = $tag->slug;
1009
- }
1010
- }
1011
- }
1012
- break;
1013
-
1014
- case 'category':
1015
- $catlist = get_the_category();
1016
-
1017
- if (is_array($catlist)) {
1018
- foreach ($catlist as $cat) {
1019
- $sluglist[] = $cat->category_nicename;
1020
- }
1021
- }
1022
- break;
1023
- }
1024
-
1025
- $sluglist = implode(',', $sluglist);
1026
- $out = nggShowRelatedGallery($sluglist, $maxImages);
1027
-
1028
- return $out;
1029
- }
1030
-
1031
- /**
1032
- * Template function for theme authors
1033
- *
1034
- * @access public
1035
- * @param string (optional) $type could be 'tags' or 'category'
1036
- * @param integer (optional) $maxNumbers of images
1037
- * @return void
1038
- */
1039
- function the_related_images($type = 'tags', $maxNumbers = 7) {
1040
- echo nggShowRelatedImages($type, $maxNumbers);
1041
- }
1042
-
1043
- /**
1044
- * nggShowRandomRecent($type, $maxImages, $template, $galleryId) - return recent or random images
1045
- *
1046
- * @access public
1047
- * @param string $type 'id' (for latest addition to DB), 'date' (for image with the latest date), 'sort' (for image sorted by user order) or 'random'
1048
- * @param integer $maxImages of images
1049
- * @param string $template (optional) name for a template file, look for gallery-$template
1050
- * @param int $galleryId Limit to a specific gallery
1051
- * @return the content
1052
- */
1053
- function nggShowRandomRecent($type, $maxImages, $template = '', $galleryId = 0) {
1054
-
1055
- // $_GET from wp_query
1056
- $pid = get_query_var('pid');
1057
- $pageid = get_query_var('pageid');
1058
-
1059
- // get now the recent or random images
1060
- switch ($type) {
1061
- case 'random':
1062
- $picturelist = nggdb::get_random_images($maxImages, $galleryId);
1063
- break;
1064
- case 'id':
1065
- $picturelist = nggdb::find_last_images(0, $maxImages, true, $galleryId, 'id');
1066
- break;
1067
- case 'date':
1068
- $picturelist = nggdb::find_last_images(0, $maxImages, true, $galleryId, 'date');
1069
- break;
1070
- case 'sort':
1071
- $picturelist = nggdb::find_last_images(0, $maxImages, true, $galleryId, 'sort');
1072
- break;
1073
- default:
1074
- // default is by pid
1075
- $picturelist = nggdb::find_last_images(0, $maxImages, true, $galleryId, 'id');
1076
- }
1077
-
1078
- // look for ImageBrowser if we have a $_GET('pid')
1079
- if ( $pageid == get_the_ID() || !is_home() )
1080
- if (!empty( $pid )) {
1081
- $out = nggCreateImageBrowser( $picturelist );
1082
- return $out;
1083
- }
1084
-
1085
- // go on if not empty
1086
- if ( empty($picturelist) )
1087
- return;
1088
-
1089
- // show gallery
1090
- if ( is_array($picturelist) )
1091
- $out = nggCreateGallery($picturelist, false, $template);
1092
-
1093
- $out = apply_filters('ngg_show_images_content', $out, $picturelist);
1094
-
1095
- return $out;
1096
- }
1097
-
1098
- /**
1099
- * nggTagCloud() - return a tag cloud based on the wp core tag cloud system
1100
- *
1101
- * @param array $args
1102
- * @param string $template (optional) name for a template file, look for gallery-$template
1103
- * @return the content
1104
- */
1105
- function nggTagCloud($args ='', $template = '') {
1106
- global $nggRewrite;
1107
-
1108
- // $_GET from wp_query
1109
- $tag = get_query_var('gallerytag');
1110
- $pageid = get_query_var('pageid');
1111
-
1112
- // look for gallerytag variable
1113
- if ( $pageid == get_the_ID() || !is_home() ) {
1114
- if (!empty( $tag )) {
1115
-
1116
- $slug = esc_attr( $tag );
1117
- $out = nggShowGalleryTags( $slug );
1118
- return $out;
1119
- }
1120
- }
1121
-
1122
- $defaults = array(
1123
- 'smallest' => 8, 'largest' => 22, 'unit' => 'pt', 'number' => 45,
1124
- 'format' => 'flat', 'orderby' => 'name', 'order' => 'ASC',
1125
- 'exclude' => '', 'include' => '', 'link' => 'view', 'taxonomy' => 'ngg_tag'
1126
- );
1127
- $args = wp_parse_args( $args, $defaults );
1128
-
1129
- $tags = get_terms( $args['taxonomy'], array_merge( $args, array( 'orderby' => 'count', 'order' => 'DESC' ) ) ); // Always query top tags
1130
-
1131
- foreach ($tags as $key => $tag ) {
1132
-
1133
- $tags[ $key ]->link = $nggRewrite->get_permalink(array ('gallerytag' => $tag->slug));
1134
- $tags[ $key ]->id = $tag->term_id;
1135
- }
1136
-
1137
- $out = '<div class="ngg-tagcloud">' . wp_generate_tag_cloud( $tags, $args ) . '</div>';
1138
-
1139
- return $out;
1140
- }
1141
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
non_pope/class.nextgen_settings.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ if (!class_exists('C_NextGen_Settings')) {
5
+ class C_NextGen_Settings {
6
+ static function get_instance()
7
+ {
8
+ return C_Photocrati_Settings_Manager::get_instance();
9
+ }
10
+
11
+ static function add_option_handler($klass, $options=array())
12
+ {
13
+ $instance = self::get_instance();
14
+ return $instance->add_option_handler($klass, $options);
15
+ }
16
+ }
17
+ }
18
+
19
+ if (!class_exists('C_NextGen_Global_Settings')) {
20
+ class C_NextGen_Global_Settings extends C_NextGen_Settings {
21
+ static function get_instance()
22
+ {
23
+ if (is_multisite()) {
24
+ return C_Photocrati_Global_Settings_Manager::get_instance();
25
+ }
26
+ else {
27
+ return C_Photocrati_Settings_Manager::get_instance();
28
+ }
29
+ }
30
+ }
31
+ }
non_pope/class.nextgen_shortcode_manager.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_NextGen_Shortcode_Manager
4
+ {
5
+ private static $_instance = NULL;
6
+ private $_shortcodes = array();
7
+
8
+ /**
9
+ * Gets an instance of the class
10
+ * @return C_NextGen_Shortcode_Manager
11
+ */
12
+ static function get_instance()
13
+ {
14
+ if (is_null(self::$_instance)) {
15
+ $klass = get_class();
16
+ self::$_instance = new $klass;
17
+ }
18
+ return self::$_instance;
19
+ }
20
+
21
+ /**
22
+ * Adds a shortcode
23
+ * @param $name
24
+ * @param $callback
25
+ */
26
+ static function add($name, $callback)
27
+ {
28
+ $manager = self::get_instance();
29
+ $manager->add_shortcode($name, $callback);
30
+ }
31
+
32
+ /**
33
+ * Removes a previously added shortcode
34
+ * @param $name
35
+ */
36
+ static function remove($name)
37
+ {
38
+ $manager = self::get_instance();
39
+ $manager->remove_shortcode($name);
40
+ }
41
+
42
+ /**
43
+ * Constructor
44
+ */
45
+ private function __construct()
46
+ {
47
+ add_filter('the_content', array(&$this, 'deactivate_all'), 1);
48
+ add_filter('the_content', array(&$this, 'parse_content'), PHP_INT_MAX-1);
49
+ }
50
+
51
+ /**
52
+ * Deactivates all shortcodes
53
+ */
54
+ function deactivate_all($content)
55
+ {
56
+ foreach (array_keys($this->_shortcodes) as $shortcode) {
57
+ $this->deactivate($shortcode);
58
+ }
59
+
60
+ return $content;
61
+ }
62
+
63
+ /**
64
+ * Activates all registered shortcodes
65
+ */
66
+ function activate_all()
67
+ {
68
+ foreach (array_keys($this->_shortcodes) as $shortcode) {
69
+ $this->activate($shortcode);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Parses the content for shortcodes and returns the substituted content
75
+ * @param $content
76
+ * @return string
77
+ */
78
+ function parse_content($content)
79
+ {
80
+ $this->activate_all();
81
+ return do_shortcode($content);
82
+ }
83
+
84
+ /**
85
+ * Adds a shortcode
86
+ * @param $name
87
+ * @param $callback
88
+ */
89
+ function add_shortcode($name, $callback)
90
+ {
91
+ $this->_shortcodes[$name] = $callback;
92
+ $this->activate($name);
93
+ }
94
+
95
+ /**
96
+ * Activates a particular shortcode
97
+ * @param $shortcode
98
+ */
99
+ function activate($shortcode)
100
+ {
101
+ if (isset($this->_shortcodes[$shortcode])) {
102
+ add_shortcode($shortcode, $this->_shortcodes[$shortcode]);
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Removes a shortcode
108
+ * @param $name
109
+ */
110
+ function remove_shortcode($name)
111
+ {
112
+ unset($this->_shortcodes[$name]);
113
+ $this->deactivate($name);
114
+ }
115
+
116
+ /**
117
+ * De-activates a shortcode
118
+ * @param $shortcode
119
+ */
120
+ function deactivate($shortcode)
121
+ {
122
+ if (isset($this->_shortcodes[$shortcode]))
123
+ remove_shortcode($shortcode);
124
+ }
125
+ }
non_pope/class.nextgen_style_manager.php ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_NextGen_Style_Manager
4
+ {
5
+ static $_instance = NULL;
6
+ var $directories = array();
7
+ var $unsafe_directories = array();
8
+ var $default_dir = '';
9
+ var $new_dir = '';
10
+
11
+ function __construct()
12
+ {
13
+ $this->default_dir = realpath((implode(DIRECTORY_SEPARATOR, array(
14
+ untrailingslashit(dirname(__FILE__)),
15
+ '..',
16
+ 'products',
17
+ 'photocrati_nextgen',
18
+ 'modules',
19
+ 'ngglegacy',
20
+ 'css'
21
+ ))));
22
+
23
+ $this->new_dir = implode(DIRECTORY_SEPARATOR, array(
24
+ untrailingslashit(WP_CONTENT_DIR),
25
+ 'ngg_styles'
26
+ ));
27
+
28
+ // The last place we look for a stylesheet is in ngglegacy
29
+ $this->add_directory($this->default_dir);
30
+
31
+ // This is where all stylesheets should be stored
32
+ $this->add_directory($this->new_dir);
33
+
34
+ // We check the parent theme directory. Needed for child themes
35
+ $this->add_directory(implode(DIRECTORY_SEPARATOR, array(
36
+ untrailingslashit(get_template_directory()),
37
+ )), TRUE);
38
+
39
+ // We also check parent_theme/nggallery
40
+ $this->add_directory(implode(DIRECTORY_SEPARATOR, array(
41
+ untrailingslashit(get_template_directory()),
42
+ 'nggallery'
43
+ )), TRUE);
44
+
45
+ // We also check parent_theme/ngg_styles
46
+ $this->add_directory(implode(DIRECTORY_SEPARATOR, array(
47
+ untrailingslashit(get_template_directory()),
48
+ 'ngg_styles'
49
+ )), TRUE);
50
+
51
+ // We check the root directory of the theme. Users shouldn't store here,
52
+ // but they might
53
+ $this->add_directory(implode(DIRECTORY_SEPARATOR, array(
54
+ untrailingslashit(get_stylesheet_directory()),
55
+ )), TRUE);
56
+
57
+ // We also check the theme/nggallery directory
58
+ $this->add_directory(implode(DIRECTORY_SEPARATOR, array(
59
+ untrailingslashit(get_stylesheet_directory()),
60
+ 'nggallery'
61
+ )), TRUE);
62
+
63
+ // We also check the theme/ngg_styles directory
64
+ $this->add_directory(implode(DIRECTORY_SEPARATOR, array(
65
+ untrailingslashit(get_stylesheet_directory()),
66
+ 'ngg_styles'
67
+ )), TRUE);
68
+ }
69
+
70
+ /**
71
+ * Add a directory to search for stylesheets
72
+ * @param $dir
73
+ * @param bool $unsafe
74
+ */
75
+ function add_directory($dir, $unsafe=FALSE)
76
+ {
77
+ array_unshift($this->directories, $dir);
78
+ if ($unsafe) {
79
+ $this->unsafe_directories[] = $dir;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Determines if a directory is upgrade-safe or not
85
+ * @param $dir
86
+ * @return bool
87
+ */
88
+ function is_directory_unsafe($dir=FALSE)
89
+ {
90
+ if (!$dir) $dir = dirname($this->find_selected_stylesheet_abspath());
91
+
92
+ return in_array($dir, $this->unsafe_directories);
93
+ }
94
+
95
+ /**
96
+ * Determines if the directory is the default ngglegacy path
97
+ * @param $dir
98
+ * @return bool
99
+ */
100
+ function is_default_dir($dir)
101
+ {
102
+ return untrailingslashit($dir) == $this->default_dir;
103
+ }
104
+
105
+ function get_new_dir($filename)
106
+ {
107
+ return implode(DIRECTORY_SEPARATOR, array(
108
+ untrailingslashit($this->new_dir),
109
+ $filename
110
+ ));
111
+ }
112
+
113
+ /**
114
+ * Gets the location where the selected stylesheet will be saved to
115
+ * @param bool|string $selected
116
+ * @return string
117
+ */
118
+ function get_selected_stylesheet_saved_abspath($selected=FALSE)
119
+ {
120
+ if (!$selected) $selected = $this->get_selected_stylesheet();
121
+
122
+ $abspath = $this->find_selected_stylesheet_abspath($selected);
123
+ if ($this->is_default_dir(dirname($abspath))) {
124
+ $abspath = $this->get_new_dir(basename($abspath));
125
+ }
126
+
127
+ return $abspath;
128
+ }
129
+
130
+ function save($contents, $selected=FALSE)
131
+ {
132
+ $retval = FALSE;
133
+
134
+ if (!$selected) $selected = $this->get_selected_stylesheet();
135
+ $abspath = $this->get_selected_stylesheet_saved_abspath($selected);
136
+
137
+ wp_mkdir_p(dirname($abspath));
138
+ if (is_writable($abspath) OR (!@file_exists($abspath) && is_writable(dirname($abspath)))) {
139
+ $retval = file_put_contents($abspath, $contents);
140
+ }
141
+ return $retval;
142
+ }
143
+
144
+ /**
145
+ * Gets the selected stylesheet from the user
146
+ * @return mixed
147
+ */
148
+ function get_selected_stylesheet()
149
+ {
150
+ return C_NextGen_Settings::get_instance()->get('CSSfile', 'nggallery.css');
151
+ }
152
+
153
+ /**
154
+ * Finds the location of the selected stylesheet
155
+ */
156
+ function find_selected_stylesheet_abspath($selected=FALSE)
157
+ {
158
+ if (!$selected) $selected = $this->get_selected_stylesheet();
159
+
160
+ $retval = implode(DIRECTORY_SEPARATOR, array(
161
+ untrailingslashit($this->default_dir),
162
+ $selected
163
+ ));
164
+
165
+ foreach ($this->directories as $dir) {
166
+ $path = implode(DIRECTORY_SEPARATOR, array(
167
+ untrailingslashit($dir),
168
+ $selected
169
+ ));
170
+
171
+ if (@file_exists($path)) {
172
+ $retval = $path;
173
+ break;
174
+ }
175
+ }
176
+
177
+ return $retval;
178
+ }
179
+
180
+ /**
181
+ * Returns the url to the selected stylesheet
182
+ * @return mixed
183
+ */
184
+ function get_selected_stylesheet_url($selected=FALSE)
185
+ {
186
+ if (!$selected) $selected = $this->get_selected_stylesheet();
187
+
188
+ $retval = str_replace(
189
+ trailingslashit(ABSPATH),
190
+ trailingslashit(site_url()),
191
+ $this->find_selected_stylesheet_abspath($selected)
192
+ );
193
+
194
+ return str_replace('\\', '/', $retval);
195
+ }
196
+
197
+
198
+ function find_all_stylesheets()
199
+ {
200
+ $retval = array();
201
+
202
+ foreach (array_reverse($this->directories) as $dir) {
203
+ $path = implode(DIRECTORY_SEPARATOR, array(
204
+ untrailingslashit($dir),
205
+ '*.css'
206
+ ));
207
+ $files = glob($path);
208
+ if (is_array($files)) foreach ($files as $abspath) {
209
+ if (($meta = $this->get_stylesheet_metadata($abspath))) {
210
+ $filename = $meta['filename'];
211
+ $retval[$filename] = $meta;
212
+ }
213
+ }
214
+ }
215
+
216
+ return $retval;
217
+ }
218
+
219
+ /**
220
+ * Gets the metadata for a particular stylesheet
221
+ * @param $abspath
222
+ * @return array
223
+ */
224
+ function get_stylesheet_metadata($abspath)
225
+ {
226
+ $retval = array();
227
+ $contents = file_get_contents($abspath);
228
+ $name = '';
229
+ $desc = '';
230
+ $version = '';
231
+ $author = '';
232
+
233
+ // Find the name of the stylesheet
234
+ if (preg_match("/CSS Name:(.*)/i", $contents, $match)) {
235
+ $name = trim($match[1]);
236
+ }
237
+
238
+ // Find the description of the stylesheet
239
+ if (preg_match("/Description:(.*)/", $contents, $match)) {
240
+ $desc = trim($match[1]);
241
+ }
242
+
243
+ // Find the author of the stylesheet
244
+ if (preg_match("/Author:(.*)/", $contents, $match)) {
245
+ $author = trim($match[1]);
246
+ }
247
+
248
+ // Find the version of the stylesheet
249
+ if (preg_match("/Version:(.*)/", $contents, $match)) {
250
+ $version = trim($match[1]);
251
+ }
252
+
253
+ if ($name) {
254
+ $retval = array(
255
+ 'filename' => basename($abspath),
256
+ 'abspath' => $abspath,
257
+ 'name' => $name,
258
+ 'description' => $desc,
259
+ 'author' => $author,
260
+ 'version' => $version
261
+ );
262
+ }
263
+
264
+ return $retval;
265
+ }
266
+
267
+ /**
268
+ * Gets an instance of the class
269
+ * @return C_NextGen_Style_Manager
270
+ */
271
+ static function get_instance()
272
+ {
273
+ if (is_null(self::$_instance)){
274
+ $klass = get_class();
275
+ self::$_instance = new $klass();
276
+ }
277
+ return self::$_instance;
278
+ }
279
+ }
non_pope/class.photocrati_cache.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Photocrati_Cache
4
+ {
5
+ static $enabled = TRUE;
6
+ static $do_not_lookup = FALSE;
7
+ static $force_update = FALSE;
8
+ static $hits = 0;
9
+ static $_instances = array();
10
+ public $group = NULL;
11
+
12
+ /**
13
+ * Gets an instance of the Cache
14
+ * @return C_Photocrati_Cache
15
+ */
16
+ static function &get_instance($group=NULL)
17
+ {
18
+ if (!$group) $group = 'ngg_cache_';
19
+ if (substr($group, -1) != '_') $group .= '_';
20
+ if (!isset(self::$_instances[$group])) {
21
+ $klass = get_class();
22
+ self::$_instances[$group] = new $klass($group);
23
+ }
24
+
25
+ return self::$_instances[$group];
26
+ }
27
+
28
+ /**
29
+ * Create a new cache for the specified group
30
+ * @param $group
31
+ */
32
+ function __construct($group)
33
+ {
34
+ $this->group = $group;
35
+ }
36
+
37
+ /**
38
+ * Gets an item from the cache
39
+ * @param $key
40
+ * @param null $default
41
+ * @return mixed
42
+ */
43
+ static function get($key, $default=NULL, $group=NULL)
44
+ {
45
+ return self::get_instance($group)->lookup($key, $default);
46
+ }
47
+
48
+ /**
49
+ * Caches an item
50
+ * @param $key
51
+ * @param null $value
52
+ * @return bool|int
53
+ */
54
+ static function set($key, $value=NULL, $group=NULL, $ttl=3600)
55
+ {
56
+ return self::get_instance($group)->update($key, $value, $ttl);
57
+ }
58
+
59
+ /**
60
+ * Removes an item from the cache
61
+ * @param $key
62
+ */
63
+ static function remove($key, $group=NULL)
64
+ {
65
+ return self::get_instance($group)->delete($key);
66
+ }
67
+
68
+ /**
69
+ * Generate a unique key from params
70
+ * @param $params
71
+ * @return string
72
+ */
73
+ static function generate_key($params)
74
+ {
75
+ if (!self::$enabled) return NULL;
76
+ if (is_object($params)) $params = (array) $params;
77
+ if (is_array($params)) {
78
+ foreach ($params as &$param) $param = json_encode($param);
79
+ $params = implode('', $params);
80
+ }
81
+
82
+ return md5($params);
83
+ }
84
+
85
+ /**
86
+ * Flush the entire cache
87
+ */
88
+ static function flush($group=NULL)
89
+ {
90
+ $retval = 0;
91
+
92
+ if (self::$enabled) {
93
+
94
+ // Delete all caches
95
+ if ($group == 'all') {
96
+ foreach (self::$_instances as $cache) {
97
+ $retval += self::flush($cache->group);
98
+ }
99
+ }
100
+
101
+ // Delete items from a single cache in particular
102
+ else {
103
+ foreach (self::get_key_list($group) as $key) {
104
+ self::delete($key, FALSE, $group);
105
+ }
106
+
107
+ // Delete list of cached items
108
+ global $wpdb;
109
+ $cache = self::get_instance($group);
110
+ $sql = $wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", '%'.$cache->group.'%');
111
+ $retval = $wpdb->query($sql);
112
+ }
113
+ }
114
+
115
+ return $retval;
116
+ }
117
+
118
+ static function get_key_list($group=NULL)
119
+ {
120
+ global $wpdb;
121
+
122
+ $cache = self::get_instance($group);
123
+ $sql = $wpdb->prepare("SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s", '%'.$cache->group.'%');
124
+ return $wpdb->get_col($sql);
125
+ }
126
+
127
+
128
+ /**
129
+ * Gets an item using a particular key
130
+ * @param $key
131
+ * @param $default
132
+ * @return mixed
133
+ */
134
+ function lookup($key, $default=NULL)
135
+ {
136
+ $retval = $default;
137
+
138
+ if (self::$enabled && self::$do_not_lookup === FALSE) {
139
+ if (is_array($key)) $key = self::generate_key($key);
140
+ if (!($retval = get_transient($key))) $retval = $default;
141
+ }
142
+
143
+ return $retval;
144
+ }
145
+
146
+ /**
147
+ * Set an item in the cache using a particular key
148
+ * @param $key
149
+ * @param $value
150
+ * @return bool|int
151
+ */
152
+ function update($key, $value, $ttl=3600)
153
+ {
154
+ $retval = FALSE;
155
+ if (self::$enabled) {
156
+ if (is_array($key)) $key = self::generate_key($key);
157
+ if (self::$force_update OR $this->lookup($key, FALSE) === FALSE) {
158
+ set_transient($key, $value, $ttl);
159
+ update_option($this->group.$key, 1);
160
+ $retval = $key;
161
+ }
162
+ }
163
+ return $retval;
164
+ }
165
+
166
+ function delete($key, $delete_ack=TRUE)
167
+ {
168
+ if (self::$enabled) {
169
+ delete_transient($key);
170
+ if ($delete_ack) {
171
+ global $wpdb;
172
+ $sql = $wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $this->group.$key);
173
+ $wpdb->query($sql);
174
+ }
175
+ return TRUE;
176
+ }
177
+ else return FALSE;
178
+ }
179
+ }
non_pope/class.photocrati_installer.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!class_exists('C_Photocrati_Installer'))
4
+ {
5
+ class C_Photocrati_Installer
6
+ {
7
+ static $_instance = NULL;
8
+ static function get_instance()
9
+ {
10
+ if (is_null(self::$_instance)) {
11
+ $klass = get_class();
12
+ self::$_instance = new $klass();
13
+ }
14
+ return self::$_instance;
15
+ }
16
+
17
+
18
+ /**
19
+ * Each product and module will register it's own handler (a class, with an install() and uninstall() method)
20
+ * to be used for install/uninstall routines
21
+ * @param $name
22
+ * @param $handler
23
+ */
24
+ static function add_handler($name, $handler)
25
+ {
26
+ self::get_instance()->_installers[$name] = $handler;
27
+ }
28
+
29
+ /**
30
+ * Gets an instance of an installation handler
31
+ * @param $name
32
+ * @return mixed
33
+ */
34
+ static function get_handler_instance($name)
35
+ {
36
+ $installers = $handler = self::get_instance()->_installers;
37
+ if (isset($installers[$name])) {
38
+ $klass = $installers[$name];
39
+ return new $klass;
40
+ }
41
+ else return NULL;
42
+ }
43
+
44
+
45
+ /**
46
+ * Uninstalls a product
47
+ * @param $product
48
+ * @param bool $hard
49
+ * @return mixed
50
+ */
51
+ static function uninstall($product, $hard=FALSE)
52
+ {
53
+ $handler = self::get_handler_instance($product);
54
+ if (method_exists($handler, 'uninstall')) return $handler->uninstall($hard);
55
+
56
+ if ($hard) {
57
+ C_NextGen_Global_Settings::get_instance()->destroy();
58
+ C_NextGen_Settings::get_instance()->destroy();
59
+ }
60
+ }
61
+
62
+ static function update($reset=FALSE)
63
+ {
64
+ $global_settings = C_NextGen_Global_Settings::get_instance();
65
+ $local_settings = C_NextGen_Settings::get_instance();
66
+ $last_module_list = $reset ? array() : $global_settings->get('pope_module_list', array());
67
+ $current_module_list = self::_generate_module_info();
68
+
69
+ if (count(($modules = array_diff($current_module_list, $last_module_list)))>0) {
70
+
71
+ // The cache should be flushed
72
+ C_Photocrati_Cache::flush();
73
+
74
+ // Delete auto-update cache
75
+ update_option('photocrati_auto_update_admin_update_list', null);
76
+ update_option('photocrati_auto_update_admin_check_date', '');
77
+
78
+ foreach ($modules as $module_name) {
79
+ if (($handler = self::get_handler_instance(array_shift(explode('|', $module_name))))) {
80
+ if (method_exists($handler, 'install')) $handler->install($reset);
81
+ }
82
+ }
83
+
84
+ // Update the module list
85
+ $global_settings->set('pope_module_list', $current_module_list);
86
+
87
+ // Save any changes settings
88
+ $global_settings->save();
89
+ $local_settings->save();
90
+ }
91
+ }
92
+
93
+ static function _generate_module_info()
94
+ {
95
+ $retval = array();
96
+ $registry = C_Component_Registry::get_instance();
97
+ foreach ($registry->get_module_list() as $module_id) {
98
+ $module_version = $registry->get_module($module_id)->module_version;
99
+ $retval[$module_id] = "{$module_id}|{$module_version}";
100
+ }
101
+ return $retval;
102
+ }
103
+ }
104
+ }
non_pope/class.photocrati_resource_manager.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Photocrati_Resource_Manager
4
+ {
5
+ static $instance = NULL;
6
+
7
+ var $buffer = '';
8
+ var $styles = '';
9
+ var $scripts = '';
10
+ var $other_output = '';
11
+ var $wrote_footer = FALSE;
12
+ var $run_shutdown = FALSE;
13
+
14
+ /**
15
+ * Start buffering all generated output. We'll then do two things with the buffer
16
+ * 1) Find stylesheets lately enqueued and move them to the header
17
+ * 2) Ensure that wp_print_footer_scripts() is called
18
+ */
19
+ function __construct()
20
+ {
21
+ // Add default request exceptions
22
+ add_filter('run_ngg_resource_manager', array(&$this, 'is_valid_request'));
23
+
24
+ // Check if we should process this request
25
+ if (apply_filters('run_ngg_resource_manager', TRUE)) {
26
+ add_action('init',array(&$this, 'start_buffer'), 1);
27
+ add_action('wp_print_footer_scripts', array(&$this, 'get_resources'), 1);
28
+ add_action('admin_print_footer_scripts', array(&$this, 'get_resources'), 1);
29
+ add_action('shutdown', array(&$this, 'shutdown'));
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Determines if the resource manager should perform it's routines for this request
35
+ * @param $retval
36
+ * @return bool
37
+ */
38
+ function is_valid_request($retval)
39
+ {
40
+ if (is_admin()) {
41
+ if (isset($_REQUEST['page']) && !preg_match("#^(ngg|nextgen)#", $_REQUEST['page'])) $retval = FALSE;
42
+ }
43
+
44
+ if (strpos($_SERVER['REQUEST_URI'], 'wp-admin/update') !== FALSE) $retval = FALSE;
45
+ else if (isset($_GET['display_gallery_iframe'])) $retval = FALSE;
46
+
47
+ return $retval;
48
+ }
49
+
50
+ /**
51
+ * Start the output buffers
52
+ */
53
+ function start_buffer()
54
+ {
55
+ ob_start(array(&$this, 'output_buffer_handler'));
56
+ ob_start(array(&$this, 'get_buffer'));
57
+ }
58
+
59
+ /**
60
+ *
61
+ **/
62
+ function get_resources()
63
+ {
64
+ ob_start();
65
+ wp_print_styles();
66
+ print_admin_styles();
67
+ $this->styles = ob_get_clean();
68
+
69
+ if (!is_admin()) {
70
+ ob_start();
71
+ wp_print_scripts();
72
+ $this->scripts = ob_get_clean();
73
+ }
74
+
75
+ $this->wrote_footer = TRUE;
76
+ }
77
+
78
+
79
+ function output_buffer_handler($content)
80
+ {
81
+ return $this->output_buffer();
82
+ }
83
+
84
+ /**
85
+ * Removes the closing </html> tag from the output buffer. We'll then write our own closing tag
86
+ * in the shutdown function after running wp_print_footer_scripts()
87
+ * @param $content
88
+ * @return mixed
89
+ */
90
+ function get_buffer($content)
91
+ {
92
+ $this->buffer = $content;
93
+ return '';
94
+ }
95
+
96
+ /**
97
+ * Moves resources to their appropriate place
98
+ */
99
+ function move_resources()
100
+ {
101
+ // Move stylesheets to head
102
+ if ($this->styles) {
103
+ $this->buffer = str_ireplace('</head>', $this->styles.'</head>', $this->buffer);
104
+ }
105
+
106
+ // Move the scripts to the bottom of the page
107
+ if ($this->scripts) {
108
+ $this->buffer = str_ireplace('</body>', $this->scripts.'</body>', $this->buffer);
109
+ }
110
+
111
+ if ($this->other_output) {
112
+ $this->buffer = str_replace('</body>', $this->other_output.'</body>', $this->buffer);
113
+ }
114
+ }
115
+
116
+ /**
117
+ * When PHP has finished, we output the footer scripts and closing tags
118
+ */
119
+ function output_buffer($in_shutdown=FALSE)
120
+ {
121
+ // If the footer scripts haven't been outputted, then
122
+ // we need to take action - as they're required
123
+ if (!$this->wrote_footer) {
124
+
125
+ // If W3TC is installed and activated, we can't output the
126
+ // scripts and manipulate the buffer, so we can only provide a warning
127
+ if (defined('W3TC')) {
128
+ define('DONOTCACHEPAGE', TRUE);
129
+ if (!did_action('wp_footer')) {
130
+ error_log("We're sorry, but your theme's page template didn't make a call to wp_footer(), which is required by NextGEN Gallery. Please add this call to your page templates.");
131
+ }
132
+ else {
133
+ error_log("We're sorry, but your theme's page template didn't make a call to wp_print_footer_scripts(), which is required by NextGEN Gallery. Please add this call to your page templates.");
134
+ }
135
+ }
136
+
137
+ // The output_buffer() function has been called in the PHP shutdown callback
138
+ // This will allow us to print the scripts ourselves and manipulate the buffer
139
+ if ($in_shutdown === TRUE) {
140
+ ob_start();
141
+ if (!did_action('wp_footer')) {
142
+ wp_footer();
143
+ }
144
+ else {
145
+ wp_print_footer_scripts();
146
+ }
147
+ $this->other_output = ob_get_clean();
148
+
149
+ }
150
+
151
+ // W3TC isn't activated and we're not in the shutdown callback.
152
+ // We'll therefore add a shutdown callback to print the scripts
153
+ else {
154
+ $this->run_shutdown = TRUE;
155
+ return '';
156
+ }
157
+ }
158
+
159
+ // Once we have the footer scripts, we can modify the buffer and
160
+ // move the resources around
161
+ if ($this->wrote_footer) $this->move_resources();
162
+
163
+ return $this->buffer;
164
+ }
165
+
166
+ /**
167
+ * PHP shutdown callback. Manipulate and output the buffer
168
+ */
169
+ function shutdown()
170
+ {
171
+ if ($this->run_shutdown) echo $this->output_buffer(TRUE);
172
+ }
173
+
174
+ static function init()
175
+ {
176
+ $klass = get_class();
177
+ return self::$instance = new $klass;
178
+ }
179
+ }
non_pope/class.photocrati_settings_manager.php ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!class_exists('C_Photocrati_Settings_Manager_Base')) {
4
+ /**
5
+ * Provides a base abstraction for a Settings Manager
6
+ * Class C_Settings_Manager_Base
7
+ */
8
+ abstract class C_Photocrati_Settings_Manager_Base implements ArrayAccess
9
+ {
10
+ static $option_name = 'pope_settings';
11
+ protected $_options = array();
12
+ protected $_defaults = array();
13
+ protected $_option_handlers = array();
14
+
15
+ abstract function save();
16
+ abstract function destroy();
17
+ abstract function load();
18
+
19
+ protected function __construct()
20
+ {
21
+ $this->load();
22
+ }
23
+
24
+ /**
25
+ * Adds a class to handle dynamic options
26
+ * @param string $klass
27
+ * @param array $options
28
+ */
29
+ function add_option_handler($klass, $options=array())
30
+ {
31
+ if (!is_array($options)) $options = array($options);
32
+ foreach ($options as $option_name) {
33
+ $this->_option_handlers[$option_name] = $klass;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Gets a handler used to provide a dynamic option
39
+ * @param string $option_name
40
+ * @return null|mixed
41
+ */
42
+ protected function _get_option_handler($option_name, $method='get')
43
+ {
44
+ $retval = NULL;;
45
+
46
+ if (isset($this->_option_handlers[$option_name])) {
47
+ if (!is_object($this->_option_handlers[$option_name])) {
48
+ $klass = $this->_option_handlers[$option_name];
49
+ $this->_option_handlers[$option_name] = new $klass;
50
+ }
51
+ $retval = $this->_option_handlers[$option_name];
52
+ if (!method_exists($retval, $method)) $retval = NULL;
53
+ }
54
+ return $retval;
55
+ }
56
+
57
+ /**
58
+ * Gets the value of a particular setting
59
+ * @param $key
60
+ * @param null $default
61
+ * @return null
62
+ */
63
+ function get($key, $default=NULL)
64
+ {
65
+ $retval = $default;
66
+
67
+ if (isset($this->_options[$key]))
68
+ $retval = $this->_options[$key];
69
+ elseif (($handler = $this->_get_option_handler($key, 'get'))) {
70
+ $retval = $handler->get($key, $default);
71
+ }
72
+
73
+ // In case a stdObject has been passed in as a value, we
74
+ // want to only return scalar values or arrays
75
+ if (is_object($retval)) $retval = (array) $retval;
76
+
77
+ return $retval;
78
+ }
79
+
80
+ /**
81
+ * Sets a setting to a particular value
82
+ * @param string $key
83
+ * @param mixed $value
84
+ * @return mixed
85
+ */
86
+ function set($key, $value=NULL, $skip_handlers=FALSE)
87
+ {
88
+ if (is_object($value)) $value = (array) $value;
89
+
90
+ if (is_array($key)) {
91
+ foreach ($key as $k=>$v) $this->set($k, $v);
92
+ }
93
+ elseif (!$skip_handlers && ($handler = $this->_get_option_handler($key, 'set'))) {
94
+ $handler->set($key, $value);
95
+ }
96
+ else $this->_options[$key] = $value;
97
+
98
+ return $this;
99
+ }
100
+
101
+ /**
102
+ * Deletes a setting
103
+ * @param string $key
104
+ */
105
+ function delete($key)
106
+ {
107
+ if (($handler = $this->_get_option_handler($key, 'delete'))) {
108
+ $handler->delete($key);
109
+ }
110
+ else {
111
+ unset($this->_options[$key]);
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Determines if a setting exists or not
117
+ * @param $key
118
+ * @return bool
119
+ */
120
+ function is_set($key)
121
+ {
122
+ return array_key_exists($key, $this->_options);
123
+ }
124
+
125
+ /**
126
+ * Alias to is_set()
127
+ * @param $key
128
+ * @return bool
129
+ */
130
+ function exists($key)
131
+ {
132
+ return $this->is_set($key);
133
+ }
134
+
135
+ function does_not_exist($key)
136
+ {
137
+ return !$this->exists($key);
138
+ }
139
+
140
+ function reset()
141
+ {
142
+ $this->_options = array();
143
+ }
144
+
145
+ /**
146
+ * This function does two things:
147
+ * a) If a value hasn't been set for the specified key, or it's been set to a previously set
148
+ * default value, then set this key to the value specified
149
+ * b) Sets a new default value for this key
150
+ */
151
+ function set_default_value($key, $default)
152
+ {
153
+ if (!isset($this->_defaults[$key])) $this->_defaults[$key] = $default;
154
+ if (is_null($this->get($key, NULL)) OR $this->get($key) == $this->_defaults[$key]) {
155
+ $this->set($key, $default);
156
+ }
157
+ $this->_defaults[$key] = $default;
158
+ return $this->get($key);
159
+ }
160
+
161
+ function offsetExists($key)
162
+ {
163
+ return $this->is_set($key);
164
+ }
165
+
166
+ function offsetGet($key)
167
+ {
168
+ return $this->get($key);
169
+ }
170
+
171
+ function offsetSet($key, $value)
172
+ {
173
+ return $this->set($key, $value);
174
+ }
175
+
176
+ function offsetUnset($key)
177
+ {
178
+ return $this->delete($key);
179
+ }
180
+
181
+ function __get($key)
182
+ {
183
+ return $this->get($key);
184
+ }
185
+
186
+ function __set($key, $value)
187
+ {
188
+ return $this->set($key, $value);
189
+ }
190
+
191
+ function __isset($key)
192
+ {
193
+ return $this->is_set($key);
194
+ }
195
+
196
+ function __toString()
197
+ {
198
+ return json_encode($this->_options);
199
+ }
200
+
201
+ function __toArray()
202
+ {
203
+ return $this->_options;
204
+ }
205
+
206
+ function to_array()
207
+ {
208
+ return $this->__toArray();
209
+ }
210
+
211
+ function to_json()
212
+ {
213
+ return json_encode($this->_options);
214
+ }
215
+
216
+ function from_json($json)
217
+ {
218
+ $this->_options = (array)json_decode($json);
219
+ }
220
+ }
221
+ }
222
+
223
+ if (!class_exists('C_Photocrati_Global_Settings_Manager')) {
224
+ class C_Photocrati_Global_Settings_Manager extends C_Photocrati_Settings_Manager_Base
225
+ {
226
+ public static function get_instance()
227
+ {
228
+ static $_instance = NULL;
229
+ if (is_null($_instance)) {
230
+ $klass = get_class();
231
+ $_instance = new $klass();
232
+ }
233
+ return $_instance;
234
+ }
235
+
236
+ function save()
237
+ {
238
+ return update_site_option(self::$option_name, $this->to_array());
239
+ }
240
+
241
+ function load()
242
+ {
243
+ $this->_options = get_site_option(self::$option_name, $this->to_array());
244
+ if (!$this->_options) $this->_options = array();
245
+ else if (is_string($this->_options)) $this->_options = unserialize($this->_options);
246
+ }
247
+
248
+ function destroy()
249
+ {
250
+ return delete_site_option(self::$option_name);
251
+ }
252
+ }
253
+ }
254
+
255
+
256
+ if (!class_exists('C_Photocrati_Settings_Manager')) {
257
+ class C_Photocrati_Settings_Manager extends C_Photocrati_Settings_Manager_Base
258
+ {
259
+ public static function get_instance()
260
+ {
261
+ static $_instance = NULL;
262
+ if (is_null($_instance)) {
263
+ $klass = get_class();
264
+ $_instance = new $klass();
265
+ }
266
+ return $_instance;
267
+ }
268
+
269
+ function get($key, $default=NULL)
270
+ {
271
+ $retval = parent::get($key, NULL);
272
+
273
+ if (is_null($retval)) {
274
+ $retval = C_Photocrati_Global_Settings_Manager::get_instance()->get($key, $default);
275
+ }
276
+ return $retval;
277
+ }
278
+
279
+ function save()
280
+ {
281
+ return update_option(self::$option_name, $this->to_array());
282
+ }
283
+
284
+ function load()
285
+ {
286
+ $this->_options = get_option(self::$option_name, array());
287
+ if (!$this->_options) $this->_options = array();
288
+ else if (is_string($this->_options)) $this->_options = unserialize($this->_options);
289
+ }
290
+
291
+ function destroy()
292
+ {
293
+ delete_option(self::$option_name);
294
+ }
295
+
296
+
297
+ }
298
+ }
299
+
pope/README.txt ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ==============
2
+ POPE FRAMEWORK
3
+ ==============
4
+
5
+ WHY "POPE"?
6
+ -----------
7
+ Pope is an attempt to provide a component framework, similiar to Python's Zope 3
8
+ framework. In otherwords, Pope is PHP's version of Zope.
9
+ See: http://wiki.zope.org/zope3/ComponentArchitectureOverview
10
+
11
+ In short it adds polymorphism or plugin-like functionality into your PHP classes.
12
+ With it you can build applications with plugins, plugins to existing applications,
13
+ and extend or change third party libraries without modifying their source.
14
+
15
+ The unit tests in the "tests" directory double as a tutorial to Pope and how to use
16
+ it. For best clarity read the source in this order:
17
+ * core
18
+ * pre_hooks
19
+ * registry
20
+ * factories
21
+ * modules
22
+ * wrappers
23
+ * advanced
24
+ * method_properties
25
+ To run the tests yourself modify run_tests.php to point to your own SimpleTest
26
+ checkout.
27
+
28
+ A component framework puts a strong emphasis on interface design, and designing
29
+ by contract. However, Pope also tries to be less restrictive by adopting duck typing
30
+ and the philosophy, "if it walks like a duck and talks like a duck then it is
31
+ a duck". This is sometimes also referred to as "monkey patching".
32
+
33
+ A component frameworks relies on the following:
34
+
35
+ - Interfaces:
36
+
37
+ Interfaces define the contracts which the design must follow.
38
+ See: http://en.wikipedia.org/wiki/Design_by_contract
39
+
40
+ - Components:
41
+
42
+ Components implement interfaces to provide specific functionality in a
43
+ desired context. The context of an object is important, as a component
44
+ can behave differently when used in a different context.
45
+
46
+ - Adapters:
47
+
48
+ Adapters modify the behavior of a component to adapt to a particular context.
49
+ For example, in a component framework there might be difference between an
50
+ image and a thumbnail - they are both images, but used in different contexts.
51
+ Adapters would be used to make a thumbnail image behave differently.
52
+
53
+ - Utilities:
54
+
55
+ Utilities are registered implementations of a particular interface. An
56
+ example of a utility is an object factory, based on the factory pattern.
57
+
58
+ - Factory:
59
+
60
+ Factories create objects.
61
+ See: http://en.wikipedia.org/wiki/Factory_method_pattern
62
+
63
+
64
+
65
+ EXTENSIBLE OBJECT
66
+ -----------------
67
+ Pope is able to use duck typing and monkey patching through the use of a class
68
+ called ExtensibleObject, which provides these capabilities. ExtensibleObject
69
+ provides a means of polymorphism and multiple inheritance using something
70
+ called "mixins".
71
+ See: http://en.wikipedia.org/wiki/Mixin
72
+
73
+ An understanding of how to use ExtensibleObject is fundamental to the understanding
74
+ of how to use Pope, and what makes it a unique and powerful tool.
75
+
76
+ ExtensibleObject is quite unique in that it brings a lot of features to PHP 5.2
77
+ that are only available in PHP 5.3 and above. It inherits a lot of it's design
78
+ from Ruby. For example,
79
+
80
+ i) Methods can be added and removed from objects at runtime through the use of
81
+ Pope extensions
82
+
83
+ ii) Pre-executed and post-executed hooks can be registered at runtime, which are
84
+ methods that are executed when a particular method has been called on an
85
+ ExtensibleObject instance.
86
+
87
+ iii) Method implementations can be replaced and restored at runtime.
88
+
89
+ To get a better understanding of how these things can truly benefit you as a
90
+ programmer and a designer, please watch David Heinemeier Hansson's keynote about
91
+ Ruby: http://vimeo.com/17420638
92
+
93
+
pope/lib/autoload.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('POPE_VERSION')) {
4
+ define('POPE_VERSION', '0.1');
5
+ require_once('class.extensibleobject.php');
6
+ require_once('interface.component.php');
7
+ require_once('class.component.php');
8
+ require_once('interface.component_factory.php');
9
+ require_once('class.component_factory.php');
10
+ require_once('class.component_registry.php');
11
+ require_once('interface.pope_module.php');
12
+ require_once('class.base_module.php');
13
+ require_once('class.base_product.php');
14
+ }
pope/lib/class.base_module.php ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }
4
+
5
+ /**
6
+ * A Module will register utilities and adapters to provide it's functionality,
7
+ * and usually provide some classes for business logic.
8
+ *
9
+ * Registered an adapter for the I_Component_Factory interface to add new
10
+ * factory methods is the most common use of an adapter.
11
+ */
12
+ abstract class C_Base_Module extends C_Component
13
+ {
14
+ var $module_id;
15
+ var $module_name;
16
+ var $module_description;
17
+ var $module_version;
18
+ var $module_uri;
19
+ var $module_author;
20
+ var $module_author_uri;
21
+ var $module_type_list = null;
22
+
23
+ function __construct($context=FALSE)
24
+ {
25
+ if ($context) {
26
+ parent::__construct(__EXTOBJ_NO_INIT__, $context);
27
+ }
28
+ else {
29
+ parent::__construct(__EXTOBJ_NO_INIT__);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Defines the module
35
+ */
36
+ function define($id, $name, $description='', $version='', $uri='', $author='', $author_uri='', $context=FALSE)
37
+ {
38
+ parent::define($context);
39
+ $this->implement('I_Pope_Module');
40
+ $this->module_id = $id;
41
+ $this->module_name = $name;
42
+ $this->module_description = $description;
43
+ $this->module_version = $version;
44
+ $this->module_uri = $uri;
45
+ $this->module_author = $author;
46
+ $this->module_author_uri = $author_uri;
47
+
48
+ $this->get_registry()->add_module($this->module_id, $this);
49
+
50
+ $this->_register_utilities();
51
+ $this->_register_adapters();
52
+ $this->_register_hooks();
53
+ }
54
+
55
+ /**
56
+ * I/O can be expensive to run repeatedly, so when a module is created we cache a listing of every file provided
57
+ *
58
+ * @return array List of types => files belonging to this module
59
+ */
60
+ function get_type_list()
61
+ {
62
+ // XXX small hack to skip photocrati theme modules scans
63
+ $except_modules = array(
64
+ 'photocrati-gallery_legacy' => array(),
65
+ 'photocrati-theme_bulk' => array(),
66
+ 'photocrati-theme_admin' => array(),
67
+ 'photocrati-auto_update' => array(
68
+ 'A_Autoupdate_Settings' => 'adapter.autoupdate_settings.php'
69
+ ),
70
+ 'photocrati-auto_update-admin' => array(
71
+ 'A_Autoupdate_Admin_Ajax' => 'adapter.autoupdate_admin_ajax.php',
72
+ 'A_Autoupdate_Admin_Factory' => 'adapter.autoupdate_admin_factory.php',
73
+ 'C_Autoupdate_Admin_Ajax' => 'class.autoupdate_admin_ajax.php',
74
+ 'C_Autoupdate_Admin_Controller' => 'class.autoupdate_admin_controller.php'
75
+ ));
76
+
77
+ if (isset($except_modules[$this->module_id]))
78
+ {
79
+ return $except_modules[$this->module_id];
80
+ }
81
+
82
+ if ($this->module_type_list === null)
83
+ {
84
+ $map = array(
85
+ 'C_' => 'class',
86
+ 'A_' => 'adapter',
87
+ 'I_' => 'interface',
88
+ 'Mixin_' => 'mixin',
89
+ 'M_' => 'module',
90
+ 'Hook_' => 'hook',
91
+ );
92
+
93
+ $type_list = array();
94
+ $dir = $this->get_registry()->get_module_dir($this->module_id) . DIRECTORY_SEPARATOR;
95
+ $iterator = new RecursiveIteratorIterator(
96
+ new RecursiveDirectoryIterator($dir)
97
+ );
98
+ foreach ($iterator as $filename) {
99
+ if (in_array(basename($filename->getPathname()), array('.', '..')))
100
+ continue;
101
+
102
+ $filename = str_replace($dir, '', $filename->getPathname());
103
+ $file_parts = explode('.', $filename);
104
+ $prefix = $file_parts[0];
105
+ $name = (!empty($file_parts[1]) ? $file_parts[1] : '');
106
+ $name_prefix = array_search($prefix, $map);
107
+
108
+ if ($name_prefix)
109
+ {
110
+ $type_name = $name_prefix . $name;
111
+
112
+ $type_list[$type_name] = $filename;
113
+ }
114
+ }
115
+
116
+ $this->module_type_list = $type_list;
117
+ }
118
+
119
+ return $this->module_type_list;
120
+ }
121
+
122
+ /**
123
+ * Provides a reliable means of determining if the current request is in the
124
+ * wp-admin panel
125
+ * @return boolean
126
+ */
127
+ function is_admin()
128
+ {
129
+ return (is_admin() OR preg_match('/wp-admin/', $_SERVER['REQUEST_URI']));
130
+ }
131
+
132
+ /**
133
+ * Join two filesystem paths together (e.g. 'give me $path relative to $base').
134
+ *
135
+ * If the $path is absolute, then the full path is returned.
136
+ * Taken from wordpress 3.4.1
137
+ *
138
+ * @param string $base
139
+ * @param string $path
140
+ * @return string The path with the base or absolute path
141
+ */
142
+ function _path_join($base, $path)
143
+ {
144
+ if ($this->_path_is_absolute($path))
145
+ {
146
+ return $path;
147
+ }
148
+ return trim($base, '/') . '/' . ltrim($path, '/');
149
+ }
150
+
151
+ /**
152
+ * Test if a give filesystem path is absolute ('/foo/bar', 'c:\windows').
153
+ *
154
+ * Taken from wordpress 3.4.1
155
+ * @param string $path File path
156
+ * @return bool True if path is absolute, false is not absolute.
157
+ */
158
+ function _path_is_absolute($path)
159
+ {
160
+ // this is definitive if true but fails if $path does not exist or contains a symbolic link
161
+ if (realpath($path) == $path)
162
+ {
163
+ return true;
164
+ }
165
+
166
+ if (strlen($path) == 0 || $path[0] == '.')
167
+ {
168
+ return false;
169
+ }
170
+
171
+ // windows allows absolute paths like this
172
+ if (preg_match('#^[a-zA-Z]:\\\\#', $path))
173
+ {
174
+ return true;
175
+ }
176
+
177
+ // a path starting with / or \ is absolute; anything else is relative
178
+ return ($path[0] == '/' || $path[0] == '\\');
179
+ }
180
+
181
+ function _register_hooks() {}
182
+ function _register_adapters() {}
183
+ function _register_utilities() {}
184
+ }
pope/lib/class.base_product.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }
4
+
5
+ /**
6
+ * A Product is a collection of modules with some meta data.
7
+ *
8
+ * Products are responsible for including and loading any modules required
9
+ * for the functionality of the product.
10
+ *
11
+ * Module initialization is handled by the bootstrap procedure.
12
+ */
13
+ abstract class C_Base_Product extends C_Base_Module
14
+ {
15
+ function define($id, $name, $description='', $version='', $uri='', $author='', $author_uri='')
16
+ {
17
+ parent::define($id, $name, $description, $version, $uri, $author, $author_uri);
18
+
19
+ $this->get_registry()->add_product($this->module_id, $this);
20
+ }
21
+
22
+ function get_type_list()
23
+ {
24
+ return array();
25
+ }
26
+
27
+ function is_background_product()
28
+ {
29
+ return false;
30
+ }
31
+
32
+ function get_dashboard_message($type = null)
33
+ {
34
+ return false;
35
+ }
36
+ }
pope/lib/class.component.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pope is a component-based framework. All classes should inherit this class.
5
+ */
6
+ class C_Component extends ExtensibleObject
7
+ {
8
+ /**
9
+ * @var string
10
+ */
11
+ var $context;
12
+ var $adapted = FALSE;
13
+
14
+ /**
15
+ * Many components will execute parent::define()
16
+ */
17
+ function define($context=FALSE)
18
+ {
19
+ $this->context = is_null($context) ? FALSE : $context;
20
+ $this->implement('I_Component');
21
+ }
22
+
23
+ // Initializes the state of the object
24
+ function initialize()
25
+ {
26
+ $this->get_registry()->apply_adapters($this);
27
+ $this->adapted = TRUE;
28
+ }
29
+
30
+ /**
31
+ * Determines if the component has one or more particular contexts assigned
32
+ * @param string|array $context
33
+ * @return boolean
34
+ */
35
+ function has_context($context)
36
+ {
37
+ $retval = TRUE;
38
+ $current_context = is_array($this->context) ? $this->context : array($this->context);
39
+ if (!is_array($context)) $context = array($context);
40
+ foreach ($context as $c) {
41
+ if (!in_array($c, $current_context)) {
42
+ $retval = FALSE;
43
+ break;
44
+ }
45
+ }
46
+ return $retval;
47
+ }
48
+
49
+ /**
50
+ * Assigns a particular context to the component
51
+ * @param type $context
52
+ */
53
+ function add_context($context)
54
+ {
55
+ if (!is_array($context)) $context = array($context);
56
+ if (!is_array($this->context)) $this->context = array($this->context);
57
+ foreach ($context as $c) {
58
+ if (in_array($c, $this->context)) continue;
59
+ else $context[] = $c;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Assigns one or more contexts to the component
65
+ * @param type $context
66
+ */
67
+ function assign_context($context)
68
+ {
69
+ $this->add_context($context);
70
+ }
71
+
72
+ /**
73
+ * Un-assigns one or more contexts from the component
74
+ * @param type $context
75
+ */
76
+ function remove_context($context)
77
+ {
78
+ if (!is_array($context)) $context = array($context);
79
+ if (!is_array($this->context)) $this->context = array($this->context);
80
+ foreach ($context as $c) {
81
+ if (($index = array_search($c, $this->context)) !== FALSE) {
82
+ unset($this->context[$index]);
83
+ }
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Assigns one or more contexts to the component
89
+ * @param type $context
90
+ */
91
+ function unassign_context($context)
92
+ {
93
+ $this->remove_context($context);
94
+ }
95
+
96
+ /**
97
+ * Gets the component registry
98
+ * @return C_Component_Registry
99
+ */
100
+ function get_registry()
101
+ {
102
+ return C_Component_Registry::get_instance();
103
+ }
104
+
105
+ /**
106
+ * Gets the component registry -- backward compatibility
107
+ * @return C_Component_Registry
108
+ */
109
+ function _get_registry()
110
+ {
111
+ return C_Component_Registry::get_instance();
112
+ }
113
+ }
pope/lib/class.component_factory.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A factory for hatching (instantiating) components
5
+ */
6
+ class C_Component_Factory extends C_Component
7
+ {
8
+ static $_instances = array();
9
+
10
+ function define()
11
+ {
12
+ parent::define();
13
+ $this->implement('I_Component_Factory');
14
+ }
15
+
16
+ function create($method, $args=array())
17
+ {
18
+ // Format the arguments for the method call
19
+ $args = func_get_args();
20
+ array_shift($args);
21
+
22
+ // Create the component and apply the adapters
23
+ $component = $this->call_method($method, $args);
24
+
25
+ return $component;
26
+ }
27
+
28
+ static function &get_instance($context = False)
29
+ {
30
+ if (!isset(self::$_instances[$context])) {
31
+ self::$_instances[$context] = new C_Component_Factory($context);
32
+ }
33
+ return self::$_instances[$context];
34
+ }
35
+ }
pope/lib/class.component_registry.php ADDED
@@ -0,0 +1,943 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A registry of registered products, modules, adapters, and utilities.
5
+ */
6
+ class C_Component_Registry
7
+ {
8
+ static $_instance = NULL;
9
+ var $_meta_info = array(); /* Contains a cached mapping of module_id -> module_info (including the path the module was installed to) */
10
+ var $_default_path = NULL;
11
+ var $_modules = array();
12
+ var $_products = array();
13
+ var $_adapters = array();
14
+ var $_utilities = array();
15
+ var $_module_type_cache = array();
16
+ var $_module_type_cache_count = 0;
17
+
18
+
19
+ /**
20
+ * This is a singleton object
21
+ */
22
+ private function __construct()
23
+ {
24
+ // Create an autoloader
25
+ spl_autoload_register(array($this, '_module_autoload'), TRUE);
26
+ }
27
+
28
+
29
+ /**
30
+ * Returns a singleton
31
+ * @return C_Component_Registry()
32
+ */
33
+ static function &get_instance()
34
+ {
35
+ if (is_null(self::$_instance)) {
36
+ $klass = get_class();
37
+ self::$_instance = new $klass();
38
+ }
39
+ return self::$_instance;
40
+ }
41
+
42
+ /**
43
+ * Saves the registry to disk
44
+ * @param string $config_file
45
+ */
46
+ function save($config_file)
47
+ {
48
+ $fp = FALSE;
49
+ $retval = TRUE;
50
+
51
+ try {
52
+ $fp = fopen($config_file, 'w');
53
+ fwrite($fp, json_encode(array(
54
+ 'modules' => $this->_modules,
55
+ 'products' => $this->_products,
56
+ 'adapters' => $this->_adapters,
57
+ 'utilities'=> $this->_utilities
58
+ )));
59
+ }
60
+ catch (Exception $e) {
61
+ if ($fp) fclose($fp);
62
+ $retval = FALSE;
63
+ }
64
+ if ($fp) fclose($fp);
65
+
66
+ return $retval;
67
+ }
68
+
69
+
70
+ function load($config_file)
71
+ {
72
+ $fp = FALSE;
73
+ $retval = TRUE;
74
+
75
+ try {
76
+ $fp = fopen($config_file);
77
+ $json = json_decode(fread($fp), TRUE);
78
+ $this->_modules = array_merge($this->_modules, $json['modules']);
79
+ $this->_products = array_merge($this->_products, $json['products']);
80
+ $this->_adapters = array_merge($this->_adapters, $json['adapters']);
81
+ $this->_utilities = array_merge($this->_utilities, $json['utilities']);
82
+ }
83
+ catch (Exception $e) {
84
+ if ($fp) fclose($fp);
85
+ $retval = FALSE;
86
+ }
87
+ if ($fp) fclose($fp);
88
+
89
+ return $retval;
90
+ }
91
+
92
+
93
+ /**
94
+ * Adds a path in the search paths for loading modules
95
+ * @param string $path
96
+ * @param bool $recurse - note, it will only recurse 1 level in the hierarchy
97
+ * @param bool $load_all - loads all modules found in the path
98
+ */
99
+ function add_module_path($path, $recurse = false, $load_all = false)
100
+ {
101
+ if ($this->get_default_module_path() == null)
102
+ {
103
+ $this->set_default_module_path($path);
104
+ }
105
+
106
+ $scan = $this->_scan_module_path($path, $recurse);
107
+
108
+ if ($scan != null)
109
+ {
110
+ $this->_meta_info = array_merge($this->_meta_info, $scan);
111
+
112
+ if ($load_all)
113
+ {
114
+ $module_list = array_keys($scan);
115
+ $load_list = array();
116
+ $count = count($module_list);
117
+ $ret = true;
118
+
119
+ for ($i = 0; $i < $count; $i++)
120
+ {
121
+ $module_id = $module_list[$i];
122
+ $info = isset($scan[$module_id]) ? $scan[$module_id] : null;
123
+ $before_index = null;
124
+
125
+ if (isset($info['before-list']))
126
+ {
127
+ $before_list = $info['before-list'];
128
+
129
+ foreach ($before_list as $before_module)
130
+ {
131
+ $load_index = array_search($before_module, $load_list);
132
+
133
+ if ($load_index !== false)
134
+ {
135
+ if ($before_index === null || $load_index < $before_index)
136
+ {
137
+ $before_index = $load_index;
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ if ($before_index !== null)
144
+ {
145
+ array_splice($load_list, $before_index, 0, array($module_id));
146
+ }
147
+ else
148
+ {
149
+ $load_list[] = $module_id;
150
+ }
151
+ }
152
+
153
+ foreach ($load_list as $module_id)
154
+ {
155
+ $loaded = $this->load_module($module_id);
156
+ $ret = $ret && $loaded;
157
+ }
158
+
159
+ return $ret;
160
+ }
161
+
162
+ return true;
163
+ }
164
+
165
+ return false;
166
+ }
167
+
168
+
169
+ /**
170
+ * Retrieves the default module path (Note: this is just the generic root container path for modules)
171
+ * @return string
172
+ */
173
+ function get_default_module_path()
174
+ {
175
+ return $this->_default_path;
176
+ }
177
+
178
+
179
+ /**
180
+ * Sets the default module path (Note: this is just the generic root container path for modules)
181
+ * @param string $path
182
+ */
183
+ function set_default_module_path($path)
184
+ {
185
+ $this->_default_path = $path;
186
+ }
187
+
188
+
189
+ /**
190
+ * Retrieves the module path
191
+ * @param string $module_id
192
+ * @return string
193
+ */
194
+ function get_module_path($module_id)
195
+ {
196
+ if (isset($this->_meta_info[$module_id])) {
197
+ $info = $this->_meta_info[$module_id];
198
+
199
+ if (isset($info['path'])) {
200
+ return $info['path'];
201
+ }
202
+ }
203
+
204
+ return null;
205
+ }
206
+
207
+
208
+ /**
209
+ * Retrieves the module installation directory
210
+ * @param string $module_id
211
+ * @return string
212
+ */
213
+ function get_module_dir($module_id)
214
+ {
215
+ $path = $this->get_module_path($module_id);
216
+
217
+ if ($path != null) {
218
+ return dirname($path);
219
+ }
220
+
221
+ return null;
222
+ }
223
+
224
+
225
+ /**
226
+ * Loads a module's code according to its dependency list
227
+ * @param string $module_id
228
+ */
229
+ function load_module($module_id)
230
+ {
231
+ return $this->_load_module_internal($module_id);
232
+ }
233
+
234
+ function load_all_modules($type = null)
235
+ {
236
+ $modules = $this->get_known_module_list();
237
+ $ret = true;
238
+
239
+ foreach ($modules as $module_id)
240
+ {
241
+ if ($type == null || $this->get_module_meta($module_id, 'type') == $type) {
242
+ $ret = $this->load_module($module_id) && $ret;
243
+ }
244
+ }
245
+
246
+ return $ret;
247
+ }
248
+
249
+
250
+ /**
251
+ * Initializes a previously loaded module
252
+ * @param string $module_id
253
+ */
254
+ function initialize_module($module_id)
255
+ {
256
+ $retval = FALSE;
257
+ if (isset($this->_modules[$module_id])) {
258
+ $module = $this->_modules[$module_id];
259
+
260
+ if (!$module->initialized) {
261
+ if ($module->has_method('initialize'))
262
+ $module->initialize();
263
+
264
+ $module->initialized = true;
265
+ }
266
+ $retval = TRUE;
267
+ }
268
+ return $retval;
269
+ }
270
+
271
+
272
+ /**
273
+ * Initializes an already loaded product
274
+ * @param string $product_id
275
+ * @return bool
276
+ */
277
+ function initialize_product($product_id)
278
+ {
279
+ return $this->initialize_module($product_id);
280
+ }
281
+
282
+
283
+ /**
284
+ * Initializes all previously loaded modules
285
+ */
286
+ function initialize_all_modules()
287
+ {
288
+ $module_list = $this->get_module_list();
289
+
290
+ foreach ($module_list as $module_id)
291
+ {
292
+ $this->initialize_module($module_id);
293
+ }
294
+ }
295
+
296
+
297
+ /**
298
+ * Adds an already loaded module to the registry
299
+ * @param string $module_id
300
+ * @param C_Base_Module $module_object
301
+ */
302
+ function add_module($module_id, $module_object)
303
+ {
304
+ if (!isset($this->_modules[$module_id])) {
305
+ $this->_modules[$module_id] = $module_object;
306
+ }
307
+ }
308
+
309
+
310
+ /**
311
+ * Deletes an already loaded module from the registry
312
+ * @param string $module_id
313
+ */
314
+ function del_module($module_id)
315
+ {
316
+ if (isset($this->_modules[$module_id])) {
317
+ unset($this->_modules[$module_id]);
318
+ }
319
+ }
320
+
321
+
322
+ /**
323
+ * Retrieves the instance of the registered module. Note: it's the instance of the module object, so the module needs to be loaded or this function won't return anything. For module info returned by scanning (with add_module_path), look at get_module_meta
324
+ * @param string $module_id
325
+ * @return C_Base_Module
326
+ */
327
+ function get_module($module_id)
328
+ {
329
+ if (isset($this->_modules[$module_id])) {
330
+ return $this->_modules[$module_id];
331
+ }
332
+
333
+ return null;
334
+ }
335
+
336
+ function get_module_meta($module_id, $meta_name)
337
+ {
338
+ $meta = $this->get_module_meta_list($module_id);
339
+
340
+ if (isset($meta[$meta_name])) {
341
+ return $meta[$meta_name];
342
+ }
343
+
344
+ return null;
345
+ }
346
+
347
+ function get_module_meta_list($module_id)
348
+ {
349
+ if (isset($this->_meta_info[$module_id])) {
350
+ return $this->_meta_info[$module_id];
351
+ }
352
+
353
+ return null;
354
+ }
355
+
356
+ /**
357
+ * Retrieves a list of instantiated module ids
358
+ * @return array
359
+ */
360
+ function get_module_list()
361
+ {
362
+ return array_keys($this->_modules);
363
+ }
364
+
365
+ /**
366
+ * Retrieves a list of registered module ids, including those that aren't loaded (i.e. get_module() call with those unloaded ids will fail)
367
+ * @return array
368
+ */
369
+ function get_known_module_list()
370
+ {
371
+ return array_keys($this->_meta_info);
372
+ }
373
+
374
+
375
+ function load_product($product_id)
376
+ {
377
+ return $this->load_module($product_id);
378
+ }
379
+
380
+ function load_all_products()
381
+ {
382
+ return $this->load_all_modules('product');
383
+ }
384
+
385
+ /**
386
+ * Adds an already loaded product in the registry
387
+ * @param string $product_id
388
+ * @param C_Base_Module $product_object
389
+ */
390
+ function add_product($product_id, $product_object)
391
+ {
392
+ if (!isset($this->_products[$product_id])) {
393
+ $this->_products[$product_id] = $product_object;
394
+ }
395
+ }
396
+
397
+
398
+ /**
399
+ * Deletes an already loaded product from the registry
400
+ * @param string $product_id
401
+ */
402
+ function del_product($product_id)
403
+ {
404
+ if (isset($this->_products[$product_id])) {
405
+ unset($this->_products[$product_id]);
406
+ }
407
+ }
408
+
409
+
410
+ /**
411
+ * Retrieves the instance of the registered product
412
+ * @param string $product_id
413
+ * @return C_Base_Module
414
+ */
415
+ function get_product($product_id)
416
+ {
417
+ if (isset($this->_products[$product_id])) {
418
+ return $this->_products[$product_id];
419
+ }
420
+
421
+ return null;
422
+ }
423
+
424
+ function get_product_meta($product_id, $meta_name)
425
+ {
426
+ $meta = $this->get_product_meta_list($product_id);
427
+
428
+ if (isset($meta[$meta_name])) {
429
+ return $meta[$meta_name];
430
+ }
431
+
432
+ return null;
433
+ }
434
+
435
+ function get_product_meta_list($product_id)
436
+ {
437
+ if (isset($this->_meta_info[$product_id]) && $this->_meta_info[$product_id]['type'] == 'product') {
438
+ return $this->_meta_info[$product_id];
439
+ }
440
+
441
+ return null;
442
+ }
443
+
444
+
445
+ /**
446
+ * Retrieves the module installation path for a specific product (Note: this is just the generic root container path for modules of this product)
447
+ * @param string $product_id
448
+ * @return string
449
+ */
450
+ function get_product_module_path($product_id)
451
+ {
452
+ if (isset($this->_meta_info[$product_id])) {
453
+ $info = $this->_meta_info[$product_id];
454
+
455
+ if (isset($info['product-module-path'])) {
456
+ return $info['product-module-path'];
457
+ }
458
+ }
459
+
460
+ return null;
461
+ }
462
+
463
+
464
+ /**
465
+ * Sets the module installation path for a specific product (Note: this is just the generic root container path for modules of this product)
466
+ * @param string $product_id
467
+ * @param string $module_path
468
+ */
469
+ function set_product_module_path($product_id, $module_path)
470
+ {
471
+ if (isset($this->_meta_info[$product_id])) {
472
+ $this->_meta_info[$product_id]['product-module-path'] = $module_path;
473
+ }
474
+ }
475
+
476
+
477
+ /**
478
+ * Retrieves a list of instantiated product ids
479
+ * @return array
480
+ */
481
+ function get_product_list()
482
+ {
483
+ return array_keys($this->_products);
484
+ }
485
+
486
+ /**
487
+ * Retrieves a list of registered product ids, including those that aren't loaded (i.e. get_product() call with those unloaded ids will fail)
488
+ * @return array
489
+ */
490
+ function get_known_product_list()
491
+ {
492
+ $list = array_keys($this->_meta_info);
493
+ $return = array();
494
+
495
+ foreach ($list as $module_id)
496
+ {
497
+ if ($this->get_product_meta_list($module_id) != null)
498
+ {
499
+ $return[] = $module_id;
500
+ }
501
+ }
502
+
503
+ return $return;
504
+ }
505
+
506
+
507
+ /**
508
+ * Registers an adapter for an interface with specific contexts
509
+ * @param string $interface
510
+ * @param string $class
511
+ * @param array $contexts
512
+ */
513
+ function add_adapter($interface, $class, $contexts=FALSE)
514
+ {
515
+ // If no specific contexts are given, then we assume
516
+ // that the adapter is to be applied in ALL contexts
517
+ if (!$contexts) $contexts = array('all');
518
+ if (!is_array($contexts)) $contexts = array($contexts);
519
+
520
+ if (!isset($this->_adapters[$interface])) {
521
+ $this->_adapters[$interface] = array();
522
+ }
523
+
524
+ // Iterate through each specific context
525
+ foreach ($contexts as $context) {
526
+ if (!isset($this->_adapters[$interface][$context])) {
527
+ $this->_adapters[$interface][$context] = array();
528
+ }
529
+ $this->_adapters[$interface][$context][] = $class;
530
+ }
531
+ }
532
+
533
+
534
+ /**
535
+ * Removes an adapter for an interface. May optionally specifify what
536
+ * contexts to remove the adapter from, leaving the rest intact
537
+ * @param string $interface
538
+ * @param string $class
539
+ * @param array $contexts
540
+ */
541
+ function del_adapter($interface, $class, $contexts=FALSE)
542
+ {
543
+ // Ensure that contexts is an array of contexts
544
+ if (!$contexts) $contexts = array('all');
545
+ if (!is_array($contexts)) $contexts = array($contexts);
546
+
547
+ // Iterate through each context for an adapter
548
+ foreach ($this->_adapters[$interface] as $context => $classes) {
549
+ if (!$context OR in_array($context, $contexts)) {
550
+ $index = array_search($class, $classes);
551
+ unset($this->_adapters[$interface][$context][$index]);
552
+ }
553
+ }
554
+ }
555
+
556
+
557
+ /**
558
+ * Apply adapters registered for the component
559
+ * @param C_Component $component
560
+ * @return C_Component
561
+ */
562
+ function &apply_adapters(C_Component &$component)
563
+ {
564
+ // Iterate through each adapted interface. If the component implements
565
+ // the interface, then apply the adapters
566
+ foreach ($this->_adapters as $interface => $contexts) {
567
+ if ($component->implements_interface($interface)) {
568
+
569
+
570
+ // Determine what context apply to the current component
571
+ $applied_contexts = array('all');
572
+ if ($component->context) {
573
+ $applied_contexts[] = $component->context;
574
+ $applied_contexts = $this->_flatten_array($applied_contexts);
575
+ }
576
+
577
+ // Iterate through each of the components contexts and apply the
578
+ // registered adapters
579
+ foreach ($applied_contexts as $context) {
580
+ if (isset($contexts[$context])) {
581
+ foreach ($contexts[$context] as $adapter) {
582
+ $component->add_mixin($adapter, TRUE);
583
+ }
584
+ }
585
+
586
+ }
587
+ }
588
+ }
589
+
590
+ return $component;
591
+ }
592
+
593
+
594
+ /**
595
+ * Adds a utility for an interface, to be used in particular contexts
596
+ * @param string $interface
597
+ * @param string $class
598
+ * @param array $contexts
599
+ */
600
+ function add_utility($interface, $class, $contexts=FALSE)
601
+ {
602
+ // If no specific contexts are given, then we assume
603
+ // that the utility is for ALL contexts
604
+ if (!$contexts) $contexts = array('all');
605
+ if (!is_array($contexts)) $contexts = array($contexts);
606
+
607
+ if (!isset($this->_utilities[$interface])) {
608
+ $this->_utilities[$interface] = array();
609
+ }
610
+
611
+ // Add the utility for each appropriate context
612
+ foreach ($contexts as $context) {
613
+ $this->_utilities[$interface][$context] = $class;
614
+ }
615
+ }
616
+
617
+
618
+ /**
619
+ * Deletes a registered utility for a particular interface.
620
+ * @param string $interface
621
+ * @param array $contexts
622
+ */
623
+ function del_utility($interface, $contexts=FALSE)
624
+ {
625
+ if (!$contexts) $contexts = array('all');
626
+ if (!is_array($contexts)) $contexts = array($contexts);
627
+
628
+ // Iterate through each context for an interface
629
+ foreach ($this->_utilities[$interface] as $context => $class) {
630
+ if (!$context OR in_array($context, $contexts)) {
631
+ unset($this->_utilities[$interface][$context]);
632
+ }
633
+ }
634
+ }
635
+
636
+ /**
637
+ * Gets the class name of the component providing a utility implementation
638
+ * @param string $interface
639
+ * @param string|array $context
640
+ * @return string
641
+ */
642
+ function get_utility_class_name($interface, $context=FALSE)
643
+ {
644
+ return $this->_retrieve_utility_class($interface, $context);
645
+ }
646
+
647
+
648
+ /**
649
+ * Retrieves an instantiates the registered utility for the provided instance.
650
+ * The instance is a singleton and must provide the get_instance() method
651
+ * @param string $interface
652
+ * @param string $context
653
+ * @return C_Component
654
+ */
655
+ function get_utility($interface, $context=FALSE)
656
+ {
657
+ if (!$context) $context='all';
658
+ $class = $this->_retrieve_utility_class($interface, $context);
659
+ return call_user_func("{$class}::get_instance", $context);
660
+ }
661
+
662
+
663
+ /**
664
+ * Flattens an array of arrays to a single array
665
+ * @param array $array
666
+ * @param array $parent (optional)
667
+ * @param bool $exclude_duplicates (optional - defaults to TRUE)
668
+ * @return array
669
+ */
670
+ function _flatten_array($array, $parent=NULL, $exclude_duplicates=TRUE)
671
+ {
672
+ if (is_array($array)) {
673
+
674
+ // We're to add each element to the parent array
675
+ if ($parent) {
676
+ foreach ($array as $index => $element) {
677
+ foreach ($this->_flatten_array($array) as $sub_element) {
678
+ if ($exclude_duplicates) {
679
+ if (!in_array($sub_element, $parent)) {
680
+ $parent[] = $sub_element;
681
+ }
682
+ }
683
+ else $parent[] = $sub_element;
684
+ }
685
+ }
686
+ $array = $parent;
687
+ }
688
+
689
+ // We're starting the process..
690
+ else {
691
+ $index = 0;
692
+ while (isset($array[$index])) {
693
+ $element = $array[$index];
694
+ if (is_array($element)) {
695
+ $array = $this->_flatten_array($element, $array);
696
+ unset($array[$index]);
697
+ }
698
+ $index += 1;
699
+ }
700
+ $array = array_values($array);
701
+ }
702
+ }
703
+ else {
704
+ $array = array($array);
705
+ }
706
+
707
+ return $array;
708
+ }
709
+
710
+
711
+ /**
712
+ * Returns a list of paths under a specific location, optionally by regex matching their names
713
+ * @param string $path starting path
714
+ * @param string $regex matched against file basename, not full path
715
+ * @param int $recurse recurse level
716
+ */
717
+ function _get_file_list($path, $recurse = null, $regex = null)
718
+ {
719
+ $path = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $path);
720
+ $file_list = array();
721
+
722
+ if (is_dir($path)) {
723
+
724
+ if ($dh = opendir($path)) {
725
+
726
+ if (substr($path, -1) != DIRECTORY_SEPARATOR) {
727
+ $path .= DIRECTORY_SEPARATOR;
728
+ }
729
+
730
+ rewinddir($dh);
731
+
732
+ while (($file = readdir($dh)) !== false) {
733
+ if ($file != '.' && $file != '..') {
734
+ $file_path = $path . $file;
735
+
736
+ if ($regex == null || preg_match($regex, $file)) {
737
+ $file_list[] = $file_path;
738
+ }
739
+
740
+ if ($recurse > 0) {
741
+ $file_list = array_merge($file_list, $this->_get_file_list($file_path, $recurse - 1, $regex));
742
+ }
743
+ }
744
+ }
745
+
746
+ closedir($dh);
747
+ }
748
+ }
749
+
750
+ return $file_list;
751
+ }
752
+
753
+ /**
754
+ * Searches a path for valid module definitions and stores their dependency lists
755
+ * @param string $path
756
+ * @param bool $recurse - note, it will only recurse 1 level in the hierarchy
757
+ */
758
+ function _scan_module_path($path, $recurse = false)
759
+ {
760
+ $path = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $path);
761
+ $base = basename($path);
762
+ $regex = '/^(?:module|product)\\..*\\.php$/';
763
+ $result = array();
764
+
765
+ if (is_file($path) && preg_match($regex, $base))
766
+ {
767
+ $result[] = $path;
768
+ }
769
+ else
770
+ {
771
+ $result = $this->_get_file_list($path, $recurse ? 1 : 0, $regex);
772
+ }
773
+
774
+ if ($result != null)
775
+ {
776
+ $scan = array();
777
+
778
+ foreach ($result as $module_path)
779
+ {
780
+ $module_dir = basename(dirname($module_path));
781
+
782
+ if (strpos($module_dir, '__') === 0)
783
+ {
784
+ continue;
785
+ }
786
+
787
+ // XXX might be necessary to use fopen/fread for very large module files
788
+ $module_content = file_get_contents($module_path);
789
+ $match = null;
790
+
791
+ if (preg_match('/\/(?:\*)+\s*\{\s*(?P<type>Module|Product):\s*(?P<id>[\w-_]+)\s*(?:,\s*Depends:\s*\{(?P<depends>.*)\})?\s*(,\s*Before:\s*\{(?P<before>.*)\})?\s*\}/m', $module_content, $match) > 0)
792
+ {
793
+ $module_type = $match['type'];
794
+ $module_id = $match['id'];
795
+ $module_deps = isset($match['depends']) ? $match['depends'] : null;
796
+ $module_before = isset($match['before']) ? $match['before'] : null;
797
+ $module_info = array('type' => strtolower($module_type), 'id' => $module_id, 'path' => $module_path);
798
+
799
+ if ($module_deps != null)
800
+ {
801
+ $module_deps = array_map('trim', explode(',', $module_deps));
802
+ $module_info['dependency-list'] = $module_deps;
803
+ }
804
+
805
+ if ($module_before != null)
806
+ {
807
+ $module_before = array_map('trim', explode(',', $module_before));
808
+ $module_info['before-list'] = $module_before;
809
+ }
810
+
811
+ $scan[$module_id] = $module_info;
812
+ }
813
+ else die("{$module_path} is not a valid Pope module");
814
+ }
815
+
816
+ return $scan;
817
+ }
818
+
819
+ return null;
820
+ }
821
+
822
+
823
+ /**
824
+ * Loads a module's code according to its dependency list and taking into consideration circular references
825
+ * @param string $module_id
826
+ * @param array $load_path
827
+ */
828
+ function _load_module_internal($module_id, $load_path = null)
829
+ {
830
+ if ($this->get_module($module_id) != null)
831
+ {
832
+ // Module already loaded
833
+ return true;
834
+ }
835
+
836
+ if (!is_array($load_path))
837
+ {
838
+ $load_path = (array) $load_path;
839
+ }
840
+
841
+ if (isset($this->_meta_info[$module_id]))
842
+ {
843
+ $module_info = $this->_meta_info[$module_id];
844
+
845
+ if (isset($module_info['dependency-list']))
846
+ {
847
+ $module_deps = $module_info['dependency-list'];
848
+ $load_path[] = $module_id;
849
+
850
+ foreach ($module_deps as $module_dep_id)
851
+ {
852
+ if (in_array($module_dep_id, $load_path))
853
+ {
854
+ // Circular reference
855
+ continue;
856
+ }
857
+
858
+ if (!$this->_load_module_internal($module_dep_id, $load_path))
859
+ {
860
+ return false;
861
+ }
862
+ }
863
+ }
864
+ if (isset($module_info['path']))
865
+ {
866
+ $module_path = $module_info['path'];
867
+
868
+ if (is_file($module_path))
869
+ {
870
+ include_once($module_path);
871
+
872
+ return true;
873
+ }
874
+ }
875
+ }
876
+
877
+ return false;
878
+ }
879
+
880
+
881
+ /**
882
+ * Private API method. Retrieves the class which currently provides the utility
883
+ * @param string $interface
884
+ * @param string $context
885
+ */
886
+ function _retrieve_utility_class($interface, $context='all')
887
+ {
888
+ $class = FALSE;
889
+
890
+ if (!$context) $context = 'all';
891
+ if (isset($this->_utilities[$interface])) {
892
+ if (isset($this->_utilities[$interface][$context])) {
893
+ $class = $this->_utilities[$interface][$context];
894
+ }
895
+
896
+ // No utility defined for the specified interface
897
+ else {
898
+ if ($context == 'all') $context = 'default';
899
+ $class = $this->_retrieve_utility_class($interface, FALSE);
900
+ if (!$class)
901
+ throw new Exception("No utility registered for `{$interface}` with the `{$context}` context.");
902
+
903
+ }
904
+ }
905
+ else throw new Exception("No utilities registered for `{$interface}`");
906
+
907
+ return $class;
908
+ }
909
+ /**
910
+ * Autoloads any classes, interfaces, or adapters needed by this module
911
+ */
912
+ function _module_autoload($name)
913
+ {
914
+ if ($this->_module_type_cache == null || count($this->_modules) > $this->_module_type_cache_count)
915
+ {
916
+ $this->_module_type_cache_count = count($this->_modules);
917
+ $modules = $this->_modules;
918
+
919
+ foreach ($modules as $module_id => $module)
920
+ {
921
+ $dir = $this->get_module_dir($module_id);
922
+ $type_list = $module->get_type_list();
923
+
924
+ foreach ($type_list as $type => $filename)
925
+ {
926
+ $this->_module_type_cache[strtolower($type)] = $dir . DIRECTORY_SEPARATOR . $filename;
927
+ }
928
+ }
929
+ }
930
+
931
+ $name = strtolower($name);
932
+
933
+ if (isset($this->_module_type_cache[$name]))
934
+ {
935
+ $module_filename = $this->_module_type_cache[$name];
936
+
937
+ if (file_exists($module_filename))
938
+ {
939
+ include_once($module_filename);
940
+ }
941
+ }
942
+ }
943
+ }
pope/lib/class.extensibleobject.php ADDED
@@ -0,0 +1,1377 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ define('__EXTOBJ_STATIC__', '__STATICALLY_CALLED__');
3
+ define('__EXTOBJ_NO_INIT__', '__NO_INIT__');
4
+
5
+
6
+ /**
7
+ * Provides helper methods for Pope objects
8
+ */
9
+ class PopeHelpers
10
+ {
11
+ /**
12
+ * Merges two associative arrays
13
+ * @param array $a1
14
+ * @param array $a2
15
+ * @return array
16
+ */
17
+ function array_merge_assoc($a1, $a2, $skip_empty=FALSE)
18
+ {
19
+ if ($a2) {
20
+ foreach ($a2 as $key => $value) {
21
+ if ($skip_empty && $value === '' OR is_null($value)) continue;
22
+ if (isset($a1[$key])) {
23
+
24
+ if (is_array($value)) {
25
+ $a1[$key] = $this->array_merge_assoc($a1[$key], $value);
26
+
27
+ }
28
+ else {
29
+ $a1[$key] = $value;
30
+ }
31
+
32
+ }
33
+ else $a1[$key] = $value;
34
+ }
35
+ }
36
+ return $a1;
37
+ }
38
+
39
+
40
+ /**
41
+ * Returns TRUE if a property is empty
42
+ * @param string $var
43
+ * @return boolean
44
+ */
45
+ function is_empty($var, $element=FALSE)
46
+ {
47
+ if (is_array($var) && $element) {
48
+ if (isset($var[$element])) $var = $var[$element];
49
+ else $var = FALSE;
50
+ }
51
+
52
+ return (is_null($var) OR (is_string($var) AND strlen($var) == 0) OR $var === FALSE);
53
+ }
54
+ }
55
+
56
+
57
+ /**
58
+ * An ExtensibleObject can be extended at runtime with methods from another
59
+ * class.
60
+ *
61
+ * - Mixins may be added or removed at any time during runtime
62
+ * - The path to the mixin is cached so that subsequent method calls are
63
+ * faster
64
+ * - Pre and post hooks can be added or removed at any time during runtime.
65
+ * - Each method call has a list of associated properties that can be modified
66
+ * by pre/post hooks, such as: return_value, run_pre_hooks, run_post_hooks, etc
67
+ * - Methods can be replaced by other methods at runtime
68
+ * - Objects can implement interfaces, and are constrained to implement all
69
+ * methods as defined by the interface
70
+ * - All methods are public. There's no added security by having private/protected
71
+ * members, as monkeypatching can always expose any method. Instead, protect
72
+ * your methods using obscurity. Conventionally, use an underscore to define
73
+ * a method that's private to an API
74
+ */
75
+ class ExtensibleObject extends PopeHelpers
76
+ {
77
+ const METHOD_PROPERTY_RUN='run';
78
+ const METHOD_PROPERTY_RUN_POST_HOOKS='run_post_hooks';
79
+ const METHOD_PROPERTY_RUN_PRE_HOOKS='run_pre_hooks';
80
+ const METHOD_PROPERTY_RETURN_VALUE='return_value';
81
+
82
+ var $_mixins = array();
83
+ var $_mixin_priorities = array();
84
+ var $_pre_hooks = array();
85
+ var $_global_pre_hooks = array();
86
+ var $_global_post_hooks= array();
87
+ var $_post_hooks = array();
88
+ var $_method_map_cache = array();
89
+ var $_interfaces = array();
90
+ var $_overrides = array();
91
+ var $_aliases = array();
92
+ var $_method_properties = array();
93
+ var $_throw_error = TRUE;
94
+ var $_wrapped_instance = FALSE;
95
+ var $object = NULL;
96
+ var $_disabled_pre_hooks = array();
97
+ var $_disabled_post_hooks = array();
98
+ var $_disabled_mixins = array();
99
+
100
+
101
+ /**
102
+ * Defines a new ExtensibleObject. Any subclass should call this constructor.
103
+ * Subclasses are expected to provide the following:
104
+ * define_instance() - adds extensions which provide instance methods
105
+ * define_class() - adds extensions which provide static methods
106
+ * initialize() - used to initialize the state of the object
107
+ */
108
+ function __construct()
109
+ {
110
+ // Mixins access their parent class by accessing $this->object.
111
+ // Sometimes users mistakenly use $this->object within the parent object
112
+ // itself. As it's becoming a common mistake, we define a $this->object
113
+ // property which points to the current instance (itself)
114
+ $this->object = $this;
115
+
116
+ $args = func_get_args();
117
+ $define_instance = TRUE;
118
+ $init_instance = TRUE;
119
+
120
+ // The first argument could be a flag to ExtensibleObject
121
+ // which indicates that only static-like methods will be called
122
+ if (count($args) >= 1) {
123
+ $first_arg = $args[0];
124
+ if (is_string($first_arg)) {
125
+ switch ($first_arg) {
126
+ case __EXTOBJ_STATIC__:
127
+ {
128
+ $define_instance = FALSE;
129
+ $init_instance = FALSE;
130
+
131
+ if (method_exists($this, 'define_class')) {
132
+ $this->call_callback($this, 'define_class', $args);
133
+ }
134
+ elseif (method_exists($this, 'define_static')) {
135
+ $this->call_callback($this, 'define_static', $args);
136
+ }
137
+
138
+ break;
139
+ }
140
+ case __EXTOBJ_NO_INIT__:
141
+ {
142
+ $init_instance = FALSE;
143
+
144
+ break;
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ // Are we to define instance methods?
151
+ if ($define_instance)
152
+ {
153
+ if (method_exists($this, 'define_instance'))
154
+ {
155
+ $reflection = new ReflectionMethod($this, 'define_instance');
156
+ $reflection->invokeArgs($this, $args);
157
+ // call_user_func_array(array($this, 'define_instance'), $args);
158
+ }
159
+ elseif (method_exists($this, 'define')) {
160
+ $reflection = new ReflectionMethod($this, 'define');
161
+ $reflection->invokeArgs($this, $args);
162
+ // call_user_func_array(array($this, 'define'), $args);
163
+ }
164
+
165
+ $this->_enforce_interface_contracts();
166
+
167
+ if ($init_instance)
168
+ {
169
+ // Initialize the state of the object
170
+ if (method_exists($this, 'initialize')) {
171
+ $reflection = new ReflectionMethod($this, 'initialize');
172
+ $reflection->invokeArgs($this, $args);
173
+ // call_user_func_array(array($this, 'initialize'), $args);
174
+ }
175
+ }
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Disabled prehooks for a particular method
181
+ * @param string $method
182
+ */
183
+ function disable_pre_hooks($method)
184
+ {
185
+ $this->_disabled_pre_hooks[] = $method;
186
+ return $this;
187
+ }
188
+
189
+
190
+ /**
191
+ * Enable prehooks for a particular method
192
+ * @param string $method
193
+ */
194
+ function enable_pre_hooks($method)
195
+ {
196
+ $index = array_search($method, $this->_disabled_pre_hooks);
197
+ if ($index !== FALSE) {
198
+ unset($this->_disabled_pre_hooks[$index]);
199
+ }
200
+ return $this;
201
+ }
202
+
203
+ /**
204
+ * Disabled posthooks for a particular method
205
+ * @param string $method
206
+ */
207
+ function disable_post_hooks($method)
208
+ {
209
+ $this->_disabled_post_hooks[] = $method;
210
+ return $this;
211
+ }
212
+
213
+
214
+ /**
215
+ * Enable post-hooks for a particular method
216
+ * @param string $method
217
+ */
218
+ function enable_post_hooks($method)
219
+ {
220
+ $index = array_search($method, $this->_disabled_post_hooks);
221
+ if ($index !== FALSE) {
222
+ unset($this->_disabled_post_hooks[$index]);
223
+ }
224
+ return $this;
225
+ }
226
+
227
+ /**
228
+ * Determines if post hooks are enabled for a particular method
229
+ * @param string $method
230
+ * @return bool
231
+ */
232
+ function are_post_hooks_enabled($method)
233
+ {
234
+ return !empty($this->_post_hooks) && (!in_array($method, $this->_disabled_post_hooks));
235
+ }
236
+
237
+
238
+ /**
239
+ * Determines if pre hooks are enabled for a particular method
240
+ * @param string $method
241
+ * @return bool
242
+ */
243
+ function are_pre_hooks_enabled($method)
244
+ {
245
+ return !empty($this->_pre_hooks) && (!in_array($method, $this->_disabled_pre_hooks));
246
+ }
247
+
248
+
249
+ /**
250
+ * Adds an extension class to the object. The extension provides
251
+ * methods for this class to expose as it's own
252
+ * @param string $class
253
+ */
254
+ function add_mixin($class, $instantiate=FALSE)
255
+ {
256
+ $retval = TRUE;
257
+
258
+ if (!$this->has_mixin($class)) {
259
+ // We used to instantiate the class, but I figure
260
+ // we might as well wait till the method is called to
261
+ // save memory. Instead, the _call() method calls the
262
+ // _instantiate_mixin() method below.
263
+ $this->_mixins[$class] = FALSE; // new $class();
264
+ array_unshift($this->_mixin_priorities, $class);
265
+ $this->_flush_cache();
266
+
267
+ // Should we instantiate the object now?
268
+ if ($instantiate) $this->_instantiate_mixin($class);
269
+ }
270
+ else $retval = FALSE;
271
+
272
+ return $retval;
273
+ }
274
+
275
+
276
+ /**
277
+ * Determines if a mixin has been added to this class
278
+ * @param string $klass
279
+ * @return bool
280
+ */
281
+ function has_mixin($klass)
282
+ {
283
+ return (isset($this->_mixins[$klass]));
284
+ }
285
+
286
+
287
+ /**
288
+ * Stores the instantiated class
289
+ * @param string $class
290
+ * @return mixed
291
+ */
292
+ function _instantiate_mixin($class)
293
+ {
294
+ $retval = FALSE;
295
+ if ($this->_mixins[$class])
296
+ $retval = $this->_mixins[$class];
297
+ else {
298
+ $obj= new $class();
299
+ $obj->object = &$this;
300
+ $retval = $this->_mixins[$class] = &$obj;
301
+ if (method_exists($obj, 'initialize')) $obj->initialize();
302
+ }
303
+
304
+
305
+ return $retval;
306
+ }
307
+
308
+
309
+ /**
310
+ * Deletes an extension from the object. The methods provided by that
311
+ * extension are no longer available for the object
312
+ * @param string $class
313
+ */
314
+ function del_mixin($class)
315
+ {
316
+ unset($this->_mixins[$class]);
317
+ $index = array_search($class, $this->_mixin_priorities);
318
+ if ($index !== FALSE) {
319
+ unset($this->_mixin_priorities[$index]);
320
+ foreach ($this->_disabled_mixins as $method => $disabled_mixins) {
321
+ $index = array_search($class, $disabled_mixins);
322
+ if (is_int($index)) unset($this->_disabled_mixins[$method][$index]);
323
+ }
324
+ $this->_flush_cache();
325
+ }
326
+
327
+ }
328
+
329
+
330
+ function remove_mixin($class)
331
+ {
332
+ $this->del_mixin($class);
333
+ }
334
+
335
+
336
+ /**
337
+ * Replaces an extension methods with that of another class.
338
+ * @param string $method
339
+ * @param string $class
340
+ * @param string $new_method
341
+ */
342
+ function replace_method($method, $class, $new_method=FALSE)
343
+ {
344
+ if (!$new_method) $new_method = $method;
345
+ $this->_overrides[$method] = $class;
346
+ $this->add_pre_hook($method, "replacement_{$method}_{$class}_{$new_method}", $class, $new_method);
347
+ $this->_flush_cache();
348
+
349
+ }
350
+
351
+
352
+ /**
353
+ * Restores a method that was replaced by a former call to replace_method()
354
+ * @param string $method
355
+ */
356
+ function restore_method($method)
357
+ {
358
+ $class = $this->_overrides[$method];
359
+ unset($this->_overrides[$method]);
360
+ $this->del_pre_hook($method, $class);
361
+ $this->_flush_cache();
362
+ }
363
+
364
+
365
+ /**
366
+ * Returns the Mixin which provides the specified method
367
+ * @param string $method
368
+ */
369
+ function get_mixin_providing($method, $return_obj=FALSE)
370
+ {
371
+ $retval = FALSE;
372
+
373
+ // If it's cached, then we've got it easy
374
+ if ($this->is_cached($method)) {
375
+
376
+ $object = $this->_method_map_cache[$method];
377
+ $retval = get_class($object);
378
+ }
379
+
380
+ // Otherwise, we have to look it up
381
+ else {
382
+ foreach ($this->get_mixin_priorities($method) as $klass) {
383
+ $object = $this->_instantiate_mixin($klass);
384
+ if (method_exists($object, $method)) {
385
+ $retval = $return_obj ? $object : get_class($object);
386
+ $this->_cache_method($object, $method);
387
+ break;
388
+ }
389
+ }
390
+ }
391
+
392
+ return $retval;
393
+ }
394
+
395
+
396
+ /**
397
+ * When an ExtensibleObject is instantiated, it checks whether all
398
+ * the registered extensions combined provide the implementation as required
399
+ * by the interfaces registered for this object
400
+ */
401
+ function _enforce_interface_contracts()
402
+ {
403
+ $errors = array();
404
+
405
+ foreach ($this->_interfaces as $i) {
406
+ $r = new ReflectionClass($i);
407
+ foreach ($r->getMethods() as $m) {
408
+ if (!$this->has_method($m->name)) {
409
+ $klass = $this->get_class_name($this);
410
+ $errors[] = "`{$klass}` does not implement `{$m->name}` as required by `{$i}`";
411
+ }
412
+ }
413
+ }
414
+
415
+ if ($errors) throw new Exception(implode(". ", $errors));
416
+ }
417
+
418
+
419
+ /**
420
+ * Implement a defined interface. Does the same as the 'implements' keyword
421
+ * for PHP, except this method takes into account extensions
422
+ * @param string $interface
423
+ */
424
+ function implement($interface)
425
+ {
426
+ $this->_interfaces[] = $interface;
427
+ }
428
+
429
+
430
+ /**
431
+ * Adds a hook that gets executed before every method call
432
+ * @param string $name
433
+ * @param string $class
434
+ * @param string $hook_method
435
+ */
436
+ function add_global_pre_hook($name, $class, $hook_method)
437
+ {
438
+ $this->add_pre_hook('*', $name, $class, $hook_method);
439
+ }
440
+
441
+ /**
442
+ * Adds a hook that gets executed after every method call
443
+ *
444
+ * @param string $name
445
+ * @param string $class
446
+ * @param string $hook_method
447
+ */
448
+ function add_global_post_hook($name, $class, $hook_method)
449
+ {
450
+ $this->add_pre_hook('*', $name, $class, $hook_method);
451
+ }
452
+
453
+
454
+ /**
455
+ * Adds a hook that will get executed before a particular method call
456
+ * @param string $method
457
+ * @param string $name
458
+ * @param string $class
459
+ * @param string $hook_method
460
+ */
461
+ function add_pre_hook($method, $name, $class, $hook_method=FALSE)
462
+ {
463
+ if (!$hook_method) $hook_method = $method;
464
+
465
+ // Is this a global pre hook?
466
+ if ($method == '*') {
467
+ $this->_global_pre_hooks[$name] = array(
468
+ new $class,
469
+ $hook_method
470
+ );
471
+ }
472
+
473
+ // This is a method-specific pre hook
474
+ else {
475
+ if (!isset($this->_pre_hooks[$method])) {
476
+ $this->_pre_hooks[$method] = array();
477
+ }
478
+
479
+ $this->_pre_hooks[$method][$name] = array(
480
+ new $class,
481
+ $hook_method
482
+ );
483
+ }
484
+ }
485
+
486
+
487
+ /**
488
+ * Adds a hook to be called after a particular method call
489
+ * @param string $method
490
+ * @param string $hook_name
491
+ * @param string $class
492
+ * @param string $hook_method
493
+ */
494
+ function add_post_hook($method, $hook_name, $class, $hook_method=FALSE)
495
+ {
496
+ // Is this a global post hook?
497
+ if ($method == '*') {
498
+ $this->_post_hooks[$hook_name] = array(
499
+ new $class,
500
+ $hook_method
501
+ );
502
+ }
503
+
504
+ // This is a method-specific post hook
505
+ else {
506
+ if (!$hook_method) $hook_method = $method;
507
+
508
+ if (!isset($this->_post_hooks[$method])) {
509
+ $this->_post_hooks[$method] = array();
510
+ }
511
+
512
+ $this->_post_hooks[$method][$hook_name] = array(
513
+ new $class,
514
+ $hook_method
515
+ );
516
+ }
517
+ }
518
+
519
+
520
+ /**
521
+ * Deletes a hook that's executed before the specified method
522
+ * @param string $method
523
+ * @param string $name
524
+ */
525
+ function del_pre_hook($method, $name)
526
+ {
527
+
528
+ unset($this->_pre_hooks[$method][$name]);
529
+ }
530
+
531
+ /**
532
+ * Deletes all pre hooks registered
533
+ **/
534
+ function del_pre_hooks($method=FALSE)
535
+ {
536
+ if (!$method)
537
+ $this->_pre_hooks = array();
538
+ else
539
+ unset($this->_pre_hooks[$method]);
540
+ }
541
+
542
+
543
+ /**
544
+ * Deletes a hook that's executed after the specified method
545
+ * @param string $method
546
+ * @param string $name
547
+ */
548
+ function del_post_hook($method, $name)
549
+ {
550
+ unset($this->_post_hooks[$method][$name]);
551
+ }
552
+
553
+ /**
554
+ * Deletes all post hooks
555
+ */
556
+ function del_post_hooks($method=FALSE)
557
+ {
558
+ if (!$method)
559
+ $this->_post_hooks = array();
560
+ else
561
+ unset($this->_post_hooks[$method]);
562
+ }
563
+
564
+
565
+ /**
566
+ * Wraps a class within an ExtensibleObject class.
567
+ * @param string $klass
568
+ * @param array callback, used to tell ExtensibleObject how to instantiate
569
+ * the wrapped class
570
+ */
571
+ function wrap($klass, $callback=FALSE, $args=array())
572
+ {
573
+ if ($callback) {
574
+ $this->_wrapped_instance = call_user_func($callback, $args);
575
+ }
576
+ else {
577
+ $this->_wrapped_instance = new $klass();
578
+ }
579
+ }
580
+
581
+
582
+ /**
583
+ * Determines if the ExtensibleObject is a wrapper for an existing class
584
+ */
585
+ function is_wrapper()
586
+ {
587
+ return $this->_wrapped_instance ? TRUE : FALSE;
588
+ }
589
+
590
+
591
+ /**
592
+ * Returns the name of the class which this ExtensibleObject wraps
593
+ * @return object
594
+ */
595
+ function &get_wrapped_instance()
596
+ {
597
+ return $this->_wrapped_instance;
598
+ }
599
+
600
+
601
+ /**
602
+ * Returns TRUE if the wrapped class provides the specified method
603
+ */
604
+ function wrapped_class_provides($method)
605
+ {
606
+ $retval = FALSE;
607
+
608
+ // Determine if the wrapped class is another ExtensibleObject
609
+ if (method_exists($this->_wrapped_instance, 'has_method')) {
610
+ $retval = $this->_wrapped_instance->has_method($method);
611
+ }
612
+ elseif (method_exists($this->_wrapped_instance, $method)){
613
+ $retval = TRUE;
614
+ }
615
+
616
+ return $retval;
617
+ }
618
+
619
+
620
+ /**
621
+ * Provides a means of calling static methods, provided by extensions
622
+ * @param string $method
623
+ * @return mixed
624
+ */
625
+ static function get_class()
626
+ {
627
+ // Note: this function is static so $this is not defined
628
+ $klass = self::get_class_name();
629
+ $obj = new $klass(__EXTOBJ_STATIC__);
630
+ return $obj;
631
+ }
632
+
633
+
634
+ /**
635
+ * Gets the name of the ExtensibleObject
636
+ * @return string
637
+ */
638
+ static function get_class_name($obj = null)
639
+ {
640
+ if ($obj)
641
+ return get_class($obj);
642
+ elseif (function_exists('get_called_class'))
643
+ return get_called_class();
644
+ else
645
+ return get_class();
646
+ }
647
+
648
+ /**
649
+ * Gets a property from a wrapped object
650
+ * @param string $property
651
+ * @return mixed
652
+ */
653
+ function &__get($property)
654
+ {
655
+ $retval = NULL;
656
+ if ($this->is_wrapper()) {
657
+ try {
658
+ $reflected_prop = new ReflectionProperty($this->_wrapped_instance, $property);
659
+
660
+ // setAccessible method is only available for PHP 5.3 and above
661
+ if (method_exists($reflected_prop, 'setAccessible')) {
662
+ $reflected_prop->setAccessible(TRUE);
663
+ }
664
+
665
+ $retval = $reflected_prop->getValue($this->_wrapped_instance);
666
+ }
667
+ catch (ReflectionException $ex)
668
+ {
669
+ $retval = $this->_wrapped_instance->$property;
670
+ }
671
+ }
672
+
673
+ return $retval;
674
+ }
675
+
676
+ /**
677
+ * Determines if a property (dynamic or not) exists for the object
678
+ * @param string $property
679
+ * @return boolean
680
+ */
681
+ function __isset($property)
682
+ {
683
+ $retval = FALSE;
684
+
685
+ if (property_exists($this, $property)) {
686
+ $retval = isset($this->$property);
687
+ }
688
+ elseif ($this->is_wrapper() && property_exists($this->_wrapped_instance, $property)) {
689
+ $retval = isset($this->$property);
690
+ }
691
+
692
+ return $retval;
693
+ }
694
+
695
+
696
+ /**
697
+ * Sets a property on a wrapped object
698
+ * @param string $property
699
+ * @param mixed $value
700
+ * @return mixed
701
+ */
702
+ function &__set($property, $value)
703
+ {
704
+ $retval = NULL;
705
+ if ($this->is_wrapper()) {
706
+ try {
707
+ $reflected_prop = new ReflectionProperty($this->_wrapped_instance, $property);
708
+
709
+ // The property must be accessible, but this is only available
710
+ // on PHP 5.3 and above
711
+ if (method_exists($reflected_prop, 'setAccessible')) {
712
+ $reflected_prop->setAccessible(TRUE);
713
+ }
714
+
715
+ $retval = &$reflected_prop->setValue($this->_wrapped_instance, $value);
716
+ }
717
+
718
+ // Sometimes reflection can fail. In that case, we need
719
+ // some ingenuity as a failback
720
+ catch (ReflectionException $ex) {
721
+ $this->_wrapped_instance->$property = $value;
722
+ $retval = &$this->_wrapped_instance->$property;
723
+ }
724
+
725
+ }
726
+ else {
727
+ $this->$property = $value;
728
+ $retval = &$this->$property;
729
+ }
730
+ return $retval;
731
+ }
732
+
733
+
734
+ /**
735
+ * Finds a method defined by an extension and calls it. However, execution
736
+ * is a little more in-depth:
737
+ * 1) Execute all global pre-hooks and any pre-hooks specific to the requested
738
+ * method. Each method call has instance properties that can be set by
739
+ * other hooks to modify the execution. For example, a pre hook can
740
+ * change the 'run_pre_hooks' property to be false, which will ensure that
741
+ * all other pre hooks will NOT be executed.
742
+ * 2) Runs the method. Checks whether the path to the method has been cached
743
+ * 3) Execute all global post-hooks and any post-hooks specific to the
744
+ * requested method. Post hooks can access method properties as well. A
745
+ * common usecase is to return the value of a post hook instead of the
746
+ * actual method call. To do this, set the 'return_value' property.
747
+ * @param string $method
748
+ * @param array $args
749
+ * @return mixed
750
+ */
751
+ function __call($method, $args)
752
+ {
753
+ $this->clear_method_properties($method, $args);
754
+
755
+ // Run pre hooks?
756
+ if ($this->are_pre_hooks_enabled($method) && $this->get_method_property($method, self::METHOD_PROPERTY_RUN_PRE_HOOKS)) {
757
+
758
+ // Combine global and method-specific pre hooks
759
+ $prehooks = $this->_global_pre_hooks;
760
+ if (isset($this->_pre_hooks[$method])) {
761
+ $prehooks = array_merge($prehooks, $this->_pre_hooks[$method]);
762
+ }
763
+
764
+ // Apply each hook
765
+ foreach ($prehooks as $hook_name => $hook) {
766
+ $method_args = $this->get_method_property($method, 'arguments', $args);
767
+ $this->_run_prehook(
768
+ $hook_name,
769
+ $method,
770
+ $hook[0],
771
+ $hook[1],
772
+ $method_args
773
+ );
774
+ }
775
+ }
776
+
777
+ // Are we to run the actual method? A pre hook might have told us
778
+ // not to
779
+ if ($this->get_method_property($method, self::METHOD_PROPERTY_RUN) && !isset($this->_overrides[$method]))
780
+ {
781
+ if (($this->get_mixin_providing($method))) {
782
+ $this->set_method_property(
783
+ $method,
784
+ self::METHOD_PROPERTY_RETURN_VALUE,
785
+ $this->_exec_cached_method($method, $this->get_method_property($method, 'arguments'))
786
+ );
787
+ }
788
+
789
+ // This is NOT a wrapped class, and no extensions provide the method
790
+ else {
791
+ // Perhaps this is a wrapper and the wrapped object
792
+ // provides this method
793
+ if ($this->is_wrapper() && $this->wrapped_class_provides($method))
794
+ {
795
+ $object = $this->add_wrapped_instance_method($method);
796
+ $this->set_method_property(
797
+ $method,
798
+ self::METHOD_PROPERTY_RETURN_VALUE,
799
+ call_user_func_array(
800
+ array(&$object, $method),
801
+ $this->get_method_property($method, 'arguments')
802
+ )
803
+ );
804
+ }
805
+ elseif ($this->_throw_error) {
806
+ throw new Exception("`{$method}` not defined for " . get_class());
807
+ }
808
+ else {
809
+ return FALSE;
810
+ }
811
+ }
812
+ }
813
+
814
+ // Are we to run post hooks? A pre hook might have told us not to
815
+ if ($this->are_post_hooks_enabled($method) && $this->get_method_property($method, self::METHOD_PROPERTY_RUN_POST_HOOKS)) {
816
+
817
+ // Combine global and method-specific post hooks
818
+ $posthooks = $this->_global_post_hooks;
819
+ if (isset($this->_post_hooks[$method])) {
820
+ $posthooks = array_merge($posthooks, $this->_post_hooks[$method]);
821
+ }
822
+
823
+ // Apply each hook
824
+ foreach ($posthooks as $hook_name => $hook) {
825
+ $method_args = $this->get_method_property($method, 'arguments', $args);
826
+ $this->_run_post_hook(
827
+ $hook_name,
828
+ $method,
829
+ $hook[0],
830
+ $hook[1],
831
+ $method_args
832
+ );
833
+ }
834
+ }
835
+
836
+ return $this->get_method_property($method, self::METHOD_PROPERTY_RETURN_VALUE);
837
+ }
838
+
839
+
840
+ /**
841
+ * Adds the implementation of a wrapped instance method to the ExtensibleObject
842
+ * @param string $method
843
+ * @return Mixin
844
+ */
845
+ function add_wrapped_instance_method($method)
846
+ {
847
+ $retval = $this->get_wrapped_instance();
848
+
849
+ // If the wrapped instance is an ExtensibleObject, then we don't need
850
+ // to use reflection
851
+ if (!is_subclass_of($this->get_wrapped_instance(), 'ExtensibleObject')) {
852
+ $func = new ReflectionMethod($this->get_wrapped_instance(), $method);
853
+
854
+ // Get the entire method definition
855
+ $filename = $func->getFileName();
856
+ $start_line = $func->getStartLine() - 1; // it's actually - 1, otherwise you wont get the function() block
857
+ $end_line = $func->getEndLine();
858
+ $length = $end_line - $start_line;
859
+ $source = file($filename);
860
+ $body = implode("", array_slice($source, $start_line, $length));
861
+ $body = preg_replace("/^\s{0,}private|protected\s{0,}/", '', $body);
862
+
863
+ // Change the context
864
+ $body = str_replace('$this', '$this->object', $body);
865
+ $body = str_replace('$this->object->object', '$this->object', $body);
866
+ $body = str_replace('$this->object->$', '$this->object->', $body);
867
+
868
+ // Define method for mixin
869
+ $wrapped_klass = get_class($this->get_wrapped_instance());
870
+ $mixin_klass = "Mixin_AutoGen_{$wrapped_klass}_{$method}";
871
+ if (!class_exists($mixin_klass)) {
872
+ eval("class {$mixin_klass} extends Mixin{
873
+ {$body}
874
+ }");
875
+ }
876
+ $this->add_mixin($mixin_klass);
877
+ $retval = $this->_instantiate_mixin($mixin_klass);
878
+ $this->_cache_method($retval, $method);
879
+
880
+ }
881
+
882
+ return $retval;
883
+ }
884
+
885
+
886
+ /**
887
+ * Provides an alternative way to call methods
888
+ */
889
+ function call_method($method, $args=array())
890
+ {
891
+ if (method_exists($this, $method))
892
+ {
893
+ $reflection = new ReflectionMethod($this, $method);
894
+ return $reflection->invokeArgs($this, array($args));
895
+ }
896
+ else {
897
+ return $this->__call($method, $args);
898
+ }
899
+ }
900
+
901
+
902
+ /**
903
+ * Returns TRUE if the method in particular has been cached
904
+ * @param string $method
905
+ * @return type
906
+ */
907
+ function is_cached($method)
908
+ {
909
+ return isset($this->_method_map_cache[$method]);
910
+ }
911
+
912
+
913
+ /**
914
+ * Caches the path to the extension which provides a particular method
915
+ * @param string $object
916
+ * @param string $method
917
+ */
918
+ function _cache_method($object, $method)
919
+ {
920
+ $this->_method_map_cache[$method] = $object;
921
+ }
922
+
923
+
924
+ /**
925
+ * Gets a list of mixins by their priority, excluding disabled mixins
926
+ * @param string $method
927
+ * @return array
928
+ */
929
+ function get_mixin_priorities($method)
930
+ {
931
+ $retval = array();
932
+ foreach ($this->_mixin_priorities as $mixin) {
933
+ if ($this->is_mixin_disabled($method, $mixin))
934
+ continue;
935
+ $retval[] = $mixin;
936
+ }
937
+ return $retval;
938
+ }
939
+
940
+
941
+ /**
942
+ * Determines if a mixin is disabled for a particular method
943
+ * @param string $method
944
+ * @param string $mixin
945
+ * @return boolean
946
+ */
947
+ function is_mixin_disabled($method, $mixin)
948
+ {
949
+ $retval = FALSE;
950
+ if (isset($this->_disabled_mixins[$method]))
951
+ if (in_array($mixin, $this->_disabled_mixins[$method]) !== FALSE)
952
+ $retval = TRUE;
953
+ return $retval;
954
+ }
955
+
956
+
957
+ /**
958
+ * Flushes the method cache
959
+ */
960
+ function _flush_cache()
961
+ {
962
+ $this->_method_map_cache = array();
963
+ }
964
+
965
+
966
+ /**
967
+ * Returns TRUE if the object provides the particular method
968
+ * @param string $method
969
+ * @return boolean
970
+ */
971
+ function has_method($method)
972
+ {
973
+ $retval = FALSE;
974
+
975
+ // Have we looked up this method before successfully?
976
+ if ($this->is_cached($method)) {
977
+ $retval = TRUE;
978
+ }
979
+
980
+ // Is this a local PHP method?
981
+ elseif (method_exists($this, $method)) {
982
+ $retval = TRUE;
983
+ }
984
+
985
+ // Is a mixin providing this method
986
+ elseif ($this->get_mixin_providing($method)) {
987
+ $retval = TRUE;
988
+ }
989
+
990
+ elseif ($this->is_wrapper() && $this->wrapped_class_provides($method)) {
991
+ $retval = TRUE;
992
+ }
993
+
994
+ return $retval;
995
+ }
996
+
997
+
998
+ /**
999
+ * Runs a particular pre hook for the specified method. The return value
1000
+ * is assigned to the "[hook_name]_prehook_retval" method property
1001
+ * @param string $hook_name
1002
+ * @param string $method_called
1003
+ * @param Ext $object
1004
+ * @param string $hook_method
1005
+ *
1006
+ */
1007
+ function _run_prehook($hook_name, $method_called, $object, $hook_method, &$args)
1008
+ {
1009
+ $object->object = &$this;
1010
+ $object->method_called = $method_called;
1011
+
1012
+ // Are we STILL to execute pre hooks? A pre-executed hook might have changed this
1013
+ if ($this->get_method_property($method_called, 'run_pre_hooks'))
1014
+ {
1015
+ $reflection = new ReflectionMethod($object, $hook_method);
1016
+ $this->set_method_property(
1017
+ $method_called,
1018
+ $hook_name . '_prehook_retval',
1019
+ $reflection->invokeArgs($object, $args)
1020
+ );
1021
+ }
1022
+ }
1023
+
1024
+ /**
1025
+ * Runs the specified post hook for the specified method
1026
+ * @param string $hook_name
1027
+ * @param string $method_called
1028
+ * @param Ext $object
1029
+ * @param string $hook_method
1030
+ */
1031
+ function _run_post_hook($hook_name, $method_called, $object, $hook_method, &$args)
1032
+ {
1033
+ $object->object = &$this;
1034
+ $object->method_called = $method_called;
1035
+
1036
+ // Are we STILL to execute post hooks? A post-executed hook might have changed this
1037
+ if ($this->get_method_property($method_called, 'run_post_hooks'))
1038
+ {
1039
+ $reflection = new ReflectionMethod($object, $hook_method);
1040
+ $this->set_method_property(
1041
+ $method_called,
1042
+ $hook_name . '_post_hook_retval',
1043
+ $reflection->invokeArgs($object, $args)
1044
+ );
1045
+ }
1046
+ }
1047
+
1048
+ /**
1049
+ * Returns TRUE if a pre-hook has been registered for the specified method
1050
+ * @param string $method
1051
+ * @return boolean
1052
+ */
1053
+ function have_prehook_for($method, $name = null)
1054
+ {
1055
+ if (is_null($name)) {
1056
+ return isset($this->_pre_hooks[$method]);
1057
+ } else {
1058
+ return isset($this->_pre_hooks[$method][$name]);
1059
+ }
1060
+
1061
+ }
1062
+
1063
+
1064
+ /**
1065
+ * Returns TRUE if a posthook has been registered for the specified method
1066
+ * @param string $method
1067
+ * @return boolean
1068
+ */
1069
+ function have_posthook_for($method, $name = null)
1070
+ {
1071
+ $retval = FALSE;
1072
+
1073
+ if (isset($this->_post_hooks[$method])) {
1074
+ if (!$name) $retval = TRUE;
1075
+ else $retval = isset($this->_post_hooks[$method][$name]);
1076
+ }
1077
+
1078
+ return $retval;
1079
+ }
1080
+
1081
+ /**
1082
+ * Disables a mixin for a particular method. This ensures that even though
1083
+ * mixin provides a particular method, it won't be used to provide the
1084
+ * implementation
1085
+ * @param string $method
1086
+ * @param string $klass
1087
+ */
1088
+ function disable_mixin($method, $klass)
1089
+ {
1090
+ unset($this->_method_map_cache[$method]);
1091
+ if (!isset($this->_disabled_mixins[$method])) {
1092
+ $this->_disabled_mixins[$method] = array();
1093
+ }
1094
+ $this->_disabled_mixins[$method][] = $klass;
1095
+ }
1096
+
1097
+
1098
+ /**
1099
+ * Enable a mixin for a particular method, that was previously disabled
1100
+ * @param string $method
1101
+ * @param string $klass
1102
+ */
1103
+ function enable_mixin($method, $klass)
1104
+ {
1105
+ unset($this->_method_map_cache[$method]);
1106
+ if (isset($this->_disabled_mixins[$method])) {
1107
+ $index = array_search($klass, $this->_disabled_mixins[$method]);
1108
+ if ($index !== FALSE) unset($this->_disabled_mixins[$method][$index]);
1109
+ }
1110
+ }
1111
+
1112
+
1113
+ /**
1114
+ * Gets a list of mixins that are currently disabled for a particular method
1115
+ * @see disable_mixin()
1116
+ * @param string $method
1117
+ * @return array
1118
+ */
1119
+ function get_disabled_mixins_for($method)
1120
+ {
1121
+ $retval = array();
1122
+ if (isset($this->_disabled_mixins[$method])) {
1123
+ $retval = $this->_disabled_mixins[$method];
1124
+ }
1125
+ return $retval;
1126
+ }
1127
+
1128
+
1129
+ /**
1130
+ * Executes a cached method
1131
+ * @param string $method
1132
+ * @param array $args
1133
+ * @return mixed
1134
+ */
1135
+ function _exec_cached_method($method, $args=array())
1136
+ {
1137
+ $object = $this->_method_map_cache[$method];
1138
+ $object->object = &$this;
1139
+ $reflection = new ReflectionMethod($object, $method);
1140
+ return $reflection->invokeArgs($object, $args);
1141
+ }
1142
+
1143
+
1144
+ /**
1145
+ * Sets the value of a method property
1146
+ * @param string $method
1147
+ * @param string $property
1148
+ * @param mixed $value
1149
+ */
1150
+ function set_method_property($method, $property, $value)
1151
+ {
1152
+ if (!isset($this->_method_properties[$method])) {
1153
+ $this->_method_properties[$method] = array();
1154
+ }
1155
+
1156
+ return $this->_method_properties[$method][$property] = $value;
1157
+ }
1158
+
1159
+
1160
+ /**
1161
+ * Gets the value of a method property
1162
+ * @param string $method
1163
+ * @param string $property
1164
+ */
1165
+ function get_method_property($method, $property, $default=NULL)
1166
+ {
1167
+ $retval = NULL;
1168
+
1169
+ if (isset($this->_method_properties[$method][$property])) {
1170
+ $retval = $this->_method_properties[$method][$property];
1171
+ }
1172
+
1173
+ if (is_null($retval)) $retval=$default;
1174
+
1175
+ return $retval;
1176
+ }
1177
+
1178
+
1179
+ /**
1180
+ * Clears all method properties to have their default values. This is called
1181
+ * before every method call (before pre-hooks)
1182
+ * @param string $method
1183
+ */
1184
+ function clear_method_properties($method, $args=array())
1185
+ {
1186
+ $this->_method_properties[$method] = array(
1187
+ 'run' => TRUE,
1188
+ 'run_pre_hooks' => TRUE,
1189
+ 'run_post_hooks' => TRUE,
1190
+ 'arguments' => $args
1191
+ );
1192
+ }
1193
+
1194
+
1195
+ /**
1196
+ * Returns TRUE if the ExtensibleObject has decided to implement a
1197
+ * particular interface
1198
+ * @param string $interface
1199
+ * @return boolean
1200
+ */
1201
+ function implements_interface($interface)
1202
+ {
1203
+ return in_array($interface, $this->_interfaces);
1204
+ }
1205
+
1206
+ function get_class_definition_dir($parent=FALSE)
1207
+ {
1208
+ return dirname($this->get_class_definition_file($parent));
1209
+ }
1210
+
1211
+ function get_class_definition_file($parent=FALSE)
1212
+ {
1213
+ $klass = $this->get_class_name($this);
1214
+ $r = new ReflectionClass($klass);
1215
+ if ($parent) {
1216
+ $parent = $r->getParentClass();
1217
+ return $parent->getFileName();
1218
+ }
1219
+ return $r->getFileName();
1220
+ }
1221
+
1222
+ /**
1223
+ * Returns get_class_methods() optionally limited by Mixin
1224
+ *
1225
+ * @param string (optional) Only show functions provided by a mixin
1226
+ * @return array Results from get_class_methods()
1227
+ */
1228
+ public function get_instance_methods($name = null)
1229
+ {
1230
+ if (is_string($name))
1231
+ {
1232
+ $methods = array();
1233
+ foreach ($this->_method_map_cache as $method => $mixin) {
1234
+ if ($name == get_class($mixin))
1235
+ {
1236
+ $methods[] = $method;
1237
+ }
1238
+ }
1239
+ return $methods;
1240
+ } else {
1241
+ $methods = get_class_methods($this);
1242
+ foreach ($this->_mixins as $mixin) {
1243
+ $methods = array_unique(array_merge($methods, get_class_methods($mixin)));
1244
+ sort($methods);
1245
+ }
1246
+
1247
+ return $methods;
1248
+ }
1249
+ }
1250
+ }
1251
+
1252
+
1253
+ /**
1254
+ * An mixin provides methods for an ExtensibleObject to use
1255
+ */
1256
+ class Mixin extends PopeHelpers
1257
+ {
1258
+ /**
1259
+ * The ExtensibleObject which called the extension's method
1260
+ * @var ExtensibleObject
1261
+ */
1262
+ var $object;
1263
+
1264
+ /**
1265
+ * The name of the method called on the ExtensibleObject
1266
+ * @var type
1267
+ */
1268
+ var $method_called;
1269
+
1270
+ /**
1271
+ * There really isn't any concept of 'parent' method. An ExtensibleObject
1272
+ * instance contains an ordered array of extension classes, which provides
1273
+ * the method implementations for the instance to use. Suppose that an
1274
+ * ExtensibleObject has two extension, and both have the same methods.The
1275
+ * last extension appears to 'override' the first extension. So, instead of calling
1276
+ * a 'parent' method, we're actually just calling an extension that was added sooner than
1277
+ * the one that is providing the current method implementation.
1278
+ */
1279
+ function call_parent($method)
1280
+ {
1281
+ $retval = NULL;
1282
+
1283
+ // To simulate a 'parent' call, we remove the current extension from the
1284
+ // ExtensibleObject that is providing the method's implementation, re-emit
1285
+ // the call on the instance to trigger the implementation from the previously
1286
+ // added extension, and then restore things by re-adding the current extension.
1287
+ // It's complicated, but it works.
1288
+
1289
+ // We need to determine the name of the extension. Because PHP 5.2 is
1290
+ // missing get_called_class(), we have to look it up in the backtrace
1291
+ $backtrace = debug_backtrace();
1292
+ $klass = get_class($backtrace[0]['object']);
1293
+
1294
+ // Perform the routine described above...
1295
+ $this->object->disable_pre_hooks($method);
1296
+ $this->object->disable_post_hooks($method);
1297
+ $this->object->disable_mixin($method, $klass);
1298
+
1299
+ // Call anchor
1300
+ $args = func_get_args();
1301
+
1302
+ // Remove $method parameter
1303
+ array_shift($args);
1304
+ $retval = $this->object->call_method($method, $args);
1305
+
1306
+ // Re-enable hooks
1307
+ $this->object->enable_pre_hooks($method);
1308
+ $this->object->enable_post_hooks($method);
1309
+ $this->object->enable_mixin($method, $klass);
1310
+
1311
+ return $retval;
1312
+ }
1313
+
1314
+ /**
1315
+ * Although is is preferrable to call $this->object->method(), sometimes
1316
+ * it's nice to use $this->method() instead.
1317
+ * @param string $method
1318
+ * @param array $args
1319
+ * @return mixed
1320
+ */
1321
+ function __call($method, $args)
1322
+ {
1323
+ if ($this->object->has_method($method)) {
1324
+ return call_user_func_array(array(&$this->object, $method), $args);
1325
+ }
1326
+ }
1327
+
1328
+ /**
1329
+ * Although extensions can have state, it's probably more desirable to maintain
1330
+ * the state in the parent object to keep a sane environment
1331
+ * @param string $property
1332
+ * @return mixed
1333
+ */
1334
+ function __get($property)
1335
+ {
1336
+ return $this->object->$property;
1337
+ }
1338
+ }
1339
+
1340
+ /**
1341
+ * An extension which has the purpose of being used as a hook
1342
+ */
1343
+ class Hook extends Mixin
1344
+ {
1345
+ // Similiar to a mixin's call_parent method.
1346
+ // If a hook needs to call the method that it applied the
1347
+ // Hook n' Anchor pattern to, then this method should be called
1348
+ function call_anchor()
1349
+ {
1350
+ // Disable hooks, so that we call the anchor point
1351
+ $this->object->disable_pre_hooks($this->method_called);
1352
+ $this->object->disable_post_hooks($this->method_called);
1353
+
1354
+ // Call anchor
1355
+ $args = func_get_args();
1356
+ $retval = $this->object->call_method($this->method_called, $args);
1357
+
1358
+ // Re-enable hooks
1359
+ $this->object->enable_pre_hooks($this->method_called);
1360
+ $this->object->enable_post_hooks($this->method_called);
1361
+
1362
+ return $retval;
1363
+ }
1364
+
1365
+ /**
1366
+ * Provides an alias for call_anchor, as there's no parent
1367
+ * to call in the context of a hook.
1368
+ */
1369
+ function call_parent()
1370
+ {
1371
+ $args = func_get_args();
1372
+ return call_user_func_array(
1373
+ array(&$this, 'call_anchor'),
1374
+ $args
1375
+ );
1376
+ }
1377
+ };
pope/lib/interface.component.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Provides a generic interface to be registered with an adapter to modify any
5
+ * component (within a particular context, if desired)
6
+ */
7
+ interface I_Component
8
+ {
9
+
10
+ }
pope/lib/interface.component_factory.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Component_Factory
4
+ {
5
+
6
+ }
pope/lib/interface.pope_module.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Pope_Module
4
+ {
5
+
6
+ }
products/photocrati_nextgen/class.nextgen_product_installer.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_NextGen_Product_Installer
4
+ {
5
+ function uninstall($hard)
6
+ {
7
+ foreach (P_Photocrati_NextGen::$modules as $module_name) {
8
+ if (($handler = C_Photocrati_Installer::get_handler_instance($module_name))) {
9
+ if (method_exists($handler, 'uninstall')) $handler->uninstall($hard);
10
+ }
11
+ }
12
+ }
13
+ }
products/photocrati_nextgen/modules/ajax/README.txt ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ AJAX MODULE
2
+ ======================
3
+
4
+ == Introduction ==
5
+ -------------------
6
+
7
+ This module provides a means for executing AJAX actions through the C_Ajax_Controller class.
8
+ This controller is registed as a route, trigged by "/photocrati_ajax" It's designed in mind
9
+ with the intention that other modules will adapt this controller to provide custom AJAX
10
+ actions.
11
+
12
+ This module also adds some client-side variables to assist with executing your AJAX actions:
13
+ => photocrati_ajax.url, the url used to post your AJAX requests to
14
+ => photacrati_ajax.wp_site_url, the url of the WordPress site
15
+
16
+ To call an AJAX method using jQuery, you'd do the following:
17
+
18
+ jQuery.post(photocrati_ajax.url, {action: "get_gallery", id: 1}, function(response){
19
+ if (typeof response != 'object) response = JSON.parse(response);
20
+ });
21
+
22
+ The above AJAX request will execute C_Ajax_Controller->get_gallery_action(), which is
23
+ expected to return valid JSON (even if there is an error)
24
+
25
+
26
+ == Caveats ==
27
+ -------------
28
+
29
+ This module does not currently have any built-in security mechanisms. Any actions you
30
+ mixin using an adapter need to perform their own authorization checks.
products/photocrati_nextgen/modules/ajax/adapter.ajax_routes.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_Ajax_Routes extends Mixin
4
+ {
5
+ function initialize()
6
+ {
7
+ // We need to add the route after the router has been fully instantiated
8
+ $this->object->add_pre_hook(
9
+ 'serve_request',
10
+ get_class(),
11
+ get_class(),
12
+ 'add_ajax_routes'
13
+ );
14
+ }
15
+
16
+ function add_ajax_routes()
17
+ {
18
+ $app = $this->object->create_app('/photocrati_ajax');
19
+ $app->route('/', 'I_Ajax_Controller#index');
20
+ }
21
+ }
products/photocrati_nextgen/modules/ajax/adapter.ajax_settings.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_Ajax_Settings extends Mixin
4
+ {
5
+ // TODO: Investigate this code. The router uses the I_Settings_Manager utility, but it looks like the..
6
+ // I_Settings_Manager utility requires the router. Ugh.
7
+ function initialize()
8
+ {
9
+ $router = $this->get_registry()->get_utility('I_Router');
10
+ $slug = 'photocrati_ajax';
11
+ $this->object->set_default('ajax_slug', $slug);
12
+ $this->object->set_default('ajax_url', $router->get_url($slug, FALSE));
13
+ $this->object->set_default('ajax_js_url', $router->get_url($slug.'/js', FALSE));
14
+ }
15
+ }
products/photocrati_nextgen/modules/ajax/class.ajax_controller.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Ajax_Controller extends C_MVC_Controller
4
+ {
5
+ static $_instances = array();
6
+
7
+ function define($context=FALSE)
8
+ {
9
+ parent::define($context);
10
+ $this->implement('I_Ajax_Controller');
11
+ }
12
+
13
+ function index_action()
14
+ {
15
+ $retval = FALSE;
16
+ $error_reporting = error_reporting(
17
+ E_CORE_ERROR|E_CORE_WARNING|E_COMPILE_ERROR|E_ERROR|E_PARSE|E_USER_ERROR|E_USER_WARNING|E_RECOVERABLE_ERROR
18
+ );
19
+
20
+ // Inform the MVC framework what type of content we're returning
21
+ $this->set_content_type('json');
22
+
23
+ // Get the action requested & find and execute the related method
24
+ if (($action = $this->param('action'))) {
25
+ $method = "{$action}_action";
26
+ if ($this->has_method($method)) {
27
+ $retval = $this->call_method($method);
28
+ }
29
+ }
30
+
31
+ // If no retval has been set, then return an error
32
+ if (!$retval)
33
+ $retval = array('error' => 'Not a valid AJAX action');
34
+
35
+ // Return the JSON to the browser
36
+ echo json_encode($retval);
37
+
38
+ // reset the reporting level
39
+ error_reporting($error_reporting);
40
+ }
41
+
42
+ /**
43
+ * Returns an instance of this class
44
+ * @param string $context
45
+ * @return C_Ajax_Controller
46
+ */
47
+ static function get_instance($context=FALSE)
48
+ {
49
+ if (!isset(self::$_instances[$context])) {
50
+ $klass = get_class();
51
+ self::$_instances[$context] = new $klass($context);
52
+ }
53
+ return self::$_instances[$context];
54
+ }
55
+ }
products/photocrati_nextgen/modules/ajax/class.ajax_installer.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Ajax_Installer
4
+ {
5
+ function install()
6
+ {
7
+ // Delete cached values. Needed for 2.0.7 and less
8
+ $settings = C_NextGen_Global_Settings::get_instance();
9
+ $settings->delete('ajax_url');
10
+ $settings->delete('ajax_slug');
11
+ $settings->delete('ajax_js_url');
12
+ }
13
+ }
products/photocrati_nextgen/modules/ajax/class.ajax_option_handler.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Ajax_Option_Handler
4
+ {
5
+ private $slug = 'photocrati_ajax';
6
+
7
+ function get_router()
8
+ {
9
+ return C_Component_Registry::get_instance()->get_utility('I_Router');
10
+ }
11
+
12
+ function get($key, $default=NULL)
13
+ {
14
+ $retval = $default;
15
+
16
+ switch($key) {
17
+ case 'ajax_slug':
18
+ $retval = $this->slug;
19
+ break;
20
+ case 'ajax_url':
21
+ $retval = $this->get_router()->get_url($this->slug, FALSE);
22
+ break;
23
+ case 'ajax_js_url':
24
+ $retval = $this->get_router()->get_static_url('photocrati-ajax#ajax.js');
25
+ break;
26
+ }
27
+ return $retval;
28
+ }
29
+ }
products/photocrati_nextgen/modules/ajax/interface.ajax_controller.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Ajax_Controller extends I_MVC_Controller
4
+ {
5
+
6
+ }
products/photocrati_nextgen/modules/ajax/module.ajax.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ {
5
+ Module: photocrati-ajax,
6
+ Depends: { photocrati-mvc }
7
+ }
8
+ */
9
+ class M_Ajax extends C_Base_Module
10
+ {
11
+ function define()
12
+ {
13
+ parent::define(
14
+ 'photocrati-ajax',
15
+ 'AJAX',
16
+ 'Provides AJAX functionality',
17
+ '0.4',
18
+ 'http://www.photocrati.com',
19
+ 'Photocrati Media',
20
+ 'http://www.photocrati.com'
21
+ );
22
+
23
+ include_once('class.ajax_option_handler.php');
24
+ C_NextGen_Global_Settings::add_option_handler('C_Ajax_Option_Handler', array(
25
+ 'ajax_slug',
26
+ 'ajax_url',
27
+ 'ajax_js_url'
28
+ ));
29
+
30
+ include_once('class.ajax_installer.php');
31
+ C_Photocrati_Installer::add_handler($this->module_id, 'C_Ajax_Installer');
32
+ }
33
+
34
+ function _register_adapters()
35
+ {
36
+ $this->get_registry()->add_adapter('I_Router', 'A_Ajax_Routes');
37
+ }
38
+
39
+ function _register_utilities()
40
+ {
41
+ $this->get_registry()->add_utility('I_Ajax_Controller', 'C_Ajax_Controller');
42
+
43
+ }
44
+
45
+ /**
46
+ * Hooks into the WordPress framework
47
+ */
48
+ function _register_hooks()
49
+ {
50
+ add_action('init', array(&$this, 'enqueue_scripts'));
51
+ }
52
+
53
+
54
+ /**
55
+ * Loads a single script to provide the photocrati_ajax settings to the web browser
56
+ */
57
+ function enqueue_scripts()
58
+ {
59
+ $settings = C_NextGen_Global_Settings::get_instance();
60
+ $router = $this->get_registry()->get_utility('I_Router');
61
+
62
+ $site_url = $router->get_base_url(TRUE);
63
+ $home_url = $router->get_base_url();
64
+
65
+ wp_register_script('photocrati_ajax', $settings->ajax_js_url);
66
+ wp_enqueue_script('photocrati_ajax');
67
+
68
+ $vars = array(
69
+ 'url' => $router->get_url($settings->ajax_slug, FALSE),
70
+ 'wp_site_url' => $home_url,
71
+ 'wp_site_static_url' => str_replace('/index.php', '', $site_url)
72
+ );
73
+ wp_localize_script('photocrati_ajax', 'photocrati_ajax', $vars);
74
+ }
75
+
76
+ function get_type_list()
77
+ {
78
+ return array(
79
+ 'A_Ajax_Routes' => 'adapter.ajax_routes.php',
80
+ 'C_Ajax_Installer' => 'class.ajax_installer.php',
81
+ 'C_Ajax_Controller' => 'class.ajax_controller.php',
82
+ 'I_Ajax_Controller' => 'interface.ajax_controller.php',
83
+ 'M_Ajax' => 'module.ajax.php'
84
+ );
85
+ }
86
+ }
87
+
88
+ new M_Ajax();
products/photocrati_nextgen/modules/ajax/static/ajax.js ADDED
@@ -0,0 +1 @@
 
1
+ // ajax.js is intentionally empty
products/photocrati_nextgen/modules/attach_to_post/adapter.attach_to_post_ajax.php ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Provides AJAX actions for the Attach To Post interface
5
+ * TODO: Need to add authorization checks to each action
6
+ */
7
+ class A_Attach_To_Post_Ajax extends Mixin
8
+ {
9
+ var $attach_to_post = NULL;
10
+
11
+ /**
12
+ * Retrieves the attach to post controller
13
+ */
14
+ function get_attach_to_post()
15
+ {
16
+ if (is_null($this->attach_to_post))
17
+ $this->attach_to_post = $this->object->get_registry()->get_utility('I_Attach_To_Post_Controller');
18
+ return $this->attach_to_post;
19
+ }
20
+
21
+
22
+ /**
23
+ * Returns a list of image sources for the Attach to Post interface
24
+ * @return type
25
+ */
26
+ function get_attach_to_post_sources_action()
27
+ {
28
+ $response = array();
29
+
30
+ if ($this->object->validate_ajax_request())
31
+ {
32
+ $response['sources'] = $this->get_attach_to_post()->get_sources();
33
+ }
34
+
35
+ return $response;
36
+ }
37
+
38
+
39
+ /**
40
+ * Gets existing galleries
41
+ * @return array
42
+ */
43
+ function get_existing_galleries_action()
44
+ {
45
+ $response = array();
46
+
47
+ if ($this->object->validate_ajax_request())
48
+ {
49
+ $limit = $this->object->param('limit');
50
+ $offset = $this->object->param('offset');
51
+
52
+ // We return the total # of galleries, so that the client can make
53
+ // pagination requests
54
+ $mapper = $this->object->get_registry()->get_utility('I_Gallery_Mapper');
55
+ $response['total'] = $mapper->count();
56
+ $response['limit'] = $limit = $limit ? $limit : 0;
57
+ $response['offset'] = $offset = $offset ? $offset : 0;
58
+
59
+ // Get the galleries
60
+ $mapper->select();
61
+ if ($limit) $mapper->limit($limit, $offset);
62
+ $response['items'] = $mapper->run_query();
63
+ }
64
+
65
+ return $response;
66
+ }
67
+
68
+
69
+ /**
70
+ * Gets existing albums
71
+ * @return array
72
+ */
73
+ function get_existing_albums_action()
74
+ {
75
+ $response = array();
76
+
77
+ if ($this->object->validate_ajax_request())
78
+ {
79
+ $limit = $this->object->param('limit');
80
+ $offset = $this->object->param('offset');
81
+
82
+ // We return the total # of albums, so that the client can make pagination requests
83
+ $mapper = $this->object->get_registry()->get_utility('I_Album_Mapper');
84
+ $response['total'] = $mapper->count();
85
+ $response['limit'] = $limit = $limit ? $limit : 0;
86
+ $response['offset']= $offset = $offset ? $offset : 0;
87
+
88
+ // Get the albums
89
+ $mapper->select();
90
+ if ($limit) $mapper->limit($limit, $offset);
91
+ $response['items'] = $mapper->run_query();
92
+ }
93
+
94
+ return $response;
95
+ }
96
+
97
+ /**
98
+ * Gets existing image tags
99
+ * @return array
100
+ */
101
+ function get_existing_image_tags_action()
102
+ {
103
+ $response = array();
104
+
105
+ if ($this->object->validate_ajax_request())
106
+ {
107
+ $limit = $this->object->param('limit');
108
+ $offset = $this->object->param('offset');
109
+ $response['limit'] = $limit = $limit ? $limit : 0;
110
+ $response['offset'] = $offset = $offset ? $offset : 0;
111
+ $response['items'] = array();
112
+ $params = array(
113
+ 'number' => $limit,
114
+ 'offset' => $offset,
115
+ 'fields' => 'names'
116
+ );
117
+ foreach (get_terms('ngg_tag', $params) as $term) {
118
+ $response['items'][] = array(
119
+ 'id' => $term,
120
+ 'title' => $term,
121
+ 'name' => $term
122
+ );
123
+ }
124
+ $response['total'] = count(get_terms('ngg_tag', array('fields' => 'ids')));
125
+ }
126
+
127
+ return $response;
128
+ }
129
+
130
+ /**
131
+ * Gets entities (such as images) for a displayed gallery (attached gallery)
132
+ */
133
+ function get_displayed_gallery_entities_action()
134
+ {
135
+ $response = array();
136
+ if ($this->object->validate_ajax_request() && ($params = $this->object->param('displayed_gallery'))) {
137
+ $limit = $this->object->param('limit');
138
+ $offset = $this->object->param('offset');
139
+ $factory = $this->object->get_registry()->get_utility('I_Component_Factory');
140
+ $displayed_gallery = $factory->create('displayed_gallery');
141
+ foreach ($params as $key => $value) $displayed_gallery->$key = $value;
142
+ $response['limit'] = $limit = $limit ? $limit : 0;
143
+ $response['offset'] = $offset = $offset ? $offset : 0;
144
+ $response['total'] = $displayed_gallery->get_entity_count('both');
145
+ $response['items'] = $displayed_gallery->get_entities($limit, $offset, FALSE, 'both');
146
+ $controller = $this->object->get_registry()->get_utility('I_Display_Type_Controller');
147
+ $storage = $this->object->get_registry()->get_utility('I_Gallery_Storage');
148
+ $image_mapper = $this->object->get_registry()->get_utility('I_Image_Mapper');
149
+ $settings = C_NextGen_Settings::get_instance();
150
+ foreach ( $response['items'] as &$entity) {
151
+ $image = $entity;
152
+ if (in_array($displayed_gallery->source, array('album','albums'))) {
153
+ // Set the alttext of the preview image to the
154
+ // name of the gallery or album
155
+ if (($image = $image_mapper->find($entity->previewpic))) {
156
+ if ($entity->is_album)
157
+ $image->alttext = _('Album: ').$entity->name;
158
+ else
159
+ $image->alttext = _('Gallery: ').$entity->title;
160
+ }
161
+
162
+ // Prefix the id of an album with 'a'
163
+ if ($entity->is_album) {
164
+ $id = $entity->{$entity->id_field};
165
+ $entity->{$entity->id_field} = 'a'.$id;
166
+ }
167
+ }
168
+
169
+ // Get the thumbnail
170
+ $entity->thumb_url = $storage->get_image_url($image, 'thumb');
171
+ $entity->thumb_html = $storage->get_image_html($image, 'thumb');
172
+ $entity->max_width = $settings->thumbwidth;
173
+ $entity->max_height = $settings->thumbheight;
174
+ }
175
+ }
176
+ else {
177
+ $response['error'] = _('Missing parameters');
178
+ }
179
+ return $response;
180
+ }
181
+
182
+
183
+ /**
184
+ * Saves the displayed gallery
185
+ */
186
+ function save_displayed_gallery_action()
187
+ {
188
+ $response = array();
189
+ $mapper = $this->object->get_registry()->get_utility('I_Displayed_Gallery_Mapper');
190
+
191
+ // Do we have fields to work with?
192
+ if ($this->object->validate_ajax_request(true) && ($params = $this->object->param('displayed_gallery'))) {
193
+
194
+ // Existing displayed gallery ?
195
+ if (($id = $this->object->param('id'))) {
196
+ $displayed_gallery = $mapper->find($id, TRUE);
197
+ if ($displayed_gallery) {
198
+ foreach ($params as $key => $value) $displayed_gallery->$key = $value;
199
+ }
200
+ }
201
+ else {
202
+ $factory = $this->object->get_registry()->get_utility('I_Component_Factory');
203
+ $displayed_gallery = $factory->create('displayed_gallery', $mapper, $params);
204
+ }
205
+
206
+ // Save the changes
207
+ if ($displayed_gallery) {
208
+ if ($displayed_gallery->save()) $response['displayed_gallery'] = $displayed_gallery->get_entity();
209
+ else $response['validation_errors'] = $this->get_attach_to_post()->show_errors_for($displayed_gallery, TRUE);
210
+ }
211
+ else
212
+ {
213
+ $response['error'] = _('Displayed gallery does not exist');
214
+ }
215
+ }
216
+ else $response['error'] = _('Invalid request');
217
+
218
+ return $response;
219
+ }
220
+
221
+ function validate_ajax_request($check_token = false)
222
+ {
223
+ $valid_request = false;
224
+ $security = $this->get_registry()->get_utility('I_Security_Manager');
225
+ $sec_token = $security->get_request_token('nextgen_edit_displayed_gallery');
226
+ $sec_actor = $security->get_current_actor();
227
+
228
+ if ($sec_actor->is_allowed('nextgen_edit_displayed_gallery') && (!$check_token || $sec_token->check_current_request()))
229
+ {
230
+ $valid_request = true;
231
+ }
232
+
233
+ return $valid_request;
234
+ }
235
+ }
products/photocrati_nextgen/modules/attach_to_post/adapter.attach_to_post_routes.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_Attach_To_Post_Routes extends Mixin
4
+ {
5
+ function initialize()
6
+ {
7
+ $this->object->add_pre_hook(
8
+ 'serve_request',
9
+ 'Adds Attach To Post Routes',
10
+ get_class(),
11
+ 'add_attach_to_post_routes'
12
+ );
13
+ }
14
+
15
+ function add_attach_to_post_routes()
16
+ {
17
+ $app = $this->object->create_app('/nextgen-attach_to_post');
18
+ $app->rewrite('/preview/{id}', '/preview/id--{id}');
19
+ $app->rewrite('/display_tab_js/{id}', '/display_tab_js/id--{id}');
20
+ $app->route('/preview', 'I_Attach_To_Post_Controller#preview');
21
+ $app->route('/display_tab_js', 'I_Attach_To_Post_Controller#display_tab_js');
22
+ $app->route('/', 'I_Attach_To_Post_Controller#index');
23
+ }
24
+ }
products/photocrati_nextgen/modules/attach_to_post/adapter.gallery_storage_frame_event.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_Gallery_Storage_Frame_Event extends Mixin
4
+ {
5
+ function initialize()
6
+ {
7
+ $this->object->add_post_hook(
8
+ 'generate_thumbnail',
9
+ 'After a new thumbnail has been generated, emits a frame event',
10
+ get_class(),
11
+ 'emit_modified_thumbnail_event'
12
+ );
13
+ }
14
+
15
+ function emit_modified_thumbnail_event($image)
16
+ {
17
+ $controller = $this->get_registry()->get_utility('I_Display_Type_Controller');
18
+ $events = $this->get_registry()->get_utility('I_Frame_Event_Publisher', 'attach_to_post');
19
+ $mapper = $this->get_registry()->get_utility('I_Image_Mapper');
20
+ $storage = $this->get_registry()->get_utility('I_Gallery_Storage');
21
+ $app = $this->get_registry()->get_utility('I_Router')->get_routed_app();
22
+
23
+ $image = $mapper->find($image);
24
+ $image->thumb_url = $controller->set_param_for(
25
+ $app->get_routed_url(TRUE),
26
+ 'timestamp',
27
+ time(),
28
+ NULL,
29
+ $storage->get_thumb_url($image)
30
+ );
31
+
32
+ $events->add_event(
33
+ array(
34
+ 'event' => 'thumbnail_modified',
35
+ 'image' => $image,
36
+ )
37
+ );
38
+ }
39
+ }
products/photocrati_nextgen/modules/attach_to_post/class.attach_controller.php ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Attach_Controller extends C_NextGen_Admin_Page_Controller
4
+ {
5
+ static $_instances = array();
6
+ var $_displayed_gallery;
7
+
8
+ static function &get_instance($context)
9
+ {
10
+ if (!isset(self::$_instances[$context])) {
11
+ $klass = get_class();
12
+ self::$_instances[$context] = new $klass($context);
13
+ }
14
+ return self::$_instances[$context];
15
+ }
16
+
17
+ function define($context)
18
+ {
19
+ if (!is_array($context)) $context = array($context);
20
+ array_unshift($context, 'ngg_attach_to_post');
21
+ parent::define($context);
22
+ $this->add_mixin('Mixin_Attach_To_Post');
23
+ $this->add_mixin('Mixin_Attach_To_Post_Display_Tab');
24
+ $this->implement('I_Attach_To_Post_Controller');
25
+ }
26
+
27
+ function initialize()
28
+ {
29
+ parent::initialize();
30
+ $this->_load_displayed_gallery();
31
+ }
32
+ }
33
+
34
+ class Mixin_Attach_To_Post extends Mixin
35
+ {
36
+ function _load_displayed_gallery()
37
+ {
38
+ $mapper = $this->get_registry()->get_utility('I_Displayed_Gallery_Mapper');
39
+ if (!($this->object->_displayed_gallery = $mapper->find($this->object->param('id'), TRUE))) {
40
+ $this->object->_displayed_gallery = $mapper->create();
41
+ }
42
+ }
43
+
44
+ function enqueue_backend_resources()
45
+ {
46
+ $this->call_parent('enqueue_backend_resources');
47
+
48
+ // Enqueue frame event publishing
49
+ wp_enqueue_script('frame_event_publisher');
50
+
51
+ // Enqueue JQuery UI libraries
52
+ wp_enqueue_script('jquery-ui-tabs');
53
+ wp_enqueue_script('jquery-ui-sortable');
54
+ wp_enqueue_script('jquery-ui-tooltip');
55
+ wp_enqueue_script('ngg_tabs', $this->get_static_url('photocrati-attach_to_post#ngg_tabs.js'));
56
+
57
+ // Ensure select2
58
+ wp_enqueue_style('select2');
59
+ wp_enqueue_script('select2');
60
+
61
+ // Ensure that the Photocrati AJAX library is loaded
62
+ wp_enqueue_script('photocrati_ajax');
63
+
64
+ // Enqueue logic for the Attach to Post interface as a whole
65
+ wp_enqueue_script(
66
+ 'ngg_attach_to_post', $this->get_static_url('photocrati-attach_to_post#attach_to_post.js')
67
+ );
68
+ wp_enqueue_style(
69
+ 'ngg_attach_to_post', $this->get_static_url('photocrati-attach_to_post#attach_to_post.css')
70
+ );
71
+
72
+ // Enqueue backbone.js library, required by the Attach to Post display tab
73
+ wp_enqueue_script('backbone'); // provided by WP
74
+
75
+ // Ensure underscore sting, a helper utility
76
+ wp_enqueue_script(
77
+ 'underscore.string',
78
+ $this->get_static_url('photocrati-attach_to_post#underscore.string.js'),
79
+ array('underscore'),
80
+ '2.3.0'
81
+ );
82
+
83
+ // Enqueue the backbone app for the display tab
84
+ $settings = C_NextGen_Global_Settings::get_instance();
85
+ $preview_url = $settings->gallery_preview_url;
86
+ $display_tab_js_url = $settings->attach_to_post_display_tab_js_url;
87
+ if ($this->object->_displayed_gallery->id()) {
88
+ $display_tab_js_url .= '/id--'.$this->object->_displayed_gallery->id();
89
+ }
90
+
91
+ wp_enqueue_script(
92
+ 'ngg_display_tab',
93
+ $display_tab_js_url,
94
+ array('backbone', 'underscore.string')
95
+ );
96
+ wp_localize_script(
97
+ 'ngg_display_tab',
98
+ 'ngg_displayed_gallery_preview_url',
99
+ $settings->gallery_preview_url
100
+ );
101
+ }
102
+
103
+ /**
104
+ * Renders the interface
105
+ */
106
+ function index_action($return=FALSE)
107
+ {
108
+ if ($this->object->_displayed_gallery->is_new()) $this->object->expires("+2 hour");
109
+
110
+ // Enqueue resources
111
+ return $this->object->render_view('photocrati-attach_to_post#attach_to_post', array(
112
+ 'page_title' => $this->object->_get_page_title(),
113
+ 'tabs' => $this->object->_get_main_tabs()
114
+ ), $return);
115
+ }
116
+
117
+
118
+ /**
119
+ * Displays a preview image for the displayed gallery
120
+ */
121
+ function preview_action()
122
+ {
123
+ $found_preview_pic = FALSE;
124
+
125
+ $dyn_thumbs = $this->object->get_registry()->get_utility('I_Dynamic_Thumbnails_Manager');
126
+ $storage = $this->object->get_registry()->get_utility('I_Gallery_Storage');
127
+ $image_mapper = $this->object->get_registry()->get_utility('I_Image_Mapper');
128
+
129
+ // Get the first entity from the displayed gallery. We will use this
130
+ // for a preview pic
131
+ $entity = array_pop($this->object->_displayed_gallery->get_included_entities(1));
132
+ $image = FALSE;
133
+ if ($entity) {
134
+ // This is an album or gallery
135
+ if (isset($entity->previewpic)) {
136
+ $image = (int)$entity->previewpic;
137
+ if (($image = $image_mapper->find($image))) {
138
+ $found_preview_pic = TRUE;
139
+ }
140
+ }
141
+
142
+ // Is this an image
143
+ else if (isset($entity->galleryid)) {
144
+ $image = $entity;
145
+ $found_preview_pic = TRUE;
146
+ }
147
+ }
148
+
149
+ // Were we able to find a preview pic? If so, then render it
150
+ $image_size = $dyn_thumbs->get_size_name(array(
151
+ 'width' => 200,
152
+ 'height' => 200,
153
+ 'quality' => 90,
154
+ 'type' => 'jpg'
155
+ ));;
156
+ $found_preview_pic = $storage->render_image($image, $image_size, TRUE);
157
+
158
+ // Render invalid image if no preview pic is found
159
+ if (!$found_preview_pic) {
160
+ $filename = $this->object->get_static_abspath('photocrati-attach_to_post#invalid_image.png');
161
+ $this->set_content_type('image/png');
162
+ readfile($filename);
163
+ $this->render();
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Returns the page title of the Attach to Post interface
169
+ * @return string
170
+ */
171
+ function _get_page_title()
172
+ {
173
+ return _('NextGEN Gallery - Attach To Post');
174
+ }
175
+
176
+
177
+ /**
178
+ * Returns the main tabs displayed on the Attach to Post interface
179
+ * @returns array
180
+ */
181
+ function _get_main_tabs()
182
+ {
183
+ $retval = array();
184
+
185
+ $security = $this->get_registry()->get_utility('I_Security_Manager');
186
+ $sec_actor = $security->get_current_actor();
187
+
188
+ if ($sec_actor->is_allowed('NextGEN Manage gallery')) {
189
+ $retval['displayed_tab'] = array(
190
+ 'content' => $this->object->_render_display_tab(),
191
+ 'title' => _('Display Galleries')
192
+ );
193
+ }
194
+
195
+ if ($sec_actor->is_allowed('NextGEN Upload images')) {
196
+ $retval['create_tab'] = array(
197
+ 'content' => $this->object->_render_create_tab(),
198
+ 'title' => _('Add Gallery / Images')
199
+ );
200
+ }
201
+
202
+ if ($sec_actor->is_allowed('NextGEN Manage others gallery') && $sec_actor->is_allowed('NextGEN Manage gallery')) {
203
+ $retval['galleries_tab'] = array(
204
+ 'content' => $this->object->_render_galleries_tab(),
205
+ 'title' => _('Manage Galleries')
206
+ );
207
+ }
208
+
209
+ if ($sec_actor->is_allowed('NextGEN Edit album')) {
210
+ $retval['albums_tab'] = array(
211
+ 'content' => $this->object->_render_albums_tab(),
212
+ 'title' => _('Manage Albums')
213
+ );
214
+ }
215
+
216
+ if ($sec_actor->is_allowed('NextGEN Manage tags')) {
217
+ $retval['tags_tab'] = array(
218
+ 'content' => $this->object->_render_tags_tab(),
219
+ 'title' => _('Manage Tags')
220
+ );
221
+ }
222
+
223
+ return $retval;
224
+ }
225
+
226
+ /**
227
+ * Renders a NextGen Gallery page in an iframe, suited for the attach to post
228
+ * interface
229
+ * @param string $page
230
+ * @return string
231
+ */
232
+ function _render_ngg_page_in_frame($page, $tab_id = null)
233
+ {
234
+ $frame_url = admin_url("/admin.php?page={$page}&attach_to_post");
235
+ $frame_url = esc_url($frame_url);
236
+
237
+ if ($tab_id) {
238
+ $tab_id = " id='ngg-iframe-{$tab_id}'";
239
+ }
240
+
241
+ return "<iframe name='{$page}' frameBorder='0'{$tab_id} class='ngg-attach-to-post ngg-iframe-page-{$page}' scrolling='no' src='{$frame_url}'></iframe>";
242
+ }
243
+
244
+ /**
245
+ * Renders the display tab for adjusting how images/galleries will be
246
+ * displayed
247
+ * @return type
248
+ */
249
+ function _render_display_tab()
250
+ {
251
+ return $this->object->render_partial('photocrati-attach_to_post#display_tab', array(
252
+ 'messages' => array(),
253
+ 'tabs' => $this->object->_get_display_tabs()
254
+ ), TRUE);
255
+ }
256
+
257
+
258
+ /**
259
+ * Renders the tab used primarily for Gallery and Image creation
260
+ * @return type
261
+ */
262
+ function _render_create_tab()
263
+ {
264
+ return $this->object->_render_ngg_page_in_frame('ngg_addgallery', 'create_tab');
265
+ }
266
+
267
+
268
+ /**
269
+ * Renders the tab used for Managing Galleries
270
+ * @return string
271
+ */
272
+ function _render_galleries_tab()
273
+ {
274
+ return $this->object->_render_ngg_page_in_frame('nggallery-manage-gallery', 'galleries_tab');
275
+ }
276
+
277
+
278
+ /**
279
+ * Renders the tab used for Managing Albums
280
+ */
281
+ function _render_albums_tab()
282
+ {
283
+ return $this->object->_render_ngg_page_in_frame('nggallery-manage-album', 'albums_tab');
284
+ }
285
+
286
+
287
+ /**
288
+ * Renders the tab used for Managing Albums
289
+ * @return string
290
+ */
291
+ function _render_tags_tab()
292
+ {
293
+ return $this->object->_render_ngg_page_in_frame('nggallery-tags', 'tags_tab');
294
+ }
295
+ }
products/photocrati_nextgen/modules/attach_to_post/class.attach_to_post_installer.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Attach_To_Post_Installer
4
+ {
5
+ function install()
6
+ {
7
+ // Delete cached values. Needed for 2.0.7 and less
8
+ $settings = C_NextGen_Global_Settings::get_instance();
9
+ $settings->delete('attach_to_post_url');
10
+ $settings->delete('gallery_preview_url');
11
+ $settings->delete('attach_to_post_display_tab_js_url');
12
+ }
13
+ }
products/photocrati_nextgen/modules/attach_to_post/class.attach_to_post_option_handler.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Attach_To_Post_Option_Handler
4
+ {
5
+ function get_router()
6
+ {
7
+ return C_Component_Registry::get_instance()->get_utility('I_Router');
8
+ }
9
+
10
+ function get($key, $default=NULL)
11
+ {
12
+ $retval = $default;
13
+
14
+ switch ($key) {
15
+ case 'attach_to_post_url':
16
+ $retval = $this->get_router()->get_url('/nextgen-attach_to_post', FALSE);
17
+ break;
18
+ case 'gallery_preview_url':
19
+ $retval = $this->get_router()->get_url('/nextgen-attach_to_post/preview', FALSE);
20
+ break;
21
+ case 'attach_to_post_display_tab_js_url':
22
+ $retval = $this->get_router()->get_url('/nextgen-attach_to_post/display_tab_js', FALSE);
23
+ break;
24
+ }
25
+
26
+ return $retval;
27
+ }
28
+ }
products/photocrati_nextgen/modules/attach_to_post/class.attach_to_post_proxy_controller.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Work in progress. This won't quite work as expected
5
+ * as we can't cache the Attach to post interface since
6
+ * it needs to be invalided when the displayed gallery changes
7
+ * Class C_Attach_To_Post_Proxy_Controller
8
+ */
9
+ class C_Attach_To_Post_Proxy_Controller
10
+ {
11
+ static $_instance = NULL;
12
+
13
+ static function get_instance()
14
+ {
15
+ if (is_null(self::$_instance)) {
16
+ $klass = get_class();
17
+ self::$_instance = new $klass();
18
+ }
19
+ return self::$_instance;
20
+ }
21
+
22
+ function index_action()
23
+ {
24
+ $url = C_Router::get_instance()->get_routed_app()->get_routed_url(TRUE);
25
+ $key = C_Photocrati_Cache::generate_key($url);
26
+
27
+ // Try fetching the contents from the cache
28
+ if (($html = C_Photocrati_Cache::get($key, FALSE))) {
29
+ echo $html;
30
+ }
31
+ else {
32
+ $controller = C_Attach_Controller::get_instance(FALSE);
33
+ $html = $controller->index_action(TRUE);
34
+ C_Photocrati_Cache::set($key, $html);
35
+ echo $html;
36
+ }
37
+
38
+ }
39
+
40
+ function display_tab_js_action()
41
+ {
42
+ $url = C_Router::get_instance()->get_routed_app()->get_routed_url(TRUE);
43
+ $key = C_Photocrati_Cache::generate_key($url);
44
+
45
+ // Try fetching the contents from the cache
46
+ if (($html = C_Photocrati_Cache::get($key, FALSE))) {
47
+ echo $html;
48
+ }
49
+ else {
50
+ $html = C_Attach_Controller::get_instance(FALSE)->display_tab_js_action(TRUE);
51
+ C_Photocrati_Cache::set($key, $html);
52
+ echo $html;
53
+ }
54
+ }
55
+
56
+ function preview_action()
57
+ {
58
+ return C_Attach_Controller::get_instance(FALSE)->preview_action();
59
+ }
60
+
61
+ private function __construct() {}
62
+ }
products/photocrati_nextgen/modules/attach_to_post/interface.attach_to_post_controller.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Attach_To_Post_Controller
4
+ {
5
+ function index_action();
6
+ }
products/photocrati_nextgen/modules/attach_to_post/mixin.attach_to_post_display_tab.php ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Provides the "Display Tab" for the Attach To Post interface/controller
5
+ */
6
+ class Mixin_Attach_To_Post_Display_Tab extends Mixin
7
+ {
8
+ /**
9
+ * Renders the JS required for the Backbone-based Display Tab
10
+ */
11
+ function display_tab_js_action($return=FALSE)
12
+ {
13
+ // Cache appropriately
14
+ $this->object->do_not_cache();
15
+
16
+ // Ensure that JS is returned
17
+ $this->object->set_content_type('javascript');
18
+
19
+ while (ob_get_level() > 0) {
20
+ ob_end_clean();
21
+ }
22
+
23
+ // Get all entities used by the display tab
24
+ $context = 'attach_to_post';
25
+ $gallery_mapper = $this->get_registry()->get_utility('I_Gallery_Mapper', $context);
26
+ $album_mapper = $this->get_registry()->get_utility('I_Album_Mapper', $context);
27
+ $display_type_mapper= $this->get_registry()->get_utility('I_Display_Type_Mapper', $context);
28
+ $source_mapper = $this->get_registry()->get_utility('I_Displayed_Gallery_Source_Mapper', $context);
29
+ $security = $this->get_registry()->get_utility('I_Security_Manager');
30
+
31
+ // Get the nextgen tags
32
+ global $wpdb;
33
+ $tags = $wpdb->get_results(
34
+ "SELECT DISTINCT name AS 'id', name FROM {$wpdb->terms}
35
+ WHERE term_id IN (
36
+ SELECT term_id FROM {$wpdb->term_taxonomy}
37
+ WHERE taxonomy = 'ngg_tag'
38
+ )");
39
+ $all_tags = new stdClass;
40
+ $all_tags->name = "All";
41
+ $all_tags->id = "All";
42
+ array_unshift($tags, $all_tags);
43
+
44
+ $display_types = $display_type_mapper->find_all();
45
+
46
+ usort($display_types, array($this->object, '_display_type_list_sort'));
47
+
48
+ $output = $this->object->render_view('photocrati-attach_to_post#display_tab_js', array(
49
+ 'displayed_gallery' => json_encode($this->object->_displayed_gallery->get_entity()),
50
+ 'sources' => json_encode($source_mapper->select()->order_by('title')->run_query()),
51
+ 'gallery_primary_key' => $gallery_mapper->get_primary_key_column(),
52
+ 'galleries' => json_encode($gallery_mapper->find_all()),
53
+ 'albums' => json_encode($album_mapper->find_all()),
54
+ 'tags' => json_encode($tags),
55
+ 'display_types' => json_encode($display_types),
56
+ 'sec_token' => $security->get_request_token('nextgen_edit_displayed_gallery')->get_json()
57
+ ), $return);
58
+
59
+ return $output;
60
+ }
61
+
62
+ function _display_type_list_sort($type_1, $type_2)
63
+ {
64
+ $order_1 = $type_1->view_order;
65
+ $order_2 = $type_2->view_order;
66
+
67
+ if ($order_1 == null) {
68
+ $order_1 = NEXTGEN_DISPLAY_PRIORITY_BASE;
69
+ }
70
+
71
+ if ($order_2 == null) {
72
+ $order_2 = NEXTGEN_DISPLAY_PRIORITY_BASE;
73
+ }
74
+
75
+ if ($order_1 > $order_2) {
76
+ return 1;
77
+ }
78
+
79
+ if ($order_1 < $order_2) {
80
+ return -1;
81
+ }
82
+
83
+ return 0;
84
+ }
85
+
86
+
87
+ /**
88
+ * Gets a list of tabs to render for the "Display" tab
89
+ */
90
+ function _get_display_tabs()
91
+ {
92
+ // The ATP requires more memmory than some applications, somewhere around 60MB.
93
+ // Because it's such an important feature of NextGEN Gallery, we temporarily disable
94
+ // any memory limits
95
+ @ini_set('memory_limit', -1);
96
+
97
+ return array(
98
+ $this->object->_render_display_types_tab(),
99
+ $this->object->_render_display_source_tab(),
100
+ $this->object->_render_display_settings_tab(),
101
+ $this->object->_render_preview_tab()
102
+ );
103
+ }
104
+
105
+
106
+ /**
107
+ * Renders the accordion tab, "What would you like to display?"
108
+ */
109
+ function _render_display_source_tab()
110
+ {
111
+ return $this->object->render_partial('photocrati-attach_to_post#accordion_tab', array(
112
+ 'id' => 'source_tab',
113
+ 'title' => _('What would you like to display?'),
114
+ 'content' => $this->object->_render_display_source_tab_contents()
115
+ ), TRUE);
116
+ }
117
+
118
+
119
+ /**
120
+ * Renders the contents of the source tab
121
+ * @return string
122
+ */
123
+ function _render_display_source_tab_contents()
124
+ {
125
+ return $this->object->render_partial('photocrati-attach_to_post#display_tab_source', array(),TRUE);
126
+ }
127
+
128
+
129
+ /**
130
+ * Renders the accordion tab for selecting a display type
131
+ * @return string
132
+ */
133
+ function _render_display_types_tab()
134
+ {
135
+ return $this->object->render_partial('photocrati-attach_to_post#accordion_tab', array(
136
+ 'id' => 'display_type_tab',
137
+ 'title' => _('Select a display type'),
138
+ 'content' => $this->object->_render_display_type_tab_contents()
139
+ ), TRUE);
140
+ }
141
+
142
+
143
+ /**
144
+ * Renders the contents of the display type tab
145
+ */
146
+ function _render_display_type_tab_contents()
147
+ {
148
+ return $this->object->render_partial('photocrati-attach_to_post#display_tab_type', array(), TRUE);
149
+ }
150
+
151
+
152
+ /**
153
+ * Renders the display settings tab for the Attach to Post interface
154
+ * @return type
155
+ */
156
+ function _render_display_settings_tab()
157
+ {
158
+ return $this->object->render_partial('photocrati-attach_to_post#accordion_tab', array(
159
+ 'id' => 'display_settings_tab',
160
+ 'title' => _('Customize the display settings'),
161
+ 'content' => $this->object->_render_display_settings_contents()
162
+ ), TRUE);
163
+ }
164
+
165
+ /**
166
+ * If editing an existing displayed gallery, retrieves the name
167
+ * of the display type
168
+ * @return string
169
+ */
170
+ function _get_selected_display_type_name()
171
+ {
172
+ $retval = '';
173
+
174
+ if ($this->object->_displayed_gallery)
175
+ $retval = $this->object->_displayed_gallery->display_type;
176
+
177
+ return $retval;
178
+ }
179
+
180
+
181
+ /**
182
+ * Is the displayed gallery that's being edited using the specified display
183
+ * type?
184
+ * @param string $name name of the display type
185
+ * @return bool
186
+ */
187
+ function is_displayed_gallery_using_display_type($name)
188
+ {
189
+ $retval = FALSE;
190
+
191
+ if ($this->object->_displayed_gallery) {
192
+ $retval = $this->object->_displayed_gallery->display_type == $name;
193
+ }
194
+
195
+ return $retval;
196
+ }
197
+
198
+
199
+ /**
200
+ * Renders the contents of the display settings tab
201
+ * @return string
202
+ */
203
+ function _render_display_settings_contents()
204
+ {
205
+ $retval = array();
206
+
207
+ // Get all display setting forms
208
+ $form_manager = C_Form_Manager::get_instance();
209
+ $forms = $form_manager->get_forms(
210
+ NEXTGEN_DISPLAY_SETTINGS_SLUG, TRUE
211
+ );
212
+
213
+ // Display each form
214
+ foreach ($forms as $form) {
215
+
216
+ // Enqueue the form's static resources
217
+ $form->enqueue_static_resources();
218
+
219
+ // Determine which classes to use for the form's "class" attribute
220
+ $model = $form->get_model();
221
+ $current = $this->object->is_displayed_gallery_using_display_type($model->name);
222
+ $css_class = $current ? 'display_settings_form' : 'display_settings_form hidden';
223
+
224
+ // If this form is used to provide the display settings for the current
225
+ // displayed gallery, then we need to override the forms settings
226
+ // with the displayed gallery settings
227
+ if ($current) {
228
+ $settings = $this->array_merge_assoc(
229
+ $model->settings,
230
+ $this->object->_displayed_gallery->display_settings,
231
+ TRUE
232
+ );
233
+
234
+ $model->settings = $settings;
235
+ }
236
+
237
+ // Output the display settings form
238
+ $retval[] = $this->object->render_partial('photocrati-attach_to_post#display_settings_form', array(
239
+ 'settings' => $form->render(),
240
+ 'display_type_name' => $model->name,
241
+ 'css_class' => $css_class
242
+ ), TRUE);
243
+ }
244
+
245
+ // In addition, we'll render a form that will be displayed when no
246
+ // display type has been selected in the Attach to Post interface
247
+ // Render the default "no display type selected" view
248
+ $css_class = $this->object->_get_selected_display_type_name() ?
249
+ 'display_settings_form hidden' : 'display_settings_form';
250
+ $retval[] = $this->object->render_partial('photocrati-attach_to_post#no_display_type_selected', array(
251
+ 'no_display_type_selected' => _('No display type selected'),
252
+ 'css_class' => $css_class
253
+
254
+ ), TRUE);
255
+
256
+ // Return all display setting forms
257
+ return implode("\n", $retval);
258
+ }
259
+
260
+
261
+ /**
262
+ * Renders the tab used to preview included images
263
+ * @return string
264
+ */
265
+ function _render_preview_tab()
266
+ {
267
+ return $this->object->render_partial('photocrati-attach_to_post#accordion_tab', array(
268
+ 'id' => 'preview_tab',
269
+ 'title' => _('Sort or Exclude Images'),
270
+ 'content' => $this->object->_render_preview_tab_contents()
271
+ ), TRUE);
272
+ }
273
+
274
+
275
+ /**
276
+ * Renders the contents of the "Preview" tab.
277
+ * @return string
278
+ */
279
+ function _render_preview_tab_contents()
280
+ {
281
+ return $this->object->render_partial('photocrati-attach_to_post#preview_tab', array(), TRUE);
282
+ }
283
+ }
products/photocrati_nextgen/modules/attach_to_post/module.attach_to_post.php ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ {
4
+ Module: photocrati-attach_to_post,
5
+ Depends: { photocrati-nextgen_gallery_display }
6
+ }
7
+ */
8
+
9
+ define('NEXTGEN_GALLERY_ATTACH_TO_POST_SLUG', 'ngg_attach_to_post');
10
+
11
+ class M_Attach_To_Post extends C_Base_Module
12
+ {
13
+ var $attach_to_post_tinymce_plugin = 'NextGEN_AttachToPost';
14
+ var $_event_publisher = NULL;
15
+
16
+ /**
17
+ * Defines the module
18
+ * @param string|bool $context
19
+ */
20
+ function define($context=FALSE)
21
+ {
22
+ parent::define(
23
+ 'photocrati-attach_to_post',
24
+ 'Attach To Post',
25
+ 'Provides the "Attach to Post" interface for displaying galleries and albums',
26
+ '0.6',
27
+ 'http://www.nextgen-gallery.com',
28
+ 'Photocrati Media',
29
+ 'http://www.photocrati.com',
30
+ $context
31
+ );
32
+
33
+ include_once('class.attach_to_post_option_handler.php');
34
+ C_NextGen_Global_Settings::add_option_handler('C_Attach_To_Post_Option_Handler', array(
35
+ 'attach_to_post_url',
36
+ 'gallery_preview_url',
37
+ 'attach_to_post_display_tab_js_url'
38
+ ));
39
+
40
+ include_once('class.attach_to_post_installer.php');
41
+ C_Photocrati_Installer::add_handler($this->module_id, 'C_Attach_To_Post_Installer');
42
+ }
43
+
44
+ /**
45
+ * Gets the Frame Event Publisher
46
+ * @return C_Component
47
+ */
48
+ function _get_frame_event_publisher()
49
+ {
50
+ if (is_null($this->_event_publisher)) {
51
+ $this->_event_publisher = $this->get_registry()->get_utility('I_Frame_Event_Publisher', 'attach_to_post');
52
+ }
53
+
54
+ return $this->_event_publisher;
55
+ }
56
+
57
+
58
+ /**
59
+ * Registers requires the utilites that this module provides
60
+ */
61
+ function _register_utilities()
62
+ {
63
+ // This utility provides a controller that renders the
64
+ // Attach to Post interface, used to manage Displayed Galleries
65
+ $this->get_registry()->add_utility(
66
+ 'I_Attach_To_Post_Controller',
67
+ 'C_Attach_Controller'
68
+ // 'C_Attach_To_Post_Proxy_Controller'
69
+ );
70
+ }
71
+
72
+ /**
73
+ * Registers the adapters that this module provides
74
+ */
75
+ function _register_adapters()
76
+ {
77
+ // Installs the Attach to Post module
78
+ $this->get_registry()->add_adapter(
79
+ 'I_Installer', 'A_Attach_To_Post_Installer'
80
+ );
81
+
82
+ // Provides routing for the Attach To Post interface
83
+ $this->get_registry()->add_adapter(
84
+ 'I_Router', 'A_Attach_To_Post_Routes'
85
+ );
86
+
87
+ // Provides AJAX actions for the Attach To Post interface
88
+ $this->get_registry()->add_adapter(
89
+ 'I_Ajax_Controller', 'A_Attach_To_Post_Ajax'
90
+ );
91
+
92
+ // Applies a post hook to the generate_thumbnail method of the
93
+ // gallery storage component
94
+ $this->get_registry()->add_adapter(
95
+ 'I_Gallery_Storage', 'A_Gallery_Storage_Frame_Event'
96
+ );
97
+ }
98
+
99
+
100
+ function _register_hooks()
101
+ {
102
+ if (is_admin()) {
103
+ add_action(
104
+ 'admin_enqueue_scripts',
105
+ array(&$this, 'enqueue_static_resources'),
106
+ 1
107
+ );
108
+ }
109
+
110
+ // Add hook to delete displayed galleries when removed from a post
111
+ add_action('pre_post_update', array(&$this, 'locate_stale_displayed_galleries'));
112
+ add_action('before_delete_post', array(&$this, 'locate_stale_displayed_galleries'));
113
+ add_action('post_updated', array(&$this, 'cleanup_displayed_galleries'));
114
+ add_action('after_delete_post', array(&$this, 'cleanup_displayed_galleries'));
115
+
116
+ // Add hook to subsitute displayed gallery placeholders
117
+ add_filter('the_content', array(&$this, 'substitute_placeholder_imgs'), PHP_INT_MAX, 1);
118
+
119
+ // Emit frame communication events
120
+ add_action('ngg_created_new_gallery', array(&$this, 'new_gallery_event'));
121
+ add_action('ngg_after_new_images_added',array(&$this, 'images_added_event'));
122
+ add_action('ngg_page_event', array(&$this, 'nextgen_page_event'));
123
+ add_action('ngg_manage_tags', array(&$this, 'manage_tags_event'));
124
+ }
125
+
126
+ /**
127
+ * Substitutes the gallery placeholder content with the gallery type frontend
128
+ * view, returns a list of static resources that need to be loaded
129
+ * @param string $content
130
+ */
131
+ function substitute_placeholder_imgs($content)
132
+ {
133
+ // Load html into parser
134
+ $doc = new simple_html_dom();
135
+ if ($content) {
136
+ $doc->load($content);
137
+
138
+ // Find all placeholder images
139
+ $imgs = $doc->find("img[class='ngg_displayed_gallery']");
140
+ if ($imgs) {
141
+
142
+ // Get some utilities
143
+ $mapper = $this->get_registry()->get_utility('I_Displayed_Gallery_Mapper');
144
+ $router = $this->get_registry()->get_utility('I_Router');
145
+
146
+ // To match ATP entries we compare the stored url against a generic path
147
+ // We must check HTTP and HTTPS as well as permalink and non-permalink forms
148
+ $preview_url = parse_url($router->join_paths(
149
+ $router->remove_url_segment('index.php', $router->get_base_url()),
150
+ '/nextgen-attach_to_post/preview'
151
+ ));
152
+ $preview_url = preg_quote($preview_url['host'] . $preview_url['path'], '#');
153
+
154
+ $alt_preview_url = parse_url($router->join_paths(
155
+ $router->remove_url_segment('index.php', $router->get_base_url()),
156
+ 'index.php/nextgen-attach_to_post/preview'
157
+ ));
158
+ $alt_preview_url = preg_quote($alt_preview_url['host'] . $alt_preview_url['path'], '#');
159
+
160
+ // Substitute each image for the gallery type frontent content
161
+ foreach ($imgs as $img) {
162
+
163
+ // The placeholder MUST have a gallery instance id
164
+ if (preg_match("#http(s)?://({$preview_url}|{$alt_preview_url})/id--(\d+)#", $img->src, $match)) {
165
+
166
+ // Find the displayed gallery
167
+ $displayed_gallery_id = $match[3];
168
+ $displayed_gallery = $mapper->find($displayed_gallery_id, TRUE);
169
+
170
+ // Get the content for the displayed gallery
171
+ $content = '<p>'._('Invalid Displayed Gallery').'</p>';
172
+ if ($displayed_gallery) {
173
+ $renderer = $this->get_registry()->get_utility('I_Displayed_Gallery_Renderer');
174
+ $content = $renderer->render($displayed_gallery, TRUE);
175
+ }
176
+
177
+ // Replace the placeholder with the displayed gallery content
178
+ $img->outertext = $content;
179
+ }
180
+ }
181
+ $content = (string)$doc->save();
182
+ }
183
+ return $content;
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Enqueues static resources required by the Attach to Post interface
189
+ */
190
+ function enqueue_static_resources()
191
+ {
192
+ $router = $this->get_registry()->get_utility('I_Router');
193
+
194
+ // Enqueue resources needed at post/page level
195
+ if (preg_match("/\/wp-admin\/(post|post-new)\.php$/", $_SERVER['SCRIPT_NAME'])) {
196
+ $this->_enqueue_tinymce_resources();
197
+
198
+ # wp_enqueue_style(
199
+ # 'ngg_custom_scrollbar', $this->get_static_url('jquery.mCustomScrollbar.css')
200
+ # );
201
+ # wp_enqueue_script(
202
+ # 'ngg_custom_scrollbar', $this->get_static_url('jquery.mCustomScrollbar.concat.min.js'), array('jquery')
203
+ # );
204
+ wp_enqueue_style(
205
+ 'ngg_attach_to_post_dialog', $router->get_static_url('photocrati-attach_to_post#attach_to_post_dialog.css')
206
+ );
207
+ }
208
+
209
+ elseif (isset($_REQUEST['attach_to_post']) OR
210
+ (isset($_REQUEST['page']) && strpos($_REQUEST['page'], 'nggallery') !== FALSE)) {
211
+ wp_enqueue_script('iframely', $router->get_static_url('photocrati-attach_to_post#iframely.js'));
212
+ wp_enqueue_style('iframely', $router->get_static_url('photocrati-attach_to_post#iframely.css'));
213
+ }
214
+ }
215
+
216
+
217
+ /**
218
+ * Enqueues resources needed by the TinyMCE editor
219
+ */
220
+ function _enqueue_tinymce_resources()
221
+ {
222
+ wp_localize_script(
223
+ 'media-editor',
224
+ 'nextgen_gallery_attach_to_post_url',
225
+ C_NextGen_Global_Settings::get_instance()->attach_to_post_url
226
+ );
227
+
228
+ // Registers our tinymce button and plugin for attaching galleries
229
+ $security = $this->get_registry()->get_utility('I_Security_Manager');
230
+ $sec_actor = $security->get_current_actor();
231
+ $checks = array(
232
+ $sec_actor->is_allowed('NextGEN Attach Interface'),
233
+ $sec_actor->is_allowed('NextGEN Use TinyMCE')
234
+ );
235
+ if (!in_array(FALSE, $checks)) {
236
+ if (get_user_option('rich_editing') == 'true') {
237
+ add_filter('mce_buttons', array(&$this, 'add_attach_to_post_button'));
238
+ add_filter('mce_external_plugins', array(&$this, 'add_attach_to_post_tinymce_plugin'));
239
+ }
240
+ }
241
+ }
242
+
243
+
244
+ /**
245
+ * Adds a TinyMCE button for the Attach To Post plugin
246
+ * @param array $buttons
247
+ * @returns array
248
+ */
249
+ function add_attach_to_post_button($buttons)
250
+ {
251
+ array_push(
252
+ $buttons,
253
+ 'separator',
254
+ $this->attach_to_post_tinymce_plugin
255
+ );
256
+ return $buttons;
257
+ }
258
+
259
+
260
+ /**
261
+ * Adds the Attach To Post TinyMCE plugin
262
+ * @param array $plugins
263
+ * @return array
264
+ * @uses mce_external_plugins filter
265
+ */
266
+ function add_attach_to_post_tinymce_plugin($plugins)
267
+ {
268
+ $router = $this->get_registry()->get_utility('I_Router');
269
+ $plugins[$this->attach_to_post_tinymce_plugin] = $router->get_static_url('photocrati-attach_to_post#ngg_attach_to_post_tinymce_plugin.js');
270
+ return $plugins;
271
+ }
272
+
273
+
274
+ /**
275
+ * Locates the ids of displayed galleries that have been
276
+ * removed from the post, and flags then for cleanup (deletion)
277
+ * @global array $displayed_galleries_to_cleanup
278
+ * @param int $post_id
279
+ */
280
+ function locate_stale_displayed_galleries($post_id)
281
+ {
282
+ global $displayed_galleries_to_cleanup;
283
+ $displayed_galleries_to_cleanup = array();
284
+ $post = get_post($post_id);
285
+ $gallery_preview_url = C_NextGen_Settings::get_instance()->get('gallery_preview_url');
286
+ $preview_url = preg_quote($gallery_preview_url, '#');
287
+ if (preg_match_all("#{$preview_url}/id--(\d+)#", html_entity_decode($post->post_content), $matches, PREG_SET_ORDER)) {
288
+ foreach ($matches as $match) {
289
+ $preview_url = preg_quote($match[0], '/');
290
+ // The post was edited, and the displayed gallery placeholder was removed
291
+ if (isset($_REQUEST['post_content']) && (!preg_match("/{$preview_url}/", $_POST['post_content']))) {
292
+ $displayed_galleries_to_cleanup[] = intval($match[1]);
293
+ }
294
+ // The post was deleted
295
+ elseif (!isset($_REQUEST['action'])) {
296
+ $displayed_galleries_to_cleanup[] = intval($match[1]);
297
+ }
298
+ }
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Deletes any displayed galleries that are no longer associated with
304
+ * a post/page
305
+ * @global array $displayed_galleries_to_cleanup
306
+ * @param int $post_id
307
+ */
308
+ function cleanup_displayed_galleries($post_id)
309
+ {
310
+ global $displayed_galleries_to_cleanup;
311
+ $mapper = $this->get_registry()->get_utility('I_Displayed_Gallery_Mapper');
312
+ foreach ($displayed_galleries_to_cleanup as $id) $mapper->destroy($id);
313
+ }
314
+
315
+
316
+ /**
317
+ * Notify frames that a new gallery has been created
318
+ * @param int $gallery_id
319
+ */
320
+ function new_gallery_event($gallery_id)
321
+ {
322
+ $gallery = $this->get_registry()->get_utility('I_Gallery_Mapper')->find($gallery_id);
323
+
324
+ $this->_get_frame_event_publisher()->add_event(array(
325
+ 'event' => 'new_gallery',
326
+ 'gallery_id'=> intval($gallery_id),
327
+ 'gallery_title' => $gallery->title
328
+ ));
329
+ }
330
+
331
+ /**
332
+ * Notifies a frame that images have been added to a gallery
333
+ * @param int $gallery_id
334
+ * @param array $image_ids
335
+ */
336
+ function images_added_event($gallery_id, $image_ids=array())
337
+ {
338
+ $this->_get_frame_event_publisher()->add_event(array(
339
+ 'event' => 'images_added',
340
+ 'gallery_id' => intval($gallery_id)
341
+ ));
342
+ }
343
+
344
+ /**
345
+ * Notifies a frame that the tags have changed
346
+ *
347
+ * @param array $tags
348
+ */
349
+ function manage_tags_event($tags = array())
350
+ {
351
+ $this->_get_frame_event_publisher()->add_event(array(
352
+ 'event' => 'manage_tags',
353
+ 'tags' => $tags
354
+ ));
355
+ }
356
+
357
+ /**
358
+ * Notifies a frame that an action has been performed on a particular
359
+ * NextGEN page
360
+ * @param array $event
361
+ */
362
+ function nextgen_page_event($event)
363
+ {
364
+ $this->_get_frame_event_publisher()->add_event($event);
365
+ }
366
+
367
+ function get_type_list()
368
+ {
369
+ return array(
370
+ 'A_Attach_To_Post_Ajax' => 'adapter.attach_to_post_ajax.php',
371
+ 'C_Attach_To_Post_Installer' => 'class.attach_to_post_installer.php',
372
+ 'A_Attach_To_Post_Routes' => 'adapter.attach_to_post_routes.php',
373
+ 'A_Gallery_Storage_Frame_Event' => 'adapter.gallery_storage_frame_event.php',
374
+ 'C_Attach_Controller' => 'class.attach_controller.php',
375
+ 'C_Attach_To_Post_Proxy_Controller' => 'class.attach_to_post_proxy_controller.php',
376
+ 'I_Attach_To_Post_Controller' => 'interface.attach_to_post_controller.php',
377
+ 'Mixin_Attach_To_Post_Display_Tab' => 'mixin.attach_to_post_display_tab.php'
378
+ );
379
+ }
380
+ }
381
+
382
+ new M_Attach_To_Post();
products/photocrati_nextgen/modules/attach_to_post/static/attach_to_post.css ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html,body {
2
+ width: 100%;
3
+ min-height: 100%;
4
+ padding: 0px;
5
+ margin: 0px;
6
+ font-size: 13px;
7
+ }
8
+
9
+ body {
10
+ position: absolute;
11
+ visibility: hidden;
12
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
13
+ filter: alpha(opacity=0);
14
+ opacity: 0.0;
15
+ }
16
+
17
+ .entity_errors {
18
+ color: red;
19
+ }
20
+
21
+ .entity_errors ul {
22
+ margin-left: 30px;
23
+ }
24
+ .entity_errors ul li{
25
+ list-style-type: disc;
26
+ }
27
+
28
+ .ui-helper-reset {
29
+ font-size: 13px;
30
+ }
31
+
32
+ #attach_to_post_tabs {
33
+ border: 0px;
34
+ background: none;
35
+ min-height: 100%;
36
+ }
37
+
38
+ .ui-tabs-panel {
39
+ min-height: 100%;
40
+ }
41
+
42
+ .ui-widget-header {
43
+ border: 0px;
44
+ border-bottom: 1px solid #dfdfdf;
45
+ background: none;
46
+ }
47
+
48
+ iframe {
49
+ width: 100%;
50
+ min-height: 100%;
51
+ border: none;
52
+ padding: 0px;
53
+ margin: 0px;
54
+ background: transparent;
55
+ }
56
+
57
+ #displayed_gallery_source {
58
+ width: 400px;
59
+ }
60
+
61
+ /** Would would you like to display tab? **/
62
+ #source_configuration td {
63
+ vertical-align: top;
64
+ }
65
+
66
+ #source_configuration .chzn-choices input[type=text] {
67
+ height: auto !important;
68
+ }
69
+
70
+ #slug_configuration #slug_label {
71
+ width: 52px;
72
+ }
73
+
74
+ #slug_configuration #slug_column input[type=text] {
75
+ width: 498px;
76
+ }
77
+
78
+ /** Select a display type tab **/
79
+ .display_type_preview {
80
+ float: left;
81
+ width: 25%;
82
+ }
83
+ .display_type_preview .image_container {
84
+ width: 100%;
85
+ vertical-align: middle;
86
+ text-align: center;
87
+ font-size: 12px;
88
+ font-weight: 600;
89
+ }
90
+ .display_type_preview .image_container p {
91
+ display: inline-block;
92
+ }
93
+
94
+ /** Display Tab **/
95
+ #preview_tab_content .previewed_entity {
96
+ width: 100%;
97
+ border-bottom: solid 1px #E0E0D6;
98
+ background-color: #FAFAF0;
99
+ }
100
+
101
+ #preview_tab_content .previewed_entity .container {
102
+ padding-top: 15px;
103
+ }
104
+
105
+ #preview_tab_content .previewed_entity.header {
106
+ background-color: #F0F0E6;
107
+ padding-bottom: 5px;
108
+ padding-top: 5px;
109
+ }
110
+
111
+ #preview_tab_content .header label {
112
+ font-size: 12px;
113
+ color: rgb(100,150,100);
114
+ font-weight: 600;
115
+ }
116
+
117
+ #preview_tab_content .ui-sortable-helper {
118
+ background: none;
119
+ }
120
+
121
+ #preview_tab_content ul {
122
+ list-style-type: none;
123
+ display: block;
124
+ border: solid 2px #E0E0D6;
125
+ padding: 0px;
126
+ position: relative;
127
+ }
128
+
129
+
130
+ #preview_tab_content .inclusion_checkbox {
131
+ margin-right: 7px;
132
+ display: block;
133
+ float: left;
134
+ }
135
+
136
+ #preview_tab_content .image_container {
137
+ background-color: white;
138
+ background-repeat: no-repeat;
139
+ background-position: center center;
140
+ padding: 19px;
141
+ margin: 7px;
142
+ border: solid 1px black;
143
+ display: block;
144
+ vertical-align: middle;
145
+ text-align: center;
146
+ position: relative;
147
+ }
148
+
149
+ #preview_tab_content .image_container img {
150
+ border: 0px;
151
+ }
152
+
153
+ #preview_tab_content #entity_list li{
154
+ float: left;
155
+ }
156
+
157
+ #preview_tab_content #entity_list .ui-state-default {
158
+ background: none;
159
+ border: none;
160
+ }
161
+
162
+ #preview_tab_content .placeholder{
163
+ background-color: #e0ddc1;
164
+ position: relative;
165
+ }
166
+
167
+ #preview_tab_content #entity_list .exclude_container {
168
+ display: block;
169
+ text-align: center;
170
+ margin: 0 auto;
171
+ color: black;
172
+ font-weight: normal;
173
+ position: absolute;
174
+ bottom: 2px;
175
+ left: 0px;
176
+ width: 100%;
177
+ }
178
+
179
+ #preview_tab_content .header_row {
180
+ margin-bottom: 5px;
181
+ }
182
+ #preview_tab_content .header_row strong {
183
+ width: 70px;
184
+ display: inline-block;
185
+ }
186
+ #preview_tab_content .header_row .separator {
187
+ display: inline-block;
188
+ margin: 0px 5px;
189
+ }
190
+
191
+ #preview_tab_content .header_row .selected {
192
+ font-weight: bold;
193
+ }
194
+
195
+ #preview_tab_content #entity_list li.clear {
196
+ float: none;
197
+ clear: both;
198
+ }
199
+
200
+ .clear {
201
+ clear: both;
202
+ float: none;
203
+ }
204
+
205
+ table {
206
+ font-size: 13px;
207
+ }
208
+
209
+ #display_settings_form table tr td:first-child {
210
+ vertical-align: top;
211
+ text-align: right;
212
+ padding-right: 7px;
213
+ width: 180px;
214
+ }
215
+
216
+ #display_settings_form table td {
217
+ text-align: left;
218
+ }
219
+
220
+ #display_settings_form table textarea {
221
+ height: 60px;
222
+ }
223
+
224
+ #display_settings_form textarea,
225
+ #display_settings_form input[type=text],
226
+ #display_settings_form input[type=number],
227
+ #display_settings_form select {
228
+ width: 157px;
229
+ }
230
+
231
+ #display_settings_form .ngg_slideshow_gallery_width,
232
+ #display_settings_form .ngg_slideshow_gallery_height,
233
+ #display_settings_form .ngg_thumbnail_dimension_width,
234
+ #display_settings_form .ngg_thumbnail_dimension_height {
235
+ width: 65px !important;
236
+ }
237
+
238
+ #display_settings_form .nextgen_settings_colorpicker {
239
+ width: 85px !important;
240
+ text-align: center;
241
+ }
242
+
243
+ /**
244
+ * Hacks used to ensure that Firefox can calculate the height of hidden content
245
+ * in iframes
246
+ **/
247
+ .ui-tabs {
248
+ visibility: visible;
249
+ position: relative;
250
+ }
251
+ .ui-tabs
252
+ .ui-tabs-hide {
253
+ display: block !important;
254
+ visibility: hidden;
255
+ position: absolute;
256
+ top: -5000px;
257
+ }
258
+ .ui-tabs .main_menu_tab {
259
+ overflow: visible;
260
+ }
261
+ /**
262
+ * Make the active tab still clickable
263
+ **/
264
+ .ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a {
265
+ cursor: pointer;
266
+ }
267
+
268
+ .select2-result-label {
269
+ white-space: nowrap;
270
+ }
271
+ .select2-results {
272
+ font-family: 'segoe ui', Arial, sans-serif;
273
+ font-size: 13px;
274
+ }
275
+
276
+ /** Refresh button in the preview area **/
277
+ .refresh_button {
278
+ float: right;
279
+ }
products/photocrati_nextgen/modules/attach_to_post/static/attach_to_post.js ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Provides a function to close the TinyMCE popup window
2
+ function close_attach_to_post_window()
3
+ {
4
+ parent.tinyMCE.activeEditor.windowManager.close(window);
5
+ }
6
+
7
+ // Adjusts the height of a frame on the page, and then executes
8
+ // the specified callback
9
+ function adjust_height_for_frame(frame, callback)
10
+ {
11
+ // Adjust height of the frame
12
+ var $frame = jQuery(frame);
13
+ var new_height = $frame.contents().find('#wpbody').height();
14
+ var parent_height = jQuery(parent.document).height();
15
+ var current_height = $frame.height();
16
+
17
+ // If the height is less than the parent window height, then use
18
+ // the parent window height instead
19
+ if (new_height < parent_height) new_height = parent_height;
20
+
21
+ // If the height has changed, then use the new height
22
+ if (current_height != new_height) {
23
+ var frame_id = $frame.attr('id');
24
+
25
+ $frame.height(new_height);
26
+
27
+ if (frame_id && frame_id.indexOf('ngg-iframe-') == 0) {
28
+ var tab_id = frame_id.substr(11);
29
+
30
+ if (tab_id) {
31
+ jQuery('#' + tab_id).height(new_height);
32
+ }
33
+ }
34
+ }
35
+
36
+ if (callback != undefined)
37
+ return callback.call(frame, new_height);
38
+ else
39
+ return true;
40
+ }
41
+
42
+ function ngg_get_measures_for_frame(frame)
43
+ {
44
+ var $frame = jQuery(frame);
45
+ var frame_id = $frame.attr('id');
46
+ var measures = {};
47
+
48
+ if (frame_id && frame_id.indexOf('ngg-iframe-') == 0) {
49
+ var tab_id = frame_id.substr(11);
50
+
51
+ if (tab_id) {
52
+ var jDoc = jQuery(document);
53
+
54
+ measures.scrollTop = jDoc.scrollTop() - 40; // remove around 40 for tabs and padding
55
+
56
+ if (window.parent) {
57
+ var jparDoc = jQuery(window.parent.document);
58
+
59
+ measures.scrollHeight = jparDoc.find('.ngg_attach_to_post_window').height() - 40; // remove around 40 for tabs and padding
60
+ }
61
+ else {
62
+ measures.scrollHeight = jDoc.height();
63
+ }
64
+
65
+ if (typeof(window.console) != 'undefined') {
66
+ console.log(measures);
67
+ }
68
+ }
69
+ }
70
+
71
+ return measures;
72
+ }
73
+
74
+ // Activates the attach to post screen elements
75
+ jQuery(function($){
76
+ // Activate horizontal tabs
77
+ $('#attach_to_post_tabs').ngg_tabs();
78
+
79
+ // If the preview area is being displayed, emit an event for that
80
+ $('.accordion h3').bind('click', function(e){
81
+ if ($(this).attr('id') == 'preview_tab') {
82
+ $('#preview_area').trigger('opened');
83
+ }
84
+ });
85
+
86
+ // Activate accordion for display tab
87
+ $('.accordion').accordion({
88
+ clearStyle: true,
89
+ autoHeight: false,
90
+ heightStyle: 'content'
91
+ });
92
+
93
+ // If the active display tab is clicked, then we assume that the user
94
+ // wants to display the original tab content
95
+ $('.ui-tabs-nav a').click(function(e){
96
+
97
+ var element = e.target ? e.target : e.srcElement;
98
+
99
+ // If the accordion tab is used to display an iframe, ensure when
100
+ // clicked that the original iframe content is always displayed
101
+ if ($(element).parent().hasClass('ui-state-active')) {
102
+ var iframe = $(element.hash+' iframe');
103
+ if (iframe.length > 0) {
104
+ if (iframe[0].contentDocument.location != iframe.attr('src')) {
105
+ iframe[0].contentDocument.location = iframe.attr('src');
106
+ }
107
+ }
108
+ }
109
+ });
110
+
111
+ // Close the window when the escape key is pressed
112
+ $(this).keydown(function(e){
113
+ if (e.keyCode == 27) close_attach_to_post_window();
114
+ return;
115
+ });
116
+
117
+ // Fade in now that all GUI elements are intact
118
+ $('body').css({
119
+ position: 'static',
120
+ visibility: 'visible'
121
+ }).animate({
122
+ opacity: 1.0
123
+ });
124
+ });
products/photocrati_nextgen/modules/attach_to_post/static/attach_to_post_dialog.css ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ .ngg_attach_to_post_window {
3
+ position: relative;
4
+ border: none !important;
5
+ }
6
+
7
+ .ngg_attach_to_post_window .mceResize,
8
+ .ngg_attach_to_post_window .mceTop,
9
+ .ngg_attach_to_post_window .mceBottom,
10
+ .ngg_attach_to_post_window .mceLeft,
11
+ .ngg_attach_to_post_window .mceRight,
12
+ .ngg_attach_to_post_window .mceCenter {
13
+ background: transparent !important;
14
+ border: none !important;
15
+ }
16
+
17
+ .ngg_attach_to_post_window .mceMiddle span {
18
+ padding-top: 6px !important;
19
+ }
20
+
21
+ .ngg_attach_to_post_window .mceTop {
22
+ display: block !important;
23
+ height: 0px !important;
24
+ font-size: 0px !important;
25
+ }
26
+
27
+ .ngg_attach_to_post_window .mceClose {
28
+ background: url('uploader-icons.png') !important;
29
+ display: block !important;
30
+ margin: 0 !important;
31
+ padding: 0 !important;
32
+ width: 15px !important;
33
+ height: 15px !important;
34
+ background-position: -100px 0 !important;
35
+ position: absolute !important;
36
+ top: 44px !important;
37
+ right: 30px !important;
38
+ }
39
+
products/photocrati_nextgen/modules/attach_to_post/static/iframely.css ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #iframely, #iframely body{
2
+ padding: 0px;
3
+ width: 100%;
4
+ height: 100%;
5
+ }
6
+
7
+ #iframely {
8
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
9
+ filter: alpha(opacity=0);
10
+ opacity: 0.0;
11
+ background-position: center center;
12
+ background-repeat: no-repeat;
13
+ position: absolute;
14
+ visibility: hidden;
15
+ }
16
+
17
+ #iframely #wpbody-content {
18
+ float: none;
19
+ padding: 0px;
20
+ }
21
+
22
+ #iframely h2,
23
+ #iframely #icon-nextgen-gallery {
24
+ display: none;
25
+ }
products/photocrati_nextgen/modules/attach_to_post/static/iframely.js ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ if (window.frameElement) {
2
+ document.getElementsByTagName('html')[0].id = 'iframely';
3
+ jQuery(function($){
4
+ // Concentrate only on the content of the page
5
+ $('#wpwrap').html($('#wpbody').html($('#wpbody-content').html($('#ngg_page_content'))));
6
+
7
+ // We need to ensure that any POST operation includes the "attach_to_post"
8
+ // parameter, to display subsequent clicks in iframely.
9
+ $('form').each(function(){
10
+ $(this).append("<input type='hidden' name='attach_to_post' value='1'/>");
11
+ });
12
+
13
+ var parent = window.parent;
14
+
15
+ if (parent == null || typeof(parent.adjust_height_for_frame) == "undefined") {
16
+ if (window != null && typeof(window.adjust_height_for_frame) != "undefined") {
17
+ parent = window;
18
+ }
19
+ }
20
+
21
+ if (typeof(parent.adjust_height_for_frame) != "undefined") {
22
+ // Adjust the height of the frame
23
+ parent.adjust_height_for_frame(window.frameElement, function(){
24
+ $('#iframely').css({
25
+ position: 'static',
26
+ visibility: 'visible'
27
+ }).animate({
28
+ opacity: 1.0
29
+ });
30
+ });
31
+ }
32
+ });
33
+ }
products/photocrati_nextgen/modules/attach_to_post/static/invalid_image.png ADDED
Binary file
{admin/tinymce → products/photocrati_nextgen/modules/attach_to_post/static}/nextgen.gif RENAMED
File without changes
products/photocrati_nextgen/modules/attach_to_post/static/ngg_attach_to_post_tinymce_plugin.js ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Self-executing function to create and register the TinyMCE plugin
2
+ (function(siteurl) {
3
+
4
+ // Create the plugin. We'll register it afterwards
5
+ tinymce.create('tinymce.plugins.NextGEN_AttachToPost', {
6
+
7
+ /**
8
+ * The WordPress Site URL
9
+ **/
10
+ siteurl: siteurl,
11
+
12
+ /**
13
+ * Returns metadata about this plugin
14
+ */
15
+ getInfo: function() {
16
+ return {
17
+ longname: 'NextGen - Attach Gallery',
18
+ author: 'Photocrati Media',
19
+ authorurl: 'http://www.photocrati.com',
20
+ infourl: 'http://www.nextgen-gallery.com',
21
+ version: '0.1'
22
+ };
23
+ },
24
+
25
+
26
+ /**
27
+ * Initializes the plugin, this will be executed after the plugin has been created.
28
+ */
29
+ init: function(editor, plugin_url) {
30
+
31
+ // Register a new TinyMCE command
32
+ editor.addCommand('ngg_attach_to_post', this.render_attach_to_post_interface, {
33
+ editor: editor,
34
+ plugin: editor.plugins.NextGEN_AttachToPost
35
+ });
36
+
37
+ // Add a button to trigger the above command
38
+ editor.addButton('NextGEN_AttachToPost', {
39
+ title: 'NextGEN Gallery - Attach To Post',
40
+ cmd: 'ngg_attach_to_post',
41
+ image: plugin_url+'/nextgen.gif'
42
+ });
43
+
44
+ // When the shortcode is clicked, open the attach to post interface
45
+ editor.settings.extended_valid_elements += ",shortcode";
46
+ editor.settings.custom_elements = "shortcode";
47
+ var self = this;
48
+ var drag_in_progress = false;
49
+ var click_timer;
50
+
51
+ editor.onMouseDown.addToTop(function(editor, e) {
52
+ if (e.target.tagName == 'IMG') {
53
+ if (self.get_class_name(e.target).indexOf('ngg_displayed_gallery') >= 0) {
54
+ click_timer = setTimeout(function() {
55
+ drag_in_progress = true;
56
+ }, 250);
57
+ }
58
+ }
59
+ });
60
+
61
+ editor.onMouseUp.addToTop(function(editor, e) {
62
+ if (!drag_in_progress && e.target.tagName == 'IMG') {
63
+ if (self.get_class_name(e.target).indexOf('ngg_displayed_gallery') >= 0) {
64
+ editor.dom.events.cancel(e);
65
+ editor.dom.events.stop(e);
66
+ var id = e.target.src.match(/\d+$/);
67
+ if (id) id = id.pop();
68
+ var obj = tinymce.extend(self, {
69
+ editor: editor,
70
+ plugin: editor.plugins.NextGEN_AttachToPost,
71
+ id: id
72
+ });
73
+ self.render_attach_to_post_interface.call(obj);
74
+ }
75
+ }
76
+ clearTimeout(click_timer);
77
+ drag_in_progress = false;
78
+ });
79
+ },
80
+
81
+ get_class_name: function(node) {
82
+ var class_name = node.getAttribute('class') ?
83
+ node.getAttribute('class') : node.className;
84
+
85
+ if (class_name) return class_name;
86
+ else return "";
87
+ },
88
+
89
+
90
+ /**
91
+ * Renders the attach to post interface
92
+ */
93
+ render_attach_to_post_interface: function(id) {
94
+
95
+ // Determine the attach to post url
96
+ var attach_to_post_url = nextgen_gallery_attach_to_post_url;
97
+ if (typeof(this.id) != 'undefined') {
98
+ attach_to_post_url += "?id="+this.id;
99
+ }
100
+
101
+ // We're going to open a dialog window. TinyMCE doesn't
102
+ // get the positioning exactly right, so we add an event
103
+ // handler to make adjustments
104
+ //
105
+ // We also make the parent window unscrollable, to avoid
106
+ // multiple scrollbars
107
+ this.editor.windowManager.onOpen.add(function(win){
108
+
109
+ // Assign the window the "ngg_attach_to_post_window" so that
110
+ // we can style it
111
+ var window_selector = '#';
112
+ if (win.params && win.params.mce_window_id)
113
+ window_selector += win.params.mce_window_id;
114
+ else if (win.features && win.features.id)
115
+ window_selector += win.features.id;
116
+
117
+ var callback = function(selector, callback){
118
+ var obj = jQuery(selector);
119
+ if (obj.length == 0) {
120
+ setTimeout(function(){
121
+ callback.call(null, selector, callback);
122
+ }, 5);
123
+ }
124
+ else {
125
+ obj.addClass('ngg_attach_to_post_window');
126
+ }
127
+ }
128
+ setTimeout(function(){
129
+ callback.call(null, window_selector, callback);
130
+ },5);
131
+
132
+ jQuery('html,body').css('overflow', 'hidden');
133
+ });
134
+
135
+ // Restore scrolling for the main content window
136
+ // when the attach to post interface is closed
137
+ this.editor.windowManager.onClose.add(function(win){
138
+ jQuery('html,body').css('overflow', 'auto');
139
+ tinyMCE.activeEditor.selection.select(tinyMCE.activeEditor.dom.select('p')[0]);
140
+ tinyMCE.activeEditor.selection.collapse(0);
141
+ });
142
+
143
+ var popupDialog = jQuery('<div style="display:none;"><div id="ngg_attach_to_post_dialog" tabindex="-1" action=""></div></div>');
144
+ popupDialog.appendTo(jQuery(document.body));
145
+
146
+ var win = window;
147
+
148
+ while (win.parent != null && win.parent != win) {
149
+ win = win.parent;
150
+ }
151
+
152
+ win = jQuery(win);
153
+ var winWidth = win.width();
154
+ var winHeight = win.height();
155
+ var popupWidth = 1200;
156
+ var popupHeight = 600;
157
+ var minWidth = 800;
158
+ var minHeight = 600;
159
+ var maxWidth = winWidth - (winWidth * 0.05);
160
+ var maxHeight = winHeight - (winHeight * 0.05);
161
+
162
+ if (maxWidth < minWidth) {
163
+ maxWidth = winWidth - 10;
164
+ }
165
+
166
+ if (maxHeight < minHeight) {
167
+ maxHeight = winHeight - 10;
168
+ }
169
+
170
+ if (popupWidth > maxWidth) {
171
+ popupWidth = maxWidth;
172
+ }
173
+
174
+ if (popupHeight > maxHeight) {
175
+ popupHeight = maxHeight;
176
+ }
177
+
178
+ // Open a window, occupying 90% of the screen real estate
179
+ var popup = this.editor.windowManager.open({
180
+ file: attach_to_post_url,
181
+ // wpDialog: true,
182
+ id: 'ngg_attach_to_post_dialog',
183
+ width: popupWidth,
184
+ height: popupHeight,
185
+ inline: true,
186
+ title: "NextGEN Gallery - Attach To Post"
187
+ });
188
+ // popupDialog.wpdialog({
189
+ // title: "NextGEN Gallery - Attach To Post",
190
+ // width: 1200,
191
+ // height: 600,
192
+ // modal: true,
193
+ // dialogClass: 'wp-dialog',
194
+ // zIndex: 300000
195
+ // });
196
+
197
+ // Ensure that the window cannot be scrolled - XXX actually allow scrolling in the main window and disable it for the inner-windows/frames/elements as to create a single scrollbar
198
+ jQuery('#'+popup.id+'_ifr').css('overflow-y', 'auto');
199
+ jQuery('#'+popup.id+'_ifr').css('overflow-x', 'hidden');
200
+ //jQuery('#'+popup.id+'_ifr').mCustomScrollbar();
201
+ //jQuery('#'+popup.id).addClass('wp-dialog');
202
+ }
203
+ });
204
+
205
+ // Register plugin
206
+ tinymce.PluginManager.add('NextGEN_AttachToPost', tinymce.plugins.NextGEN_AttachToPost);
207
+ })(photocrati_ajax.wp_site_url);
products/photocrati_nextgen/modules/attach_to_post/static/ngg_tabs.js ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(function($){
2
+
3
+ // Creates a Firefox-friendly wrapper around jQuery Tabs
4
+ $.fn.ngg_tabs = function(options){
5
+
6
+ // Create jQuery tabs
7
+ this.tabs(options);
8
+
9
+ // Change from display:none to visbibility:hidden
10
+ var i = 0;
11
+ this.find('.main_menu_tab').each(function(){
12
+ if (i == 0) $.fn.ngg_tabs.show_tab(this);
13
+ else $.fn.ngg_tabs.hide_tab(this);
14
+ i++;
15
+ });
16
+
17
+ // When the selected tab changes, then we need to re-adjust
18
+ this.bind('tabsactivate', function(event, ui){
19
+
20
+ // Ensure that all tabs are still displayed, but hidden ;)
21
+ $.fn.ngg_tabs.hide_tab($.fn.ngg_tabs.get_tab_by_li(ui.oldTab));
22
+ $.fn.ngg_tabs.show_tab($.fn.ngg_tabs.get_tab_by_li(ui.newTab));
23
+ });
24
+ };
25
+
26
+ $.fn.ngg_tabs.hide_tab = function(tab){
27
+ tab = $(tab);
28
+ setTimeout(function(){
29
+ tab.css({
30
+ display: 'block',
31
+ position: 'absolute',
32
+ top: -1000,
33
+ visibility: 'hidden',
34
+ height: 0
35
+ });
36
+ }, 0);
37
+ };
38
+
39
+ $.fn.ngg_tabs.show_tab = function(tab){
40
+ tab = $(tab);
41
+ setTimeout(function(){
42
+ tab.css({
43
+ display: 'block',
44
+ position: 'static',
45
+ top: 0,
46
+ visibility: 'visible',
47
+ height: '100%'
48
+ });
49
+ }, 0);
50
+ };
51
+
52
+ $.fn.ngg_tabs.get_tab_by_li = function(list_item){
53
+ var active_id = list_item.attr('aria-labelledby');
54
+ var active_tab = list_item.parents('div').find('.main_menu_tab[aria-labelledby="'+active_id+'"]');
55
+ return active_tab;
56
+ }
57
+ });
products/photocrati_nextgen/modules/attach_to_post/static/spinner.gif ADDED
Binary file
products/photocrati_nextgen/modules/attach_to_post/static/underscore.string.js ADDED
@@ -0,0 +1,600 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Underscore.string
2
+ // (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
3
+ // Underscore.string is freely distributable under the terms of the MIT license.
4
+ // Documentation: https://github.com/epeli/underscore.string
5
+ // Some code is borrowed from MooTools and Alexandru Marasteanu.
6
+ // Version '2.3.0'
7
+
8
+ !function(root, String){
9
+ 'use strict';
10
+
11
+ // Defining helper functions.
12
+
13
+ var nativeTrim = String.prototype.trim;
14
+ var nativeTrimRight = String.prototype.trimRight;
15
+ var nativeTrimLeft = String.prototype.trimLeft;
16
+
17
+ var parseNumber = function(source) { return source * 1 || 0; };
18
+
19
+ var strRepeat = function(str, qty){
20
+ if (qty < 1) return '';
21
+ var result = '';
22
+ while (qty > 0) {
23
+ if (qty & 1) result += str;
24
+ qty >>= 1, str += str;
25
+ }
26
+ return result;
27
+ };
28
+
29
+ var slice = [].slice;
30
+
31
+ var defaultToWhiteSpace = function(characters) {
32
+ if (characters == null)
33
+ return '\\s';
34
+ else if (characters.source)
35
+ return characters.source;
36
+ else
37
+ return '[' + _s.escapeRegExp(characters) + ']';
38
+ };
39
+
40
+ var escapeChars = {
41
+ lt: '<',
42
+ gt: '>',
43
+ quot: '"',
44
+ apos: "'",
45
+ amp: '&'
46
+ };
47
+
48
+ var reversedEscapeChars = {};
49
+ for(var key in escapeChars){ reversedEscapeChars[escapeChars[key]] = key; }
50
+
51
+ // sprintf() for JavaScript 0.7-beta1
52
+ // http://www.diveintojavascript.com/projects/javascript-sprintf
53
+ //
54
+ // Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
55
+ // All rights reserved.
56
+
57
+ var sprintf = (function() {
58
+ function get_type(variable) {
59
+ return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
60
+ }
61
+
62
+ var str_repeat = strRepeat;
63
+
64
+ var str_format = function() {
65
+ if (!str_format.cache.hasOwnProperty(arguments[0])) {
66
+ str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
67
+ }
68
+ return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
69
+ };
70
+
71
+ str_format.format = function(parse_tree, argv) {
72
+ var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
73
+ for (i = 0; i < tree_length; i++) {
74
+ node_type = get_type(parse_tree[i]);
75
+ if (node_type === 'string') {
76
+ output.push(parse_tree[i]);
77
+ }
78
+ else if (node_type === 'array') {
79
+ match = parse_tree[i]; // convenience purposes only
80
+ if (match[2]) { // keyword argument
81
+ arg = argv[cursor];
82
+ for (k = 0; k < match[2].length; k++) {
83
+ if (!arg.hasOwnProperty(match[2][k])) {
84
+ throw new Error(sprintf('[_.sprintf] property "%s" does not exist', match[2][k]));
85
+ }
86
+ arg = arg[match[2][k]];
87
+ }
88
+ } else if (match[1]) { // positional argument (explicit)
89
+ arg = argv[match[1]];
90
+ }
91
+ else { // positional argument (implicit)
92
+ arg = argv[cursor++];
93
+ }
94
+
95
+ if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
96
+ throw new Error(sprintf('[_.sprintf] expecting number but found %s', get_type(arg)));
97
+ }
98
+ switch (match[8]) {
99
+ case 'b': arg = arg.toString(2); break;
100
+ case 'c': arg = String.fromCharCode(arg); break;
101
+ case 'd': arg = parseInt(arg, 10); break;
102
+ case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
103
+ case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
104
+ case 'o': arg = arg.toString(8); break;
105
+ case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
106
+ case 'u': arg = Math.abs(arg); break;
107
+ case 'x': arg = arg.toString(16); break;
108
+ case 'X': arg = arg.toString(16).toUpperCase(); break;
109
+ }
110
+ arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
111
+ pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
112
+ pad_length = match[6] - String(arg).length;
113
+ pad = match[6] ? str_repeat(pad_character, pad_length) : '';
114
+ output.push(match[5] ? arg + pad : pad + arg);
115
+ }
116
+ }
117
+ return output.join('');
118
+ };
119
+
120
+ str_format.cache = {};
121
+
122
+ str_format.parse = function(fmt) {
123
+ var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
124
+ while (_fmt) {
125
+ if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
126
+ parse_tree.push(match[0]);
127
+ }
128
+ else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
129
+ parse_tree.push('%');
130
+ }
131
+ else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
132
+ if (match[2]) {
133
+ arg_names |= 1;
134
+ var field_list = [], replacement_field = match[2], field_match = [];
135
+ if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
136
+ field_list.push(field_match[1]);
137
+ while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
138
+ if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
139
+ field_list.push(field_match[1]);
140
+ }
141
+ else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
142
+ field_list.push(field_match[1]);
143
+ }
144
+ else {
145
+ throw new Error('[_.sprintf] huh?');
146
+ }
147
+ }
148
+ }
149
+ else {
150
+ throw new Error('[_.sprintf] huh?');
151
+ }
152
+ match[2] = field_list;
153
+ }
154
+ else {
155
+ arg_names |= 2;
156
+ }
157
+ if (arg_names === 3) {
158
+ throw new Error('[_.sprintf] mixing positional and named placeholders is not (yet) supported');
159
+ }
160
+ parse_tree.push(match);
161
+ }
162
+ else {
163
+ throw new Error('[_.sprintf] huh?');
164
+ }
165
+ _fmt = _fmt.substring(match[0].length);
166
+ }
167
+ return parse_tree;
168
+ };
169
+
170
+ return str_format;
171
+ })();
172
+
173
+
174
+
175
+ // Defining underscore.string
176
+
177
+ var _s = {
178
+
179
+ VERSION: '2.3.0',
180
+
181
+ isBlank: function(str){
182
+ if (str == null) str = '';
183
+ return (/^\s*$/).test(str);
184
+ },
185
+
186
+ stripTags: function(str){
187
+ if (str == null) return '';
188
+ return String(str).replace(/<\/?[^>]+>/g, '');
189
+ },
190
+
191
+ capitalize : function(str){
192
+ str = str == null ? '' : String(str);
193
+ return str.charAt(0).toUpperCase() + str.slice(1);
194
+ },
195
+
196
+ chop: function(str, step){
197
+ if (str == null) return [];
198
+ str = String(str);
199
+ step = ~~step;
200
+ return step > 0 ? str.match(new RegExp('.{1,' + step + '}', 'g')) : [str];
201
+ },
202
+
203
+ clean: function(str){
204
+ return _s.strip(str).replace(/\s+/g, ' ');
205
+ },
206
+
207
+ count: function(str, substr){
208
+ if (str == null || substr == null) return 0;
209
+ return String(str).split(substr).length - 1;
210
+ },
211
+
212
+ chars: function(str) {
213
+ if (str == null) return [];
214
+ return String(str).split('');
215
+ },
216
+
217
+ swapCase: function(str) {
218
+ if (str == null) return '';
219
+ return String(str).replace(/\S/g, function(c){
220
+ return c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase();
221
+ });
222
+ },
223
+
224
+ escapeHTML: function(str) {
225
+ if (str == null) return '';
226
+ return String(str).replace(/[&<>"']/g, function(m){ return '&' + reversedEscapeChars[m] + ';'; });
227
+ },
228
+
229
+ unescapeHTML: function(str) {
230
+ if (str == null) return '';
231
+ return String(str).replace(/\&([^;]+);/g, function(entity, entityCode){
232
+ var match;
233
+
234
+ if (entityCode in escapeChars) {
235
+ return escapeChars[entityCode];
236
+ } else if (match = entityCode.match(/^#x([\da-fA-F]+)$/)) {
237
+ return String.fromCharCode(parseInt(match[1], 16));
238
+ } else if (match = entityCode.match(/^#(\d+)$/)) {
239
+ return String.fromCharCode(~~match[1]);
240
+ } else {
241
+ return entity;
242
+ }
243
+ });
244
+ },
245
+
246
+ escapeRegExp: function(str){
247
+ if (str == null) return '';
248
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
249
+ },
250
+
251
+ splice: function(str, i, howmany, substr){
252
+ var arr = _s.chars(str);
253
+ arr.splice(~~i, ~~howmany, substr);
254
+ return arr.join('');
255
+ },
256
+
257
+ insert: function(str, i, substr){
258
+ return _s.splice(str, i, 0, substr);
259
+ },
260
+
261
+ include: function(str, needle){
262
+ if (needle === '') return true;
263
+ if (str == null) return false;
264
+ return String(str).indexOf(needle) !== -1;
265
+ },
266
+
267
+ join: function() {
268
+ var args = slice.call(arguments),
269
+ separator = args.shift();
270
+
271
+ if (separator == null) separator = '';
272
+
273
+ return args.join(separator);
274
+ },
275
+
276
+ lines: function(str) {
277
+ if (str == null) return [];
278
+ return String(str).split("\n");
279
+ },
280
+
281
+ reverse: function(str){
282
+ return _s.chars(str).reverse().join('');
283
+ },
284
+
285
+ startsWith: function(str, starts){
286
+ if (starts === '') return true;
287
+ if (str == null || starts == null) return false;
288
+ str = String(str); starts = String(starts);
289
+ return str.length >= starts.length && str.slice(0, starts.length) === starts;
290
+ },
291
+
292
+ endsWith: function(str, ends){
293
+ if (ends === '') return true;
294
+ if (str == null || ends == null) return false;
295
+ str = String(str); ends = String(ends);
296
+ return str.length >= ends.length && str.slice(str.length - ends.length) === ends;
297
+ },
298
+
299
+ succ: function(str){
300
+ if (str == null) return '';
301
+ str = String(str);
302
+ return str.slice(0, -1) + String.fromCharCode(str.charCodeAt(str.length-1) + 1);
303
+ },
304
+
305
+ titleize: function(str){
306
+ if (str == null) return '';
307
+ return String(str).replace(/(?:^|\s)\S/g, function(c){ return c.toUpperCase(); });
308
+ },
309
+
310
+ camelize: function(str){
311
+ return _s.trim(str).replace(/[-_\s]+(.)?/g, function(match, c){ return c.toUpperCase(); });
312
+ },
313
+
314
+ underscored: function(str){
315
+ return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase();
316
+ },
317
+
318
+ dasherize: function(str){
319
+ return _s.trim(str).replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase();
320
+ },
321
+
322
+ classify: function(str){
323
+ return _s.titleize(String(str).replace(/_/g, ' ')).replace(/\s/g, '');
324
+ },
325
+
326
+ humanize: function(str){
327
+ return _s.capitalize(_s.underscored(str).replace(/_id$/,'').replace(/_/g, ' '));
328
+ },
329
+
330
+ trim: function(str, characters){
331
+ if (str == null) return '';
332
+ if (!characters && nativeTrim) return nativeTrim.call(str);
333
+ characters = defaultToWhiteSpace(characters);
334
+ return String(str).replace(new RegExp('\^' + characters + '+|' + characters + '+$', 'g'), '');
335
+ },
336
+
337
+ ltrim: function(str, characters){
338
+ if (str == null) return '';
339
+ if (!characters && nativeTrimLeft) return nativeTrimLeft.call(str);
340
+ characters = defaultToWhiteSpace(characters);
341
+ return String(str).replace(new RegExp('^' + characters + '+'), '');
342
+ },
343
+
344
+ rtrim: function(str, characters){
345
+ if (str == null) return '';
346
+ if (!characters && nativeTrimRight) return nativeTrimRight.call(str);
347
+ characters = defaultToWhiteSpace(characters);
348
+ return String(str).replace(new RegExp(characters + '+$'), '');
349
+ },
350
+
351
+ truncate: function(str, length, truncateStr){
352
+ if (str == null) return '';
353
+ str = String(str); truncateStr = truncateStr || '...';
354
+ length = ~~length;
355
+ return str.length > length ? str.slice(0, length) + truncateStr : str;
356
+ },
357
+
358
+ /**
359
+ * _s.prune: a more elegant version of truncate
360
+ * prune extra chars, never leaving a half-chopped word.
361
+ * @author github.com/rwz
362
+ */
363
+ prune: function(str, length, pruneStr){
364
+ if (str == null) return '';
365
+
366
+ str = String(str); length = ~~length;
367
+ pruneStr = pruneStr != null ? String(pruneStr) : '...';
368
+
369
+ if (str.length <= length) return str;
370
+
371
+ var tmpl = function(c){ return c.toUpperCase() !== c.toLowerCase() ? 'A' : ' '; },
372
+ template = str.slice(0, length+1).replace(/.(?=\W*\w*$)/g, tmpl); // 'Hello, world' -> 'HellAA AAAAA'
373
+
374
+ if (template.slice(template.length-2).match(/\w\w/))
375
+ template = template.replace(/\s*\S+$/, '');
376
+ else
377
+ template = _s.rtrim(template.slice(0, template.length-1));
378
+
379
+ return (template+pruneStr).length > str.length ? str : str.slice(0, template.length)+pruneStr;
380
+ },
381
+
382
+ words: function(str, delimiter) {
383
+ if (_s.isBlank(str)) return [];
384
+ return _s.trim(str, delimiter).split(delimiter || /\s+/);
385
+ },
386
+
387
+ pad: function(str, length, padStr, type) {
388
+ str = str == null ? '' : String(str);
389
+ length = ~~length;
390
+
391
+ var padlen = 0;
392
+
393
+ if (!padStr)
394
+ padStr = ' ';
395
+ else if (padStr.length > 1)
396
+ padStr = padStr.charAt(0);
397
+
398
+ switch(type) {
399
+ case 'right':
400
+ padlen = length - str.length;
401
+ return str + strRepeat(padStr, padlen);
402
+ case 'both':
403
+ padlen = length - str.length;
404
+ return strRepeat(padStr, Math.ceil(padlen/2)) + str
405
+ + strRepeat(padStr, Math.floor(padlen/2));
406
+ default: // 'left'
407
+ padlen = length - str.length;
408
+ return strRepeat(padStr, padlen) + str;
409
+ }
410
+ },
411
+
412
+ lpad: function(str, length, padStr) {
413
+ return _s.pad(str, length, padStr);
414
+ },
415
+
416
+ rpad: function(str, length, padStr) {
417
+ return _s.pad(str, length, padStr, 'right');
418
+ },
419
+
420
+ lrpad: function(str, length, padStr) {
421
+ return _s.pad(str, length, padStr, 'both');
422
+ },
423
+
424
+ sprintf: sprintf,
425
+
426
+ vsprintf: function(fmt, argv){
427
+ argv.unshift(fmt);
428
+ return sprintf.apply(null, argv);
429
+ },
430
+
431
+ toNumber: function(str, decimals) {
432
+ if (str == null || str == '') return 0;
433
+ str = String(str);
434
+ var num = parseNumber(parseNumber(str).toFixed(~~decimals));
435
+ return num === 0 && !str.match(/^0+$/) ? Number.NaN : num;
436
+ },
437
+
438
+ numberFormat : function(number, dec, dsep, tsep) {
439
+ if (isNaN(number) || number == null) return '';
440
+
441
+ number = number.toFixed(~~dec);
442
+ tsep = tsep || ',';
443
+
444
+ var parts = number.split('.'), fnums = parts[0],
445
+ decimals = parts[1] ? (dsep || '.') + parts[1] : '';
446
+
447
+ return fnums.replace(/(\d)(?=(?:\d{3})+$)/g, '$1' + tsep) + decimals;
448
+ },
449
+
450
+ strRight: function(str, sep){
451
+ if (str == null) return '';
452
+ str = String(str); sep = sep != null ? String(sep) : sep;
453
+ var pos = !sep ? -1 : str.indexOf(sep);
454
+ return ~pos ? str.slice(pos+sep.length, str.length) : str;
455
+ },
456
+
457
+ strRightBack: function(str, sep){
458
+ if (str == null) return '';
459
+ str = String(str); sep = sep != null ? String(sep) : sep;
460
+ var pos = !sep ? -1 : str.lastIndexOf(sep);
461
+ return ~pos ? str.slice(pos+sep.length, str.length) : str;
462
+ },
463
+
464
+ strLeft: function(str, sep){
465
+ if (str == null) return '';
466
+ str = String(str); sep = sep != null ? String(sep) : sep;
467
+ var pos = !sep ? -1 : str.indexOf(sep);
468
+ return ~pos ? str.slice(0, pos) : str;
469
+ },
470
+
471
+ strLeftBack: function(str, sep){
472
+ if (str == null) return '';
473
+ str += ''; sep = sep != null ? ''+sep : sep;
474
+ var pos = str.lastIndexOf(sep);
475
+ return ~pos ? str.slice(0, pos) : str;
476
+ },
477
+
478
+ toSentence: function(array, separator, lastSeparator, serial) {
479
+ separator = separator || ', '
480
+ lastSeparator = lastSeparator || ' and '
481
+ var a = array.slice(), lastMember = a.pop();
482
+
483
+ if (array.length > 2 && serial) lastSeparator = _s.rtrim(separator) + lastSeparator;
484
+
485
+ return a.length ? a.join(separator) + lastSeparator + lastMember : lastMember;
486
+ },
487
+
488
+ toSentenceSerial: function() {
489
+ var args = slice.call(arguments);
490
+ args[3] = true;
491
+ return _s.toSentence.apply(_s, args);
492
+ },
493
+
494
+ slugify: function(str) {
495
+ if (str == null) return '';
496
+
497
+ var from = "ąà áäâãåæćęèéëêìíïîłńòóöôõøùúüûñçżź",
498
+ to = "aaaaaaaaceeeeeiiiilnoooooouuuunczz",
499
+ regex = new RegExp(defaultToWhiteSpace(from), 'g');
500
+
501
+ str = String(str).toLowerCase().replace(regex, function(c){
502
+ var index = from.indexOf(c);
503
+ return to.charAt(index) || '-';
504
+ });
505
+
506
+ return _s.dasherize(str.replace(/[^\w\s-]/g, ''));
507
+ },
508
+
509
+ surround: function(str, wrapper) {
510
+ return [wrapper, str, wrapper].join('');
511
+ },
512
+
513
+ quote: function(str) {
514
+ return _s.surround(str, '"');
515
+ },
516
+
517
+ exports: function() {
518
+ var result = {};
519
+
520
+ for (var prop in this) {
521
+ if (!this.hasOwnProperty(prop) || prop.match(/^(?:include|contains|reverse)$/)) continue;
522
+ result[prop] = this[prop];
523
+ }
524
+
525
+ return result;
526
+ },
527
+
528
+ repeat: function(str, qty, separator){
529
+ if (str == null) return '';
530
+
531
+ qty = ~~qty;
532
+
533
+ // using faster implementation if separator is not needed;
534
+ if (separator == null) return strRepeat(String(str), qty);
535
+
536
+ // this one is about 300x slower in Google Chrome
537
+ for (var repeat = []; qty > 0; repeat[--qty] = str) {}
538
+ return repeat.join(separator);
539
+ },
540
+
541
+ levenshtein: function(str1, str2) {
542
+ if (str1 == null && str2 == null) return 0;
543
+ if (str1 == null) return String(str2).length;
544
+ if (str2 == null) return String(str1).length;
545
+
546
+ str1 = String(str1); str2 = String(str2);
547
+
548
+ var current = [], prev, value;
549
+
550
+ for (var i = 0; i <= str2.length; i++)
551
+ for (var j = 0; j <= str1.length; j++) {
552
+ if (i && j)
553
+ if (str1.charAt(j - 1) === str2.charAt(i - 1))
554
+ value = prev;
555
+ else
556
+ value = Math.min(current[j], current[j - 1], prev) + 1;
557
+ else
558
+ value = i + j;
559
+
560
+ prev = current[j];
561
+ current[j] = value;
562
+ }
563
+
564
+ return current.pop();
565
+ }
566
+ };
567
+
568
+ // Aliases
569
+
570
+ _s.strip = _s.trim;
571
+ _s.lstrip = _s.ltrim;
572
+ _s.rstrip = _s.rtrim;
573
+ _s.center = _s.lrpad;
574
+ _s.rjust = _s.lpad;
575
+ _s.ljust = _s.rpad;
576
+ _s.contains = _s.include;
577
+ _s.q = _s.quote;
578
+
579
+ // CommonJS module is defined
580
+ if (typeof exports !== 'undefined') {
581
+ if (typeof module !== 'undefined' && module.exports) {
582
+ // Export module
583
+ module.exports = _s;
584
+ }
585
+ exports._s = _s;
586
+
587
+ } else if (typeof define === 'function' && define.amd) {
588
+ // Register as a named module with AMD.
589
+ define('underscore.string', [], function() {
590
+ return _s;
591
+ });
592
+
593
+ } else {
594
+ // Integrate with Underscore.js if defined
595
+ // or create our own underscore object.
596
+ root._ = root._ || {};
597
+ root._.string = root._.str = _s;
598
+ }
599
+
600
+ }(this, String);
products/photocrati_nextgen/modules/attach_to_post/static/uploader-icons-2x.png ADDED
Binary file
products/photocrati_nextgen/modules/attach_to_post/static/uploader-icons.png ADDED
Binary file
products/photocrati_nextgen/modules/attach_to_post/templates/accordion_tab.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <h3 class="accordion_tab" id="<?php echo esc_attr($id) ?>"><a href="#"><?php echo_h($title) ?></a></h3>
2
+ <div id="<?php echo esc_attr($id) ?>_content">
3
+ <?php echo $content ?>
4
+ </div>
products/photocrati_nextgen/modules/attach_to_post/templates/attach_to_post.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><?php echo_h($page_title)?></title>
5
+ <?php
6
+ wp_print_styles();
7
+ wp_print_scripts();
8
+ ?>
9
+ </head>
10
+ <body>
11
+ <div id="attach_to_post_tabs">
12
+ <div class='ui-tabs-icon'><span class="nextgen_logo"><?php echo_h('NextGEN')?></span> <span class="nextgen_logo_sub"><?php echo_h('Gallery')?></span></div>
13
+ <ul>
14
+ <?php foreach ($tabs as $id => $tab_params): ?>
15
+ <li>
16
+ <a href='#<?php echo esc_attr($id)?>'>
17
+ <?php echo_h($tab_params['title']) ?>
18
+ </a>
19
+ </li>
20
+ <?php endforeach ?>
21
+ </ul>
22
+ <?php reset($tabs); foreach ($tabs as $id => $tab_params): ?>
23
+ <div class="main_menu_tab" id="<?php echo esc_attr($id) ?>"><?php echo $tab_params['content'] ?></div>
24
+ <?php endforeach ?>
25
+ </div>
26
+
27
+ <?php wp_print_footer_scripts() ?>
28
+ </body>
29
+ </html>
products/photocrati_nextgen/modules/attach_to_post/templates/display_settings_form.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <form rel="<?php echo esc_attr($display_type_name) ?>" class="<?php echo esc_attr($css_class) ?>" method='POST' action='<?php echo esc_attr($_SERVER['REQUEST_URI'])?>'>
2
+ <?php echo $settings ?>
3
+ </form>
products/photocrati_nextgen/modules/attach_to_post/templates/display_tab.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="errors">
2
+
3
+ </div>
4
+ <div class="accordion" id="display_settings_accordion">
5
+ <?php foreach($tabs as $tab): ?>
6
+ <?php echo $tab ?>
7
+ <?php endforeach ?>
8
+ </div>
9
+ <p>
10
+ <input type="button" id="save_displayed_gallery" value="Save"/>
11
+ </p>
products/photocrati_nextgen/modules/attach_to_post/templates/display_tab_js.php ADDED
@@ -0,0 +1,1654 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(function($){
2
+
3
+ /*****************************************************************************
4
+ ** NGG DEFINITION
5
+ ***/
6
+
7
+ /**
8
+ Setup a namespace for NextGEN-offered Backbone components
9
+ **/
10
+ var Ngg = {
11
+ Models: {},
12
+ Views: {}
13
+ };
14
+
15
+ /*****************************************************************************
16
+ ** NGG MODELS
17
+ ***/
18
+
19
+ /**
20
+ * Ngg.Models.SelectableItems
21
+ * A collection of items that can be selectable. Commonly used with the
22
+ * Ngg.Views.SelectTag widget (view)
23
+ **/
24
+ Ngg.Models.SelectableItems = Backbone.Collection.extend({
25
+ selected: function(){
26
+ return this.filter(function(item){
27
+ return item.get('selected') == true;
28
+ });
29
+ },
30
+
31
+ deselect_all: function(){
32
+ this.each(function(item){
33
+ item.set('selected', false);
34
+ });
35
+ },
36
+
37
+ selected_ids: function(){
38
+ return _.pluck(this.selected(), 'id');
39
+ },
40
+
41
+ select: function(ids){
42
+ if (!_.isArray(ids)) ids = [ids];
43
+ this.each(function(item){
44
+ if (_.indexOf(ids, item.id) >= 0) {
45
+ item.set('selected', true);
46
+ }
47
+ });
48
+ this.trigger('selected');
49
+ }
50
+ });
51
+
52
+
53
+ /*****************************************************************************
54
+ ** NGG VIEWS
55
+ ***/
56
+
57
+ /**
58
+ * Ngg.Views.SelectTag
59
+ * Used to render a Select tag (drop-down list)
60
+ **/
61
+ Ngg.Views.SelectTag = Backbone.View.extend({
62
+ tagName: 'select',
63
+
64
+ collection: null,
65
+
66
+ multiple: false,
67
+
68
+ value_field: 'id',
69
+
70
+ text_field: 'title',
71
+
72
+ initialize: function(){
73
+ _.each(this.options, function(value, key){
74
+ this[key] = value;
75
+ }, this);
76
+ this.collection.on('add', this.render_new_option, this);
77
+ this.collection.on('remove', this.remove_existing_option, this);
78
+ this.collection.on('reset', this.empty_list, this);
79
+ },
80
+
81
+ events: {
82
+ 'change': 'selection_changed'
83
+ },
84
+
85
+ empty_list: function(){
86
+ this.$el.empty();
87
+ },
88
+
89
+ render_new_option: function(item){
90
+ this.$el.append(new this.Option({
91
+ model: item,
92
+ value_field: this.value_field,
93
+ text_field: this.text_field
94
+ }).render().el);
95
+ },
96
+
97
+ remove_existing_option: function(item){
98
+ this.$el.find("option[value='"+item.id+"']").remove();
99
+ },
100
+
101
+ /**
102
+ * After a selection has changed, set the 'selected' property for each item in the
103
+ * collection
104
+ * @triggers 'selected'
105
+ **/
106
+ selection_changed: function(){
107
+ // Get selected options from DOM
108
+ var selections = _.map(this.$el.find(':selected'), function(element){
109
+ return $(element).val();
110
+ });
111
+
112
+ // Set the 'selected' attribute for each item in the collection
113
+ this.collection.each(function(item){
114
+ if (_.indexOf(selections, item.id) >= 0 || _.indexOf(selections, item.id.toString()) >= 0)
115
+ item.set('selected', true);
116
+ else
117
+ item.set('selected', false);
118
+ });
119
+ this.collection.trigger('selected');
120
+ },
121
+
122
+ render: function(){
123
+ this.$el.empty();
124
+ if (this.options.include_blank) {
125
+ this.$el.append("<option></option>");
126
+ }
127
+ this.collection.each(function(item){
128
+ var option = new this.Option({
129
+ model: item,
130
+ value_field: this.value_field,
131
+ text_field: this.text_field
132
+ });
133
+ this.$el.append(option.render().el);
134
+ }, this);
135
+ if (this.multiple) this.$el.prop('multiple', true);
136
+ if (this.width) this.$el.width(this.width);
137
+ return this;
138
+ },
139
+
140
+ /**
141
+ * Represents an option in the Select drop-down
142
+ **/
143
+ Option: Backbone.View.extend({
144
+ tagName: 'option',
145
+
146
+ model: null,
147
+
148
+ initialize: function(){
149
+ _.each(this.options, function(value, key){
150
+ this[key] = value;
151
+ }, this);
152
+ this.model.on('change', this.render, this);
153
+ },
154
+
155
+ render: function(){
156
+ var self = this;
157
+ this.$el.html(this.model.get(this.text_field).replace(/\\&/g, '&').replace(/\\'/g, "'"));
158
+ this.$el.prop({
159
+ value: this.value_field == 'id' ? this.model.id : this.model.get(this.value_field),
160
+ });
161
+ if (self.model.get('selected') == true) {
162
+ this.$el.attr('selected', 'selected');
163
+ }
164
+ return this;
165
+ }
166
+ })
167
+ });
168
+
169
+
170
+ Ngg.Views.Chosen = Backbone.View.extend({
171
+ tagName: 'span',
172
+
173
+ initialize: function(){
174
+ this.collection = this.options.collection;
175
+ if (!this.options.multiple) this.options.include_blank = true;
176
+ this.select_tag = new Ngg.Views.SelectTag(this.options);
177
+ this.collection.on('change', this.selection_changed, this);
178
+ },
179
+
180
+ selection_changed: function(e){
181
+ if (_.isUndefined(e.changed['selected'])) this.render();
182
+ },
183
+
184
+ render: function(){
185
+
186
+ this.$el.append(this.select_tag.render().$el);
187
+ if (this.options.width)
188
+ this.select_tag.$el.width(this.options.width);
189
+
190
+ // Configure select2 options
191
+ this.select2_opts = {
192
+ placeholder: this.options.placeholder
193
+ };
194
+
195
+ // Create the select2 drop-down
196
+ if (this.$el.parent().length == 0) {
197
+ $('body').append(this.$el);
198
+ this.select_tag.$el.select2(this.select2_opts);
199
+ var container = this.select_tag.$el.select2('container').detach();
200
+ this.$el.append(container);
201
+ this.$el.detach();
202
+
203
+ }
204
+ else this.select_tag.$el.select2(this.select2_opts);
205
+
206
+ // Hack for multi-select elements
207
+ if (this.options.multiple && this.collection.selected().length == 0)
208
+ this.select_tag.$el.select2('val', '');
209
+
210
+ // For IE, ensure that the text field has a width
211
+ this.$el.find('.select2-input').width(this.options.width-20);
212
+
213
+ // For IE8, ensure that the selection is being displayed
214
+ if (!this.options.multiple) {
215
+ var selected_value = this.$el.find('.select2-choice span:first');
216
+ if (selected_value.text().length == 0 && this.collection.selected().length > 0) {
217
+ var selected_item = this.collection.selected().pop();
218
+ selected_value.text(selected_item.get(this.select_tag.text_field));
219
+ }
220
+ }
221
+ else {
222
+ var selected_values = this.$el.find('.select2-search-choice');
223
+ if (this.collection.selected().length > 0 && selected_values.length == 0) {
224
+ this.select_tag.$el.select2('val', '');
225
+ var data = [];
226
+ var value_field = this.select_tag.value_field;
227
+ _.each(this.collection.selected(), function(item){
228
+ var value = value_field == 'id' ? item.id : item.get(value_field);
229
+ data.push({
230
+ id: value,
231
+ text: item.get(this.select_tag.text_field)
232
+ });
233
+ }, this);
234
+ this.select_tag.$el.select2('data', data);
235
+ }
236
+ }
237
+
238
+ return this;
239
+ }
240
+ });
241
+
242
+ /*****************************************************************************
243
+ ** DISPLAY TAB DEFINITION
244
+ ***/
245
+
246
+ /**
247
+ * Setup a namespace
248
+ **/
249
+ Ngg.DisplayTab = {
250
+ Models: {},
251
+ Views: {},
252
+ App: {}
253
+ };
254
+
255
+ /*****************************************************************************
256
+ * MODEL CLASSES
257
+ **/
258
+
259
+ /**
260
+ * A collection that can fetch it's entities from the server
261
+ **/
262
+ Ngg.Models.Remote_Collection = Ngg.Models.SelectableItems.extend({
263
+ fetch_limit: 50,
264
+ in_progress: false,
265
+ fetch_url: photocrati_ajax.url,
266
+ action: '',
267
+ extra_data: {},
268
+
269
+ _create_request: function(limit, offset) {
270
+ var request = <?php echo $sec_token?>;
271
+ request = _.extend(request, {
272
+ action: this.action,
273
+ limit: limit ? limit : this.fetch_limit,
274
+ offset: offset ? offset : 0
275
+
276
+ });
277
+ for (var index in this.extra_data) {
278
+ var value = this.extra_data[index];
279
+ if (typeof(request[index]) == 'undefined') {
280
+ request[index] = {};
281
+ }
282
+ if (typeof(value['toJSON']) != 'undefined') {
283
+ value = value.toJSON();
284
+ }
285
+ request[index] = _.extend(request[index], value);
286
+ }
287
+ return request;
288
+ },
289
+
290
+ _add_item: function(item) {
291
+ this.push(item);
292
+ },
293
+
294
+ fetch: function(limit, offset){
295
+ // Request the entities from the server
296
+ var self = this;
297
+ this.in_progress = true;
298
+ $.post(this.fetch_url, this._create_request(limit, offset), function(response){
299
+ if (!_.isObject(response)) response = JSON.parse(response);
300
+
301
+ if (response.items) {
302
+ _.each(response.items, function(item){
303
+ self._add_item(item);
304
+ });
305
+
306
+ // Continue fetching ?
307
+ if (response.total >= response.limit+response.offset) {
308
+ self.fetch(response.limit, response.offset+response.limit);
309
+ }
310
+ else {
311
+ self.in_progress = false;
312
+ self.trigger('finished_fetching');
313
+ }
314
+ }
315
+ });
316
+ }
317
+ });
318
+
319
+
320
+ /**
321
+ * Ngg.DisplayTab.Models.Displayed_Gallery
322
+ * Represents the displayed gallery being edited or created by the Display Tab
323
+ **/
324
+ Ngg.DisplayTab.Models.Displayed_Gallery = Backbone.Model.extend({
325
+ defaults: {
326
+ source: null,
327
+ container_ids: [],
328
+ entity_ids: [],
329
+ display_type: null,
330
+ display_settings: {},
331
+ exclusions: [],
332
+ sortorder: [],
333
+ slug: null
334
+ }
335
+ });
336
+
337
+ /**
338
+ * Ngg.DisplayTab.Models.Source
339
+ * Represents an individual source used to collect displayable entities from
340
+ **/
341
+ Ngg.DisplayTab.Models.Source = Backbone.Model.extend({
342
+ idAttribute: 'name',
343
+ defaults: {
344
+ title: '',
345
+ name: '',
346
+ selected: false
347
+ }
348
+ });
349
+
350
+ /**
351
+ * Ngg.DisplayTab.Models.Source_Collection
352
+ * Used as a collection of all the available sources for entities
353
+ **/
354
+ Ngg.DisplayTab.Models.Source_Collection = Ngg.Models.SelectableItems.extend({
355
+ model: Ngg.DisplayTab.Models.Source,
356
+
357
+ selected_value: function(){
358
+ var retval = null;
359
+ var selected = this.selected();
360
+ if (selected.length > 0) {
361
+ retval = selected[0].get('name');
362
+ }
363
+ return retval;
364
+ }
365
+ });
366
+
367
+ /**
368
+ * Ngg.DisplayTab.Models.Gallery
369
+ * Represents an individual gallery entity
370
+ **/
371
+ Ngg.DisplayTab.Models.Gallery = Backbone.Model.extend({
372
+ idAttribute: '<?php echo $gallery_primary_key ?>',
373
+ defaults: {
374
+ title: '',
375
+ name: ''
376
+ }
377
+ });
378
+
379
+ /**
380
+ * Ngg.DisplayTab.Models.Gallery_Collection
381
+ * Collection of gallery objects
382
+ **/
383
+ Ngg.DisplayTab.Models.Gallery_Collection = Ngg.Models.Remote_Collection.extend({
384
+ model: Ngg.DisplayTab.Models.Gallery,
385
+
386
+ action: 'get_existing_galleries'
387
+ });
388
+
389
+ /**
390
+ * Ngg.DisplayTab.Models.Album
391
+ * Represents an individual Album object
392
+ **/
393
+ Ngg.DisplayTab.Models.Album = Backbone.Model.extend({
394
+ defaults: {
395
+ title: '',
396
+ name: ''
397
+ }
398
+ });
399
+
400
+ /**
401
+ * Ngg.DisplayTab.Models.Album_Collection
402
+ * Used as a collection of album objects
403
+ **/
404
+ Ngg.DisplayTab.Models.Album_Collection = Ngg.Models.Remote_Collection.extend({
405
+ model: Ngg.DisplayTab.Models.Album,
406
+
407
+ action: 'get_existing_albums'
408
+ });
409
+
410
+ /**
411
+ * Ngg.DisplayTab.Models.Tag
412
+ * Represents an individual tag object
413
+ **/
414
+ Ngg.DisplayTab.Models.Tag = Backbone.Model.extend({
415
+ defaults: {
416
+ title: ''
417
+ }
418
+ });
419
+
420
+ /**
421
+ * Ngg.DisplayTab.Models.Tag_Collection
422
+ * Represents a collection of tag objects
423
+ **/
424
+ Ngg.DisplayTab.Models.Tag_Collection = Ngg.Models.Remote_Collection.extend({
425
+ model: Ngg.DisplayTab.Models.Tag,
426
+ /*
427
+ selected_ids: function(){
428
+ return this.selected().map(function(item){
429
+ return item.get('name');
430
+ });
431
+ },
432
+ */
433
+
434
+ action: 'get_existing_image_tags'
435
+ });
436
+
437
+ /**
438
+ * Ngg.DisplayTab.Models.Display_Type
439
+ * Represents an individual display type
440
+ **/
441
+ Ngg.DisplayTab.Models.Display_Type = Backbone.Model.extend({
442
+ idAttribute: 'name',
443
+ defaults: {
444
+ title: ''
445
+ },
446
+
447
+ is_compatible_with_source: function(source){
448
+ var success = true;
449
+ for (index in source.get('returns')) {
450
+ var returned_entity_type = source.get('returns')[index];
451
+ if (_.indexOf(this.get('entity_types'), returned_entity_type) < 0) {
452
+ success = false;
453
+ break;
454
+ }
455
+ }
456
+ return success;
457
+ }
458
+ });
459
+
460
+ /**
461
+ * Ngg.DisplayTab.Models.Display_Type_Collection
462
+ * Represents a collection of display type objects
463
+ **/
464
+ Ngg.DisplayTab.Models.Display_Type_Collection = Ngg.Models.SelectableItems.extend({
465
+ model: Ngg.DisplayTab.Models.Display_Type,
466
+
467
+ selected_value: function(){
468
+ var retval = null;
469
+ var selected = this.selected();
470
+ if (selected.length > 0) {
471
+ return selected[0].get('name');
472
+ }
473
+ return retval;
474
+ }
475
+ });
476
+
477
+ /**
478
+ * Ngg.DisplayTab.Models.Entity
479
+ * Represents an entity to display on the front-end
480
+ **/
481
+ Ngg.DisplayTab.Models.Entity = Backbone.Model.extend({
482
+ entity_id: function(){
483
+ return this.get(this.get('id_field'));
484
+ },
485
+
486
+ is_excluded: function() {
487
+ current_value = this.get('exclude');
488
+ if (_.isUndefined(current_value)) return false;
489
+ else if (_.isBoolean(current_value)) return current_value;
490
+ else return parseInt(current_value) == 0 ? false : true;
491
+ },
492
+
493
+ is_included: function(){
494
+ return !this.is_excluded();
495
+ },
496
+
497
+ is_gallery: function(){
498
+ retval = false;
499
+ if (this.get('is_gallery') == true) retval = true;
500
+ return retval;
501
+ },
502
+
503
+ is_album: function(){
504
+ retval = false;
505
+ if (this.get('is_album') == true) retval = true;
506
+ return retval;
507
+ },
508
+
509
+ is_image: function(){
510
+ return !this.is_album() && !this.is_gallery();
511
+ },
512
+
513
+ alttext: function(){
514
+ if (this.is_image()) {
515
+ return this.get('alttext');
516
+ }
517
+ else if (this.is_gallery()) {
518
+ return this.get('title');
519
+ }
520
+ else if (this.is_album()) {
521
+ return this.get('name');
522
+ }
523
+ }
524
+ });
525
+
526
+ /**
527
+ * Ngg.DisplayTab.Models.Entity_Collection
528
+ * Represents a collection of entities
529
+ **/
530
+ Ngg.DisplayTab.Models.Entity_Collection = Ngg.Models.Remote_Collection.extend({
531
+ model: Ngg.DisplayTab.Models.Entity,
532
+
533
+ action: 'get_displayed_gallery_entities',
534
+
535
+ _add_item: function(item){
536
+ item.exclude = parseInt(item.exclude) == 1 ? true : false;
537
+ item.is_gallery = parseInt(item.is_gallery) == 1 ? true : false;
538
+ item.is_album = parseInt(item.is_album) == 1 ? true : false;
539
+ this.push(item);
540
+ },
541
+
542
+ entity_ids: function(){
543
+ return this.map(function(item){
544
+ return item.entity_id();
545
+ });
546
+ },
547
+
548
+ included_ids: function(){
549
+ return _.compact(this.map(function(item){
550
+ if (item.is_included()) return item.entity_id();
551
+ }));
552
+ },
553
+
554
+ excluded_ids: function() {
555
+ return _.compact(this.map(function(item) {
556
+ if (!item.is_included()) {
557
+ return item.entity_id();
558
+ }
559
+ }));
560
+ }
561
+ });
562
+
563
+
564
+ Ngg.DisplayTab.Models.SortOrder = Backbone.Model.extend({
565
+ });
566
+
567
+ Ngg.DisplayTab.Models.SortOrder_Options = Ngg.Models.SelectableItems.extend({
568
+ model: Ngg.DisplayTab.Models.SortOrder
569
+ });
570
+ Ngg.DisplayTab.Models.SortDirection = Backbone.Model.extend({
571
+
572
+ });
573
+ Ngg.DisplayTab.Models.SortDirection_Options = Backbone.Collection.extend({
574
+ model: Ngg.DisplayTab.Models.SortDirection
575
+ });
576
+
577
+ Ngg.DisplayTab.Models.Slug = Backbone.Model.extend({});
578
+
579
+ /*****************************************************************************
580
+ * VIEW CLASSES
581
+ **/
582
+
583
+ /**
584
+ * Ngg.DisplayTab.Views.Source_Config
585
+ * Used to populate the source configuration tab
586
+ **/
587
+ Ngg.DisplayTab.Views.Source_Config = Backbone.View.extend({
588
+ el: '#source_configuration',
589
+
590
+ selected_view: null,
591
+
592
+ /**
593
+ * Bind to the "sources" collection to know when a selection has been made
594
+ * and determine what sub-view to render
595
+ **/
596
+ initialize: function(){
597
+ this.sources = Ngg.DisplayTab.instance.sources;
598
+ this.sources.on('selected', this.render, this);
599
+ _.bindAll(this, 'render');
600
+ this.render();
601
+ },
602
+
603
+ render: function(){
604
+ var chosen = new Ngg.Views.Chosen({
605
+ id: 'source_select',
606
+ collection: this.sources,
607
+ placeholder: 'Select a source',
608
+ width: 500
609
+ });
610
+
611
+ this.$el.html('<tr><td><label>Sources</label></td><td id="source_column"></td></tr>');
612
+ this.$el.find('#source_column').append(chosen.render().el);
613
+
614
+ var selected = this.sources.selected();
615
+ if (selected.length) {
616
+ var view_name = _.str.capitalize(selected.pop().id)+"Source";
617
+ if (typeof(Ngg.DisplayTab.Views[view_name]) != 'undefined') {
618
+ var selected_view = new Ngg.DisplayTab.Views[view_name];
619
+ this.$el.append(selected_view.render().el);
620
+ }
621
+ }
622
+
623
+ return this;
624
+ }
625
+ });
626
+
627
+ Ngg.DisplayTab.Views.Slug_Config = Backbone.View.extend({
628
+ el: '#slug_configuration',
629
+
630
+ selected_view: null,
631
+
632
+ initialize: function() {
633
+ this.displayed_gallery = Ngg.DisplayTab.instance.displayed_gallery;
634
+ this.slug = Ngg.DisplayTab.instance.displayed_gallery.get('slug');
635
+ this.render();
636
+ },
637
+
638
+ render: function() {
639
+ var self = this;
640
+
641
+ var input = $('<input>').prop({
642
+ type: 'text',
643
+ name: 'slug',
644
+ value: this.slug,
645
+ placeholder: '(optional)',
646
+ id: 'field_slug'
647
+ });
648
+
649
+ input.change(function() {
650
+ self.displayed_gallery.set('slug', $(this).val());
651
+ });
652
+
653
+ var tooltip = 'Sets an SEO-friendly name to this gallery for URLs. Currently only in use by the Pro Lightbox.';
654
+ this.$el.append('<tr><td id="slug_label"><label for="field_slug" class="tooltip" title="' + tooltip + '">Slug</label></td><td id="slug_column"></td></tr>');
655
+ this.$el.find('#slug_column').append(input);
656
+
657
+ return this;
658
+ }
659
+ });
660
+
661
+ Ngg.DisplayTab.Views.Display_Type_Selector = Backbone.View.extend({
662
+ el: '#display_type_selector',
663
+
664
+ initialize: function(){
665
+ this.display_types = Ngg.DisplayTab.instance.display_types;
666
+ this.display_type_order_base = Ngg.DisplayTab.instance.display_type_order_base;
667
+ this.display_type_order_step = Ngg.DisplayTab.instance.display_type_order_step;
668
+ this.sources = Ngg.DisplayTab.instance.sources;
669
+ this.render();
670
+ },
671
+
672
+ selection_changed: function(value){
673
+ var selected_type = null;
674
+ this.display_types.each(function(item){
675
+ if (item.get('name') == value) {
676
+ selected_type = item;
677
+ item.set('selected', true);
678
+ }
679
+ else {
680
+ item.set('selected', false);
681
+ }
682
+ });
683
+
684
+ if (selected_type) {
685
+ var selected_source = this.sources.selected_value();
686
+ var default_source = selected_type.get('default_source');
687
+
688
+ // If the default source isn't selected, then select it
689
+ if (default_source && selected_source != default_source) {
690
+
691
+ // Get the default source object by name
692
+ default_source = this.sources.where({
693
+ name: default_source
694
+ });
695
+
696
+ // Does the default source exist ?
697
+ if (default_source.length > 0) {
698
+ default_source = default_source[0];
699
+ this.sources.deselect_all();
700
+ this.sources.select(default_source.id);
701
+ }
702
+ }
703
+ }
704
+
705
+ $('.display_settings_form').each(function(){
706
+ $this = $(this);
707
+ if ($this.attr('rel') == value) $this.removeClass('hidden');
708
+ else $this.addClass('hidden');
709
+ });
710
+ },
711
+
712
+ render: function(){
713
+ var selected_source = this.sources.selected();
714
+ var current_step = 0;
715
+ selected_source = selected_source.length > 0 ? selected_source[0] : false;
716
+ this.$el.empty();
717
+
718
+ var order_base = this.display_type_order_base;
719
+ var order_step = this.display_type_order_step;
720
+
721
+ this.display_types.each(function(item){
722
+ if (selected_source && !item.is_compatible_with_source(selected_source)) {
723
+
724
+ // Show all display types if we're viewing the display type
725
+ // selector tab
726
+ var display_tab = $('#display_type_tab_content:visible');
727
+ if (display_tab.length == 0) return;
728
+ else if (display_tab.css('visibility') == 'hidden') return;
729
+ }
730
+ var display_type = new this.DisplayType;
731
+ display_type.model = item;
732
+ display_type.on('selected', this.selection_changed, this);
733
+ if (!this.display_types.selected_value()) {
734
+ item.set('selected', true);
735
+ this.selection_changed(item.id);
736
+ }
737
+ var display_order = item.get('view_order');
738
+ if (!display_order)
739
+ display_order = order_base;
740
+ var display_step = Math.floor(display_order / order_step);
741
+ if (current_step > 0 && display_step > current_step) {
742
+ this.$el.append('<li class="clear" style="height: 10px" />');
743
+ }
744
+ current_step = display_step;
745
+ this.$el.append(display_type.render().el);
746
+ }, this);
747
+ return this;
748
+ },
749
+
750
+ DisplayType: Backbone.View.extend({
751
+ className: 'display_type_preview',
752
+
753
+ events: {
754
+ click: 'clicked'
755
+ },
756
+
757
+ clicked: function(e){
758
+ this.trigger('selected', this.model.get('name'));
759
+ },
760
+
761
+ render: function() {
762
+ // Create all elements
763
+ var image_container = $('<div/>').addClass('image_container');
764
+ var img = $('<img/>').attr({
765
+ src: photocrati_ajax.wp_site_static_url + '/' + this.model.get('preview_image_relpath'),
766
+ title: this.model.get('title'),
767
+ alt: this.model.get('alt')
768
+ });
769
+ var inner_div = $('<div/>');
770
+ var radio_button = $('<input/>').prop({
771
+ type: 'radio',
772
+ value: this.model.get('name'),
773
+ title: this.model.get('title'),
774
+ name: 'display_type',
775
+ checked: this.model.get('selected')
776
+ });
777
+ image_container.append(inner_div);
778
+ image_container.append(img);
779
+ inner_div.append(radio_button);
780
+ inner_div.append(this.model.get('title'));
781
+ this.$el.append(image_container);
782
+ return this;
783
+ }
784
+ })
785
+ });
786
+
787
+ Ngg.DisplayTab.Views.Preview_Area = Backbone.View.extend({
788
+ el: '#preview_area',
789
+
790
+ initialize: function(){
791
+ this.entities = Ngg.DisplayTab.instance.entities;
792
+ this.sources = Ngg.DisplayTab.instance.sources;
793
+ this.displayed_gallery = Ngg.DisplayTab.instance.displayed_gallery;
794
+
795
+ // Create the entity list
796
+ this.entity_list = $('<ul/>').attr('id', 'entity_list').append('<li class="clear"/>');
797
+
798
+ // When an entity is added/removed to the collection, we'll add/remove it on the DOM
799
+ this.entities.on('add', this.render_entity, this);
800
+ this.entities.on('remove', this.remove_entity, this);
801
+
802
+ // When the collection is reset, we add a list item to clear the float. This is important -
803
+ // jQuery sortable() will break without the cleared element.
804
+ this.entities.on('reset', this.entities_reset, this);
805
+
806
+ // When jQuery sortable() is finished sorting, we need to adjust the order of models in the collection
807
+ this.entities.on('change:sortorder', function(model){
808
+ this.entities.remove(model, {silent: true});
809
+ this.entities.add(model, {at: model.changed.sortorder, silent: true});
810
+ this.displayed_gallery.set('sortorder', this.entities.entity_ids());
811
+ this.displayed_gallery.set('order_by', 'sortorder');
812
+ }, this);
813
+
814
+ // Reset when the source changes
815
+ this.sources.on('selected', this.render, this);
816
+
817
+ this.render();
818
+ },
819
+
820
+ events: {
821
+ opened: 'entities_reset'
822
+ },
823
+
824
+ entities_reset: function(e){
825
+ this.entities.reset(null, {silent: true});
826
+ this.entity_list.empty().append('<li class="clear"/>');
827
+ if (!this.entities.in_progress) this.entities.fetch();
828
+ },
829
+
830
+ render_entity: function(model){
831
+ var entity_element = new this.EntityElement({model: model});
832
+ this.entity_list.find('.clear').before(entity_element.render().$el);
833
+ entity_element.$el.css('visibility', 'hidden');
834
+ setTimeout(function(){
835
+ entity_element.$el.css('visibility', 'visible');
836
+ }, 0);
837
+ if (this.$el.find('.no_entities').length == 1) {
838
+ this.render();
839
+ }
840
+ else if (this.entities.length > 1) {
841
+ this.entity_list.sortable('refresh');
842
+ }
843
+ },
844
+
845
+ remove_entity: function(model){
846
+ var id = this.id = model.get('id_field')+'_'+model.entity_id();
847
+ var entity = this.entity_list.find('#'+id).remove();
848
+ this.entity_list.sortable('refresh');
849
+ if (this.entities.length == 0) {
850
+ this.render_no_images_notice();
851
+ }
852
+ },
853
+
854
+ render_no_images_notice: function(){
855
+ this.$el.empty();
856
+ this.$el.append("<p class='no_entities'>No entities to display for this source.</p>");
857
+ },
858
+
859
+ render: function(){
860
+ this.$el.empty();
861
+ if (this.entities.length > 0 && this.displayed_gallery.get('container_ids').length > 0) {
862
+
863
+ // Render header rows
864
+ this.$el.append(new this.RefreshButton({
865
+ entities: this.entities
866
+ }).render().el);
867
+ this.$el.append(new this.SortButtons({
868
+ entities: this.entities,
869
+ displayed_gallery: this.displayed_gallery,
870
+ sources: this.sources
871
+ }).render().el);
872
+ this.$el.append(new this.ExcludeButtons({
873
+ entities: this.entities
874
+ }).render().el);
875
+
876
+ this.$el.append(this.entity_list);
877
+
878
+ // Activate jQuery Sortable for the entity list
879
+ this.entity_list.sortable({
880
+ placeholder: 'placeholder',
881
+ forcePlaceholderSize: true,
882
+ containment: 'parent',
883
+ opacity: 0.7,
884
+ revert: true,
885
+ dropOnEmpty: true,
886
+ start: function(e, ui){
887
+ ui.placeholder.css({
888
+ height: ui.item.height()
889
+ });
890
+ return true;
891
+ },
892
+ stop: function(e, ui) {
893
+ ui.item.trigger('drop', ui.item.index());
894
+ }
895
+ });
896
+ this.entity_list.disableSelection();
897
+ }
898
+ else {
899
+ this.render_no_images_notice();
900
+ }
901
+ return this;
902
+ },
903
+
904
+ RefreshButton: Backbone.View.extend({
905
+ className: 'refresh_button',
906
+
907
+ tagName: 'input',
908
+
909
+ label: 'Refresh',
910
+
911
+ events: {
912
+ click: 'clicked'
913
+ },
914
+
915
+ clicked: function(){
916
+ this.entities.reset();
917
+ },
918
+
919
+ initialize: function(){
920
+ _.each(this.options, function(value, key){
921
+ this[key] = value;
922
+ }, this);
923
+ },
924
+
925
+ render: function(){
926
+ this.$el.attr({
927
+ value: this.label,
928
+ type: 'button'
929
+ });
930
+ return this;
931
+ }
932
+ }),
933
+
934
+ ExcludeButtons: Backbone.View.extend({
935
+ className: 'header_row',
936
+
937
+ initialize: function(){
938
+ _.each(this.options, function(value, key){
939
+ this[key] = value;
940
+ }, this);
941
+ },
942
+
943
+ render: function(){
944
+ this.$el.empty();
945
+ this.$el.append('<strong>Exclude:</strong>');
946
+ var all_button = new this.Button({
947
+ value: true,
948
+ text: 'All',
949
+ entities: this.entities
950
+ });
951
+ this.$el.append(all_button.render().el);
952
+ this.$el.append('<span class="separator">|</span>');
953
+ var none_button = new this.Button({
954
+ value: false,
955
+ text: 'None',
956
+ entities: this.entities
957
+ });
958
+ this.$el.append(none_button.render().el);
959
+ return this;
960
+ },
961
+
962
+ Button: Backbone.View.extend({
963
+ tagName: 'a',
964
+
965
+ value: 1,
966
+
967
+ text: '',
968
+
969
+ events: {
970
+ click: 'clicked'
971
+ },
972
+
973
+ initialize: function(){
974
+ _.each(this.options, function(value, key){
975
+ this[key] = value;
976
+ }, this);
977
+ },
978
+
979
+ clicked: function(e){
980
+ e.preventDefault();
981
+ this.entities.each(function(item){
982
+ item.set('exclude', this.value);
983
+ }, this);
984
+ },
985
+
986
+ render: function(){
987
+ this.$el.text(this.text).attr('href', '#');
988
+ return this;
989
+ }
990
+ })
991
+ }),
992
+
993
+ SortButtons: Backbone.View.extend({
994
+ className: 'header_row',
995
+
996
+ initialize: function(){
997
+ _.each(this.options, function(value, key){
998
+ this[key] = value;
999
+ }, this);
1000
+ this.sortorder_options = new Ngg.DisplayTab.Models.SortOrder_Options();
1001
+ this.sortorder_options.on('change:selected', this.sortoption_changed, this);
1002
+
1003
+ // Create sort directions and listen for selection changes
1004
+ this.sortdirection_options = new Ngg.DisplayTab.Models.SortDirection_Options([
1005
+ {
1006
+ value: 'ASC',
1007
+ title: 'Ascending',
1008
+ selected: this.displayed_gallery.get('order_direction') == 'ASC'
1009
+ },
1010
+ {
1011
+ value: 'DESC',
1012
+ title: 'Descending',
1013
+ selected: this.displayed_gallery.get('order_direction') == 'DESC'
1014
+ }
1015
+ ]);
1016
+ this.sortdirection_options.on('change:selected', this.sortdirection_changed, this);
1017
+ },
1018
+
1019
+ populate_sorting_fields: function(){
1020
+ // We display difference sorting buttons depending on what type of entities we're dealing with.
1021
+ var entity_types = this.sources.selected().pop().get('returns');
1022
+ if (_.indexOf(entity_types, 'image') !== -1) {
1023
+ this.fill_image_sortorder_options();
1024
+ }
1025
+ else {
1026
+ this.fill_gallery_sortorder_options();
1027
+ }
1028
+ },
1029
+
1030
+ create_sortorder_option: function(name, title){
1031
+ return new Ngg.DisplayTab.Models.SortOrder({
1032
+ name: name,
1033
+ title: title,
1034
+ value: name,
1035
+ selected: this.displayed_gallery.get('order_by') == name
1036
+ });
1037
+ },
1038
+
1039
+ fill_image_sortorder_options: function(){
1040
+ this.sortorder_options.reset();
1041
+ this.sortorder_options.push(this.create_sortorder_option('sortorder', 'Custom'));
1042
+ this.sortorder_options.push(this.create_sortorder_option(Ngg.DisplayTab.instance.image_key, 'Image ID'));
1043
+ this.sortorder_options.push(this.create_sortorder_option('filename', 'Filename'));
1044
+ this.sortorder_options.push(this.create_sortorder_option('alttext', 'Alt/Title Text'));
1045
+ this.sortorder_options.push(this.create_sortorder_option('imagedate', 'Date/Time'));
1046
+ },
1047
+
1048
+ fill_gallery_sortorder_options: function(){
1049
+ this.sortorder_options.reset();
1050
+ this.sortorder_options.push(this.create_sortorder_option('sortorder' ,'Custom'));
1051
+ this.sortorder_options.push(this.create_sortorder_option('name', 'Name'));
1052
+ this.sortorder_options.push(this.create_sortorder_option('galdesc', 'Description'));
1053
+ },
1054
+
1055
+ sortoption_changed: function(model){
1056
+ this.sortorder_options.each(function(item){
1057
+ item.set('selected', model.get('value') == item.get('value') ? true : false, {silent: true});
1058
+ });
1059
+ this.displayed_gallery.set('order_by', model.get('value'));
1060
+ this.entities.reset();
1061
+ this.$el.find('a.sortorder').each(function(){
1062
+ var $item = $(this);
1063
+ if ($item.attr('value') == model.get('value'))
1064
+ $item.addClass('selected');
1065
+ else
1066
+ $item.removeClass('selected');
1067
+ });
1068
+ },
1069
+
1070
+ sortdirection_changed: function(model){
1071
+ this.sortdirection_options.each(function(item){
1072
+ item.set('selected', model.get('value') == item.get('value') ? true : false, {silent: true});
1073
+ });
1074
+ this.displayed_gallery.set('order_direction', model.get('value'));
1075
+ this.entities.reset();
1076
+ this.$el.find('a.sortdirection').each(function(){
1077
+ var $item = $(this);
1078
+ if ($item.attr('value') == model.get('value'))
1079
+ $item.addClass('selected');
1080
+ else
1081
+ $item.removeClass('selected');
1082
+ });
1083
+ },
1084
+
1085
+ render: function(){
1086
+ this.$el.empty();
1087
+ this.populate_sorting_fields();
1088
+ this.$el.append('<strong>Sort By:</strong>');
1089
+ this.sortorder_options.each(function(item, index){
1090
+ var button = new this.Button({model: item, className: 'sortorder'});
1091
+ this.$el.append(button.render().el);
1092
+ if (this.sortorder_options.length-1 > index) {
1093
+ this.$el.append('<span class="separator">|</span>');
1094
+ }
1095
+ }, this);
1096
+ this.$el.append('<strong style="margin-left: 30px;">Order By:</strong>');
1097
+ this.sortdirection_options.each(function(item, index){
1098
+ var button = new this.Button({model: item, className: 'sortdirection'});
1099
+ this.$el.append(button.render().el);
1100
+ if (this.sortdirection_options.length-1 > index) {
1101
+ this.$el.append('<span class="separator">|</span>');
1102
+ }
1103
+ }, this);
1104
+ return this;
1105
+ },
1106
+
1107
+ Button: Backbone.View.extend({
1108
+ tagName: 'a',
1109
+
1110
+ initialize: function(){
1111
+ _.each(this.options, function(value, key){
1112
+ this[key] = value;
1113
+ }, this);
1114
+ },
1115
+
1116
+ events: {
1117
+ click: 'clicked'
1118
+ },
1119
+
1120
+ clicked: function(e){
1121
+ e.preventDefault();
1122
+ this.model.set('selected', true);
1123
+ },
1124
+
1125
+ render: function(){
1126
+ this.$el.prop({
1127
+ value: this.model.get('value'),
1128
+ href: '#'
1129
+ });
1130
+ this.$el.text(this.model.get('title'));
1131
+ if (this.model.get('selected')) this.$el.addClass('selected');
1132
+ return this;
1133
+ }
1134
+ })
1135
+ }),
1136
+
1137
+ // Individual entity in the preview area
1138
+ EntityElement: Backbone.View.extend({
1139
+ tagName: 'li',
1140
+
1141
+ events: {
1142
+ drop: 'item_dropped'
1143
+ },
1144
+
1145
+ initialize: function(){
1146
+ _.each(this.options, function(value, key){
1147
+ this[key] = value;
1148
+ }, this);
1149
+ this.model.on('change', this.render, this);
1150
+ this.id = this.model.get('id_field')+'_'+this.model.entity_id()
1151
+ },
1152
+
1153
+ item_dropped: function(e, index){
1154
+ this.model.set('sortorder', index);
1155
+ },
1156
+
1157
+ render: function(){
1158
+ this.$el.empty();
1159
+ var image_container = $('<div/>').addClass('image_container');
1160
+ var alt_text = this.model.alttext().replace(/\\&/g, '&').replace(/\\'/g, "'");
1161
+ var timestamp = new Date().getTime();
1162
+ image_container.attr({
1163
+ title: alt_text,
1164
+ style: "background-image: url('"+this.model.get('thumb_url')+"?timestamp"+timestamp+"')"
1165
+ }).css({
1166
+ width: this.model.get('max_width'),
1167
+ height: this.model.get('max_height'),
1168
+ 'max-width': this.model.get('max_width'),
1169
+ 'max-height': this.model.get('max_height')
1170
+ });
1171
+
1172
+ this.$el.append(image_container).addClass('ui-state-default');
1173
+
1174
+ // Add exclude checkbox
1175
+ var exclude_container = $('<div/>').addClass('exclude_container');
1176
+ exclude_container.append('Exclude?');
1177
+ var exclude_checkbox = new this.ExcludeCheckbox({model: this.model});
1178
+ exclude_container.append(exclude_checkbox.render().el);
1179
+ image_container.append(exclude_container);
1180
+ return this;
1181
+ },
1182
+
1183
+ ExcludeCheckbox: Backbone.View.extend({
1184
+ tagName: 'input',
1185
+
1186
+ events: {
1187
+ 'change': 'entity_excluded'
1188
+ },
1189
+
1190
+ type_set: false,
1191
+
1192
+ entity_excluded: function(e){
1193
+ this.model.set('exclude', e.target.checked);
1194
+ },
1195
+
1196
+ initialize: function(){
1197
+ _.each(this.options, function(value, key){
1198
+ this[key] = value;
1199
+ }, this);
1200
+ this.model.on('change:exclude', this.render, this);
1201
+ },
1202
+
1203
+ render: function(){
1204
+ if (!this.type_set) {
1205
+ this.$el.attr('type', 'checkbox');
1206
+ this.type_set = true;
1207
+ }
1208
+ if (this.model.is_excluded()) this.$el.prop('checked', true);
1209
+ else this.$el.prop('checked', false);
1210
+ return this;
1211
+ }
1212
+ })
1213
+ })
1214
+ });
1215
+
1216
+
1217
+ // Additional source configuration views. These will be rendered dynamically by PHP.
1218
+ // Adapters will add them.
1219
+ Ngg.DisplayTab.Views.GalleriesSource = Backbone.View.extend({
1220
+ tagName: 'tbody',
1221
+
1222
+ initialize: function(){
1223
+ this.galleries = Ngg.DisplayTab.instance.galleries;
1224
+ },
1225
+
1226
+ render: function(){
1227
+ var select = new Ngg.Views.Chosen({
1228
+ collection: this.galleries,
1229
+ placeholder: 'Select a gallery',
1230
+ multiple: true,
1231
+ width: 500
1232
+ });
1233
+ var html = $('<tr><td><label>Galleries</label></td><td class="galleries_column"></td></tr>');
1234
+ this.$el.empty();
1235
+ this.$el.append(html);
1236
+ this.$el.find('.galleries_column').append(select.render().el);
1237
+ return this;
1238
+ }
1239
+ });
1240
+
1241
+ Ngg.DisplayTab.Views.AlbumsSource = Backbone.View.extend({
1242
+ tagName: 'tbody',
1243
+
1244
+ initialize: function(){
1245
+ this.albums = Ngg.DisplayTab.instance.albums;
1246
+ },
1247
+
1248
+ render: function(){
1249
+ var album_select = new Ngg.Views.Chosen({
1250
+ collection: this.albums,
1251
+ multiple: true,
1252
+ placeholder: 'Select an album',
1253
+ text_field: 'name',
1254
+ width: 500
1255
+ });
1256
+ this.$el.empty();
1257
+ this.$el.append('<tr><td><label>Albums</label></td><td class="albums_column"></td></tr>');
1258
+ this.$el.find('.albums_column').append(album_select.render().el);
1259
+ return this;
1260
+ }
1261
+ });
1262
+
1263
+ Ngg.DisplayTab.Views.TagsSource = Backbone.View.extend({
1264
+ tagName: 'tbody',
1265
+
1266
+ initialize: function(){
1267
+ this.tags = Ngg.DisplayTab.instance.tags;
1268
+ },
1269
+
1270
+ render: function(){
1271
+ var tag_select = new Ngg.Views.Chosen({
1272
+ collection: this.tags,
1273
+ multiple: true,
1274
+ placeholder: 'Select a tag',
1275
+ text_field: 'name',
1276
+ width: 500
1277
+ });
1278
+ this.$el.empty();
1279
+ this.$el.append('<tr><td><label>Tags</label></td><td class="tags_column"></td></tr>');
1280
+ this.$el.find('.tags_column').append(tag_select.render().el);
1281
+ return this;
1282
+ }
1283
+ });
1284
+
1285
+ Ngg.DisplayTab.Views.Recent_imagesSource = Backbone.View.extend({
1286
+ tagName: 'tbody',
1287
+
1288
+ initialize: function(){
1289
+ this.displayed_gallery = Ngg.DisplayTab.instance.displayed_gallery;
1290
+ this.maximum_entity_count = Ngg.DisplayTab.instance.displayed_gallery.get('maximum_entity_count');
1291
+ this.displayed_gallery.set('container_ids', []);
1292
+ },
1293
+
1294
+ render: function(){
1295
+ var self = this;
1296
+ var edit_field = $('<input/>').prop({
1297
+ type: 'text',
1298
+ value: this.maximum_entity_count,
1299
+ name: 'maximum_entity_count'
1300
+ });
1301
+
1302
+ edit_field.change(function () {
1303
+ self.displayed_gallery.set('maximum_entity_count', $(this).val());
1304
+ });
1305
+
1306
+ this.$el.empty();
1307
+ this.$el.append('<tr><td><label># of Images To Display</label></td><td class="recent_images_column"></td></tr>');
1308
+ this.$el.find('.recent_images_column').append(edit_field);
1309
+ return this;
1310
+ }
1311
+ });
1312
+
1313
+ Ngg.DisplayTab.Views.Random_imagesSource = Backbone.View.extend({
1314
+ tagName: 'tbody',
1315
+
1316
+ initialize: function(){
1317
+ this.displayed_gallery = Ngg.DisplayTab.instance.displayed_gallery;
1318
+ this.maximum_entity_count = Ngg.DisplayTab.instance.displayed_gallery.get('maximum_entity_count');
1319
+ this.displayed_gallery.set('container_ids', []);
1320
+ },
1321
+
1322
+ render: function(){
1323
+ var self = this;
1324
+ var edit_field = $('<input/>').prop({
1325
+ type: 'text',
1326
+ value: this.maximum_entity_count,
1327
+ name: 'maximum_entity_count'
1328
+ });
1329
+
1330
+ edit_field.change(function () {
1331
+ self.displayed_gallery.set('maximum_entity_count', $(this).val());
1332
+ });
1333
+
1334
+ this.$el.empty();
1335
+ this.$el.append('<tr><td><label># of Images To Display</label></td><td class="random_images_column"></td></tr>');
1336
+ this.$el.find('.random_images_column').append(edit_field);
1337
+ return this;
1338
+ }
1339
+ });
1340
+
1341
+ Ngg.DisplayTab.Views.SaveButton = Backbone.View.extend({
1342
+ el: '#save_displayed_gallery',
1343
+
1344
+ errors_el: '#errors',
1345
+
1346
+ displayed_gallery: null,
1347
+
1348
+ events: {
1349
+ click: 'clicked'
1350
+ },
1351
+
1352
+ initialize: function(){
1353
+ this.displayed_gallery = Ngg.DisplayTab.instance.displayed_gallery;
1354
+ this.entities = Ngg.DisplayTab.instance.entities;
1355
+ this.render();
1356
+ },
1357
+
1358
+ clicked: function(){
1359
+ this.set_display_settings();
1360
+ var request = <?php echo $sec_token?>;
1361
+ request = _.extend(request, {
1362
+ action: 'save_displayed_gallery',
1363
+ displayed_gallery: this.displayed_gallery.toJSON()
1364
+ });
1365
+
1366
+ var self = this;
1367
+ $.post(photocrati_ajax.url, request, function(response){
1368
+ if (!_.isObject(response)) response = JSON.parse(response);
1369
+ if (response['validation_errors'] != undefined) {
1370
+ $(self.errors_el).empty().append(response.validation_errors);
1371
+ }
1372
+ else if (response['error'] != undefined) {
1373
+ alert(response.error);
1374
+ }
1375
+ else {
1376
+ var id_field = response.displayed_gallery.id_field;
1377
+ var id = response.displayed_gallery[id_field];
1378
+ self.displayed_gallery.set('id', id);
1379
+ var editor = parent.tinyMCE.activeEditor;
1380
+ var preview_url = ngg_displayed_gallery_preview_url + '/id--'+id;
1381
+ var snippet = "<img class='ngg_displayed_gallery mceItem' src='" + preview_url + "'/>";
1382
+ if (editor.getContent().indexOf(preview_url) < 0)
1383
+ editor.execCommand('mceInsertContent', false, snippet);
1384
+ else {
1385
+ $(editor.contentDocument).find(".ngg_displayed_gallery[src='"+preview_url+"']").attr('src', preview_url);
1386
+ }
1387
+ close_attach_to_post_window();
1388
+ }
1389
+ });
1390
+ },
1391
+
1392
+ set_display_settings: function(){
1393
+ var display_type = this.displayed_gallery.get('display_type');
1394
+ if (display_type) {
1395
+ // Collect display settings
1396
+ var form = $("form[rel='"+display_type+"']");
1397
+ var display_settings = (function(item){
1398
+ var obj = {};
1399
+ $.each(item.serializeArray(), function(key, item) {
1400
+ var parts = item.name.split('[');
1401
+ var current_obj = obj;
1402
+ for (var i=0; i<parts.length; i++) {
1403
+ var part = parts[i].replace(/\]$/, '');
1404
+ if (!current_obj[part]) {
1405
+ if (i == parts.length-1)
1406
+ current_obj[part] = item.value;
1407
+ else
1408
+ current_obj[part] = {};
1409
+ }
1410
+ current_obj = current_obj[part];
1411
+ }
1412
+ });
1413
+ return obj;
1414
+ })(form);
1415
+
1416
+ // Set display settings for displayed gallery
1417
+ this.displayed_gallery.set('display_settings', display_settings[display_type]);
1418
+ }
1419
+ },
1420
+
1421
+ render: function(){
1422
+ return this;
1423
+ }
1424
+ });
1425
+
1426
+ /*****************************************************************************
1427
+ * APPLICATION
1428
+ **/
1429
+ Ngg.DisplayTab.App = Backbone.View.extend({
1430
+ /**
1431
+ * Initializes the DisplayTab object
1432
+ **/
1433
+ initialize: function(){
1434
+ // TODO: We're currently fetching ALL galleries, albums, and tags
1435
+ // in one shot. Instead, we should display the displayed_gallery's
1436
+ // containers, if there are any, otherwise get the first 100 or so.
1437
+ // We can then use AJAX to fetch the rest of batches.
1438
+ this.displayed_gallery = new Ngg.DisplayTab.Models.Displayed_Gallery(
1439
+ <?php echo $displayed_gallery ?>
1440
+ );
1441
+
1442
+ this.original_displayed_gallery = new Ngg.DisplayTab.Models.Displayed_Gallery(
1443
+ <?php echo $displayed_gallery ?>
1444
+ );
1445
+ this.galleries = new Ngg.DisplayTab.Models.Gallery_Collection(
1446
+ <?php echo $galleries ?>
1447
+ );
1448
+ this.albums = new Ngg.DisplayTab.Models.Album_Collection(
1449
+ <?php echo $albums ?>
1450
+ );
1451
+ this.tags = new Ngg.DisplayTab.Models.Tag_Collection(
1452
+ <?php echo $tags ?>
1453
+ );
1454
+ this.sources = new Ngg.DisplayTab.Models.Source_Collection(
1455
+ <?php echo $sources ?>
1456
+ )
1457
+ this.display_types = new Ngg.DisplayTab.Models.Display_Type_Collection(
1458
+ <?php echo $display_types ?>
1459
+ );
1460
+ this.display_type_order_base = <?php echo NEXTGEN_DISPLAY_PRIORITY_BASE; ?>;
1461
+ this.display_type_order_step = <?php echo NEXTGEN_DISPLAY_PRIORITY_STEP; ?>;
1462
+ this.entities = new Ngg.DisplayTab.Models.Entity_Collection();
1463
+ this.entities.extra_data.displayed_gallery = this.displayed_gallery;
1464
+
1465
+ // Pre-select current displayed gallery values
1466
+ if (this.displayed_gallery.get('source')) {
1467
+
1468
+ // Pre-select source
1469
+ if (this.displayed_gallery.get('source')) {
1470
+ var source = this.sources.find(function(item){
1471
+ return item.get('name') == this.displayed_gallery.get('source');
1472
+ }, this);
1473
+ if (source) source.set('selected', true);
1474
+ }
1475
+
1476
+ // Pre-select containers
1477
+ if (this.displayed_gallery.get('container_ids')) {
1478
+ _.each(this.displayed_gallery.get('container_ids'), function(id){
1479
+ var container = this[this.displayed_gallery.get('source')].find(function(item){
1480
+ return item.id == id;
1481
+ }, this);
1482
+ if (container) container.set('selected', true);
1483
+ }, this);
1484
+ }
1485
+
1486
+ // Pre-select display type
1487
+ if (this.displayed_gallery.get('display_type')) {
1488
+ var display_type = this.display_types.find(function(item){
1489
+ return item.get('name') == this.displayed_gallery.get('display_type');
1490
+ }, this);
1491
+ if (display_type) display_type.set('selected', true);
1492
+ }
1493
+ }
1494
+
1495
+ // Bind to the 'selected' event for each of the collections, and update the displayed
1496
+ // gallery object's 'container_ids' attribute when something has changed
1497
+ collections = ['galleries', 'albums', 'tags'];
1498
+ _.each(collections, function(collection){
1499
+ this[collection].on('selected', function(){this.update_selected_containers(collection);}, this);
1500
+ }, this);
1501
+
1502
+ // Bind to the 'selected' event for the display types collection, updating the displayed gallery
1503
+ this.display_types.on('change:selected', function(){
1504
+ this.displayed_gallery.set('display_type', this.display_types.selected_value());
1505
+ }, this);
1506
+
1507
+ // Bind to the 'selected' event for the source, updating the displayed gallery
1508
+ this.sources.on('selected', function(){
1509
+ this.displayed_gallery.set('source', this.sources.selected_value());
1510
+
1511
+ // If the source changed, and it's not the set to the original value, then
1512
+ // exclusions get's set to []
1513
+ if (this.sources.selected_value() != this.original_displayed_gallery.get('source'))
1514
+ this.displayed_gallery.set('exclusions', this.entities.excluded_ids());
1515
+
1516
+ // Otherwise, we revert to the original exclusions
1517
+ else
1518
+ this.displayed_gallery.set('exclusions', this.original_displayed_gallery.get('exclusions'));
1519
+
1520
+ // special exemption: these should default to a reasonable limit
1521
+ if (this.sources.selected_value() == 'random_images' || this.sources.selected_value() == 'recent_images') {
1522
+ this.displayed_gallery.set('maximum_entity_count', 20);
1523
+ }
1524
+
1525
+ // Reset everything else
1526
+ this.galleries.deselect_all();
1527
+ this.albums.deselect_all();
1528
+ this.tags.deselect_all();
1529
+
1530
+ // If the selected source is incompatible with the current display type, then
1531
+ // display a new list
1532
+ var selected_display_type = this.display_types.selected();
1533
+ var selected_source = this.sources.selected();
1534
+ if (selected_display_type.length > 0 && selected_source.length > 0) {
1535
+ selected_display_type = selected_display_type[0];
1536
+ selected_source = selected_source[0];
1537
+ if (!selected_display_type.is_compatible_with_source(selected_source))
1538
+ this.display_types.deselect_all();
1539
+ if (this.display_type_selector) this.display_type_selector.render();
1540
+ }
1541
+ if (this.preview_area) this.preview_area.render();
1542
+ }, this);
1543
+
1544
+ // Synchronize changes made to entities with the displayed gallery
1545
+ this.entities.on('change:exclude finished_fetching', function(){
1546
+ //this.displayed_gallery.set('sortorder', this.entities.entity_ids());
1547
+ this.displayed_gallery.set('exclusions', this.entities.excluded_ids());
1548
+ }, this);
1549
+
1550
+ // Monitor events in other tabs and respond as appropriate
1551
+ if (window.Frame_Event_Publisher) {
1552
+ var app = this;
1553
+
1554
+ // New gallery event
1555
+ Frame_Event_Publisher.listen_for('attach_to_post:new_gallery', function(){
1556
+ app.galleries.reset();
1557
+ app.galleries.fetch();
1558
+ });
1559
+
1560
+ // A change has been made using the "Manage Galleries" page
1561
+ Frame_Event_Publisher.listen_for('attach_to_post:manage_galleries attach_to_post:manage_images', function(data){
1562
+
1563
+ // Refresh the list of galleries
1564
+ app.galleries.reset();
1565
+ app.galleries.fetch();
1566
+
1567
+ // If we're viewing galleries or images, then we need to refresh the entity list
1568
+ var selected_source = app.sources.selected().pop();
1569
+ if (selected_source) {
1570
+ if (_.indexOf(selected_source.get('returns'), 'image') >= 0 ||
1571
+ _.indexOf(selected_source.get('returns'), 'gallery')) {
1572
+ app.entities.reset();
1573
+ }
1574
+ }
1575
+ });
1576
+
1577
+ // A change has been made using the "Manage Albums" page
1578
+ Frame_Event_Publisher.listen_for('attach_to_post:manage_album', function(data){
1579
+ // Refresh the list of albums
1580
+ app.albums.reset();
1581
+ app.albums.fetch();
1582
+
1583
+ // If we're viewing albums, then we need to refresh the entity list
1584
+ var selected_source = app.sources.selected().pop();
1585
+ if (selected_source) {
1586
+ if (_.indexOf(selected_source.get('returns'), 'album') >= 0) {
1587
+ app.entities.reset();
1588
+ }
1589
+ }
1590
+ });
1591
+
1592
+ // A change has been made using the "Manage Tags" page
1593
+ Frame_Event_Publisher.listen_for('attach_to_post:manage_tags attach_to_post:manage_images', function(data){
1594
+ // Refresh the list of tags
1595
+ app.tags.reset();
1596
+ app.tags.fetch();
1597
+
1598
+ // If we're viewing galleries or images, then we need to refresh the entity list
1599
+ var selected_source = app.sources.selected().pop();
1600
+ if (selected_source) {
1601
+ if (_.indexOf(selected_source.get('returns'), 'image') >= 0 ||
1602
+ _.indexOf(selected_source.get('returns'), 'gallery')) {
1603
+ app.entities.reset();
1604
+ }
1605
+ }
1606
+ });
1607
+
1608
+ // Thumbnail modified event
1609
+ Frame_Event_Publisher.listen_for('attach_to_post:thumbnail_modified', function(data){
1610
+ var selected_source = app.sources.selected().pop();
1611
+ var image_id = data.image[data.image.id_field];
1612
+
1613
+ if (selected_source) {
1614
+
1615
+ // Does the currently selected source return images? If so,
1616
+ // check refresh the modified image's thumbnail
1617
+ if(_.indexOf(selected_source.get('returns'), 'image') >= 0) {
1618
+ var image = app.entities.find(function(item){
1619
+ return parseInt(item.entity_id()) == parseInt(image_id);
1620
+ }, this);
1621
+ if (image) image.set('thumb_url', data.image.thumb_url);
1622
+ }
1623
+
1624
+ // It must be an album or gallery
1625
+ else {
1626
+ var entity = app.entities.find(function(item){
1627
+ return parseInt(item.get('previewpic')) == image_id;
1628
+ }, this);
1629
+ if (entity) entity.trigger('change');
1630
+ }
1631
+ }
1632
+ });
1633
+ }
1634
+ },
1635
+
1636
+ // Updates the selected container_ids for the displayed gallery
1637
+ update_selected_containers: function(collection){
1638
+ this.displayed_gallery.set('container_ids', this[collection].selected_ids());
1639
+ },
1640
+
1641
+ render: function(){
1642
+ this.display_type_selector = new Ngg.DisplayTab.Views.Display_Type_Selector();
1643
+ new Ngg.DisplayTab.Views.Source_Config();
1644
+ new Ngg.DisplayTab.Views.Slug_Config();
1645
+ this.preview_area = new Ngg.DisplayTab.Views.Preview_Area();
1646
+ new Ngg.DisplayTab.Views.SaveButton();
1647
+ }
1648
+ });
1649
+ Ngg.DisplayTab.instance = new Ngg.DisplayTab.App();
1650
+ Ngg.DisplayTab.instance.render();
1651
+
1652
+ // Invoke styling libraries
1653
+ $('span.tooltip, label.tooltip').tooltip();
1654
+ });
products/photocrati_nextgen/modules/attach_to_post/templates/display_tab_source.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <table id="source_configuration"></table>
2
+ <table id='slug_configuration'></table>
products/photocrati_nextgen/modules/attach_to_post/templates/display_tab_type.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <div id="display_type_selector">
2
+
3
+ </div>
products/photocrati_nextgen/modules/attach_to_post/templates/no_display_type_selected.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <p class="<?php echo esc_attr($css_class) ?>">
2
+ <?php echo_h($no_display_type_selected)?>
3
+ </p>
products/photocrati_nextgen/modules/attach_to_post/templates/preview_tab.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <div id="preview_area">
2
+
3
+ </div>
products/photocrati_nextgen/modules/cache/class.cache.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Cache extends C_Component
4
+ {
5
+ public static $_instances = array();
6
+
7
+ function define($context = FALSE)
8
+ {
9
+ parent::define($context);
10
+ $this->add_mixin('Mixin_Cache');
11
+ $this->implement('I_Cache');
12
+ }
13
+
14
+ public static function get_instance($context = False)
15
+ {
16
+ if (!isset(self::$_instances[$context]))
17
+ {
18
+ self::$_instances[$context] = new C_Cache($context);
19
+ }
20
+ return self::$_instances[$context];
21
+ }
22
+ }
23
+
24
+ class Mixin_Cache extends Mixin
25
+ {
26
+ /**
27
+ * Empties a directory of all of its content
28
+ *
29
+ * @param string $directory Absolute path
30
+ * @param bool $recursive Remove files from subdirectories of the cache
31
+ * @param string $regex (optional) Only remove files matching pattern; '/^.+\.png$/i' will match all .png
32
+ */
33
+ public function flush_directory($directory, $recursive = TRUE, $regex = NULL)
34
+ {
35
+ // It is possible that the cache directory has not been created yet
36
+ if (!is_dir($directory))
37
+ {
38
+ return;
39
+ }
40
+
41
+ if ($recursive)
42
+ {
43
+ $directory = new DirectoryIterator($directory);
44
+ }
45
+ else {
46
+ $directory = new RecursiveIteratorIterator(
47
+ new RecursiveDirectoryIterator($directory),
48
+ RecursiveIteratorIterator::CHILD_FIRST
49
+ );
50
+ }
51
+
52
+ if (!is_null($regex))
53
+ {
54
+ $iterator = RegexIterator($directory, $regex, RecursiveRegexIterator::GET_MATCH);
55
+ }
56
+ else {
57
+ $iterator = $directory;
58
+ }
59
+
60
+ foreach ($iterator as $file) {
61
+ if ($file->isFile() || $file->isLink()) {
62
+ unlink($file->getPathname());
63
+ }
64
+ elseif ($file->isDir() && !$file->isDot() && $recursive) {
65
+ rmdir($file->getPathname());
66
+ }
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Flushes cache from all available galleries
72
+ *
73
+ * @param array $galleries When provided only the requested galleries' cache is flushed
74
+ */
75
+ public function flush_galleries($galleries = array())
76
+ {
77
+ if (empty($galleries))
78
+ $galleries = $this->object->get_registry()->get_utility('I_Gallery_Mapper')->find_all();
79
+
80
+ foreach ($galleries as $gallery) {
81
+ $this->object->get_registry()->get_utility('I_Gallery_Storage')->flush_cache($gallery);
82
+ }
83
+ }
84
+
85
+ }
products/photocrati_nextgen/modules/cache/interface.cache.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Cache
4
+ {
5
+ function flush_directory($directory, $recursive = TRUE, $regex = NULL);
6
+ function flush_galleries($galleries = array());
7
+ }
products/photocrati_nextgen/modules/cache/module.cache.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /***
3
+ {
4
+ Module: photocrati-cache
5
+ }
6
+ ***/
7
+ class M_Cache extends C_Base_Module
8
+ {
9
+ /**
10
+ * Defines the module name & version
11
+ */
12
+ function define()
13
+ {
14
+ parent::define(
15
+ 'photocrati-cache',
16
+ 'Cache',
17
+ 'Handles clearing of NextGen caches',
18
+ '0.1',
19
+ 'http://www.nextgen-gallery.com',
20
+ 'Photocrati Media',
21
+ 'http://www.photocrati.com'
22
+ );
23
+ }
24
+
25
+ /**
26
+ * Register utilities
27
+ */
28
+ function _register_utilities()
29
+ {
30
+ $this->get_registry()->add_utility('I_Cache', 'C_Cache');
31
+ }
32
+
33
+ function get_type_list()
34
+ {
35
+ return array(
36
+ 'C_Cache' => 'class.cache.php',
37
+ 'I_Cache' => 'interface.cache.php'
38
+ );
39
+ }
40
+ }
41
+
42
+ new M_Cache();
products/photocrati_nextgen/modules/datamapper/README.txt ADDED
@@ -0,0 +1 @@
 
1
+ See the datamapper unit tests for details about the API
products/photocrati_nextgen/modules/datamapper/adapter.datamapper_factory.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_DataMapper_Factory extends Mixin
4
+ {
5
+ function datamapper_model($mapper, $properties=array(), $context=FALSE)
6
+ {
7
+ return new C_DataMapper_Model($mapper, $properties=array(), $context);
8
+ }
9
+
10
+ function datamapper($object_name, $context=FALSE)
11
+ {
12
+ return new C_DataMapper($object_name, $context);
13
+ }
14
+
15
+ function custom_table_datamapper($object_name, $context=FALSE)
16
+ {
17
+ return new C_CustomTable_DataMapper_Driver($object_name, $context);
18
+ }
19
+
20
+ function custom_post_datamapper($object_name, $context=FALSE)
21
+ {
22
+ return new C_CustomPost_DataMapper_Driver($object_name, $context);
23
+ }
24
+ }
products/photocrati_nextgen/modules/datamapper/class.custompost_datamapper_driver.php ADDED
@@ -0,0 +1,547 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Mixin_CustomPost_DataMapper_Driver extends Mixin
4
+ {
5
+
6
+ /**
7
+ * Returns a list of querable table columns for posts
8
+ * @return array
9
+ */
10
+ function _get_querable_table_columns()
11
+ {
12
+ return array('name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count');
13
+ }
14
+
15
+ /**
16
+ * Used to select which fields should be returned. NOT currently used by
17
+ * this implementation of the datamapper driver
18
+ * @param type $fields
19
+ * @return C_DataMapper_Driver_Base
20
+ */
21
+ function select($fields='*')
22
+ {
23
+ $this->object->_query_args = array(
24
+ 'post_type' => $this->object->get_object_name(),
25
+ 'paged' => FALSE,
26
+ 'fields' => $fields,
27
+ 'post_status' => 'any',
28
+ 'datamapper' => TRUE,
29
+ 'posts_per_page'=> -1,
30
+ 'is_select' => TRUE,
31
+ 'is_delete' => FALSE
32
+ );
33
+ return $this->object;
34
+ }
35
+
36
+
37
+ /**
38
+ * Specifies an order clause
39
+ * @param type $order_by
40
+ * @param type $direction
41
+ * @return C_DataMapper_Driver_Base
42
+ */
43
+ function order_by($order_by, $direction='ASC')
44
+ {
45
+ // Make an exception for the rand() method
46
+ $order_by = preg_replace("/rand\(\s*\)/", 'rand', $order_by);
47
+
48
+ if (in_array($order_by, $this->object->_get_querable_table_columns())) {
49
+ $this->object->_query_args['orderby'] = $order_by;
50
+ }
51
+ else { // ordering by a meta value
52
+ $this->object->_query_args['orderby'] = 'meta_value';
53
+ $this->object->_query_args['meta_key'] = $order_by;
54
+ }
55
+ $this->object->_query_args['order'] = $direction;
56
+
57
+ return $this->object;
58
+ }
59
+
60
+ /**
61
+ * Specifies a limit and optional offset
62
+ * @param integer $max
63
+ * @param integer $offset
64
+ * @return C_DataMapper_Driver_Base
65
+ */
66
+ function limit($max, $offset=FALSE)
67
+ {
68
+ if ($max) {
69
+ $this->object->_query_args['paged'] = TRUE;
70
+ $this->object->_query_args['offset'] = $offset;
71
+ $this->object->_query_args['posts_per_page'] = $max;
72
+ }
73
+
74
+ return $this->object;
75
+ }
76
+
77
+
78
+ /**
79
+ * Specifies a list of columns to group by
80
+ * @param array|string $columns
81
+ */
82
+ function group_by($columns=array())
83
+ {
84
+ if (!isset($this->object->_query_args['group_by_columns']))
85
+ $this->object->_query_args['group_by_columns'] = $columns;
86
+ else {
87
+ $this->object->_query_args['group_by_columns'] = array_merge(
88
+ $this->object->_query_args['group_by_columns'],
89
+ $columns
90
+ );
91
+ }
92
+
93
+ return $this->object;
94
+ }
95
+
96
+ /**
97
+ * Adds a WP_Query where clause
98
+ * @param array $where_clauses
99
+ * @param string $join
100
+ */
101
+ function _add_where_clause($where_clauses, $join)
102
+ {
103
+ foreach ($where_clauses as $clause) {
104
+ // $clause => array(
105
+ // 'column' => 'ID',
106
+ // 'value' => 1210,
107
+ // 'compare' => '='
108
+ // )
109
+
110
+ // Determine where what the where clause is comparing
111
+ switch($clause['column']) {
112
+ case 'author':
113
+ case 'author_id':
114
+ $this->object->_query_args['author'] = $clause['value'];
115
+ break;
116
+ case 'author_name':
117
+ $this->object->_query_args['author_name'] = $clause['value'];
118
+ break;
119
+ case 'cat':
120
+ case 'cat_id':
121
+ case 'category_id':
122
+ switch($clause['compare']) {
123
+ case '=':
124
+ case 'BETWEEN';
125
+ case 'IN';
126
+ if (!isset($this->object->_query_args['category__in'])) {
127
+ $this->object->_query_args['category__in'] = array();
128
+ }
129
+ $this->object->_query_args['category__in'][] = $clause['value'];
130
+ break;
131
+ case '!=':
132
+ case 'NOT BETWEEN';
133
+ case 'NOT IN';
134
+ if (!isset($this->object->_query_args['category__not_in'])) {
135
+ $this->object->_query_args['category__not_in'] = array();
136
+ }
137
+ $this->object->_query_args['category__not_in'][] = $clause['value'];
138
+ break;
139
+ }
140
+ break;
141
+ case 'category_name':
142
+ $this->object->_query_args['category_name'] = $clause['value'];
143
+ break;
144
+ case 'post_id':
145
+ case $this->object->get_primary_key_column():
146
+ switch ($clause['compare']) {
147
+ case '=':
148
+ case 'IN';
149
+ case 'BETWEEN';
150
+ if (!isset($this->object->_query_args['post__in'])) {
151
+ $this->object->_query_args['post__in'] = array();
152
+ }
153
+ $this->object->_query_args['post__in'][] = $clause['value'];
154
+ break;
155
+ default:
156
+ if (!isset($this->object->_query_args['post__not_in'])) {
157
+ $this->object->_query_args['post__not_in'] = array();
158
+ }
159
+ $this->object->_query_args['post__not_in'][] = $clause['value'];
160
+ break;
161
+ }
162
+ break;
163
+ case 'pagename':
164
+ case 'postname':
165
+ case 'page_name':
166
+ case 'post_name':
167
+ if ($clause['compare'] == 'LIKE')
168
+ $this->object->_query_args['page_name__like'] = $clause['value'];
169
+ elseif ($clause['compare'] == '=')
170
+ $this->object->_query_args['pagename'] = $clause['value'];
171
+ elseif ($clause['compare'] == 'IN')
172
+ $this->object->_query_args['page_name__in'] = $clause['value'];
173
+ break;
174
+ case 'post_title':
175
+ // Post title uses custom WHERE clause
176
+ if ($clause['compare'] == 'LIKE')
177
+ $this->object->_query_args['post_title__like'] = $clause['value'];
178
+ else
179
+ $this->object->_query_args['post_title'] = $clause['value'];
180
+ break;
181
+ default:
182
+ // Must be metadata
183
+ $clause['key'] = $clause['column'];
184
+ unset($clause['column']);
185
+
186
+ // Convert values to array, when required
187
+ if (in_array($clause['compare'], array('IN', 'BETWEEN'))) {
188
+ $clause['value'] = explode(',', $clause['value']);
189
+ foreach ($clause['value'] as &$val) {
190
+ if (!is_numeric($val)) {
191
+
192
+ // In the _parse_where_clause() method, we
193
+ // quote the strings and add slashes
194
+ $val = stripslashes($val);
195
+ $val = substr($val, 1, strlen($val)-2);
196
+ }
197
+ }
198
+ }
199
+
200
+ if (!isset($this->object->_query_args['meta_query'])) {
201
+ $this->object->_query_args['meta_query'] = array();
202
+ }
203
+ $this->object->_query_args['meta_query'][] = $clause;
204
+ break;
205
+ }
206
+ }
207
+
208
+ // If any where clauses have been added, specify how the conditions
209
+ // will be conbined/joined
210
+ if (isset($this->object->_query_args['meta_query'])) {
211
+ $this->object->_query_args['meta_query']['relation'] = $join;
212
+ }
213
+
214
+ }
215
+
216
+
217
+ /**
218
+ * Destroys/deletes an entity from the database
219
+ * @param stdObject|C_DataMapper_Model $entity
220
+ * @return type
221
+ */
222
+ function destroy($entity, $skip_trash=TRUE)
223
+ {
224
+ $retval = FALSE;
225
+
226
+ $key = $this->object->get_primary_key_column();
227
+
228
+ // Find the id of the entity
229
+ if (is_object($entity) && isset($entity->$key)) {
230
+ $id = (int)$entity->$key;
231
+ }
232
+ else {
233
+ $id = (int)$entity;
234
+ }
235
+
236
+ // If we have an ID, then delete the post
237
+ if (is_integer($id)) {
238
+
239
+ // TODO: We assume that we can skip the trash. Is that correct?
240
+ // FYI, Deletes postmeta as wells
241
+ if (is_object(wp_delete_post($id, TRUE))) $retval = TRUE;
242
+ }
243
+
244
+ return $retval;
245
+ }
246
+
247
+ /**
248
+ * Converts a post to an entity
249
+ * @param \stdClass $post
250
+ * @param boolean $model
251
+ * @return \stdClass
252
+ */
253
+ function convert_post_to_entity($post, $model=FALSE)
254
+ {
255
+
256
+ $entity = new stdClass();
257
+ foreach ($post as $key => $value) {
258
+ if ($key == 'post_content') {
259
+ $post_content = $this->object->unserialize($value);
260
+ if ($post_content) {
261
+ foreach ($post_content as $key2 => $value2) {
262
+ $entity->$key2 = $value2;
263
+ }
264
+ }
265
+ }
266
+ else $entity->$key = $value;
267
+ }
268
+ $this->object->_convert_to_entity($entity);
269
+ return $model? $this->object->convert_to_model($entity) : $entity;
270
+ }
271
+
272
+
273
+ /**
274
+ * Converts an entity to a post
275
+ * @param type $entity
276
+ * @return type
277
+ */
278
+ function _convert_entity_to_post($entity)
279
+ {
280
+ // Was a model passed instead of an entity?
281
+ $post = $entity;
282
+ if (!($entity instanceof stdClass)) $post = $entity->get_entity();
283
+
284
+ // Create the post content
285
+ unset($post->id_field);
286
+ unset($post->post_content_filtered);
287
+ unset($post->post_content);
288
+ $post->post_content = $this->object->serialize($post);
289
+ $post->post_content_filtered = $post->post_content;
290
+ $post->post_type = $this->object->get_object_name();
291
+
292
+ // Sometimes an entity can contain a data stored in an array or object
293
+ // Those will be removed from the post, and serialized in the
294
+ // post_content field
295
+ foreach ($post as $key => $value) {
296
+ if (in_array(strtolower(gettype($value)), array('object','array')))
297
+ unset($post->$key);
298
+ }
299
+
300
+ // A post required a title
301
+ if (!property_exists($post, 'post_title')) {
302
+ $post->post_title = $this->object->get_post_title($post);
303
+ }
304
+
305
+ // A post also requires an excerpt
306
+ if (!property_exists($post, 'post_excerpt')) {
307
+ $post->post_excerpt = $this->object->get_post_excerpt($post);
308
+ }
309
+
310
+ return $post;
311
+ }
312
+
313
+ /**
314
+ * Returns the WordPress database class
315
+ * @global wpdb $wpdb
316
+ * @return wpdb
317
+ */
318
+ function _wpdb()
319
+ {
320
+ global $wpdb;
321
+ return $wpdb;
322
+ }
323
+
324
+
325
+ /**
326
+ * Flush and update all postmeta for a particular post
327
+ * @param int $post_id
328
+ */
329
+ function _flush_and_update_postmeta($post_id, $entity, $omit=array())
330
+ {
331
+ // We need to insert post meta data for each property
332
+ // Unfortunately, that means flushing all existing postmeta
333
+ // and then inserting new values. Depending on the number of
334
+ // properties, this could be slow. So, we directly access the database
335
+ /* @var $wpdb wpdb */
336
+ global $wpdb;
337
+ if (!is_array($omit)) $omit = array($omit);
338
+ $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE post_id = %s", $post_id));
339
+ $sql_parts = array();
340
+ foreach($entity as $key => $value) {
341
+ if (in_array($key, $omit)) continue;
342
+ if (is_array($value) or is_object($value)) {
343
+ $value = $this->object->serialize($value);
344
+ }
345
+ $sql_parts[] = $wpdb->prepare("(%s, %s, %s)", $post_id, $key, $value);
346
+ }
347
+ $wpdb->query("INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) VALUES ".implode(',', $sql_parts));
348
+ }
349
+
350
+
351
+ /**
352
+ * Saves an entity to the database
353
+ * @param stdObject $entity
354
+ */
355
+ function _save_entity($entity)
356
+ {
357
+ $post = $this->object->_convert_entity_to_post($entity);
358
+ $primary_key = $this->object->get_primary_key_column();
359
+
360
+ if (($post_id = wp_insert_post($post))) {
361
+
362
+ $new_entity = $this->object->find($post_id, TRUE);
363
+ foreach ($new_entity->get_entity() as $key => $value) $entity->$key = $value;
364
+
365
+ // Save properties as post meta
366
+ $this->object->_flush_and_update_postmeta(
367
+ $post_id,
368
+ $entity instanceof stdClass ? $entity : $entity->get_entity()
369
+ );
370
+ }
371
+
372
+ $entity->id_field = $primary_key;
373
+
374
+ return $post_id;
375
+ }
376
+
377
+
378
+ /**
379
+ * Determines whether the current statement is SELECT
380
+ * @return boolean
381
+ */
382
+ function is_select_statement()
383
+ {
384
+ return isset($this->object->_query_args['is_select']) && $this->object->_query_args['is_select'];
385
+ }
386
+
387
+
388
+ /**
389
+ * Determines whether the current statement is DELETE
390
+ * @return type
391
+ */
392
+ function is_delete_statement()
393
+ {
394
+ return isset($this->object->_query_args['is_delete']) && $this->object->_query_args['is_delete'];
395
+ }
396
+
397
+
398
+ /**
399
+ * Starts a new DELETE statement
400
+ */
401
+ function delete()
402
+ {
403
+ $this->object->select();
404
+ $this->object->_query_args['is_select'] = FALSE;
405
+ $this->object->_query_args['is_delete'] = TRUE;
406
+ return $this->object;
407
+ }
408
+
409
+
410
+ /**
411
+ * Runs the query
412
+ * @param string $sql optionally run the specified query
413
+ * @return array
414
+ */
415
+ function run_query($sql=FALSE, $model=FALSE)
416
+ {
417
+ $retval = array();
418
+
419
+ if ($sql)
420
+ {
421
+ $this->object->_query_args['cache_results'] = FALSE;
422
+ $this->object->_query_args['custom_sql'] = $sql;
423
+ }
424
+
425
+ // Execute the query
426
+ $query = new WP_Query();
427
+ $query->query_vars = $this->object->_query_args;
428
+ add_action('pre_get_posts', array(&$this, 'set_query_args'), PHP_INT_MAX-1, 1);
429
+ foreach ($query->get_posts() as $row) {
430
+ $row = $this->object->convert_post_to_entity($this->scrub_result($row), $model);
431
+ if (!$model)
432
+ $row->id_field = $this->object->get_primary_key_column();
433
+ $retval[] = $row;
434
+ }
435
+ remove_action('pre_get_posts', array(&$this, 'set_query_args'), PHP_INT_MAX-1, 1);
436
+
437
+ return $retval;
438
+ }
439
+
440
+ /**
441
+ * Ensure that the query args are set. We need to do this in case a third-party
442
+ * plugin overrides our query
443
+ * @param $query
444
+ */
445
+ function set_query_args($query)
446
+ {
447
+ if ($query->get('datamapper')) $query->query_vars = $this->object->_query_args;
448
+ }
449
+
450
+ /**
451
+ * Fetches the last row
452
+ * @param array $conditions
453
+ * @return C_DataMapper_Entity
454
+ */
455
+ function find_last($conditions=array(), $model=FALSE)
456
+ {
457
+ $retval = NULL;
458
+
459
+ // Get row number for the last row
460
+ $table_name = $this->object->_clean_column($this->object->get_table_name());
461
+ $object_name = $this->object->_clean_column($this->object->get_object_name());
462
+ $sql = $this->_wpdb()->prepare("SELECT COUNT(*) FROM {$table_name} WHERE post_type = %s", $object_name);
463
+ $count = $this->_wpdb()->get_var($sql);
464
+ $offset = $count-1;
465
+ $results = $this->select()->where_and($conditions)->limit(1, $offset)->run_query();
466
+ if ($results) {
467
+ $retval = $model? $this->object->convert_to_model($results[0]) : $results[0];
468
+ }
469
+
470
+ return $retval;
471
+ }
472
+
473
+
474
+
475
+ /**
476
+ * Returns the number of total records/entities that exist
477
+ * @return int
478
+ */
479
+ function count()
480
+ {
481
+ $retval = 0;
482
+
483
+ global $wpdb;
484
+ $key = $this->object->get_primary_key_column();
485
+ $sql = $wpdb->prepare(
486
+ "SELECT COUNT({$key}) FROM {$wpdb->posts} WHERE post_type = %s",
487
+ $this->object->get_object_name()
488
+ );
489
+ $results = $this->object->run_query($sql);
490
+ if ($results && isset($results[0]->$key))
491
+ $retval = (int)$results[0]->$key;
492
+
493
+ return $retval;
494
+ }
495
+
496
+
497
+ /**
498
+ * Returns the title of the post. Used when post_title is not set
499
+ * @param stdClass $entity
500
+ * @return string
501
+ */
502
+ function get_post_title($entity)
503
+ {
504
+ return "Untitled {$this->object->get_object_name()}";
505
+ }
506
+
507
+ /**
508
+ * Returns the excerpt of the post. Used when post_excerpt is not set
509
+ * @param stdClass $entity
510
+ * @return string
511
+ */
512
+ function get_post_excerpt($entity)
513
+ {
514
+ return '';
515
+ }
516
+ }
517
+
518
+ class C_CustomPost_DataMapper_Driver extends C_DataMapper_Driver_Base
519
+ {
520
+ var $_query_args = array();
521
+ var $_primary_key_column = 'ID';
522
+
523
+ function define($object_name, $context=FALSE)
524
+ {
525
+ parent::define($object_name, $context);
526
+ $this->add_mixin('Mixin_CustomPost_DataMapper_Driver');
527
+ $this->implement('I_CustomPost_DataMapper');
528
+ }
529
+
530
+ function initialize($object_name)
531
+ {
532
+ if (strlen($object_name) > 20) throw new Exception("The custom post name can be no longer than 20 characters long");
533
+ parent::initialize($object_name);
534
+ }
535
+
536
+
537
+ /**
538
+ * Gets the name of the table
539
+ * @global string $table_prefix
540
+ * @return string
541
+ */
542
+ function get_table_name()
543
+ {
544
+ global $table_prefix;
545
+ return $table_prefix.'posts';
546
+ }
547
+ }
products/photocrati_nextgen/modules/datamapper/class.customtable_datamapper_driver.php ADDED
@@ -0,0 +1,486 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_CustomTable_DataMapper_Driver_Mixin extends Mixin
4
+ {
5
+ /**
6
+ * Gets the name of the primary key column
7
+ * @return string
8
+ */
9
+ function get_primary_key_column()
10
+ {
11
+ return $this->object->_primary_key_column;
12
+ }
13
+
14
+
15
+ /**
16
+ * Selects which fields to collect from the table.
17
+ * NOTE: Not protected from SQL injection - DO NOT let your users
18
+ * specify DB columns
19
+ * @param string $fields
20
+ */
21
+ function select($fields='*')
22
+ {
23
+ // Create a fresh slate
24
+ $this->object->_init();
25
+ $this->object->_select_clause = "SELECT {$fields}";
26
+
27
+ return $this->object;
28
+ }
29
+
30
+ /**
31
+ * Determines whether we're going to execute a SELECT statement
32
+ * @return boolean
33
+ */
34
+ function is_select_statement()
35
+ {
36
+ return ($this->object->_select_clause) ? TRUE : FALSE;
37
+ }
38
+
39
+ /**
40
+ * Determines if we're going to be executing a DELETE statement
41
+ * @return type
42
+ */
43
+ function is_delete_statement()
44
+ {
45
+ return $this->object->_delete_clause ? TRUE : FALSE;
46
+ }
47
+
48
+
49
+ /**
50
+ * Start a delete statement
51
+ */
52
+ function delete()
53
+ {
54
+ // Create a fresh slate
55
+ $this->object->_init();
56
+ $this->object->_delete_clause = "DELETE";
57
+ return $this->object;
58
+ }
59
+
60
+
61
+ /**
62
+ * Orders the results of the query
63
+ * This method may be used multiple of times to order by more than column
64
+ * @param $order_by
65
+ * @param $direction
66
+ */
67
+ function order_by($order_by, $direction='ASC')
68
+ {
69
+ // We treat the rand() function as an exception
70
+ if (preg_match("/rand\(\s*\)/", $order_by)) {
71
+ $order = 'rand()';
72
+ }
73
+ else {
74
+ $order_by = $this->object->_clean_column($order_by);
75
+
76
+ // If the order by clause is a column, then it should be backticked
77
+ if ($this->object->has_column($order_by)) $order_by = "`{$order_by}`";
78
+
79
+ $direction = $this->object->_clean_column($direction);
80
+ $order = "{$order_by} {$direction}";
81
+ }
82
+
83
+ $this->object->_order_clauses[] = $order;
84
+
85
+ return $this->object;
86
+ }
87
+
88
+ /**
89
+ * Specifies a limit and optional offset
90
+ * @param integer $max
91
+ * @param integer $offset
92
+ */
93
+ function limit($max, $offset=0)
94
+ {
95
+ if ($offset)
96
+ $limit = $this->_wpdb()->prepare("LIMIT %d, %d",$offset,$max);
97
+ else
98
+ $limit = $this->_wpdb()->prepare("LIMIT %d", $max);
99
+ if ($limit) $this->object->_limit_clause = $limit;
100
+
101
+ return $this->object;
102
+ }
103
+
104
+
105
+ /**
106
+ * Specifics a group by clause for one or more columns
107
+ * @param array|string $columns
108
+ */
109
+ function group_by($columns=array())
110
+ {
111
+ if (!is_array($columns)) $columns = array($columns);
112
+ $this->object->_group_by_columns = array_merge($this->object->_group_by_columns, $columns);
113
+ return $this->object;
114
+ }
115
+
116
+
117
+ /**
118
+ * Adds a where clause to the driver
119
+ * @param array $where_clauses
120
+ * @param string $join
121
+ */
122
+ function _add_where_clause($where_clauses, $join)
123
+ {
124
+ $clauses = array();
125
+
126
+ foreach ($where_clauses as $clause) {
127
+ extract($clause);
128
+ if ($this->object->has_column($column)) $column = "`{$column}`";
129
+ if (!is_array($value)) $value = array($value);
130
+ foreach ($value as $index => $v) {
131
+ $v = $clause['type'] == 'numeric' ? $v : "'{$v}'";
132
+ $value[$index] = $v;
133
+ }
134
+ if ($compare == 'BETWEEN') {
135
+ $value = "{$value[0]} AND {$value[1]}";
136
+ }
137
+ else {
138
+ $value = implode(', ', $value);
139
+ if (strpos($compare, 'IN') !== FALSE) $value = "({$value})";
140
+ }
141
+
142
+ $clauses[] = "{$column} {$compare} {$value}";
143
+ }
144
+
145
+ $this->object->_where_clauses[] = implode(" {$join} ", $clauses);
146
+ }
147
+
148
+
149
+ /**
150
+ * Returns the total number of entities known
151
+ * @return type
152
+ */
153
+ function count()
154
+ {
155
+ $retval = 0;
156
+
157
+ $key = $this->object->get_primary_key_column();
158
+ $results = $this->object->run_query(
159
+ "SELECT COUNT(`{$key}`) AS `{$key}` FROM `{$this->object->get_table_name()}`"
160
+ );
161
+ if ($results && isset($results[0]->$key))
162
+ $retval = (int)$results[0]->$key;
163
+
164
+ return $retval;
165
+ }
166
+
167
+ /**
168
+ * Returns the generated SQL query to be executed
169
+ * @return string
170
+ */
171
+ function get_generated_query()
172
+ {
173
+ $sql = array();
174
+
175
+ if ($this->object->is_select_statement()) $sql[] = $this->object->_select_clause;
176
+ elseif ($this->object->is_delete_statement()) $sql[] = $this->object->_delete_clause;
177
+ $sql[] = 'FROM `'.$this->object->get_table_name().'`';
178
+ $where_clauses = array();
179
+ foreach ($this->object->_where_clauses as $where) {
180
+ $where_clauses[] = '('.$where.')';
181
+ }
182
+ if ($where_clauses) $sql[] = 'WHERE '.implode(' AND ', $where_clauses);
183
+
184
+ if ($this->object->is_select_statement()) {
185
+ if ($this->object->_order_clauses) $sql[] = 'ORDER BY '.implode(', ', $this->object->_order_clauses);
186
+ if ($this->object->_group_by_columns) $sql[] = 'GROUP BY '.implode(', ', $this->object->_group_by_columns);
187
+ if ($this->object->_limit_clause) $sql[] = $this->object->_limit_clause;
188
+ }
189
+ return implode(' ', $sql);
190
+ }
191
+
192
+
193
+ /**
194
+ * Run the query
195
+ * @param $sql optionally run the specified SQL insteads
196
+ * return
197
+ */
198
+ function run_query($sql=FALSE, $no_entities=FALSE)
199
+ {
200
+ $retval = array();
201
+
202
+ // Or generate SQL query
203
+ if (!$sql)
204
+ $sql = $this->object->get_generated_query();
205
+
206
+ // If we have a SQL statement to execute, then heck, execute it!
207
+ if ($sql)
208
+ {
209
+ if ($this->object->debug)
210
+ var_dump($sql);
211
+
212
+ $this->_wpdb()->query($sql);
213
+
214
+ if ($this->_wpdb()->last_result)
215
+ {
216
+ $retval = array();
217
+ // For each row, create an entity, update it's properties, and add it to the result set
218
+ if ($no_entities)
219
+ {
220
+ $retval = $this->_wpdb()->last_result;
221
+ }
222
+ else {
223
+ foreach ($this->_wpdb()->last_result as $row) {
224
+ $retval[] = $this->_convert_to_entity($this->scrub_result($row));
225
+ }
226
+ }
227
+ }
228
+ }
229
+
230
+ return $retval;
231
+ }
232
+
233
+ /**
234
+ * Stores the entity
235
+ * @param stdClass $entity
236
+ */
237
+ function _save_entity($entity)
238
+ {
239
+ $retval = FALSE;
240
+
241
+ unset($entity->id_field);
242
+ $primary_key = $this->object->get_primary_key_column();
243
+ if (isset($entity->$primary_key)) {
244
+ if($this->object->_update($entity)) $retval = intval($entity->$primary_key);
245
+ }
246
+ else {
247
+ $retval = $this->object->_create($entity);
248
+ if ($retval) {
249
+ $new_entity = $this->object->find($retval);
250
+ foreach ($new_entity as $key => $value) $entity->$key = $value;
251
+ }
252
+ }
253
+ $entity->id_field = $primary_key;
254
+
255
+ return $retval;
256
+ }
257
+
258
+ /**
259
+ * Converts an entity to something suitable for inserting into
260
+ * a database column
261
+ * @param stdObject $entity
262
+ * @return array
263
+ */
264
+ function _convert_to_table_data($entity)
265
+ {
266
+ $data = (array) $entity;
267
+ foreach ($data as $key => $value) {
268
+ if (is_array($value)) $data[$key] = $this->object->serialize($value);
269
+ }
270
+
271
+ return $data;
272
+ }
273
+
274
+
275
+ /**
276
+ * Destroys/deletes an entity
277
+ * @param stdObject|C_DataMapper_Model|int $entity
278
+ * @return boolean
279
+ */
280
+ function destroy($entity)
281
+ {
282
+ $retval = FALSE;
283
+ $key = $this->object->get_primary_key_column();
284
+
285
+ // Find the id of the entity
286
+ if (is_object($entity) && isset($entity->$key)) {
287
+ $id = (int)$entity->$key;
288
+ }
289
+ else {
290
+ $id = (int)$entity;
291
+ }
292
+
293
+ // If we have an ID, then delete the post
294
+ if (is_numeric($id)) {
295
+ $sql = $this->object->_wpdb()->prepare(
296
+ "DELETE FROM `{$this->object->get_table_name()}` WHERE {$key} = %s",
297
+ $id
298
+ );
299
+ $retval = $this->object->_wpdb()->query($sql);
300
+ }
301
+
302
+ return $retval;
303
+ }
304
+
305
+ /**
306
+ * Creates a new record in the database
307
+ * @param stdObject $entity
308
+ * @return boolean
309
+ */
310
+ function _create($entity)
311
+ {
312
+ $retval = FALSE;
313
+ $id = $this->object->_wpdb()->insert(
314
+ $this->object->get_table_name(),
315
+ $this->object->_convert_to_table_data($entity)
316
+ );
317
+ if ($id) {
318
+ $key = $this->object->get_primary_key_column();
319
+ $retval = $entity->$key = intval($this->object->_wpdb()->insert_id);
320
+ }
321
+ return $retval;
322
+ }
323
+
324
+
325
+ /**
326
+ * Updates a record in the database
327
+ * @param stdObject $entity
328
+ */
329
+ function _update($entity)
330
+ {
331
+ $key = $this->object->get_primary_key_column();
332
+
333
+ return $this->object->_wpdb()->update(
334
+ $this->object->get_table_name(),
335
+ $this->object->_convert_to_table_data($entity),
336
+ array($key => $entity->$key)
337
+ );
338
+ }
339
+
340
+
341
+ /**
342
+ * Fetches the last row
343
+ * @param array $conditions
344
+ * @return C_DataMapper_Entity
345
+ */
346
+ function find_last($conditions=array(), $model=FALSE)
347
+ {
348
+ $retval = NULL;
349
+
350
+ // Get row number for the last row
351
+ $table_name = $this->object->_clean_column($this->object->get_table_name());
352
+ $count = $this->_wpdb()->get_var("SELECT COUNT(*) FROM `{$table_name}`");
353
+ $offset = $count-1;
354
+ $results = $this->select()->where_and($conditions)->limit(1, $offset)->run_query();
355
+ if ($results) {
356
+ $retval = $model? $this->object->convert_to_model($results[0]) : $results[0];
357
+ }
358
+
359
+ return $retval;
360
+ }
361
+
362
+
363
+ /**
364
+ * Looks up using SQL the columns existing in the database
365
+ */
366
+ function lookup_columns()
367
+ {
368
+ $this->object->_columns = array();
369
+ $sql = "SHOW COLUMNS FROM `{$this->object->get_table_name()}`";
370
+ foreach ($this->object->run_query($sql, TRUE) as $row) {
371
+ $this->object->_columns[] = $row->Field;
372
+ }
373
+ return $this->object->_columns;
374
+ }
375
+
376
+ /**
377
+ * Determines whether a column is present for the table
378
+ * @param string $column_name
379
+ * @return string
380
+ */
381
+ function has_column($column_name)
382
+ {
383
+ if (empty($this->object->_columns)) $this->object->lookup_columns();
384
+ return array_search($column_name, $this->object->_columns);
385
+ }
386
+
387
+ /**
388
+ * Defines a column for this table
389
+ * @param string $column_name
390
+ * @param string $datatype
391
+ */
392
+ function define_column($column_name, $datatype)
393
+ {
394
+ $this->object->_defined_columns[$column_name] = $datatype;
395
+ }
396
+
397
+ function add_column($column_name, $datatype=FALSE)
398
+ {
399
+ // If no datatype was specified, perhaps the column was already defined
400
+ if (!$datatype && isset($this->object->_defined_columns[$column_name])) {
401
+ $datatype = $this->object->_defined_columns[$column_name];
402
+ }
403
+
404
+ // Ensure that we have a datatype before continuing...
405
+ if ($datatype) {
406
+ $sql = "ALTER TABLE `{$this->get_table_name()}` ADD COLUMN ``{$column_name}` {$datatype}";
407
+ $this->object->run_query($sql);
408
+ }
409
+
410
+ $this->object->lookup_columns();
411
+ }
412
+
413
+ /**
414
+ * Migrates the schema of the database
415
+ */
416
+ function migrate()
417
+ {
418
+ if (empty($this->object->_columns)) $this->object->lookup_columns();
419
+ foreach ($this->object->_columns as $column_name) {
420
+ if (!$this->object->has_column($column_name)) {
421
+ $this->object->add_column($column_name);
422
+ }
423
+ }
424
+ }
425
+
426
+
427
+ function _init()
428
+ {
429
+ $this->object->_where_clauses = array();
430
+ $this->object->_order_clauses = array();
431
+ $this->object->_group_by_columns = array();
432
+ $this->object->_limit_clause = '';
433
+ $this->object->_select_clause = '';
434
+ }
435
+ }
436
+
437
+ class C_CustomTable_DataMapper_Driver extends C_DataMapper_Driver_Base
438
+ {
439
+ /**
440
+ * The WordPress Database Connection
441
+ * @var wpdb
442
+ */
443
+ var $_where_clauses = array();
444
+ var $_order_clauses = array();
445
+ var $_group_by_columns = array();
446
+ var $_limit_clause = '';
447
+ var $_select_clause = '';
448
+ var $_delete_clause = '';
449
+ var $_columns = array();
450
+ var $_defined_columns = array();
451
+
452
+ function define($object_name, $context=FALSE)
453
+ {
454
+ parent::define($context);
455
+ $this->add_mixin('C_CustomTable_DataMapper_Driver_Mixin');
456
+ $this->implement('I_CustomTable_DataMapper');
457
+ }
458
+
459
+ function initialize($object_name)
460
+ {
461
+ parent::initialize($object_name);
462
+ if (!isset($this->_primary_key_column))
463
+ $this->_primary_key_column = $this->_lookup_primary_key_column();
464
+ }
465
+
466
+ /**
467
+ * Returns the database connection object for WordPress
468
+ * @global wpdb $wpdb
469
+ * @return wpdb
470
+ */
471
+ function _wpdb()
472
+ {
473
+ global $wpdb;
474
+ return $wpdb;
475
+ }
476
+
477
+ /**
478
+ * Looks up the primary key column for this table
479
+ */
480
+ function _lookup_primary_key_column()
481
+ {
482
+ $key = $this->_wpdb()->get_row("SHOW INDEX FROM {$this->get_table_name()} WHERE Key_name='PRIMARY'", ARRAY_A);
483
+ if (!$key) throw new Exception("Please specify the primary key for {$this->get_table_name ()}");
484
+ return $key['Column_name'];
485
+ }
486
+ }
products/photocrati_nextgen/modules/datamapper/class.datamapper_driver_base.php ADDED
@@ -0,0 +1,603 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Thrown when an entity does not exist
5
+ */
6
+ class E_EntityNotFoundException extends RuntimeException
7
+ {
8
+
9
+ }
10
+
11
+ /**
12
+ * Thrown when an invalid data type is used as an entity, such as an associative
13
+ * array which is not yet supported due to a problem with references and the
14
+ * call_user_func_array() function.
15
+ */
16
+ class E_InvalidEntityException extends RuntimeException
17
+ {
18
+ function __construct($message_or_previous=FALSE, $code=0, $previous=NULL)
19
+ {
20
+ // We don't know if we have been passed a message yet or not
21
+ $message = FALSE;
22
+
23
+ // Determine if the first parameter is a string or exception
24
+ if ($message_or_previous) {
25
+ if (is_string($message_or_previous))
26
+ $message = $message_or_previous;
27
+ else {
28
+ $previous = $message_or_previous;
29
+ }
30
+ }
31
+
32
+ // If no message was provided, create a default message
33
+ if (!$message) {
34
+ $message = "Invalid data type used for entity. Please use stdClass
35
+ or a subclass of C_DataMapper_Model. Arrays will be supported in
36
+ the future.";
37
+ }
38
+ parent::__construct($message, $code);
39
+ }
40
+ }
41
+
42
+
43
+ class Mixin_DataMapper_Driver_Base extends Mixin
44
+ {
45
+ /**
46
+ * Used to clean column or table names in a SQL query
47
+ * @param string $val
48
+ * @return string
49
+ */
50
+ function _clean_column($val)
51
+ {
52
+ return str_replace(
53
+ array(';', "'", '"', '`'),
54
+ array(''),
55
+ $val
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Serializes the data
61
+ * @param mixed $value
62
+ * @return string
63
+ */
64
+ function serialize($value)
65
+ {
66
+ //Using json_encode here because PHP's serialize is not Unicode safe
67
+ return base64_encode(json_encode($value));
68
+ }
69
+
70
+
71
+ /**
72
+ * Unserializes data using our proprietary format
73
+ * @param string $value
74
+ * @return mixed
75
+ */
76
+ function unserialize($value)
77
+ {
78
+ $retval = NULL;
79
+ if (is_string($value))
80
+ {
81
+ $retval = stripcslashes($value);
82
+
83
+ if (strlen($value) > 1)
84
+ {
85
+ //Using json_decode here because PHP's unserialize is not Unicode safe
86
+ $retval = json_decode(base64_decode($retval), TRUE);
87
+
88
+ // JSON Decoding failed. Perhaps it's PHP serialized data?
89
+ if ($retval === NULL) {
90
+ $er = error_reporting(0);
91
+ $retval = unserialize($value);
92
+ error_reporting($er);
93
+ }
94
+ }
95
+ }
96
+
97
+ return $retval;
98
+ }
99
+
100
+
101
+ /**
102
+ * Finds a partiular entry by id
103
+ * @param int|stdClass|C_DataMapper_Model $entity
104
+ * @return C_DataMapper_Entity
105
+ */
106
+ function find($entity, $model=FALSE)
107
+ {
108
+ $retval = NULL;
109
+
110
+ // Get primary key of the entity
111
+ $pkey = $this->object->get_primary_key_column();
112
+ if (!is_numeric($entity)) {
113
+ $entity = isset($entity->$pkey) ? intval($entity->$pkey) : FALSE;
114
+ }
115
+
116
+ // If we have an entity ID, then get the record
117
+ if ($entity) {
118
+ $results = $this->object->select()->where_and(
119
+ array("{$pkey} = %d", $entity)
120
+ )->limit(1,0)->run_query();
121
+
122
+ if ($results) $retval = $model ? $this->object->convert_to_model($results[0]) : $results[0];
123
+ }
124
+
125
+ return $retval;
126
+ }
127
+
128
+ /**
129
+ * Fetches the first row
130
+ * @param array $conditions
131
+ * @return C_DataMapper_Entity
132
+ */
133
+ function find_first($conditions=array(), $model=FALSE)
134
+ {
135
+ $results = $this->object->select()->where_and($conditions)->limit(1,0)->run_query();
136
+ if ($results)
137
+ return $model? $this->object->convert_to_model($results[0]) : $results[0];
138
+ else
139
+ return NULL;
140
+ }
141
+
142
+
143
+ /**
144
+ * Queries all rows
145
+ * @param array $conditions
146
+ * @return array
147
+ */
148
+ function find_all($conditions=array(), $model=FALSE)
149
+ {
150
+ // Sometimes users will forget that the first parameter is conditions, and think it's $model instead
151
+ if ($conditions === TRUE)
152
+ {
153
+ $conditions = array();
154
+ $model = TRUE;
155
+ }
156
+
157
+ if ($conditions === FALSE)
158
+ {
159
+ $conditions = array();
160
+ $model = FALSE;
161
+ }
162
+
163
+ $results = $this->object->select()->where_and($conditions)->run_query();
164
+ if ($results && $model)
165
+ {
166
+ foreach ($results as &$r) {
167
+ $r = $this->object->convert_to_model($r);
168
+ }
169
+ }
170
+
171
+ return $results;
172
+ }
173
+
174
+
175
+ /**
176
+ * Filters the query using conditions:
177
+ * E.g.
178
+ * array("post_title = %s", "Foo")
179
+ * array(
180
+ * array("post_title = %s", "Foo"),
181
+ *
182
+ * )
183
+ */
184
+ function where_and($conditions=array())
185
+ {
186
+ return $this->object->_where($conditions, 'AND');
187
+ }
188
+
189
+ function where_or($conditions=array())
190
+ {
191
+ return $this->object->where($conditions, 'OR');
192
+ }
193
+
194
+
195
+ function where($conditions=array())
196
+ {
197
+ return $this->object->_where($conditions, 'AND');
198
+ }
199
+
200
+
201
+ /** Parses the where clauses
202
+ * They could look like the following:
203
+ *
204
+ * array(
205
+ * "post_id = 1"
206
+ * array("post_id = %d", 1),
207
+ * )
208
+ *
209
+ * or simply "post_id = 1"
210
+ * @param array|string $conditions
211
+ * @param string $operator
212
+ * @return ExtensibleObject
213
+ */
214
+ function _where($conditions=array(), $operator)
215
+ {
216
+ $where_clauses = array();
217
+
218
+ // If conditions is not an array, make it one
219
+ if (!is_array($conditions)) $conditions = array($conditions);
220
+ elseif (!empty($conditions) && !is_array($conditions[0])) {
221
+ // Just a single condition was passed, but with a bind
222
+ $conditions = array($conditions);
223
+ }
224
+
225
+ // Iterate through each condition
226
+ foreach ($conditions as $condition) {
227
+ if (is_string($condition)) {
228
+ $clause = $this->object->_parse_where_clause($condition);
229
+ if ($clause) $where_clauses[] = $clause;
230
+ }
231
+ else {
232
+ $clause = array_shift($condition);
233
+ $clause = $this->object->_parse_where_clause($clause, $condition);
234
+ if ($clause) $where_clauses[] = $clause;
235
+ }
236
+ }
237
+
238
+ // Add where clause to query
239
+ if ($where_clauses) $this->object->_add_where_clause($where_clauses, $operator);
240
+
241
+ return $this->object;
242
+ }
243
+
244
+ /**
245
+ * Parses a where clause and returns an associative array
246
+ * representing the query
247
+ *
248
+ * E.g. parse_where_clause("post_title = %s", "Foo Bar")
249
+ *
250
+ * @global wpdb $wpdb
251
+ * @param string $condition
252
+ * @return array
253
+ */
254
+ function _parse_where_clause($condition)
255
+ {
256
+ $column = '';
257
+ $operator = '';
258
+ $value = '';
259
+ $numeric = TRUE;
260
+
261
+ // Substitute any placeholders
262
+ global $wpdb;
263
+ $binds = func_get_args();
264
+ $binds = $binds[1]; // first argument is the condition
265
+ foreach ($binds as &$bind) {
266
+
267
+ // A bind could be an array, used for the 'IN' operator
268
+ // or a simple scalar value. We need to convert arrays
269
+ // into scalar values
270
+ if (is_object($bind)) $bind = (array)$bind;
271
+ if (is_array($bind)) {
272
+ if (empty($bind)) return FALSE;
273
+ foreach ($bind as &$val) {
274
+ if (!is_numeric($val)) {
275
+ $val = '"'.addslashes($val).'"';
276
+ $numeric = FALSE;
277
+ }
278
+ }
279
+ $bind = implode(',', $bind);
280
+ }
281
+ elseif(!is_numeric($bind)) $numeric = FALSE;
282
+ }
283
+ $condition = $wpdb->prepare($condition, $binds);
284
+
285
+ // Parse the where clause
286
+ if (preg_match("/^[^\s]+/", $condition, $match)) {
287
+ $column = trim(array_shift($match));
288
+ $condition = str_replace($column, '', $condition);
289
+ }
290
+
291
+ if (preg_match("/(NOT )?IN|(NOT )?LIKE|(NOT )?BETWEEN|[=!<>]+/i", $condition, $match)) {
292
+ $operator = trim(array_shift($match));
293
+ $condition = str_replace($operator, '', $condition);
294
+ $operator = strtolower($operator);
295
+ $value = trim($condition);
296
+ }
297
+
298
+ // Values will automatically be quoted, so remove them
299
+ // If the value is part of an IN clause or BETWEEN clause and
300
+ // has multiple values, we attempt to split the values apart into an
301
+ // array and iterate over them individually
302
+ if ($operator == 'in') {
303
+ $values = preg_split("/'?\s?(,)\s?'?/i", $value);
304
+ }
305
+ elseif ($operator == 'between') {
306
+ $values = preg_split("/'?\s?(AND)\s?'?/i", $value);
307
+ }
308
+
309
+ // If there's a single value, treat it as an array so that we
310
+ // can still iterate
311
+ if (empty($values)) $values = array($value);
312
+ foreach ($values as $index => $value) {
313
+ $value = preg_replace("/^(\()?'/", '', $value);
314
+ $value = preg_replace("/'(\))?$/", '', $value);
315
+ $values[$index] = $value;
316
+ }
317
+ if (count($values)>1) $value = $values;
318
+
319
+ // Return the WP Query meta query parameters
320
+ $retval = array(
321
+ 'column' => $column,
322
+ 'value' => $value,
323
+ 'compare' => strtoupper($operator),
324
+ 'type' => $numeric ? 'numeric' : 'string',
325
+ );
326
+
327
+ return $retval;
328
+ }
329
+
330
+ /**
331
+ * Converts a stdObject to an Entity
332
+ * @param stdObject $stdObject
333
+ * @return stdObject
334
+ */
335
+ function _convert_to_entity($stdObject)
336
+ {
337
+ // Add name of the id_field to the entity, and convert
338
+ // the ID to an integer
339
+ $stdObject->id_field = $key = $this->object->get_primary_key_column();
340
+ if (isset($stdObject->$key)) {
341
+ $stdObject->$key = (int) $stdObject->$key;
342
+ }
343
+
344
+ // Set defaults for this entity
345
+ $this->object->set_defaults($stdObject);
346
+
347
+ return $stdObject;
348
+ }
349
+
350
+ /**
351
+ * Converts a stdObject entity to a model
352
+ * @param stdObject $stdObject
353
+ */
354
+ function convert_to_model($stdObject, $context=FALSE)
355
+ {
356
+ // Create a factory
357
+ $retval = NULL;
358
+
359
+ try {
360
+ $this->object->_convert_to_entity($stdObject);
361
+ }
362
+ catch (Exception $ex) {
363
+ throw new E_InvalidEntityException($ex);
364
+ }
365
+ $retval = $this->object->create($stdObject, $context);
366
+
367
+ return $retval;
368
+ }
369
+
370
+ /**
371
+ * Creates a new model
372
+ * @param stdClass|array $properties
373
+ * @return C_DataMapper_Model
374
+ */
375
+ function create($properties=array(), $context=FALSE)
376
+ {
377
+ $entity = $properties;
378
+ $factory = $this->object->get_registry()->get_utility('I_Component_Factory');
379
+ if (!is_object($properties)) {
380
+ $entity = new stdClass;
381
+ foreach ($properties as $k=>$v) $entity->$k = $v;
382
+ }
383
+ return $factory->create($this->object->get_model_factory_method(), $this->object, $entity, $context);
384
+ }
385
+
386
+
387
+ /**
388
+ * Determines whether an object is actually a model
389
+ * @param mixed $obj
390
+ * @return bool
391
+ */
392
+ function is_model($obj)
393
+ {
394
+ return is_subclass_of($obj, 'C_DataMapper_Model') or get_class($obj) == 'C_DataMapper_Model';
395
+ }
396
+
397
+ /**
398
+ * Saves an entity
399
+ * @param stdClass|C_DataMapper_Model $entity
400
+ * @return bool
401
+ */
402
+ function save($entity)
403
+ {
404
+ $retval = FALSE;
405
+ $model = $entity;
406
+
407
+ // Attempt to use something else, most likely an associative array
408
+ // TODO: Support assocative arrays. The trick is to support references
409
+ // with dynamic calls using __call() and call_user_func_array().
410
+ if (is_array($entity)) throw new E_InvalidEntityException();
411
+
412
+ // We can work with what we have. But we need to ensure that we've got
413
+ // a model
414
+ elseif (!$this->object->is_model($entity)) {
415
+ $model = $this->object->convert_to_model($entity);
416
+ }
417
+
418
+ // Validate the model
419
+ $model->validate();
420
+
421
+ if ($model->is_valid()) {
422
+ $saved_entity = $model->get_entity();
423
+ unset($saved_entity->_errors);
424
+ $retval = $this->object->_save_entity($saved_entity);
425
+ }
426
+
427
+ // We always return the same type of entity that we given
428
+ if (get_class($entity) == 'stdClass') $model->get_entity();
429
+
430
+ return $retval;
431
+ }
432
+
433
+
434
+ /**
435
+ * Gets validation errors for the entity
436
+ * @param stdClass|C_DataMapper_Model $entity
437
+ * @return array
438
+ */
439
+ function get_errors($entity)
440
+ {
441
+ $model = $entity;
442
+ if (!$this->object->is_model($entity)) {
443
+ $model = $this->object->convert_to_model($entity);
444
+ }
445
+ $model->validate();
446
+ return $model->get_errors();
447
+ }
448
+
449
+ /**
450
+ * Called to set defaults for the record/model/entity.
451
+ * Subclasses and adapters should extend this method to provide their
452
+ * implementation. The implementation should make use of the
453
+ * _set_default_value() method
454
+ */
455
+ function set_defaults()
456
+ {
457
+
458
+ }
459
+
460
+ /**
461
+ * If a field has no value, then use the default value.
462
+ * @param stdClass|C_DataMapper_Model $object
463
+ */
464
+ function _set_default_value($object)
465
+ {
466
+ $array = NULL;
467
+ $field = NULL;
468
+ $default_value = NULL;
469
+
470
+ // The first argument MUST be an object
471
+ if (!is_object($object)) throw new E_InvalidEntityException();
472
+
473
+ // This method has two signatures:
474
+ // 1) _set_default_value($object, $field, $default_value)
475
+ // 2) _set_default_value($object, $array_field, $field, $default_value)
476
+
477
+ // Handle #1
478
+ $args = func_get_args();
479
+ if (count($args) == 4) {
480
+ list($object, $array, $field, $default_value) = $args;
481
+ if (!isset($object->{$array})) {
482
+ $object->{$array} = array();
483
+ $object->{$array}[$field] = NULL;
484
+ }
485
+ else {
486
+ $arr = &$object->{$array};
487
+ if (!isset($arr[$field])) $arr[$field] = NULL;
488
+ }
489
+ $array = &$object->{$array};
490
+ $value = &$array[$field];
491
+ if ($value === '' OR is_null($value)) $value = $default_value;
492
+ }
493
+
494
+ // Handle #2
495
+ else {
496
+ list($object, $field, $default_value) = $args;
497
+ if (!isset($object->$field)) {
498
+ $object->$field = NULL;
499
+ }
500
+ $value = $object->$field;
501
+ if ($value === '' OR is_null($value)) $object->$field = $default_value;
502
+ }
503
+ }
504
+
505
+ function scrub_result($result)
506
+ {
507
+ if (is_object($result))
508
+ {
509
+ $new_result = new stdClass();
510
+ foreach ($result as $key => $value) {
511
+ $new_value = $this->scrub_result($value);
512
+ $new_result->$key = $new_value;
513
+ }
514
+ return $new_result;
515
+ }
516
+ else if (is_array($result)) {
517
+ $new_array = array();
518
+ foreach ($result as $key => $value) {
519
+ $new_array[$key] = $this->scrub_result($value);
520
+ }
521
+ return $new_array;
522
+ } else {
523
+ return stripslashes($result);
524
+ }
525
+ }
526
+ }
527
+
528
+ class C_DataMapper_Driver_Base extends C_Component
529
+ {
530
+ var $_object_name;
531
+ var $_model_factory_method = FALSE;
532
+
533
+ function define($object_name, $context=FALSE)
534
+ {
535
+ parent::define($context);
536
+ $this->add_mixin('Mixin_DataMapper_Driver_Base');
537
+ $this->implement('I_DataMapper_Driver');
538
+ }
539
+
540
+ function initialize($object_name)
541
+ {
542
+ parent::initialize();
543
+ $this->_object_name = $object_name;
544
+ }
545
+
546
+ /**
547
+ * Gets the object name
548
+ * @return string
549
+ */
550
+ function get_object_name()
551
+ {
552
+ return $this->_object_name;
553
+ }
554
+
555
+ /**
556
+ * Gets the name of the table
557
+ * @global string $table_prefix
558
+ * @return string
559
+ */
560
+ function get_table_name()
561
+ {
562
+ global $table_prefix;
563
+ return $table_prefix.$this->_object_name;
564
+ }
565
+
566
+ /**
567
+ * Sets the name of the factory method used to create a model for this entity
568
+ * @param string $method_name
569
+ */
570
+ function set_model_factory_method($method_name)
571
+ {
572
+ $this->_model_factory_method = $method_name;
573
+ }
574
+
575
+
576
+ /**
577
+ * Gets the name of the factory method used to create a model for this entity
578
+ */
579
+ function get_model_factory_method()
580
+ {
581
+ return $this->_model_factory_method;
582
+ }
583
+
584
+
585
+ /**
586
+ * Gets the name of the primary key column
587
+ * @return string
588
+ */
589
+ function get_primary_key_column()
590
+ {
591
+ return $this->_primary_key_column;
592
+ }
593
+
594
+
595
+ /**
596
+ * Gets the class name of the driver used
597
+ * @return string
598
+ */
599
+ function get_driver_class_name()
600
+ {
601
+ return get_called_class();
602
+ }
603
+ }
products/photocrati_nextgen/modules/datamapper/class.datamapper_installer.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_DataMapper_Installer
4
+ {
5
+ function __construct()
6
+ {
7
+ $this->settings = C_NextGen_Global_Settings::get_instance();
8
+ }
9
+
10
+ function install()
11
+ {
12
+ $this->settings->set_default_value('datamapper_driver', 'custom_post_datamapper');
13
+ }
14
+ }
products/photocrati_nextgen/modules/datamapper/class.datamapper_model.php ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_DataMapper_Model extends C_Component
4
+ {
5
+ var $_mapper;
6
+ var $_stdObject;
7
+
8
+ /**
9
+ * Define the model
10
+ */
11
+ function define($mapper, $properties, $context=FALSE)
12
+ {
13
+ parent::define($context);
14
+ $this->add_mixin('Mixin_Validation');
15
+ $this->add_mixin('Mixin_DataMapper_Model_Instance_Methods');
16
+ $this->add_mixin('Mixin_DataMapper_Model_Validation');
17
+ $this->implement('I_DataMapper_Model');
18
+ }
19
+
20
+ /**
21
+ * Creates a new entity for the specified mapper
22
+ * @param C_DataMapper_Driver_Base $mapper
23
+ * @param array|stdClass $properties
24
+ * @param string $context
25
+ */
26
+ function initialize($mapper, $properties=FALSE)
27
+ {
28
+ $this->_mapper = $mapper;
29
+ $this->_stdObject = $properties ? (object)$properties : new stdClass();
30
+ parent::initialize();
31
+ $this->set_defaults();
32
+ }
33
+
34
+ /**
35
+ * Gets the data mapper for the entity
36
+ * @return C_DataMapper_Driver_Base
37
+ */
38
+ function get_mapper()
39
+ {
40
+ return $this->_mapper;
41
+ }
42
+
43
+
44
+ /**
45
+ * Gets a property of the model
46
+ */
47
+ function &__get($property_name)
48
+ {
49
+ if (isset($this->_stdObject->$property_name)) {
50
+ $retval = &$this->_stdObject->$property_name;
51
+ return $retval;
52
+ }
53
+ else {
54
+ // We need to assign NULL to a variable first, since only
55
+ // variables can be returned by reference
56
+ $retval = NULL;
57
+ return $retval;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Sets a property for the model
63
+ */
64
+ function __set($property_name, $value)
65
+ {
66
+ return $this->_stdObject->$property_name = $value;
67
+ }
68
+
69
+
70
+ function __isset($property_name)
71
+ {
72
+ return isset($this->_stdObject->$property_name);
73
+ }
74
+
75
+
76
+ /**
77
+ * Saves the entity
78
+ * @param type $updated_attributes
79
+ */
80
+ function save($updated_attributes=array())
81
+ {
82
+ $this->update_attributes($updated_attributes);
83
+ return $this->get_mapper()->save($this->get_entity());
84
+ }
85
+
86
+ /**
87
+ * Updates the attributes for an object
88
+ */
89
+ function update_attributes($array=array())
90
+ {
91
+ foreach ($array as $key => $value) $this->_stdObject->$key = $value;
92
+ }
93
+
94
+
95
+ /**
96
+ * Sets the default values for this model
97
+ */
98
+ function set_defaults()
99
+ {
100
+ $this->get_mapper()->set_defaults($this);
101
+ }
102
+
103
+ /**
104
+ * Destroys or deletes the entity
105
+ */
106
+ function destroy()
107
+ {
108
+ $this->get_mapper()->destroy($this->_stdObject);
109
+ }
110
+
111
+
112
+ /**
113
+ * Determines whether the object is new or existing
114
+ * @return type
115
+ */
116
+ function is_new()
117
+ {
118
+ return $this->id() ? FALSE: TRUE;
119
+ }
120
+
121
+ /**
122
+ * Gets/sets the primary key
123
+ */
124
+ function id()
125
+ {
126
+ $key = $this->get_mapper()->get_primary_key_column();
127
+ $args = func_get_args();
128
+ if ($args) {
129
+ return $this->__set($key, $args[0]);
130
+ }
131
+ else {
132
+ return $this->__get($key);
133
+ }
134
+ }
135
+ }
136
+
137
+ /**
138
+ * This mixin should be overwritten by other modules
139
+ */
140
+ class Mixin_DataMapper_Model_Validation extends Mixin
141
+ {
142
+ function validation()
143
+ {
144
+ return $this->object->is_valid();
145
+ }
146
+ }
147
+
148
+ class Mixin_DataMapper_Model_Instance_Methods extends Mixin
149
+ {
150
+ /**
151
+ * Returns the associated entity
152
+ */
153
+ function &get_entity()
154
+ {
155
+ return $this->object->_stdObject;
156
+ }
157
+ }
products/photocrati_nextgen/modules/datamapper/interface.custompost_datamapper.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_CustomPost_DataMapper
4
+ {
5
+
6
+ }
products/photocrati_nextgen/modules/datamapper/interface.customtable_datamapper.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_CustomTable_DataMapper
4
+ {
5
+
6
+ }
products/photocrati_nextgen/modules/datamapper/interface.datamapper_driver.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_DataMapper_Driver
4
+ {
5
+ function select($fields='*');
6
+ function order_by($order_by, $direction);
7
+ function limit($offset, $limit);
8
+ function where_and($conditions=array());
9
+ function where($conditions=array());
10
+ function where_or($conditions=array());
11
+ function group_by($columns=array());
12
+ function find($id=NULL);
13
+ function find_first();
14
+ function find_last();
15
+ function find_all();
16
+ function run_query();
17
+ function get_table_name();
18
+ function get_object_name();
19
+ function _save_entity($entity);
20
+ function get_primary_key_column();
21
+ function get_model_factory_method();
22
+ function set_model_factory_method($method_name);
23
+ function count();
24
+ function convert_to_model($stdObject, $context=FALSE);
25
+ function get_driver_class_name();
26
+ function is_select_statement();
27
+ function is_delete_statement();
28
+ function delete();
29
+ }
products/photocrati_nextgen/modules/datamapper/interface.datamapper_model.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_DataMapper_Model
4
+ {
5
+ function save($attributes=array());
6
+ function destroy();
7
+ function update_attributes();
8
+ function is_new();
9
+ }
products/photocrati_nextgen/modules/datamapper/module.datamapper.php ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /***
4
+ {
5
+ Module: photocrati-datamapper,
6
+ Depends: { photocrati-validation }
7
+ }
8
+ ***/
9
+ class M_DataMapper extends C_Base_Module
10
+ {
11
+ function define()
12
+ {
13
+ parent::define(
14
+ 'photocrati-datamapper',
15
+ 'DataMapper',
16
+ 'Provides a database abstraction layer following the DataMapper pattern',
17
+ '0.2',
18
+ 'http://www.photocrati.com',
19
+ 'Photocrati Media',
20
+ 'http://www.photocrati.com'
21
+ );
22
+
23
+ include_once('class.datamapper_installer.php');
24
+ C_Photocrati_Installer::add_handler($this->module_id, 'C_Datamapper_Installer');
25
+ }
26
+
27
+ function _register_adapters()
28
+ {
29
+ $this->get_registry()->add_adapter('I_Component_Factory', 'A_DataMapper_Factory');
30
+ }
31
+
32
+
33
+ function _register_hooks()
34
+ {
35
+ add_filter('posts_request', array(&$this, 'set_custom_wp_query'), 50, 2);
36
+ add_filter('posts_fields', array(&$this, 'set_custom_wp_query_fields'), 50, 2);
37
+ add_filter('posts_where', array(&$this, 'set_custom_wp_query_where'), 50, 2);
38
+ add_filter('posts_groupby', array(&$this, 'set_custom_wp_query_groupby'), 50, 2);
39
+ }
40
+
41
+
42
+ /**
43
+ * Sets a custom SQL query for the WP_Query class, when the Custom Post
44
+ * DataMapper implementation is used
45
+ * @param string $sql
46
+ * @param WP_Query $wp_query
47
+ * @return string
48
+ */
49
+ function set_custom_wp_query($sql, &$wp_query)
50
+ {
51
+ // Set the custom query
52
+ if (($custom_sql = $wp_query->get('custom_sql'))) {
53
+ $sql = $custom_sql;
54
+ }
55
+
56
+ // Perhaps we're to initiate a delete query instead?
57
+ elseif ($wp_query->get('is_delete')) {
58
+ $sql = preg_replace("/^SELECT.*FROM/i", "DELETE FROM", $sql);
59
+ }
60
+
61
+ return $sql;
62
+ }
63
+
64
+ /**
65
+ * Sets custom fields to select from the database
66
+ * @param string $fields
67
+ * @param WP_Query $wp_query
68
+ * @return string
69
+ */
70
+ function set_custom_wp_query_fields($fields, &$wp_query)
71
+ {
72
+ $custom_fields = $wp_query->get('fields');
73
+ return $custom_fields ? $custom_fields : $fields;
74
+ }
75
+
76
+
77
+ /**
78
+ * Sets custom where clauses for a query
79
+ * @param string $where
80
+ * @param WP_Query $wp_query
81
+ * @return string
82
+ */
83
+ function set_custom_wp_query_where($where, &$wp_query)
84
+ {
85
+ $this->add_post_title_where_clauses($where, $wp_query);
86
+ $this->add_post_name_where_clauses($where, $wp_query);
87
+ return $where;
88
+ }
89
+
90
+
91
+ /**
92
+ * Adds additional group by clauses to the SQL query
93
+ * @param string $groupby
94
+ * @param WP_Query $wp_query
95
+ * @return string
96
+ */
97
+ function set_custom_wp_query_groupby($groupby, &$wp_query)
98
+ {
99
+ $retval = $groupby;
100
+ $group_by_columns = $wp_query->get('group_by_columns');
101
+ if ($group_by_columns) {
102
+ $retval = str_replace('GROUP BY', '', $retval);
103
+ $columns = explode(',', $retval);
104
+ foreach (array_reverse($columns) as $column) {
105
+ array_unshift($group_by_columns, trim($column));
106
+ }
107
+ $retval = "GROUP BY ".implode(', ', $group_by_columns);
108
+ }
109
+ // Not all mysql servers allow access to create temporary tables which are used when doing GROUP BY
110
+ // statements; this can potentially ruin basic queries. If no group_by_columns is set AND the query originates
111
+ // within the datamapper we strip the "GROUP BY" clause entirely in this filter.
112
+ else if ($wp_query->get('datamapper')) {
113
+ $retval = '';
114
+ }
115
+ return $retval;
116
+ }
117
+
118
+
119
+ /**
120
+ * Formats the value of used in a WHERE IN
121
+ * SQL clause for use in the WP_Query where clause
122
+ * @param string|array $values
123
+ * @return string
124
+ */
125
+ function format_where_in_value($values)
126
+ {
127
+ if (is_string($values) && strpos($values, ',') !== FALSE)
128
+ $values = explode(", ", $values);
129
+ elseif (!is_array($values))
130
+ $values = array($values);
131
+
132
+ // Quote the titles
133
+ foreach ($values as $index => $value) {
134
+ $values[$index] = "'{$value}'";
135
+ }
136
+
137
+ return implode(', ', $values);
138
+ }
139
+
140
+
141
+ /**
142
+ * Adds post_title to the where clause
143
+ * @param string $where
144
+ * @param WP_Query $wp_query
145
+ * @return string
146
+ */
147
+ function add_post_title_where_clauses(&$where, &$wp_query)
148
+ {
149
+ global $wpdb;
150
+
151
+ // Handle post_title query var
152
+ if (($titles = $wp_query->get('post_title'))) {
153
+ $titles = $this->format_where_in_value($titles);
154
+ $where .= " AND {$wpdb->posts}.post_title IN ({$titles})";
155
+ }
156
+
157
+ // Handle post_title_like query var
158
+ elseif (($value = $wp_query->get('post_title__like'))) {
159
+ $where .= " AND {$wpdb->posts}.post_title LIKE '{$value}'";
160
+ }
161
+ }
162
+
163
+
164
+ /**
165
+ * Adds post_name to the where clause
166
+ * @param type $where
167
+ * @param type $wp_query
168
+ */
169
+ function add_post_name_where_clauses(&$where, &$wp_query)
170
+ {
171
+ global $wpdb;
172
+
173
+ if (($name = $wp_query->get('page_name__like'))) {
174
+ $where .= " AND {$wpdb->posts}.post_name LIKE '{$name}'";
175
+ }
176
+ elseif (($names = $wp_query->get('page_name__in'))) {
177
+ $names = $this->format_where_in_value($names);
178
+ $where .= " AND {$wpdb->posts}.post_name IN ({$names})";
179
+ }
180
+ }
181
+
182
+ function get_type_list()
183
+ {
184
+ return array(
185
+ 'A_Datamapper_Factory' => 'adapter.datamapper_factory.php',
186
+ 'C_Datamapper_Installer' => 'class.datamapper_installer.php',
187
+ 'C_Datamapper' => 'class.datamapper.php',
188
+ 'C_Custompost_Datamapper_Driver' => 'class.custompost_datamapper_driver.php',
189
+ 'C_Customtable_Datamapper_Driver' => 'class.customtable_datamapper_driver.php',
190
+ 'C_Datamapper_Driver_Base' => 'class.datamapper_driver_base.php',
191
+ 'C_Datamapper_Model' => 'class.datamapper_model.php',
192
+ 'I_Custompost_Datamapper' => 'interface.custompost_datamapper.php',
193
+ 'I_Customtable_Datamapper' => 'interface.customtable_datamapper.php',
194
+ 'I_Datamapper_Driver' => 'interface.datamapper_driver.php',
195
+ 'I_Datamapper_Model' => 'interface.datamapper_model.php',
196
+ 'M_Datamapper' => 'module.datamapper.php'
197
+ );
198
+ }
199
+ }
200
+ new M_DataMapper();
products/photocrati_nextgen/modules/dynamic_stylesheet/adapter.dynamic_stylesheet_routes.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_Dynamic_Stylesheet_Routes extends Mixin
4
+ {
5
+ function initialize()
6
+ {
7
+ $this->object->add_pre_hook(
8
+ 'serve_request',
9
+ 'Add Dynamic Stylesheet Route',
10
+ get_class(),
11
+ 'add_dynamic_stylesheet_route'
12
+ );
13
+ }
14
+
15
+ function add_dynamic_stylesheet_route()
16
+ {
17
+ $app = $this->create_app('/nextgen-dcss');
18
+ $app->rewrite('/{\d}/{*}', '/index--{1}/data--{2}');
19
+ $app->route('/', 'I_Dynamic_Stylesheet#index');
20
+ }
21
+ }
products/photocrati_nextgen/modules/dynamic_stylesheet/class.dynamic_stylesheet_controller.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Dynamic_Stylesheet_Controller extends C_MVC_Controller
4
+ {
5
+ static $_instances = array();
6
+ var $_known_templates = array();
7
+ var $_app = NULL;
8
+
9
+ function define($context=FALSE)
10
+ {
11
+ parent::define($context);
12
+ $this->add_mixin('Mixin_Dynamic_Stylesheet_Instance_Methods');
13
+ $this->add_mixin('Mixin_Dynamic_Stylesheet_Actions');
14
+ $this->implement('I_Dynamic_Stylesheet');
15
+ }
16
+
17
+ function initialize()
18
+ {
19
+ parent::initialize();
20
+ $this->_app = C_NextGen_Global_Settings::get_instance()->dynamic_stylesheet_slug;
21
+ }
22
+
23
+ static function &get_instance($context=FALSE)
24
+ {
25
+ if (!isset(self::$_instances[$context])) {
26
+ $klass = get_class();
27
+ self::$_instances[$context] = new $klass($context);
28
+ }
29
+ return self::$_instances[$context];
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Provides instance methods for the dynamic stylesheet utility
35
+ */
36
+ class Mixin_Dynamic_Stylesheet_Instance_Methods extends Mixin
37
+ {
38
+ /**
39
+ * Registers a template with the dynamic stylesheet utility. A template
40
+ * must be registered before it can be loaded
41
+ * @param string $name
42
+ * @param string $template
43
+ */
44
+ function register($name, $template)
45
+ {
46
+ $this->object->_known_templates[$name] = $template;
47
+ }
48
+
49
+ /**
50
+ * Finds a registered template by name
51
+ * @param string $name
52
+ * @return int
53
+ */
54
+ function get_css_template_index($name)
55
+ {
56
+ return array_search($name, array_keys($this->object->_known_templates));
57
+ }
58
+
59
+ function get_css_template($index)
60
+ {
61
+ $keys = array_keys($this->object->_known_templates);
62
+ return $this->object->_known_templates[$keys[$index]];
63
+ }
64
+
65
+ /**
66
+ * Loads a template, along with the dynamic variables to be interpolated
67
+ * @param string $name
68
+ * @param array $vars
69
+ */
70
+ function enqueue($name, $data=array())
71
+ {
72
+ if (($index = $this->object->get_css_template_index($name)) !== FALSE)
73
+ {
74
+ if (is_subclass_of($data, 'C_DataMapper_Model'))
75
+ $data = $data->get_entity();
76
+ $data = $this->object->encode($data);
77
+ wp_enqueue_style(
78
+ 'dyncss-' . $index . $data . '@dynamic',
79
+ $this->object->get_router()->get_url("/{$this->object->_app}", FALSE) . "/{$index}/{$data}"
80
+ );
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Encodes $data
86
+ *
87
+ * base64 encoding uses '==' to denote the end of the sequence, but keep it out of the url
88
+ * @param $data
89
+ * @return string
90
+ */
91
+ function encode($data)
92
+ {
93
+ $data = json_encode($data);
94
+ $data = base64_encode($data);
95
+ $data = str_replace('/', '\\', $data);
96
+ $data = rtrim($data, '=');
97
+ return $data;
98
+ }
99
+
100
+ /**
101
+ * Decodes $data
102
+ *
103
+ * @param $data
104
+ * @return array|mixed
105
+ */
106
+ function decode($data)
107
+ {
108
+ $data = str_replace('\\', '/', $data);
109
+ $data = base64_decode($data . '==');
110
+ $data = json_decode($data);
111
+ return $data;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Provides controller actions for the dynamic stylesheet
117
+ */
118
+ class Mixin_Dynamic_Stylesheet_Actions extends Mixin
119
+ {
120
+ function index_action()
121
+ {
122
+ $this->set_content_type('css');
123
+ if (($data = $this->param('data')) !== FALSE && ($index = $this->param('index')) !== FALSE) {
124
+ $data = $this->object->decode($data);
125
+ $this->render_view($this->object->get_css_template($index), $data);
126
+ }
127
+ }
128
+ }
products/photocrati_nextgen/modules/dynamic_stylesheet/class.dynamic_stylesheet_installer.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Dynamic_Stylesheet_Installer
4
+ {
5
+ function __construct()
6
+ {
7
+ $this->settings = C_NextGen_Global_Settings::get_instance();
8
+ }
9
+
10
+ function install()
11
+ {
12
+ $this->settings->set_default_value('dynamic_stylesheet_slug', 'nextgen-dcss');
13
+ }
14
+ }
products/photocrati_nextgen/modules/dynamic_stylesheet/interface.dynamic_stylesheet.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Dynamic_Stylesheet
4
+ {
5
+ function register($name, $template);
6
+ function enqueue($name, $vars);
7
+ }
products/photocrati_nextgen/modules/dynamic_stylesheet/module.dynamic_stylesheet.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ {
5
+ Module: photocrati-dynamic_stylesheet,
6
+ Depends: { photocrati-mvc, photocrati-lzw }
7
+ }
8
+ */
9
+ class M_Dynamic_Stylesheet extends C_Base_Module
10
+ {
11
+ function define($context=FALSE)
12
+ {
13
+ parent::define(
14
+ 'photocrati-dynamic_stylesheet',
15
+ 'Dynamic Stylesheet',
16
+ 'Provides the ability to generate and enqueue a dynamic stylesheet',
17
+ '0.3',
18
+ 'http://www.nextgen-gallery.com',
19
+ 'Photocrati Media',
20
+ 'http://www.photocrati.com',
21
+ $context
22
+ );
23
+
24
+ include_once('class.dynamic_stylesheet_installer.php');
25
+ C_Photocrati_Installer::add_handler($this->module_id, 'C_Dynamic_Stylesheet_Installer');
26
+ }
27
+
28
+ function _register_utilities()
29
+ {
30
+ $this->get_registry()->add_utility(
31
+ "I_Dynamic_Stylesheet", 'C_Dynamic_Stylesheet_Controller'
32
+ );
33
+ }
34
+
35
+ function _register_adapters()
36
+ {
37
+ $this->get_registry()->add_adapter(
38
+ 'I_Router', 'A_Dynamic_Stylesheet_Routes'
39
+ );
40
+ }
41
+
42
+ function get_type_list()
43
+ {
44
+ return array(
45
+ 'A_Dynamic_Stylesheet_Routes' => 'adapter.dynamic_stylesheet_routes.php',
46
+ 'C_Dynamic_Stylesheet_Installer' => 'class.dynamic_stylesheet_installer.php',
47
+ 'C_Dynamic_Stylesheet_Controller' => 'class.dynamic_stylesheet_controller.php',
48
+ 'I_Dynamic_Stylesheet' => 'interface.dynamic_stylesheet.php'
49
+ );
50
+ }
51
+ }
52
+
53
+ new M_Dynamic_Stylesheet;
products/photocrati_nextgen/modules/dynamic_thumbnails/adapter.dynamic_thumbnail_routes.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_Dynamic_Thumbnail_Routes extends Mixin
4
+ {
5
+ function initialize()
6
+ {
7
+ $this->object->add_pre_hook(
8
+ 'serve_request',
9
+ 'Adds Dynamic Thumbnail routes',
10
+ get_class(),
11
+ 'add_dynamic_thumbnail_routes'
12
+ );
13
+ }
14
+
15
+ function add_dynamic_thumbnail_routes()
16
+ {
17
+ $app = $this->create_app('/nextgen-image');
18
+
19
+ // The C_Dynamic_Thumbnails Controller was created before the new
20
+ // router implementation was conceptualized. It uses it's own mechanism
21
+ // to parse the REQUEST_URI. It should be refactored to use the router's
22
+ // parameter mechanism, but for now - we'll just removed the segments
23
+ // from the router's visibility, and let the Dynamic Thumbnails Controller
24
+ // do it's own parsing
25
+ $app->rewrite('/{*}', '/');
26
+ $app->route('/', 'I_Dynamic_Thumbnails_Controller#index');
27
+ }
28
+ }
products/photocrati_nextgen/modules/dynamic_thumbnails/adapter.dynamic_thumbnails_storage_driver.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_Dynamic_Thumbnails_Storage_Driver extends Mixin
4
+ {
5
+ function get_image_abspath($image, $size=FALSE, $check_existance=FALSE)
6
+ {
7
+ $retval = NULL;
8
+ $dynthumbs = $this->object->get_registry()->get_utility('I_Dynamic_Thumbnails_Manager');
9
+
10
+ if ($dynthumbs && $dynthumbs->is_size_dynamic($size))
11
+ {
12
+ // If we have the id, get the actual image entity
13
+ if (is_numeric($image)) {
14
+ $image = $this->object->_image_mapper->find($image);
15
+ }
16
+
17
+ // Ensure we have the image entity - user could have passed in an
18
+ // incorrect id
19
+ if (is_object($image)) {
20
+ if ($folder_path = $this->object->get_cache_abspath($image->galleryid))
21
+ {
22
+ $params = $dynthumbs->get_params_from_name($size, true);
23
+ $image_filename = $dynthumbs->get_image_name($image, $params);
24
+
25
+ $image_path = path_join($folder_path, $image_filename);
26
+
27
+ if ($check_existance)
28
+ {
29
+ if (@file_exists($image_path))
30
+ {
31
+ $retval = $image_path;
32
+ }
33
+ }
34
+ else
35
+ {
36
+ $retval = $image_path;
37
+ }
38
+ }
39
+ }
40
+ }
41
+ else {
42
+ $retval = $this->call_parent('get_image_abspath', $image, $size, $check_existance);
43
+ }
44
+
45
+ return $retval;
46
+ }
47
+
48
+ function get_image_url($image, $size='full')
49
+ {
50
+ $retval = NULL;
51
+ $dynthumbs = $this->object->get_registry()->get_utility('I_Dynamic_Thumbnails_Manager');
52
+
53
+ if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) {
54
+
55
+ $abspath = $this->object->get_image_abspath($image, $size, true);
56
+
57
+ if ($abspath == null) {
58
+ $params = $dynthumbs->get_params_from_name($size, true);
59
+ $retval = $dynthumbs->get_image_url($image, $params);
60
+ }
61
+ }
62
+
63
+ if ($retval == null) {
64
+ $retval = $this->call_parent('get_image_url', $image, $size);
65
+ }
66
+
67
+ return $retval;
68
+ }
69
+
70
+ function get_image_dimensions($image, $size = 'full')
71
+ {
72
+ $retval = $this->call_parent('get_image_dimensions', $image, $size);
73
+
74
+ if ($retval == null) {
75
+ $dynthumbs = $this->object->get_registry()->get_utility('I_Dynamic_Thumbnails_Manager');
76
+
77
+ if ($dynthumbs && $dynthumbs->is_size_dynamic($size))
78
+ {
79
+ $new_dims = $this->object->calculate_image_size_dimensions($image, $size);
80
+
81
+ $retval = array('width' => $new_dims['real_width'], 'height' => $new_dims['real_height']);
82
+ }
83
+ }
84
+
85
+ return $retval;
86
+ }
87
+
88
+ function get_image_size_params($image, $size, $params = null, $skip_defaults = false)
89
+ {
90
+ $dynthumbs = $this->object->get_registry()->get_utility('I_Dynamic_Thumbnails_Manager');
91
+
92
+ if ($dynthumbs && $dynthumbs->is_size_dynamic($size))
93
+ {
94
+ $named_params = $dynthumbs->get_params_from_name($size, true);
95
+
96
+ foreach ($named_params as $param_name => $param_value)
97
+ {
98
+ $params[$param_name] = $param_value;
99
+ }
100
+ }
101
+
102
+ return $this->call_parent('get_image_size_params', $image, $size, $params, $skip_defaults);
103
+ }
104
+ }
products/photocrati_nextgen/modules/dynamic_thumbnails/class.dynamic_thumbnails_controller.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Dynamic_Thumbnails_Controller extends C_MVC_Controller
4
+ {
5
+ static $_instances = array();
6
+
7
+ function define($context=FALSE)
8
+ {
9
+ parent::define($context);
10
+ $this->implement('I_Dynamic_Thumbnails_Controller');
11
+ }
12
+
13
+ /**
14
+ * Returns an instance of this class
15
+ *
16
+ * @param string $context
17
+ * @return C_Dynamic_Thumbnails_Controller
18
+ */
19
+ static function get_instance($context=FALSE)
20
+ {
21
+ if (!isset(self::$_instances[$context])) {
22
+ $klass = get_class();
23
+ self::$_instances[$context] = new $klass($context);
24
+ }
25
+ return self::$_instances[$context];
26
+ }
27
+
28
+ function index_action()
29
+ {
30
+ $dynthumbs = $this->get_registry()->get_utility('I_Dynamic_Thumbnails_Manager');
31
+
32
+ $uri = $_SERVER['REQUEST_URI'];
33
+ $params = $dynthumbs->get_params_from_uri($uri);
34
+ $request_params = $params;
35
+
36
+ if ($params != null)
37
+ {
38
+ $storage = $this->get_registry()->get_utility('I_Gallery_Storage');
39
+
40
+ // Note, URLs should always include quality setting when returned by Gallery Storage component
41
+ // this sanity check is mostly for manually testing URLs
42
+ if (!isset($params['quality'])) {
43
+ // Note: there's a problem when doing this as using the same set of parameters to *retrieve* the image path/URL will lead to a different filename than the one tha was used to *generate* it (which went through here)
44
+ // The statement above about URLs always containing quality setting is not true anymore, this is because we need to retrieve default quality from the imgQuality and thumbquality settings, depending on "full" or "thumbnail" request in the ngglegacy storage
45
+ //$params['quality'] = 100;
46
+ }
47
+
48
+ $image_id = $params['image'];
49
+ $size = $dynthumbs->get_size_name($params);
50
+ $abspath = $storage->get_image_abspath($image_id, $size, true);
51
+ $valid = true;
52
+
53
+ // Render invalid image if hash check fails
54
+ if ($abspath == null) {
55
+ $uri_plain = $dynthumbs->get_uri_from_params($request_params);
56
+ $hash = wp_hash($uri_plain);
57
+
58
+ if (strpos($uri, $hash) === false) {
59
+ $valid = false;
60
+ $filename = $this->object->find_static_file('invalid_image.png');
61
+ $this->set_content_type('image/png');
62
+ readfile($filename);
63
+ $this->render();
64
+ }
65
+ }
66
+
67
+ if ($valid) {
68
+ $storage->render_image($image_id, $size);
69
+ }
70
+ }
71
+ }
72
+ }
products/photocrati_nextgen/modules/dynamic_thumbnails/class.dynamic_thumbnails_installer.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Dynamic_Thumbnails_Installer
4
+ {
5
+ function __construct()
6
+ {
7
+ $this->settings = C_NextGen_Global_Settings::get_instance();
8
+ }
9
+
10
+ function install()
11
+ {
12
+ $this->settings->set_default_value('dynamic_thumbnail_slug', 'nextgen-image');
13
+ }
14
+ }
products/photocrati_nextgen/modules/dynamic_thumbnails/class.dynamic_thumbnails_manager.php ADDED
@@ -0,0 +1,517 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Mixin_Dynamic_Thumbnails_Manager extends Mixin
4
+ {
5
+ function get_route_name()
6
+ {
7
+ return C_NextGen_Global_Settings::get_instance()->get('dynamic_thumbnail_slug');
8
+ }
9
+
10
+ function _get_params_sanitized($params)
11
+ {
12
+ if (isset($params['rotation']))
13
+ {
14
+ $rotation = intval($params['rotation']);
15
+
16
+ if ($rotation && in_array(abs($rotation), array(90, 180, 270)))
17
+ {
18
+ $rotation = $rotation % 360;
19
+
20
+ if ($rotation < 0)
21
+ {
22
+ $rotation = 360 - $rotation;
23
+ }
24
+
25
+ $params['rotation'] = $rotation;
26
+ }
27
+ else
28
+ {
29
+ unset($params['rotation']);
30
+ }
31
+ }
32
+
33
+ if (isset($params['flip']))
34
+ {
35
+ $flip = strtolower($params['flip']);
36
+
37
+ if (in_array($flip, array('h', 'v', 'hv')))
38
+ {
39
+ $params['flip'] = $flip;
40
+ }
41
+ else
42
+ {
43
+ unset($params['flip']);
44
+ }
45
+ }
46
+
47
+ return $params;
48
+ }
49
+
50
+ function get_uri_from_params($params)
51
+ {
52
+ $params = $this->object->_get_params_sanitized($params);
53
+
54
+ $image = isset($params['image']) ? $params['image'] : null;
55
+ $image_id = is_scalar($image) ? ((int)$image) : $image->pid;
56
+ $image_width = isset($params['width']) ? $params['width'] : null;
57
+ $image_height = isset($params['height']) ? $params['height'] : null;
58
+ $image_quality = isset($params['quality']) ? $params['quality'] : null;
59
+ $image_type = isset($params['type']) ? $params['type'] : null;
60
+ $image_crop = isset($params['crop']) ? $params['crop'] : null;
61
+ $image_watermark = isset($params['watermark']) ? $params['watermark'] : null;
62
+ $image_rotation = isset($params['rotation']) ? $params['rotation'] : null;
63
+ $image_flip = isset($params['flip']) ? $params['flip'] : null;
64
+ $image_reflection = isset($params['reflection']) ? $params['reflection'] : null;
65
+
66
+ $router = $this->get_registry()->get_utility('I_Router');
67
+
68
+ $uri = null;
69
+
70
+ $uri .= '/';
71
+ $uri .= $this->object->get_route_name() . '/';
72
+ $uri .= strval($image_id) . '/';
73
+
74
+ $uri .= strval($image_width) . 'x' . strval($image_height);
75
+
76
+ if ($image_quality != null)
77
+ {
78
+ $uri .= 'x' . strval($image_quality);
79
+ }
80
+
81
+ $uri .= '/';
82
+
83
+ if ($image_type != null)
84
+ {
85
+ $uri .= $image_type . '/';
86
+ }
87
+
88
+ if ($image_crop)
89
+ {
90
+ $uri .= 'crop/';
91
+ }
92
+
93
+ if ($image_watermark)
94
+ {
95
+ $uri .= 'watermark/';
96
+ }
97
+
98
+ if ($image_rotation)
99
+ {
100
+ $uri .= 'rotation-' . $image_rotation . '/';
101
+ }
102
+
103
+ if ($image_flip)
104
+ {
105
+ $uri .= 'flip-' . $image_flip . '/';
106
+ }
107
+
108
+ if ($image_reflection)
109
+ {
110
+ $uri .= 'reflection/';
111
+ }
112
+
113
+ return $uri;
114
+ }
115
+
116
+ function get_image_uri($image, $params)
117
+ {
118
+ $params['image'] = $image;
119
+ $uri = $this->object->get_uri_from_params($params);
120
+
121
+ if (substr($uri, -1) != '/')
122
+ {
123
+ $uri .= '/';
124
+ }
125
+
126
+ $uri .= wp_hash($uri) . '/';
127
+
128
+ return $uri;
129
+ }
130
+
131
+ function get_image_url($image, $params)
132
+ {
133
+ $router = $this->get_registry()->get_utility('I_Router');
134
+
135
+ return $router->get_url($this->object->get_image_uri($image, $params), FALSE);
136
+ }
137
+
138
+ function get_params_from_uri($uri)
139
+ {
140
+ $regex = '/\\/?' . $this->object->get_route_name() . '\\/(\\d+)(?:\\/(.*))?/';
141
+ $match = null;
142
+
143
+ // XXX move this URL clean up to I_Router?
144
+ $uri = preg_replace('/\\/index.php\\//', '/', $uri, 1);
145
+ $uri = trim($uri, '/');
146
+
147
+ if (@preg_match($regex, $uri, $match) > 0)
148
+ {
149
+ $image_id = $match[1];
150
+ $uri_args = isset($match[2]) ? explode('/', $match[2]) : array();
151
+ $params = array(
152
+ 'image' => $image_id,
153
+ );
154
+
155
+ foreach ($uri_args as $uri_arg)
156
+ {
157
+ $uri_arg_set = explode('-', $uri_arg);
158
+ $uri_arg_name = array_shift($uri_arg_set);
159
+ $uri_arg_value = $uri_arg_set ? array_shift($uri_arg_set) : null;
160
+ $size_match = null;
161
+
162
+ if ($uri_arg == 'watermark')
163
+ {
164
+ $params['watermark'] = true;
165
+ }
166
+ else if ($uri_arg_name == 'rotation')
167
+ {
168
+ $params['rotation'] = $uri_arg_value;
169
+ }
170
+ else if ($uri_arg_name == 'flip')
171
+ {
172
+ $params['flip'] = $uri_arg_value;
173
+ }
174
+ else if ($uri_arg == 'reflection')
175
+ {
176
+ $params['reflection'] = true;
177
+ }
178
+ else if ($uri_arg == 'crop')
179
+ {
180
+ $params['crop'] = true;
181
+ }
182
+ else if (in_array(strtolower($uri_arg), array('gif', 'jpg', 'png')))
183
+ {
184
+ $params['type'] = $uri_arg;
185
+ }
186
+ else if (preg_match('/(\\d+)x(\\d+)(?:x(\\d+))?/i', $uri_arg, $size_match) > 0)
187
+ {
188
+ $params['width'] = $size_match[1];
189
+ $params['height'] = $size_match[2];
190
+
191
+ if (isset($size_match[3]))
192
+ {
193
+ $params['quality'] = $size_match[3];
194
+ }
195
+ }
196
+ }
197
+
198
+ return $this->object->_get_params_sanitized($params);
199
+ }
200
+
201
+ return null;
202
+ }
203
+
204
+ function _get_name_prefix_list()
205
+ {
206
+ return array(
207
+ 'id' => 'nggid0',
208
+ 'size' => 'ngg0dyn-',
209
+ 'flags' => '00f0',
210
+ 'flag' => array('w0' => 'watermark', 'c0' => 'crop', 'r1' => 'rotation', 'f1' => 'flip', 'r0' => 'reflection', 't0' => 'type'),
211
+ 'flag_len' => 2,
212
+ 'max_value_length' => 15, // Note: this can't be increased beyond 15, as a single hexadecimal character is used to encode the value length in names. Increasing it over 15 requires changing the algorithm to use an arbitrary letter instead of a hexadecimal digit (this would bump max length to 35, 9 numbers + 26 letters)
213
+ );
214
+ }
215
+
216
+ function get_name_from_params($params, $only_size_name = false, $id_in_name = true)
217
+ {
218
+ $prefix_list = $this->object->_get_name_prefix_list();
219
+ $id_prefix = $prefix_list['id'];
220
+ $size_prefix = $prefix_list['size'];
221
+ $flags_prefix = $prefix_list['flags'];
222
+ $flags = $prefix_list['flag'];
223
+ $max_value_length = $prefix_list['max_value_length'];
224
+
225
+ $params = $this->object->_get_params_sanitized($params);
226
+ $image = isset($params['image']) ? $params['image'] : null;
227
+ $image_width = isset($params['width']) ? $params['width'] : null;
228
+ $image_height = isset($params['height']) ? $params['height'] : null;
229
+ $image_quality = isset($params['quality']) ? $params['quality'] : null;
230
+
231
+ $extension = null;
232
+ $name = null;
233
+
234
+ // if $only_size_name is false then we include the file name and image id for the image
235
+ if (!$only_size_name)
236
+ {
237
+ if (is_int($image))
238
+ {
239
+ $imap = $this->object->get_registry()->get_utility('I_Image_Mapper');
240
+ $image = $imap->find($image);
241
+ }
242
+
243
+ if ($image != null)
244
+ {
245
+ // this is used to remove the extension and then add it back at the end of the name
246
+ $extension = pathinfo($image->filename, PATHINFO_EXTENSION);
247
+
248
+ if ($extension != null)
249
+ {
250
+ $extension = '.' . $extension;
251
+ }
252
+
253
+ $name .= basename($image->filename, $extension);
254
+ $name .= '-';
255
+
256
+ if ($id_in_name)
257
+ {
258
+ $image_id = strval($image->pid);
259
+ $id_len = min($max_value_length, strlen($image_id));
260
+ $id_len_hex = dechex($id_len);
261
+
262
+ // sanity check, should never occurr if $max_value_length is not messed up, ensure only 1 character is used to encode length or else skip parameter
263
+ if (strlen($id_len_hex) == 1)
264
+ {
265
+ $name .= $id_prefix . $id_len . substr($image_id, 0, $id_len);
266
+ $name .= '-';
267
+ }
268
+ }
269
+ }
270
+ }
271
+
272
+ $name .= $size_prefix;
273
+ $name .= strval($image_width) . 'x' . strval($image_height);
274
+
275
+ if ($image_quality != null)
276
+ {
277
+ $name .= 'x' . $image_quality;
278
+ }
279
+
280
+ $name .= '-';
281
+
282
+ $name .= $flags_prefix;
283
+
284
+ foreach ($flags as $flag_prefix => $flag_name)
285
+ {
286
+ $flag_value = 0;
287
+
288
+ if (isset($params[$flag_name]))
289
+ {
290
+ $flag_value = $params[$flag_name];
291
+
292
+ if (!is_string($flag_value))
293
+ {
294
+ // only strings or ints allowed, sprintf is required because intval(0) returns '' and not '0'
295
+ $flag_value = intval($flag_value);
296
+ $flag_value = sprintf('%d', $flag_value);
297
+ }
298
+ }
299
+
300
+ $flag_value = strval($flag_value);
301
+ $flag_len = min($max_value_length, strlen($flag_value));
302
+ $flag_len_hex = dechex($flag_len);
303
+
304
+ // sanity check, should never occurr if $max_value_length is not messed up, ensure only 1 character is used to encode length or else skip parameter
305
+ if (strlen($flag_len_hex) == 1)
306
+ {
307
+ $name .= $flag_prefix . $flag_len . substr($flag_value, 0, $flag_len);
308
+ }
309
+ }
310
+
311
+ $name .= $extension;
312
+
313
+ return $name;
314
+ }
315
+
316
+ function get_size_name($params)
317
+ {
318
+ $name = $this->object->get_name_from_params($params, true);
319
+
320
+ return $name;
321
+ }
322
+
323
+ function get_image_name($image, $params)
324
+ {
325
+ $params['image'] = $image;
326
+ $name = $this->object->get_name_from_params($params);
327
+
328
+ return $name;
329
+ }
330
+
331
+ function get_params_from_name($name, $is_only_size_name = false)
332
+ {
333
+ $prefix_list = $this->object->_get_name_prefix_list();
334
+ $id_prefix = $prefix_list['id'];
335
+ $size_prefix = $prefix_list['size'];
336
+ $flags_prefix = $prefix_list['flags'];
337
+ $max_value_length = $prefix_list['max_value_length'];
338
+ $size_name = null;
339
+ $id_name = null;
340
+ $params = array();
341
+
342
+ if (!$is_only_size_name)
343
+ {
344
+ $extension = pathinfo($name, PATHINFO_EXTENSION);
345
+
346
+ if ($extension != null)
347
+ {
348
+ $extension = '.' . $extension;
349
+ }
350
+
351
+ $name = basename($name, $extension);
352
+ }
353
+
354
+ $size_index = strrpos($name, $size_prefix);
355
+
356
+ if ($size_index > 0 || $size_index === 0)
357
+ {
358
+ // check if name contains dynamic size/params info by looking for prefix
359
+ $size_name = substr($name, $size_index);
360
+ }
361
+
362
+ if (!$is_only_size_name)
363
+ {
364
+ // name should contain the image id, search for prefix
365
+ $id_index = strrpos($name, $id_prefix);
366
+
367
+ if ($id_index > 0 || $id_index === 0)
368
+ {
369
+ if ($size_index > 0 && $size_index > $id_index)
370
+ {
371
+ $id_name = substr($name, $id_index, ($size_index - $id_index));
372
+ }
373
+ else
374
+ {
375
+ $id_name = substr($name, $id_index);
376
+ }
377
+ }
378
+ }
379
+
380
+ // Double check we got a correct dynamic size/params string
381
+ if (substr($size_name, 0, strlen($size_prefix)) == $size_prefix)
382
+ {
383
+ $flags = $prefix_list['flag'];
384
+ // get the length of the flag id (the key in the $flags array) in the string (how many characters to consume)
385
+ $flag_id_len = $prefix_list['flag_len'];
386
+ $params_str = substr($size_name, strlen($size_prefix));
387
+ $params_parts = explode('-', $params_str);
388
+
389
+ // $param_part is a single param, separated by '-'
390
+ foreach ($params_parts as $param_part)
391
+ {
392
+ // Parse WxHxQ - Q=quality
393
+ $param_size = explode('x', $param_part);
394
+ $param_size_count = count($param_size);
395
+
396
+ if (substr($param_part, 0, strlen($flags_prefix)) == $flags_prefix)
397
+ {
398
+ /* Set flags, using $flags keys as prefixes */
399
+
400
+ // move string pointer up (after the main flags prefix)
401
+ $param_flags = substr($param_part, strlen($flags_prefix));
402
+ $param_flags_len = strlen($param_flags);
403
+ $flags_todo = $flags;
404
+
405
+ while (true)
406
+ {
407
+ // ensure we don't run into an infinite loop ;)
408
+ if (count($flags_todo) == 0 || strlen($param_flags) == 0)
409
+ {
410
+ break;
411
+ }
412
+
413
+ // get the flag prefix (a key in the $flags array) using flag id length
414
+ $flag_prefix = substr($param_flags, 0, $flag_id_len);
415
+ // move string pointer up (after the single flag prefix)
416
+ $param_flags = substr($param_flags, $flag_id_len);
417
+
418
+ // get the length of the flag value in the string (how many characters to consume)
419
+ // flag value length is stored in a single hexadecimal character next to the flag prefix
420
+ $flag_value_len = min(hexdec(substr($param_flags, 0, 1)), min($max_value_length, strlen($param_flags) - 1));
421
+ // get the flag value
422
+ $flag_value = substr($param_flags, 1, $flag_value_len);
423
+ // move string pointer up (after the entire flag)
424
+ $param_flags = substr($param_flags, $flag_value_len + 1);
425
+
426
+ // make sure the flag is supported
427
+ if (isset($flags[$flag_prefix]))
428
+ {
429
+ $flag_name = $flags[$flag_prefix];
430
+
431
+ if (is_numeric($flag_value))
432
+ {
433
+ // convert numerical flags to integers
434
+ $flag_value = intval($flag_value);
435
+ }
436
+
437
+ $params[$flag_name] = $flag_value;
438
+
439
+ if (isset($flags_todo[$flag_prefix]))
440
+ {
441
+ unset($flags_todo[$flag_prefix]);
442
+ }
443
+ }
444
+ else
445
+ {
446
+ // XXX unknown flag?
447
+ }
448
+ }
449
+ }
450
+ else if ($param_size_count == 2 || $param_size_count == 3)
451
+ {
452
+ // Set W H Q
453
+ $params['width'] = intval($param_size[0]);
454
+ $params['height'] = intval($param_size[1]);
455
+
456
+ if (isset($param_size[2]) && intval($param_size[2]) > 0)
457
+ {
458
+ $params['quality'] = intval($param_size[2]);
459
+ }
460
+ }
461
+ }
462
+ }
463
+
464
+ // Double check we got a correct id string
465
+ if (substr($id_name, 0, strlen($id_prefix)) == $id_prefix)
466
+ {
467
+ // move string pointer up (after the prefix)
468
+ $id_name = substr($id_name, strlen($id_prefix));
469
+ // get the length of the image id in the string (how many characters to consume)
470
+ $id_len = min(hexdec(substr($id_name, 0, 1)), min($max_value_length, strlen($id_name) - 1));
471
+ // get the id based on old position and id length
472
+ $image_id = intval(substr($id_name, 1, $id_len));
473
+
474
+ if ($image_id > 0)
475
+ {
476
+ $params['image'] = $image_id;
477
+ }
478
+ }
479
+
480
+ return $this->object->_get_params_sanitized($params);
481
+ }
482
+
483
+ function is_size_dynamic($name, $is_only_size_name = false)
484
+ {
485
+ $params = $this->object->get_params_from_name($name, $is_only_size_name);
486
+
487
+ if (isset($params['width']) && isset($params['height']))
488
+ {
489
+ return true;
490
+ }
491
+
492
+ return false;
493
+ }
494
+ }
495
+
496
+ class C_Dynamic_Thumbnails_Manager extends C_Component
497
+ {
498
+ static $_instances = array();
499
+
500
+ function define($context=FALSE)
501
+ {
502
+ parent::define($context);
503
+
504
+ $this->implement('I_Dynamic_Thumbnails_Manager');
505
+ $this->add_mixin('Mixin_Dynamic_Thumbnails_Manager');
506
+ }
507
+
508
+ static function get_instance($context = False)
509
+ {
510
+ if (!isset(self::$_instances[$context]))
511
+ {
512
+ self::$_instances[$context] = new C_Dynamic_Thumbnails_Manager($context);
513
+ }
514
+
515
+ return self::$_instances[$context];
516
+ }
517
+ }
products/photocrati_nextgen/modules/dynamic_thumbnails/interface.dynamic_thumbnails_controller.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Dynamic_Thumbnails_Controller
4
+ {
5
+ }
products/photocrati_nextgen/modules/dynamic_thumbnails/interface.dynamic_thumbnails_manager.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Dynamic_Thumbnails_Manager
4
+ {
5
+ function get_route_name();
6
+
7
+ function get_uri_from_params($params);
8
+
9
+ function get_image_uri($image, $params);
10
+
11
+ function get_image_url($image, $params);
12
+
13
+ function get_params_from_uri($uri);
14
+
15
+ function get_name_from_params($params, $only_size_name = false, $id_in_name = true);
16
+
17
+ function get_size_name($params);
18
+
19
+ function get_image_name($image, $params);
20
+
21
+ function get_params_from_name($name, $is_only_size_name = false);
22
+
23
+ function is_size_dynamic($name, $is_only_size_name = false);
24
+ }
products/photocrati_nextgen/modules/dynamic_thumbnails/module.dynamic_thumbnails.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /***
4
+ {
5
+ Module: photocrati-dynamic_thumbnails
6
+ }
7
+ ***/
8
+ class M_Dynamic_Thumbnails extends C_Base_Module
9
+ {
10
+ function define()
11
+ {
12
+ parent::define(
13
+ 'photocrati-dynamic_thumbnails',
14
+ 'Dynamic Thumbnails',
15
+ 'Adds support for dynamic thumbnails',
16
+ '0.2',
17
+ 'http://www.nextgen-gallery.com',
18
+ 'Photocrati Media',
19
+ 'http://www.photocrati.com'
20
+ );
21
+
22
+ include_once('class.dynamic_thumbnails_installer.php');
23
+ C_Photocrati_Installer::add_handler($this->module_id, 'C_Dynamic_Thumbnails_Installer');
24
+ }
25
+
26
+ function _register_adapters()
27
+ {
28
+ $this->get_registry()->add_adapter('I_Router', 'A_Dynamic_Thumbnail_Routes');
29
+ $this->get_registry()->add_adapter('I_GalleryStorage_Driver', 'A_Dynamic_Thumbnails_Storage_Driver');
30
+ }
31
+
32
+ function _register_utilities()
33
+ {
34
+ $this->get_registry()->add_utility('I_Dynamic_Thumbnails_Manager', 'C_Dynamic_Thumbnails_Manager');
35
+ $this->get_registry()->add_utility('I_Dynamic_Thumbnails_Controller', 'C_Dynamic_Thumbnails_Controller');
36
+ }
37
+
38
+ function get_type_list()
39
+ {
40
+ return array(
41
+ 'A_Dynamic_Thumbnails_Storage_Driver' => 'adapter.dynamic_thumbnails_storage_driver.php',
42
+ 'A_Dynamic_Thumbnail_Routes' => 'adapter.dynamic_thumbnail_routes.php',
43
+ 'C_Dynamic_Thumbnails_Installer' => 'class.dynamic_thumbnails_installer.php',
44
+ 'C_Dynamic_Thumbnails_Controller' => 'class.dynamic_thumbnails_controller.php',
45
+ 'C_Dynamic_Thumbnails_Manager' => 'class.dynamic_thumbnails_manager.php',
46
+ 'I_Dynamic_Thumbnails_Controller' => 'interface.dynamic_thumbnails_controller.php',
47
+ 'I_Dynamic_Thumbnails_Manager' => 'interface.dynamic_thumbnails_manager.php'
48
+ );
49
+ }
50
+
51
+ }
52
+
53
+ new M_Dynamic_Thumbnails();
products/photocrati_nextgen/modules/dynamic_thumbnails/static/invalid_image.png ADDED
Binary file
products/photocrati_nextgen/modules/frame_communication/class.frame_communication_installer.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Frame_Communication_Installer
4
+ {
5
+ function __construct()
6
+ {
7
+ $this->settings = C_NextGen_Global_Settings::get_instance();
8
+ }
9
+
10
+ function install()
11
+ {
12
+ $this->settings->set_default_value('frame_communication_option_name', 'X-Frame-Events');
13
+ }
14
+ }
products/photocrati_nextgen/modules/frame_communication/class.frame_event_publisher.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Frame_Event_Publisher extends C_Component
4
+ {
5
+ static $_instances = array();
6
+ var $setting_name = NULL;
7
+
8
+ function define($context=FALSE)
9
+ {
10
+ parent::define($context);
11
+ $this->add_mixin('Mixin_Frame_Event_Publisher');
12
+ $this->implement('I_Frame_Event_Publisher');
13
+ }
14
+
15
+ function initialize()
16
+ {
17
+ parent::initialize();
18
+ $this->setting_name = C_NextGen_Global_Settings::get_instance()->frame_communication_option_name;
19
+ }
20
+
21
+ /**
22
+ * Gets an instance of the publisher
23
+ * @param string $context
24
+ * @return C_Frame_Event_Publisher
25
+ */
26
+ static function get_instance($context=FALSE)
27
+ {
28
+ if (!isset(self::$_instances[$context])) {
29
+ $klass = get_class();
30
+ self::$_instances[$context] = new $klass($context);
31
+ }
32
+ return self::$_instances[$context];
33
+ }
34
+ }
35
+
36
+ class Mixin_Frame_Event_Publisher extends Mixin
37
+ {
38
+ /**
39
+ * Encodes data for a setting
40
+ * @param array $data
41
+ * @return string
42
+ */
43
+ function _encode($data)
44
+ {
45
+ return rawurlencode(json_encode($data));
46
+ }
47
+
48
+ /**
49
+ * Decodes data from a setting
50
+ * @param string $data
51
+ * @return array
52
+ */
53
+ function _decode($data)
54
+ {
55
+ return (array)json_decode(rawurldecode($data));
56
+ }
57
+
58
+ /**
59
+ * Adds a setting to the frame events
60
+ * @param type $data
61
+ * @return type
62
+ */
63
+ function add_event($data)
64
+ {
65
+ $id = md5(serialize($data));
66
+ $data['context'] = $this->object->context;
67
+ setrawcookie($this->object->setting_name.'_'.$id,$this->object->_encode($data));
68
+
69
+ return $data;
70
+ }
71
+ }
products/photocrati_nextgen/modules/frame_communication/interface.frame_event_publisher.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Frame_Event_Publisher
4
+ {
5
+
6
+ }
products/photocrati_nextgen/modules/frame_communication/module.frame_communication.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /***
4
+ {
5
+ Module: photocrati-frame_communication,
6
+ Depends: { photocrati-router }
7
+ }
8
+ ***/
9
+
10
+ class M_Frame_Communication extends C_Base_Module
11
+ {
12
+ function define($context=FALSE)
13
+ {
14
+ parent::define(
15
+ 'photocrati-frame_communication',
16
+ 'Frame/iFrame Inter-Communication',
17
+ 'Provides a means for HTML frames to share server-side events with each other',
18
+ '0.2',
19
+ 'http://www.nextgen-gallery.com',
20
+ 'Photocrati Media',
21
+ 'http://www.photocrati.com',
22
+ $context
23
+ );
24
+
25
+ include_once('class.frame_communication_installer.php');
26
+ C_Photocrati_Installer::add_handler($this->module_id, 'C_Frame_Communication_Installer');
27
+ }
28
+
29
+ function _register_utilities()
30
+ {
31
+ $this->get_registry()->add_utility(
32
+ 'I_Frame_Event_Publisher', 'C_Frame_Event_Publisher'
33
+ );
34
+ }
35
+
36
+ function _register_hooks()
37
+ {
38
+ add_action('admin_enqueue_scripts', array(&$this, 'enqueue_admin_scripts'));
39
+
40
+ }
41
+
42
+ function enqueue_admin_scripts()
43
+ {
44
+ $router = $this->get_registry()->get_utility('I_Router');
45
+
46
+ wp_register_script(
47
+ 'frame_event_publisher',
48
+ $router->get_static_url('photocrati-frame_communication#frame_event_publisher.js'),
49
+ array('jquery')
50
+ );
51
+ wp_enqueue_script('frame_event_publisher');
52
+ }
53
+
54
+ function get_type_list()
55
+ {
56
+ return array(
57
+ 'C_Frame_Communication_Installer' => 'class.frame_communication_installer.php',
58
+ 'C_Frame_Event_Publisher' => 'class.frame_event_publisher.php',
59
+ 'I_Frame_Event_Publisher' => 'interface.frame_event_publisher.php'
60
+ );
61
+ }
62
+ }
63
+
64
+ new M_Frame_Communication();
products/photocrati_nextgen/modules/frame_communication/static/frame_event_publisher.js ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ window.Frame_Event_Publisher = {
2
+ id: window.name,
3
+ cookie_name: 'X-Frame-Events',
4
+ received: [],
5
+ initialized: false,
6
+ children: {},
7
+
8
+ is_parent: function(){
9
+ return self.parent.document === self.document;
10
+ },
11
+
12
+ is_child: function(){
13
+ return !this.is_parent();
14
+ },
15
+
16
+ setup_ajax_handlers: function() {
17
+ var publisher = this;
18
+ jQuery(document).ajaxComplete(function(e, xhr, settings) {
19
+ setTimeout(function() {
20
+ publisher.ajax_handler();
21
+ }, 0);
22
+ });
23
+ },
24
+
25
+ ajax_handler: function() {
26
+ this.broadcast(this.get_events(document.cookie));
27
+ },
28
+
29
+ initialize: function(){
30
+ this.setup_ajax_handlers();
31
+ if (this.id.length == 0) this.id = "Unknown";
32
+ this.received = this.get_events(document.cookie);
33
+ this.initialized = true;
34
+ if (this.is_parent()) this.emit(this.received, true);
35
+ return this.received;
36
+ },
37
+
38
+ register_child: function(child) {
39
+ this.children[child.id] = child;
40
+ },
41
+
42
+ broadcast: function(events, child){
43
+ if (!this.initialized) events = this.initialize();
44
+ if (this.is_child()) {
45
+ if (arguments.length <= 1) child = window;
46
+ this.find_parent(child).register_child(child.Frame_Event_Publisher);
47
+ this.notify_parent(events, child);
48
+ }
49
+ else {
50
+ if (arguments.length == 0) events = this.received;
51
+ this.notify_children(events);
52
+ }
53
+
54
+ },
55
+
56
+ /**
57
+ * Notifies the parent with a list of events to broadcast
58
+ */
59
+ notify_parent: function(events, child){
60
+ this.find_parent(child).broadcast(events, child);
61
+ },
62
+
63
+ /**
64
+ * Notifies (broadcasts) to children the list of available events
65
+ */
66
+ notify_children: function(events){
67
+ this.emit(events);
68
+ for (var index in this.children) {
69
+ var child = this.children[index];
70
+ try {
71
+ child.emit(events);
72
+ }
73
+ catch (ex) {
74
+ if (typeof(console) != "undefined") console.log(ex);
75
+ delete this.children.index;
76
+ }
77
+ }
78
+ },
79
+
80
+ /**
81
+ * Finds the parent window for the current child window
82
+ */
83
+ find_parent: function(child){
84
+ var retval = child;
85
+ try {
86
+ while (retval.document !== retval.parent.document) retval = retval.parent;
87
+ }
88
+ catch (ex){
89
+ if (typeof(console) != "undefined") console.log(ex);
90
+ }
91
+ return retval.Frame_Event_Publisher;
92
+ },
93
+
94
+ /**
95
+ * Emits all known events to all children
96
+ */
97
+ emit: function(events, forced){
98
+ if (typeof(forced) == "undefined") forced = false;
99
+ for (var event_id in events) {
100
+ var event = events[event_id];
101
+ if (!forced && !this.has_received_event(event_id)) {
102
+ if (typeof(console) != "undefined") console.log("Emitting "+event_id+":"+event.event+" to "+this.id);
103
+ this.trigger_event(event_id, events[event_id]);
104
+ }
105
+ }
106
+ },
107
+
108
+ has_received_event: function(id){
109
+ return this.received[id] != undefined;
110
+ },
111
+
112
+ trigger_event: function(id, event){
113
+ var signal = event.context+':'+event.event;
114
+ event.id = id;
115
+ if (typeof(window) != "undefined") jQuery(window).trigger(signal, event);
116
+ this.received[id] = event;
117
+ },
118
+
119
+ /**
120
+ * Parses the events found in the cookie
121
+ */
122
+ get_events: function(cookie){
123
+ var frame_events = {};
124
+ var cookies = cookie.split(' ');
125
+ try {
126
+ for (var i=0; i<cookies.length; i++) {
127
+ var current_cookie = cookies[i];
128
+ var parts = current_cookie.match(/X-Frame-Events_([^=]+)=(.*)/);
129
+ if (parts) {
130
+ var event_id = parts[1];
131
+ var event_data = parts[2].replace(/;$/, '');
132
+ frame_events[event_id] = JSON.parse(unescape(event_data));
133
+ var cookie_name = 'X-Frame-Events_'+event_id;
134
+ this.delete_cookie(cookie_name);
135
+ }
136
+ }
137
+ }
138
+ catch (Exception) {}
139
+ return frame_events;
140
+ },
141
+
142
+ delete_cookie: function(cookie){
143
+ var date = new Date();
144
+ document.cookie = cookie+'=; expires='+date.toGMTString()+';';
145
+ },
146
+
147
+ listen_for: function(signal, callback){
148
+ var publisher = this;
149
+ jQuery(window).bind(signal, function(e, event){
150
+ var context = event.context;
151
+ var event_id = event.id;
152
+ if (!publisher.has_received_event(event_id)) {
153
+ callback.call(publisher, event);
154
+ publisher.received[event_id] = event;
155
+ }
156
+ });
157
+ }
158
+ }
159
+
160
+ jQuery(function($){
161
+ Frame_Event_Publisher.broadcast();
162
+ });
products/photocrati_nextgen/modules/fs/class.fs.php ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Fs extends C_Component
4
+ {
5
+ static $_instances = array();
6
+ var $_document_root;
7
+
8
+ /**
9
+ * Gets an instance of the FS utility
10
+ * @param mixed $context
11
+ * @return C_Fs
12
+ */
13
+ static function &get_instance($context=FALSE)
14
+ {
15
+ if (!isset(self::$_instances[$context])) {
16
+ $klass = get_class();
17
+ self::$_instances[$context] = new $klass($context);
18
+ }
19
+ return self::$_instances[$context];
20
+ }
21
+
22
+ /**
23
+ * Defines the instance of the FS utility
24
+ * @param mixed $context the context in this case is the product
25
+ */
26
+ function define($context=FALSE)
27
+ {
28
+ parent::define($context);
29
+ $this->add_mixin('Mixin_Fs_Instance_Methods');
30
+ $this->implement('I_Fs');
31
+ }
32
+
33
+ function initialize()
34
+ {
35
+ parent::initialize();
36
+ $this->_document_root = $this->set_document_root($_SERVER['DOCUMENT_ROOT']);
37
+ }
38
+ }
39
+
40
+ class Mixin_Fs_Instance_Methods extends Mixin
41
+ {
42
+
43
+ function add_trailing_slash($path)
44
+ {
45
+ if (substr($path, -1) != '/') $path .= '/';
46
+ return $path;
47
+ }
48
+
49
+
50
+ /**
51
+ * Returns a calculated path to a file
52
+ * @param string $path
53
+ * @param string $module
54
+ * @param boolean $relpath
55
+ * @returns string
56
+ */
57
+ function get_abspath($path, $module=FALSE, $relpath=FALSE)
58
+ {
59
+ // Wel'l assume that we're to calculate the path relative to
60
+ // the site document root
61
+ $retval = $path;
62
+ if (strpos($path, $this->get_document_root()) === FALSE) {
63
+ $retval = $this->join_paths(
64
+ $this->get_document_root(),
65
+ $path
66
+ );
67
+ }
68
+
69
+ // If a module is provided, then we should calculate the path
70
+ // relative to the module directory
71
+ if ($module) {
72
+ if (($module_dir = $this->get_registry()->get_module_dir($module))) {
73
+ $retval = $this->join_paths($module_dir, $path);
74
+ }
75
+ else {
76
+ $retval = $this->join_path(
77
+ $this->get_document_root(), $module, $path
78
+ );
79
+ }
80
+ }
81
+
82
+ // Return the calculated path relative to the document root
83
+ if ($relpath) $retval = $this->object->remove_path_segment(
84
+ $retval, $this->get_document_root()
85
+ );
86
+
87
+ return $retval;
88
+ }
89
+
90
+
91
+ /**
92
+ * Returns a calculated relpath to a particular file
93
+ * @param string $path
94
+ * @param string $module
95
+ * @return string
96
+ */
97
+ function get_relpath($path, $module=FALSE)
98
+ {
99
+ return $this->object->get_abspath($path, $module, TRUE);
100
+ }
101
+
102
+ /**
103
+ * Removes a path segment from a url or filesystem path
104
+ * @param string $path
105
+ * @param string $segment
106
+ * @return string
107
+ */
108
+ function remove_path_segment($path, $segment)
109
+ {
110
+ if (substr($segment, -1) == '/') $segment = substr($segment, 0, -1);
111
+ $parts = explode($segment, $path);
112
+ return $this->join_paths($parts);
113
+ }
114
+
115
+
116
+ /**
117
+ * Gets the absolute path to a file/directory for a specific Pope product
118
+ *
119
+ * If the path doesn't exist, then NULL is returned
120
+ * @param string $path
121
+ * @param string $module
122
+ * @returns string|NULL
123
+ */
124
+ function find_abspath($path, $module=FALSE, $relpath=FALSE, $search_paths=array())
125
+ {
126
+ $retval = NULL;
127
+
128
+ // Ensure that we weren't passed a module id in the path
129
+ if (!$module)
130
+ list($path, $module) = $this->object->parse_formatted_path($path);
131
+
132
+ if (@file_exists($path))
133
+ {
134
+ $retval = $path;
135
+ }
136
+ else {
137
+
138
+ // Ensure that we know where to search for the file
139
+ if (!$search_paths)
140
+ $search_paths = $this->object->get_search_paths($path, $module);
141
+
142
+ // See if the file is located under one of the search paths directly
143
+ foreach ($search_paths as $dir) {
144
+ if (@file_exists($this->join_paths($dir, $path))) {
145
+ $retval = $this->join_paths($dir, $path);
146
+ break;
147
+ }
148
+ }
149
+
150
+ // Use rglob to find the file
151
+ if (!$retval) foreach ($search_paths as $dir) {
152
+ if (($retval = $this->object->_rglob($dir, $path))) {
153
+ break;
154
+ }
155
+ }
156
+
157
+ // Return the relative path if we're to do so
158
+ if ($relpath) {
159
+ $retval = $this->object->remove_path_segment($retval, $this->get_document_root());
160
+ }
161
+ }
162
+
163
+ return $retval;
164
+ }
165
+
166
+ /**
167
+ * Returns a list of directories to search for a particular filename
168
+ * @param string $path
169
+ * @param string $module
170
+ * @return array
171
+ */
172
+ function get_search_paths($path, $module=FALSE)
173
+ {
174
+ $append_module = FALSE;
175
+
176
+ // Ensure that we weren't passed a module id in the path
177
+ if (!$module) list($path, $module) = $this->object->parse_formatted_path($path);
178
+
179
+ // Directories to search
180
+ $directories = array();
181
+
182
+ // If a name of a module has been provided, then we need to search within
183
+ // that directory first
184
+ if ($module) {
185
+
186
+ // Were we given a module id?
187
+ if (($module_dir = $this->get_registry()->get_module_dir($module))) {
188
+ $directories[] = $module_dir;
189
+ }
190
+ else {
191
+ $append_module = TRUE;
192
+ }
193
+ }
194
+
195
+ // Add product's module directories
196
+ foreach ($this->get_registry()->get_product_list() as $product_id) {
197
+ $product_dir = $this->get_registry()->get_product_module_path($product_id);
198
+ if ($append_module) $directories[] = $this->join_paths(
199
+ $product_dir, $module
200
+ );
201
+ $directories[] = $product_dir;
202
+ }
203
+
204
+ // If all else fails, we search from the document root
205
+ $directories[] = $this->get_document_root();
206
+
207
+ return $directories;
208
+ }
209
+
210
+ /**
211
+ * Searches for a file recursively
212
+ *
213
+ * @param string $base_path
214
+ * @param string $file
215
+ * @return string
216
+ */
217
+ function _rglob($base_path, $file)
218
+ {
219
+ $retval = NULL;
220
+
221
+ $results = @file_exists($this->join_paths($base_path, $file));
222
+
223
+ // Must be located in a sub-directory
224
+ if (!$results)
225
+ {
226
+ // the modules cache a list of all their files when they are initialized. Ask POPE for our current
227
+ // modules and inspect their file listing to determine which module provides what we need
228
+ $modules = $this->object->get_registry()->get_module_list();
229
+ foreach ($modules as $module) {
230
+ $module_file_list = array_values($this->object->get_registry()->get_module($module)->get_type_list());
231
+ $module_dir = $this->object->get_registry()->get_module_dir($module);
232
+
233
+ $variations = array(
234
+ $file,
235
+ ltrim($file, DIRECTORY_SEPARATOR)
236
+ );
237
+
238
+ foreach ($variations as $variant) {
239
+ if (in_array($variant, $module_file_list))
240
+ {
241
+ $retval = $this->join_paths($module_dir, $variant);
242
+ break 2;
243
+ }
244
+ }
245
+ }
246
+ }
247
+ else {
248
+ $retval = $this->join_paths($base_path, $file);
249
+ }
250
+
251
+ return $retval;
252
+ }
253
+
254
+ /**
255
+ * Gets the relative path to a file/directory for a specific Pope product.
256
+ * If the path doesn't exist, then NULL is returned
257
+ * @param type $path
258
+ * @param type $module
259
+ * @returns string|NULL
260
+ */
261
+ function find_relpath($path, $module=FALSE)
262
+ {
263
+ return $this->object->find_abspath($path, $module, TRUE);
264
+ }
265
+
266
+
267
+ /**
268
+ * Joins multiple path segments together
269
+ * @return string
270
+ */
271
+ function join_paths()
272
+ {
273
+ $segments = array();
274
+ $retval = array();
275
+ $protocol = NULL;
276
+ $params = func_get_args();
277
+ $this->_flatten_array($params, $segments);
278
+
279
+ // if a protocol exists strip it from the string and store it for later
280
+ $pattern = "#^[a-zA-Z].+://#i";
281
+ preg_match($pattern, $segments[0], $matches);
282
+ if (!empty($matches)) {
283
+ $protocol = reset($matches);
284
+ $segments[0] = preg_replace($pattern, '', $segments[0], 1);
285
+ }
286
+
287
+ foreach ($segments as $segment) {
288
+ $segment = trim($segment, '/\\');
289
+ $pieces = array_values(preg_split('/[\/\\\\]/', $segment));
290
+
291
+ // determine if each piece should be appended to $retval
292
+ foreach ($pieces as $ndx => $val) {
293
+ $one = array_search($val, $retval);
294
+ $two = array_search($val, $pieces);
295
+ $one = (FALSE === $one ? 0 : count($one) + 1);
296
+ $two = (FALSE === $two ? 0 : count($two) + 1);
297
+ if (!empty($protocol)) {
298
+ if (@$retval[$ndx] !== $val || $two >= $one)
299
+ $retval[] = $val;
300
+ }
301
+ else {
302
+ if (@$retval[$ndx] !== $val && $two >= $one)
303
+ $retval[] = $val;
304
+ }
305
+ }
306
+
307
+ }
308
+
309
+ $retval = $protocol . implode('/', $retval);
310
+
311
+ if ((empty($protocol) && 'WINNT' !== PHP_OS)
312
+ && strpos($retval, '/') !== 0
313
+ && is_null($protocol)
314
+ && !@file_exists($retval))
315
+ {
316
+ $retval = '/' . $retval;
317
+ }
318
+
319
+ return $retval;
320
+ }
321
+
322
+ function _flatten_array($obj, &$arr)
323
+ {
324
+ if (is_array($obj)) {
325
+ foreach ($obj as $inner_obj) $this->_flatten_array($inner_obj, $arr);
326
+ }
327
+ elseif ($obj) $arr[] = $obj;
328
+ }
329
+
330
+ /**
331
+ * Parses the path for a module and filename
332
+ * @param string $str
333
+ */
334
+ function parse_formatted_path($str)
335
+ {
336
+ $module = FALSE;
337
+ $path = $str;
338
+ $parts = explode('#', $path);
339
+ if (count($parts) > 1) {
340
+ $module = array_shift($parts);
341
+ $path = array_shift($parts);
342
+ }
343
+ return array($path, $module);
344
+ }
345
+
346
+ /**
347
+ * Gets the document root for this application
348
+ * @return string
349
+ */
350
+ function get_document_root()
351
+ {
352
+ return $this->_document_root;
353
+ }
354
+
355
+ /**
356
+ * Sets the document root for this application
357
+ * @param type $value
358
+ * @return type
359
+ */
360
+ function set_document_root($value)
361
+ {
362
+ // Even for windows hosts we force '/' as the path separator
363
+ return $this->_document_root = untrailingslashit(str_replace('\\', '/', $value));
364
+ }
365
+ }
products/photocrati_nextgen/modules/fs/interface.fs.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Fs
4
+ {
5
+
6
+ }
products/photocrati_nextgen/modules/fs/module.fs.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ {
4
+ Module: photocrati-fs
5
+ }
6
+ */
7
+ class M_Fs extends C_Base_Module
8
+ {
9
+ function define()
10
+ {
11
+ parent::define(
12
+ 'photocrati-fs',
13
+ 'Filesystem',
14
+ 'Provides a filesystem abstraction layer for Pope modules',
15
+ '0.1',
16
+ 'http://www.photocrati.com',
17
+ 'Photocrati Media',
18
+ 'http://www.photocrati.com'
19
+ );
20
+ }
21
+
22
+ function _register_utilities()
23
+ {
24
+ $this->get_registry()->add_utility('I_Fs', 'C_Fs');
25
+ }
26
+
27
+ function get_type_list()
28
+ {
29
+ return array(
30
+ 'C_Fs' => 'class.fs.php',
31
+ 'I_Fs' => 'interface.fs.php'
32
+ );
33
+ }
34
+ }
35
+
36
+ new M_Fs;
products/photocrati_nextgen/modules/lightbox/adapter.lightbox_factory.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_Lightbox_Factory extends Mixin
4
+ {
5
+ function lightbox_library($mapper=FALSE, $properties=array(), $context=FALSE)
6
+ {
7
+ return new C_Lightbox_Library($mapper, $properties, $context);
8
+ }
9
+
10
+ function lightbox($mapper=FALSE, $properties=array(), $context=FALSE)
11
+ {
12
+ return $this->object->lightbox_library($mapper, $properties, $context);
13
+ }
14
+ }
products/photocrati_nextgen/modules/lightbox/adapter.lightbox_library_form.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A_Lightbox_Library_Form extends Mixin
4
+ {
5
+ function get_model()
6
+ {
7
+ return $this->object
8
+ ->get_registry()
9
+ ->get_utility('I_Lightbox_Library_Mapper')
10
+ ->find_by_name($this->object->context, TRUE);
11
+ }
12
+
13
+ /**
14
+ * Returns a list of fields to render on the settings page
15
+ */
16
+ function _get_field_names()
17
+ {
18
+ return array(
19
+ 'lightbox_library_code',
20
+ 'lightbox_library_css_stylesheets',
21
+ 'lightbox_library_scripts'
22
+ );
23
+ }
24
+
25
+ /**
26
+ * @param $lightbox
27
+ * @return mixed
28
+ */
29
+ function _render_lightbox_library_code_field($lightbox)
30
+ {
31
+ return $this->_render_text_field(
32
+ $lightbox,
33
+ 'code',
34
+ 'Code',
35
+ $lightbox->code
36
+ );
37
+ }
38
+
39
+ /**
40
+ * @param $lightbox
41
+ * @return mixed
42
+ */
43
+ function _render_lightbox_library_css_stylesheets_field($lightbox)
44
+ {
45
+ return $this->_render_textarea_field(
46
+ $lightbox,
47
+ 'css_stylesheets',
48
+ 'Stylesheet URL',
49
+ $lightbox->css_stylesheets
50
+ );
51
+ }
52
+
53
+ /**
54
+ * @param $lightbox
55
+ * @return mixed
56
+ */
57
+ function _render_lightbox_library_scripts_field($lightbox)
58
+ {
59
+ return $this->_render_textarea_field(
60
+ $lightbox,
61
+ 'scripts',
62
+ 'Javascript URL',
63
+ $lightbox->scripts
64
+ );
65
+ }
66
+ }
products/photocrati_nextgen/modules/lightbox/class.lightbox_installer.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class C_Lightbox_Installer
4
+ {
5
+ function __construct()
6
+ {
7
+ $this->registry = C_Component_Registry::get_instance();
8
+ $this->router = $this->registry->get_utility('I_Router');
9
+ $this->mapper = $this->registry->get_utility('I_Lightbox_Library_Mapper');
10
+ }
11
+
12
+
13
+ function set_attr(&$obj, $key, $val)
14
+ {
15
+ if (!isset($obj->$key))
16
+ $obj->$key = $val;
17
+ }
18
+
19
+ /**
20
+ * Installs a lightbox library
21
+ * @param string $name
22
+ * @param string $code
23
+ * @param array $stylesheet_paths
24
+ * @param array $script_paths
25
+ * @param array $values
26
+ */
27
+ function install_lightbox($name, $title, $code, $stylesheet_paths=array(), $script_paths=array(), $values=array())
28
+ {
29
+ // Try to find the existing lightbox. If we can't find it, we'll create
30
+ $lightbox = $this->mapper->find_by_name($name);
31
+ if (!$lightbox)
32
+ $lightbox = new stdClass;
33
+
34
+ $styles = array();
35
+ foreach ($stylesheet_paths as $stylesheet) {
36
+ if (preg_match("/http(s)?/", $stylesheet))
37
+ $styles[] = $stylesheet;
38
+ else
39
+ $styles[] = $this->router->get_static_url($stylesheet);
40
+ }
41
+
42
+ $scripts = array();
43
+ foreach ($script_paths as $script) {
44
+ if (preg_match("/http(s)?/", $script))
45
+ $scripts[] = $script;
46
+ else
47
+ $scripts[] = $this->router->get_static_url($script);
48
+ }
49
+
50
+ // Set properties
51
+ $lightbox->name = $name;
52
+ $this->set_attr($lightbox, 'title', $title);
53
+ $this->set_attr($lightbox, 'code', $code);
54
+ $this->set_attr($lightbox, 'values', $values);
55
+ $this->set_attr($lightbox, 'css_stylesheets', implode("\n", $styles));
56
+ $this->set_attr($lightbox, 'scripts', implode("\n", $scripts));
57
+
58
+ // Save the lightbox
59
+ $this->mapper->save($lightbox);
60
+ }
61
+
62
+ /**
63
+ * Uninstalls an existing lightbox
64
+ * @param string $name
65
+ */
66
+ function uninstall_lightbox($name)
67
+ {
68
+ if (($lightbox = $this->mapper->find_by_name($name))) {
69
+ $this->mapper->destroy($lightbox);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Installs all of the lightbox provided by this module
75
+ */
76
+ function install()
77
+ {
78
+ // Install "None" option
79
+ $this->install_lightbox(
80
+ 'none',
81
+ 'No lightbox',
82
+ '',
83
+ array(),
84
+ array()
85
+ );
86
+
87
+ $this->install_lightbox(
88
+ 'lightbox',
89
+ 'Lightbox',
90
+ "class='ngg_lightbox'",
91
+ array('photocrati-lightbox#jquery.lightbox/jquery.lightbox-0.5.css'),
92
+ array(
93
+ 'photocrati-lightbox#jquery.lightbox/jquery.lightbox-0.5.min.js',
94
+ 'photocrati-lightbox#jquery.lightbox/nextgen_lightbox_init.js'
95
+ ),
96
+ array(
97
+ 'nextgen_lightbox_loading_img_url' =>
98
+ $this->router->get_static_url('photocrati-lightbox#jquery.lightbox/lightbox-ico-loading.gif'),
99
+
100
+ 'nextgen_lightbox_close_btn_url' =>
101
+ $this->router->get_static_url('photocrati-lightbox#jquery.lightbox/lightbox-btn-close.gif'),
102
+
103
+ 'nextgen_lightbox_btn_prev_url' =>
104
+ $this->router->get_static_url('photocrati-lightbox#jquery.lightbox/lightbox-btn-prev.gif'),
105
+
106
+ 'nextgen_lightbox_btn_next_url' =>
107
+ $this->router->get_static_url('photocrati-lightbox#jquery.lightbox/lightbox-btn-next.gif'),
108
+
109
+ 'nextgen_lightbox_blank_img_url' =>
110
+ $this->router->get_static_url('photocrati-lightbox#jquery.lightbox/lightbox-blank.gif')
111
+ )
112
+ );
113
+
114
+ // Install Fancybox 1.3.4
115
+ $this->install_lightbox(
116
+ 'fancybox',
117
+ 'Fancybox',
118
+ 'class="ngg-fancybox" rel="%GALLERY_NAME%"',
119
+ array('photocrati-lightbox#fancybox/jquery.fancybox-1.3.4.css'),
120
+ array(
121
+ 'photocrati-lightbox#fancybox/jquery.easing-1.3.pack.js',
122
+ 'photocrati-lightbox#fancybox/jquery.fancybox-1.3.4.pack.js',
123
+ 'photocrati-lightbox#fancybox/nextgen_fancybox_init.js'
124
+ )
125
+ );
126
+
127
+ // Install highslide
128
+ $this->install_lightbox(
129
+ 'highslide',
130
+ 'Highslide',
131
+ 'class="highslide" onclick="return hs.expand(this, galleryOptions);"',
132
+ array('photocrati-lightbox#highslide/highslide.css'),
133
+ array('photocrati-lightbox#highslide/highslide-full.packed.js', 'photocrati-lightbox#highslide/nextgen_highslide_init.js'),
134
+ array('nextgen_highslide_graphics_dir' => $this->router->get_static_url('photocrati-lightbox#highslide/graphics'))
135
+ );
136
+
137
+ // Install Shutter
138
+ $this->install_lightbox(
139
+ 'shutter',
140
+ 'Shutter',
141
+ 'class="shutterset_%GALLERY_NAME%"',
142
+ array('photocrati-lightbox#shutter/shutter.css'),
143
+ array('photocrati-lightbox#shutter/shutter.js', 'photocrati-lightbox#shutter/nextgen_shutter.js'),
144
+ array(
145
+ 'msgLoading' => 'L O A D I N G',
146
+ 'msgClose' => 'Click to Close',
147
+ )
148
+ );
149
+
150
+ // Install Shutter Reloaded
151
+ $this->install_lightbox(
152
+ 'shutter2',
153
+ 'Shutter 2',
154
+ 'class="shutterset_%GALLERY_NAME%"',
155
+ array('photocrati-lightbox#shutter_reloaded/shutter.css'),
156
+ array('photocrati-lightbox#shutter_reloaded/shutter.js', 'photocrati-lightbox#shutter_reloaded/nextgen_shutter_reloaded.js')
157
+ );
158
+
159
+ // Install Thickbox
160
+ $this->install_lightbox(
161
+ 'thickbox',
162
+ 'Thickbox',
163
+ "class='thickbox' rel='%GALLERY_NAME%'",
164
+ array(includes_url('/js/thickbox/thickbox.css')),
165
+ array('photocrati-lightbox#thickbox/nextgen_thickbox_init.js', includes_url('/js/thickbox/thickbox.js'))
166
+ );
167
+ }
168
+
169
+ /**
170
+ * Uninstalls all lightboxes
171
+ */
172
+ function uninstall($hard = FALSE)
173
+ {
174
+ if ($hard) $this->mapper->delete()->run_query();
175
+ }
176
+ }
products/photocrati_nextgen/modules/lightbox/class.lightbox_library.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Provides an entity for Lightbox Libraries.
5
+ *
6
+ * Properties:
7
+ * - name
8
+ * - code
9
+ * - css_stylesheets
10
+ * - scripts
11
+ */
12
+ class C_Lightbox_Library extends C_DataMapper_Model
13
+ {
14
+ function define($mapper, $properties, $context=FALSE)
15
+ {
16
+ parent::define($mapper, $properties, $context);
17
+ $this->add_mixin('Mixin_Lightbox_Library_Validation');
18
+ $this->implement('I_Lightbox_Library');
19
+ }
20
+ }
21
+
22
+ class Mixin_Lightbox_Library_Validation extends Mixin
23
+ {
24
+ function validation()
25
+ {
26
+ $this->object->validates_presence_of('name');
27
+ $this->object->validates_uniqueness_of('name');
28
+
29
+ return $this->object->is_valid();
30
+ }
31
+ }
products/photocrati_nextgen/modules/lightbox/class.lightbox_library_mapper.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Provides CRUD operations for lightbox libraries
5
+ */
6
+ class C_Lightbox_Library_Mapper extends C_CustomPost_DataMapper_Driver
7
+ {
8
+ static $_instances = array();
9
+
10
+ /**
11
+ * Defines the lightbox library datamapper
12
+ * @param type $context
13
+ */
14
+ function define($context = FALSE)
15
+ {
16
+ if (!is_array($context)) $context = array($context);
17
+ array_push($context, 'lightbox_library');
18
+ parent::define('lightbox_library', $context);
19
+ $this->add_mixin('Mixin_Lightbox_Library_Mapper');
20
+ $this->implement('I_Lightbox_Library_Mapper');
21
+ $this->set_model_factory_method('lightbox_library');
22
+ }
23
+
24
+ /**
25
+ * Initializes the datamapper
26
+ */
27
+ function initialize()
28
+ {
29
+ parent::initialize('lightbox_library');
30
+ }
31
+
32
+ /**
33
+ * Returns an instance of the mapper
34
+ * @param string|FALSE $context
35
+ * @return C_Lightbox_Library_Mapper
36
+ */
37
+ static function get_instance($context=FALSE)
38
+ {
39
+ $klass = get_class();
40
+ if (!isset(self::$_instances[$context])) {
41
+ self::$_instances[$context] = new $klass($context);
42
+ }
43
+ return self::$_instances[$context];
44
+ }
45
+ }
46
+
47
+ class Mixin_Lightbox_Library_Mapper
48
+ {
49
+ /**
50
+ * Uses the name property as the post title when the Custom Post driver
51
+ * is used
52
+ * @param stdClass $entity
53
+ * @return string
54
+ */
55
+ function get_post_title($entity)
56
+ {
57
+ return $entity->name;
58
+ }
59
+
60
+
61
+ /**
62
+ * Selects a lightbox library by name
63
+ * @param string $name
64
+ * @param type $model
65
+ */
66
+ function find_by_name($name, $model=FALSE)
67
+ {
68
+ $results = $this->object->select()->where(array('name = %s', $name))->run_query(FALSE, $model);
69
+ if ($results) $results = $results[0];
70
+ return $results;
71
+ }
72
+
73
+ /**
74
+ * Sets default values for the lightbox library
75
+ * @param stdClass|C_DataMapper_Model $entity
76
+ */
77
+ function set_defaults($entity)
78
+ {
79
+ $this->object->_set_default_value($entity, 'css_stylesheets', '');
80
+ $this->object->_set_default_value($entity, 'scripts', '');
81
+ $this->object->_set_default_value($entity, 'display_settings', array());
82
+ }
83
+ }
products/photocrati_nextgen/modules/lightbox/interface.lightbox_library.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Lightbox_Library extends I_DataMapper_Model
4
+ {
5
+
6
+ }
products/photocrati_nextgen/modules/lightbox/interface.lightbox_library_mapper.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface I_Lightbox_Library_Mapper
4
+ {
5
+
6
+ }
products/photocrati_nextgen/modules/lightbox/module.lightbox.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /***
4
+ {
5
+ Module: photocrati-lightbox,
6
+ Depends: { photocrati-nextgen_admin }
7
+ }
8
+ ***/
9
+
10
+ define('NEXTGEN_LIGHTBOX_OPTIONS_SLUG', 'ngg_lightbox_options');
11
+ define('NEXTGEN_LIGHTBOX_ADVANCED_OPTIONS_SLUG', 'ngg_lightbox_advanced_options');
12
+
13
+ class M_Lightbox extends C_Base_Module
14
+ {
15
+ function define()
16
+ {
17
+ parent::define(
18
+ 'photocrati-lightbox',
19
+ 'Lightbox',
20
+ _("Provides integration with JQuery's lightbox plugin"),
21
+ '0.3',
22
+ 'http://leandrovieira.com/projects/jquery/lightbox/',
23
+ 'Photocrati Media',
24
+ 'http://www.photocrati.com'
25
+ );
26
+
27
+ include_once('class.lightbox_installer.php');
28
+ C_Photocrati_Installer::add_handler($this->module_id, 'C_Lightbox_Installer');
29
+ }
30
+
31
+ function initialize()
32
+ {
33
+ parent::initialize();
34
+ if (is_admin()) {
35
+ add_action('admin_init', array(&$this, 'add_all_lightbox_forms'));
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Adds a configuration form to each library
41
+ */
42
+ function add_all_lightbox_forms()
43
+ {
44
+ foreach ($this->get_registry()->get_utility('I_Lightbox_Library_Mapper')->find_all() as $lib) {
45
+ $this->get_registry()->add_adapter('I_Form', 'A_Lightbox_Library_Form', $lib->name);
46
+ C_Form_Manager::get_instance()->add_form(NEXTGEN_LIGHTBOX_ADVANCED_OPTIONS_SLUG, $lib->name);
47
+ }
48
+ }
49
+
50
+ function _register_utilities()
51
+ {
52
+ // Provides a utility to perform CRUD operations for Lightbox libraries
53
+ $this->get_registry()->add_utility(
54
+ 'I_Lightbox_Library_Mapper',
55
+ 'C_Lightbox_Library_Mapper'
56
+ );
57
+ }
58
+
59
+ function _register_adapters()
60
+ {
61
+ // Provides factory methods for instantiating lightboxes
62
+ $this->get_registry()->add_adapter('I_Component_Factory', 'A_Lightbox_Factory');
63
+
64
+ // Provides an installer for lightbox libraries
65
+ $this->get_registry()->add_adapter('I_Installer', 'A_Lightbox_Installer');
66
+ }
67
+
68
+ function get_type_list()
69
+ {
70
+ return array(
71
+ 'A_Lightbox_Factory' => 'adapter.lightbox_factory.php',
72
+ 'C_Lightbox_Installer' => 'class.lightbox_installer.php',
73
+ 'A_Lightbox_Library_Form' => 'adapter.lightbox_library_form.php',
74
+ 'C_Lightbox_Library' => 'class.lightbox_library.php',
75
+ 'C_Lightbox_Library_Mapper' => 'class.lightbox_library_mapper.php',
76
+ 'I_Lightbox_Library' => 'interface.lightbox_library.php',
77
+ 'I_Lightbox_Library_Mapper' => 'interface.lightbox_library_mapper.php'
78
+ );
79
+ }
80
+ }
81
+
82
+ new M_Lightbox();
products/photocrati_nextgen/modules/lightbox/static/fancybox/blank.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_close.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_loading.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_nav_left.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_nav_right.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_e.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_n.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_ne.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_nw.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_s.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_se.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_sw.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_shadow_w.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_title_left.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_title_main.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_title_over.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancy_title_right.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancybox-x.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancybox-y.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/fancybox.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.easing-1.3.pack.js ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
3
+ *
4
+ * Uses the built in easing capabilities added In jQuery 1.1
5
+ * to offer multiple easing options
6
+ *
7
+ * TERMS OF USE - jQuery Easing
8
+ *
9
+ * Open source under the BSD License.
10
+ *
11
+ * Copyright © 2008 George McGinley Smith
12
+ * All rights reserved.
13
+ *
14
+ * Redistribution and use in source and binary forms, with or without modification,
15
+ * are permitted provided that the following conditions are met:
16
+ *
17
+ * Redistributions of source code must retain the above copyright notice, this list of
18
+ * conditions and the following disclaimer.
19
+ * Redistributions in binary form must reproduce the above copyright notice, this list
20
+ * of conditions and the following disclaimer in the documentation and/or other materials
21
+ * provided with the distribution.
22
+ *
23
+ * Neither the name of the author nor the names of contributors may be used to endorse
24
+ * or promote products derived from this software without specific prior written permission.
25
+ *
26
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
27
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
31
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
35
+ *
36
+ */
37
+
38
+ // t: current time, b: begInnIng value, c: change In value, d: duration
39
+ eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('h.i[\'1a\']=h.i[\'z\'];h.O(h.i,{y:\'D\',z:9(x,t,b,c,d){6 h.i[h.i.y](x,t,b,c,d)},17:9(x,t,b,c,d){6 c*(t/=d)*t+b},D:9(x,t,b,c,d){6-c*(t/=d)*(t-2)+b},13:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t+b;6-c/2*((--t)*(t-2)-1)+b},X:9(x,t,b,c,d){6 c*(t/=d)*t*t+b},U:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t+1)+b},R:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t+b;6 c/2*((t-=2)*t*t+2)+b},N:9(x,t,b,c,d){6 c*(t/=d)*t*t*t+b},M:9(x,t,b,c,d){6-c*((t=t/d-1)*t*t*t-1)+b},L:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t+b;6-c/2*((t-=2)*t*t*t-2)+b},K:9(x,t,b,c,d){6 c*(t/=d)*t*t*t*t+b},J:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t*t*t+1)+b},I:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t*t+b;6 c/2*((t-=2)*t*t*t*t+2)+b},G:9(x,t,b,c,d){6-c*8.C(t/d*(8.g/2))+c+b},15:9(x,t,b,c,d){6 c*8.n(t/d*(8.g/2))+b},12:9(x,t,b,c,d){6-c/2*(8.C(8.g*t/d)-1)+b},Z:9(x,t,b,c,d){6(t==0)?b:c*8.j(2,10*(t/d-1))+b},Y:9(x,t,b,c,d){6(t==d)?b+c:c*(-8.j(2,-10*t/d)+1)+b},W:9(x,t,b,c,d){e(t==0)6 b;e(t==d)6 b+c;e((t/=d/2)<1)6 c/2*8.j(2,10*(t-1))+b;6 c/2*(-8.j(2,-10*--t)+2)+b},V:9(x,t,b,c,d){6-c*(8.o(1-(t/=d)*t)-1)+b},S:9(x,t,b,c,d){6 c*8.o(1-(t=t/d-1)*t)+b},Q:9(x,t,b,c,d){e((t/=d/2)<1)6-c/2*(8.o(1-t*t)-1)+b;6 c/2*(8.o(1-(t-=2)*t)+1)+b},P:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6-(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b},H:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6 a*8.j(2,-10*t)*8.n((t*d-s)*(2*8.g)/p)+c+b},T:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d/2)==2)6 b+c;e(!p)p=d*(.3*1.5);e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);e(t<1)6-.5*(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b;6 a*8.j(2,-10*(t-=1))*8.n((t*d-s)*(2*8.g)/p)*.5+c+b},F:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*(t/=d)*t*((s+1)*t-s)+b},E:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},16:9(x,t,b,c,d,s){e(s==u)s=1.l;e((t/=d/2)<1)6 c/2*(t*t*(((s*=(1.B))+1)*t-s))+b;6 c/2*((t-=2)*t*(((s*=(1.B))+1)*t+s)+2)+b},A:9(x,t,b,c,d){6 c-h.i.v(x,d-t,0,c,d)+b},v:9(x,t,b,c,d){e((t/=d)<(1/2.k)){6 c*(7.q*t*t)+b}m e(t<(2/2.k)){6 c*(7.q*(t-=(1.5/2.k))*t+.k)+b}m e(t<(2.5/2.k)){6 c*(7.q*(t-=(2.14/2.k))*t+.11)+b}m{6 c*(7.q*(t-=(2.18/2.k))*t+.19)+b}},1b:9(x,t,b,c,d){e(t<d/2)6 h.i.A(x,t*2,0,c,d)*.5+b;6 h.i.v(x,t*2-d,0,c,d)*.5+c*.5+b}});',62,74,'||||||return||Math|function|||||if|var|PI|jQuery|easing|pow|75|70158|else|sin|sqrt||5625|asin|||undefined|easeOutBounce|abs||def|swing|easeInBounce|525|cos|easeOutQuad|easeOutBack|easeInBack|easeInSine|easeOutElastic|easeInOutQuint|easeOutQuint|easeInQuint|easeInOutQuart|easeOutQuart|easeInQuart|extend|easeInElastic|easeInOutCirc|easeInOutCubic|easeOutCirc|easeInOutElastic|easeOutCubic|easeInCirc|easeInOutExpo|easeInCubic|easeOutExpo|easeInExpo||9375|easeInOutSine|easeInOutQuad|25|easeOutSine|easeInOutBack|easeInQuad|625|984375|jswing|easeInOutBounce'.split('|'),0,{}))
40
+
41
+ /*
42
+ *
43
+ * TERMS OF USE - EASING EQUATIONS
44
+ *
45
+ * Open source under the BSD License.
46
+ *
47
+ * Copyright © 2001 Robert Penner
48
+ * All rights reserved.
49
+ *
50
+ * Redistribution and use in source and binary forms, with or without modification,
51
+ * are permitted provided that the following conditions are met:
52
+ *
53
+ * Redistributions of source code must retain the above copyright notice, this list of
54
+ * conditions and the following disclaimer.
55
+ * Redistributions in binary form must reproduce the above copyright notice, this list
56
+ * of conditions and the following disclaimer in the documentation and/or other materials
57
+ * provided with the distribution.
58
+ *
59
+ * Neither the name of the author nor the names of contributors may be used to endorse
60
+ * or promote products derived from this software without specific prior written permission.
61
+ *
62
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
63
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
64
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
65
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
66
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
67
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
68
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
69
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
70
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
71
+ *
72
+ */
products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.fancybox-1.3.4.css ADDED
@@ -0,0 +1,366 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * FancyBox - jQuery Plugin
3
+ * Simple and fancy lightbox alternative
4
+ *
5
+ * Examples and documentation at: http://fancybox.net
6
+ *
7
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
8
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
9
+ *
10
+ * Version: 1.3.4 (11/11/2010)
11
+ * Requires: jQuery v1.3+
12
+ *
13
+ * Dual licensed under the MIT and GPL licenses:
14
+ * http://www.opensource.org/licenses/mit-license.php
15
+ * http://www.gnu.org/licenses/gpl.html
16
+ */
17
+
18
+ #fancybox-loading {
19
+ position: fixed;
20
+ top: 50%;
21
+ left: 50%;
22
+ width: 40px;
23
+ height: 40px;
24
+ margin-top: -20px;
25
+ margin-left: -20px;
26
+ cursor: pointer;
27
+ overflow: hidden;
28
+ z-index: 1104;
29
+ display: none;
30
+ }
31
+
32
+ #fancybox-loading div {
33
+ position: absolute;
34
+ top: 0;
35
+ left: 0;
36
+ width: 40px;
37
+ height: 480px;
38
+ background-image: url('fancybox.png');
39
+ }
40
+
41
+ #fancybox-overlay {
42
+ position: absolute;
43
+ top: 0;
44
+ left: 0;
45
+ width: 100%;
46
+ z-index: 1100;
47
+ display: none;
48
+ }
49
+
50
+ #fancybox-tmp {
51
+ padding: 0;
52
+ margin: 0;
53
+ border: 0;
54
+ overflow: auto;
55
+ display: none;
56
+ }
57
+
58
+ #fancybox-wrap {
59
+ position: absolute;
60
+ top: 0;
61
+ left: 0;
62
+ padding: 20px;
63
+ z-index: 1101;
64
+ outline: none;
65
+ display: none;
66
+ }
67
+
68
+ #fancybox-outer {
69
+ position: relative;
70
+ width: 100%;
71
+ height: 100%;
72
+ background: #fff;
73
+ }
74
+
75
+ #fancybox-content {
76
+ width: 0;
77
+ height: 0;
78
+ padding: 0;
79
+ outline: none;
80
+ position: relative;
81
+ overflow: hidden;
82
+ z-index: 1102;
83
+ border: 0px solid #fff;
84
+ }
85
+
86
+ #fancybox-hide-sel-frame {
87
+ position: absolute;
88
+ top: 0;
89
+ left: 0;
90
+ width: 100%;
91
+ height: 100%;
92
+ background: transparent;
93
+ z-index: 1101;
94
+ }
95
+
96
+ #fancybox-close {
97
+ position: absolute;
98
+ top: -15px;
99
+ right: -15px;
100
+ width: 30px;
101
+ height: 30px;
102
+ background: transparent url('fancybox.png') -40px 0px;
103
+ cursor: pointer;
104
+ z-index: 1103;
105
+ display: none;
106
+ }
107
+
108
+ #fancybox-error {
109
+ color: #444;
110
+ font: normal 12px/20px Arial;
111
+ padding: 14px;
112
+ margin: 0;
113
+ }
114
+
115
+ #fancybox-img {
116
+ width: 100%;
117
+ height: 100%;
118
+ padding: 0;
119
+ margin: 0;
120
+ border: none;
121
+ outline: none;
122
+ line-height: 0;
123
+ vertical-align: top;
124
+ }
125
+
126
+ #fancybox-frame {
127
+ width: 100%;
128
+ height: 100%;
129
+ border: none;
130
+ display: block;
131
+ }
132
+
133
+ #fancybox-left, #fancybox-right {
134
+ position: absolute;
135
+ bottom: 0px;
136
+ height: 100%;
137
+ width: 35%;
138
+ cursor: pointer;
139
+ outline: none;
140
+ background: transparent url('blank.gif');
141
+ z-index: 1102;
142
+ display: none;
143
+ }
144
+
145
+ #fancybox-left {
146
+ left: 0px;
147
+ }
148
+
149
+ #fancybox-right {
150
+ right: 0px;
151
+ }
152
+
153
+ #fancybox-left-ico, #fancybox-right-ico {
154
+ position: absolute;
155
+ top: 50%;
156
+ left: -9999px;
157
+ width: 30px;
158
+ height: 30px;
159
+ margin-top: -15px;
160
+ cursor: pointer;
161
+ z-index: 1102;
162
+ display: block;
163
+ }
164
+
165
+ #fancybox-left-ico {
166
+ background-image: url('fancybox.png');
167
+ background-position: -40px -30px;
168
+ }
169
+
170
+ #fancybox-right-ico {
171
+ background-image: url('fancybox.png');
172
+ background-position: -40px -60px;
173
+ }
174
+
175
+ #fancybox-left:hover, #fancybox-right:hover {
176
+ visibility: visible; /* IE6 */
177
+ }
178
+
179
+ #fancybox-left:hover span {
180
+ left: 20px;
181
+ }
182
+
183
+ #fancybox-right:hover span {
184
+ left: auto;
185
+ right: 20px;
186
+ }
187
+
188
+ .fancybox-bg {
189
+ position: absolute;
190
+ padding: 0;
191
+ margin: 0;
192
+ border: 0;
193
+ width: 20px;
194
+ height: 20px;
195
+ z-index: 1001;
196
+ }
197
+
198
+ #fancybox-bg-n {
199
+ top: -20px;
200
+ left: 0;
201
+ width: 100%;
202
+ background-image: url('fancybox-x.png');
203
+ }
204
+
205
+ #fancybox-bg-ne {
206
+ top: -20px;
207
+ right: -20px;
208
+ background-image: url('fancybox.png');
209
+ background-position: -40px -162px;
210
+ }
211
+
212
+ #fancybox-bg-e {
213
+ top: 0;
214
+ right: -20px;
215
+ height: 100%;
216
+ background-image: url('fancybox-y.png');
217
+ background-position: -20px 0px;
218
+ }
219
+
220
+ #fancybox-bg-se {
221
+ bottom: -20px;
222
+ right: -20px;
223
+ background-image: url('fancybox.png');
224
+ background-position: -40px -182px;
225
+ }
226
+
227
+ #fancybox-bg-s {
228
+ bottom: -20px;
229
+ left: 0;
230
+ width: 100%;
231
+ background-image: url('fancybox-x.png');
232
+ background-position: 0px -20px;
233
+ }
234
+
235
+ #fancybox-bg-sw {
236
+ bottom: -20px;
237
+ left: -20px;
238
+ background-image: url('fancybox.png');
239
+ background-position: -40px -142px;
240
+ }
241
+
242
+ #fancybox-bg-w {
243
+ top: 0;
244
+ left: -20px;
245
+ height: 100%;
246
+ background-image: url('fancybox-y.png');
247
+ }
248
+
249
+ #fancybox-bg-nw {
250
+ top: -20px;
251
+ left: -20px;
252
+ background-image: url('fancybox.png');
253
+ background-position: -40px -122px;
254
+ }
255
+
256
+ #fancybox-title {
257
+ font-family: Helvetica;
258
+ font-size: 12px;
259
+ z-index: 1102;
260
+ }
261
+
262
+ .fancybox-title-inside {
263
+ padding-bottom: 10px;
264
+ text-align: center;
265
+ color: #333;
266
+ background: #fff;
267
+ position: relative;
268
+ }
269
+
270
+ .fancybox-title-outside {
271
+ padding-top: 10px;
272
+ color: #fff;
273
+ }
274
+
275
+ .fancybox-title-over {
276
+ position: absolute;
277
+ bottom: 0;
278
+ left: 0;
279
+ color: #FFF;
280
+ text-align: left;
281
+ }
282
+
283
+ #fancybox-title-over {
284
+ padding: 10px;
285
+ background-image: url('fancy_title_over.png');
286
+ display: block;
287
+ }
288
+
289
+ .fancybox-title-float {
290
+ position: absolute;
291
+ left: 0;
292
+ bottom: -20px;
293
+ height: 32px;
294
+ }
295
+
296
+ #fancybox-title-float-wrap {
297
+ border: none;
298
+ border-collapse: collapse;
299
+ width: auto;
300
+ }
301
+
302
+ #fancybox-title-float-wrap td {
303
+ border: none;
304
+ white-space: nowrap;
305
+ }
306
+
307
+ #fancybox-title-float-left {
308
+ padding: 0 0 0 15px;
309
+ background: url('fancybox.png') -40px -90px no-repeat;
310
+ }
311
+
312
+ #fancybox-title-float-main {
313
+ color: #FFF;
314
+ line-height: 29px;
315
+ font-weight: bold;
316
+ padding: 0 0 3px 0;
317
+ background: url('fancybox-x.png') 0px -40px;
318
+ }
319
+
320
+ #fancybox-title-float-right {
321
+ padding: 0 0 0 15px;
322
+ background: url('fancybox.png') -55px -90px no-repeat;
323
+ }
324
+
325
+ /* IE6 */
326
+
327
+ .fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
328
+
329
+ .fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
330
+ .fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
331
+
332
+ .fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
333
+ .fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
334
+ .fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
335
+ .fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
336
+
337
+ .fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
338
+ height: expression(this.parentNode.clientHeight + "px");
339
+ }
340
+
341
+ #fancybox-loading.fancybox-ie6 {
342
+ position: absolute; margin-top: 0;
343
+ top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
344
+ }
345
+
346
+ #fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
347
+
348
+ /* IE6, IE7, IE8 */
349
+
350
+ .fancybox-ie .fancybox-bg { background: transparent !important; }
351
+
352
+ .fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
353
+ .fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
354
+ .fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
355
+ .fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
356
+ .fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
357
+ .fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
358
+ .fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
359
+ .fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); }
360
+
361
+ /* Note: Prevents issues with "style resets" or themes that apply 'box-sizing: border-box' to everything */
362
+ #fancybox-wrap, #fancybox-content, #fancybox-outer {
363
+ box-sizing: content-box;
364
+ -moz-box-sizing: content-box;
365
+ -webkit-box-sizing: content-box;
366
+ }
products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.fancybox-1.3.4.js ADDED
@@ -0,0 +1,1156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * FancyBox - jQuery Plugin
3
+ * Simple and fancy lightbox alternative
4
+ *
5
+ * Examples and documentation at: http://fancybox.net
6
+ *
7
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
8
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
9
+ *
10
+ * Version: 1.3.4 (11/11/2010)
11
+ * Requires: jQuery v1.3+
12
+ *
13
+ * Dual licensed under the MIT and GPL licenses:
14
+ * http://www.opensource.org/licenses/mit-license.php
15
+ * http://www.gnu.org/licenses/gpl.html
16
+ */
17
+
18
+ ;(function($) {
19
+ var tmp, loading, overlay, wrap, outer, content, close, title, nav_left, nav_right,
20
+
21
+ selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],
22
+
23
+ ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i,
24
+
25
+ loadingTimer, loadingFrame = 1,
26
+
27
+ titleHeight = 0, titleStr = '', start_pos, final_pos, busy = false, fx = $.extend($('<div/>')[0], { prop: 0 }),
28
+
29
+ isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest,
30
+
31
+ /*
32
+ * Private methods
33
+ */
34
+
35
+ _abort = function() {
36
+ loading.hide();
37
+
38
+ imgPreloader.onerror = imgPreloader.onload = null;
39
+
40
+ if (ajaxLoader) {
41
+ ajaxLoader.abort();
42
+ }
43
+
44
+ tmp.empty();
45
+ },
46
+
47
+ _error = function() {
48
+ if (false === selectedOpts.onError(selectedArray, selectedIndex, selectedOpts)) {
49
+ loading.hide();
50
+ busy = false;
51
+ return;
52
+ }
53
+
54
+ selectedOpts.titleShow = false;
55
+
56
+ selectedOpts.width = 'auto';
57
+ selectedOpts.height = 'auto';
58
+
59
+ tmp.html( '<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>' );
60
+
61
+ _process_inline();
62
+ },
63
+
64
+ _start = function() {
65
+ var obj = selectedArray[ selectedIndex ],
66
+ href,
67
+ type,
68
+ title,
69
+ str,
70
+ emb,
71
+ ret;
72
+
73
+ _abort();
74
+
75
+ selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));
76
+
77
+ ret = selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts);
78
+
79
+ if (ret === false) {
80
+ busy = false;
81
+ return;
82
+ } else if (typeof ret == 'object') {
83
+ selectedOpts = $.extend(selectedOpts, ret);
84
+ }
85
+
86
+ title = selectedOpts.title || (obj.nodeName ? $(obj).attr('title') : obj.title) || '';
87
+
88
+ if (obj.nodeName && !selectedOpts.orig) {
89
+ selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj);
90
+ }
91
+
92
+ if (title === '' && selectedOpts.orig && selectedOpts.titleFromAlt) {
93
+ title = selectedOpts.orig.attr('alt');
94
+ }
95
+
96
+ href = selectedOpts.href || (obj.nodeName ? $(obj).attr('href') : obj.href) || null;
97
+
98
+ if ((/^(?:javascript)/i).test(href) || href == '#') {
99
+ href = null;
100
+ }
101
+
102
+ if (selectedOpts.type) {
103
+ type = selectedOpts.type;
104
+
105
+ if (!href) {
106
+ href = selectedOpts.content;
107
+ }
108
+
109
+ } else if (selectedOpts.content) {
110
+ type = 'html';
111
+
112
+ } else if (href) {
113
+ if (href.match(imgRegExp)) {
114
+ type = 'image';
115
+
116
+ } else if (href.match(swfRegExp)) {
117
+ type = 'swf';
118
+
119
+ } else if ($(obj).hasClass("iframe")) {
120
+ type = 'iframe';
121
+
122
+ } else if (href.indexOf("#") === 0) {
123
+ type = 'inline';
124
+
125
+ } else {
126
+ type = 'ajax';
127
+ }
128
+ }
129
+
130
+ if (!type) {
131
+ _error();
132
+ return;
133
+ }
134
+
135
+ if (type == 'inline') {
136
+ obj = href.substr(href.indexOf("#"));
137
+ type = $(obj).length > 0 ? 'inline' : 'ajax';
138
+ }
139
+
140
+ selectedOpts.type = type;
141
+ selectedOpts.href = href;
142
+ selectedOpts.title = title;
143
+
144
+ if (selectedOpts.autoDimensions) {
145
+ if (selectedOpts.type == 'html' || selectedOpts.type == 'inline' || selectedOpts.type == 'ajax') {
146
+ selectedOpts.width = 'auto';
147
+ selectedOpts.height = 'auto';
148
+ } else {
149
+ selectedOpts.autoDimensions = false;
150
+ }
151
+ }
152
+
153
+ if (selectedOpts.modal) {
154
+ selectedOpts.overlayShow = true;
155
+ selectedOpts.hideOnOverlayClick = false;
156
+ selectedOpts.hideOnContentClick = false;
157
+ selectedOpts.enableEscapeButton = false;
158
+ selectedOpts.showCloseButton = false;
159
+ }
160
+
161
+ selectedOpts.padding = parseInt(selectedOpts.padding, 10);
162
+ selectedOpts.margin = parseInt(selectedOpts.margin, 10);
163
+
164
+ tmp.css('padding', (selectedOpts.padding + selectedOpts.margin));
165
+
166
+ $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {
167
+ $(this).replaceWith(content.children());
168
+ });
169
+
170
+ switch (type) {
171
+ case 'html' :
172
+ tmp.html( selectedOpts.content );
173
+ _process_inline();
174
+ break;
175
+
176
+ case 'inline' :
177
+ if ( $(obj).parent().is('#fancybox-content') === true) {
178
+ busy = false;
179
+ return;
180
+ }
181
+
182
+ $('<div class="fancybox-inline-tmp" />')
183
+ .hide()
184
+ .insertBefore( $(obj) )
185
+ .bind('fancybox-cleanup', function() {
186
+ $(this).replaceWith(content.children());
187
+ }).bind('fancybox-cancel', function() {
188
+ $(this).replaceWith(tmp.children());
189
+ });
190
+
191
+ $(obj).appendTo(tmp);
192
+
193
+ _process_inline();
194
+ break;
195
+
196
+ case 'image':
197
+ busy = false;
198
+
199
+ $.fancybox.showActivity();
200
+
201
+ imgPreloader = new Image();
202
+
203
+ imgPreloader.onerror = function() {
204
+ _error();
205
+ };
206
+
207
+ imgPreloader.onload = function() {
208
+ busy = true;
209
+
210
+ imgPreloader.onerror = imgPreloader.onload = null;
211
+
212
+ _process_image();
213
+ };
214
+
215
+ imgPreloader.src = href;
216
+ break;
217
+
218
+ case 'swf':
219
+ selectedOpts.scrolling = 'no';
220
+
221
+ str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>';
222
+ emb = '';
223
+
224
+ $.each(selectedOpts.swf, function(name, val) {
225
+ str += '<param name="' + name + '" value="' + val + '"></param>';
226
+ emb += ' ' + name + '="' + val + '"';
227
+ });
228
+
229
+ str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>';
230
+
231
+ tmp.html(str);
232
+
233
+ _process_inline();
234
+ break;
235
+
236
+ case 'ajax':
237
+ busy = false;
238
+
239
+ $.fancybox.showActivity();
240
+
241
+ selectedOpts.ajax.win = selectedOpts.ajax.success;
242
+
243
+ ajaxLoader = $.ajax($.extend({}, selectedOpts.ajax, {
244
+ url : href,
245
+ data : selectedOpts.ajax.data || {},
246
+ error : function(XMLHttpRequest, textStatus, errorThrown) {
247
+ if ( XMLHttpRequest.status > 0 ) {
248
+ _error();
249
+ }
250
+ },
251
+ success : function(data, textStatus, XMLHttpRequest) {
252
+ var o = typeof XMLHttpRequest == 'object' ? XMLHttpRequest : ajaxLoader;
253
+ if (o.status == 200) {
254
+ if ( typeof selectedOpts.ajax.win == 'function' ) {
255
+ ret = selectedOpts.ajax.win(href, data, textStatus, XMLHttpRequest);
256
+
257
+ if (ret === false) {
258
+ loading.hide();
259
+ return;
260
+ } else if (typeof ret == 'string' || typeof ret == 'object') {
261
+ data = ret;
262
+ }
263
+ }
264
+
265
+ tmp.html( data );
266
+ _process_inline();
267
+ }
268
+ }
269
+ }));
270
+
271
+ break;
272
+
273
+ case 'iframe':
274
+ _show();
275
+ break;
276
+ }
277
+ },
278
+
279
+ _process_inline = function() {
280
+ var
281
+ w = selectedOpts.width,
282
+ h = selectedOpts.height;
283
+
284
+ if (w.toString().indexOf('%') > -1) {
285
+ w = parseInt( ($(window).width() - (selectedOpts.margin * 2)) * parseFloat(w) / 100, 10) + 'px';
286
+
287
+ } else {
288
+ w = w == 'auto' ? 'auto' : w + 'px';
289
+ }
290
+
291
+ if (h.toString().indexOf('%') > -1) {
292
+ h = parseInt( ($(window).height() - (selectedOpts.margin * 2)) * parseFloat(h) / 100, 10) + 'px';
293
+
294
+ } else {
295
+ h = h == 'auto' ? 'auto' : h + 'px';
296
+ }
297
+
298
+ tmp.wrapInner('<div style="width:' + w + ';height:' + h + ';overflow: ' + (selectedOpts.scrolling == 'auto' ? 'auto' : (selectedOpts.scrolling == 'yes' ? 'scroll' : 'hidden')) + ';position:relative;"></div>');
299
+
300
+ selectedOpts.width = tmp.width();
301
+ selectedOpts.height = tmp.height();
302
+
303
+ _show();
304
+ },
305
+
306
+ _process_image = function() {
307
+ selectedOpts.width = imgPreloader.width;
308
+ selectedOpts.height = imgPreloader.height;
309
+
310
+ $("<img />").attr({
311
+ 'id' : 'fancybox-img',
312
+ 'src' : imgPreloader.src,
313
+ 'alt' : selectedOpts.title
314
+ }).appendTo( tmp );
315
+
316
+ _show();
317
+ },
318
+
319
+ _show = function() {
320
+ var pos, equal;
321
+
322
+ loading.hide();
323
+
324
+ if (wrap.is(":visible") && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
325
+ $.event.trigger('fancybox-cancel');
326
+
327
+ busy = false;
328
+ return;
329
+ }
330
+
331
+ busy = true;
332
+
333
+ $(content.add( overlay )).unbind();
334
+
335
+ $(window).unbind("resize.fb scroll.fb");
336
+ $(document).unbind('keydown.fb');
337
+
338
+ if (wrap.is(":visible") && currentOpts.titlePosition !== 'outside') {
339
+ wrap.css('height', wrap.height());
340
+ }
341
+
342
+ currentArray = selectedArray;
343
+ currentIndex = selectedIndex;
344
+ currentOpts = selectedOpts;
345
+
346
+ if (currentOpts.overlayShow) {
347
+ overlay.css({
348
+ 'background-color' : currentOpts.overlayColor,
349
+ 'opacity' : currentOpts.overlayOpacity,
350
+ 'cursor' : currentOpts.hideOnOverlayClick ? 'pointer' : 'auto',
351
+ 'height' : $(document).height()
352
+ });
353
+
354
+ if (!overlay.is(':visible')) {
355
+ if (isIE6) {
356
+ $('select:not(#fancybox-tmp select)').filter(function() {
357
+ return this.style.visibility !== 'hidden';
358
+ }).css({'visibility' : 'hidden'}).one('fancybox-cleanup', function() {
359
+ this.style.visibility = 'inherit';
360
+ });
361
+ }
362
+
363
+ overlay.show();
364
+ }
365
+ } else {
366
+ overlay.hide();
367
+ }
368
+
369
+ final_pos = _get_zoom_to();
370
+
371
+ _process_title();
372
+
373
+ if (wrap.is(":visible")) {
374
+ $( close.add( nav_left ).add( nav_right ) ).hide();
375
+
376
+ pos = wrap.position(),
377
+
378
+ start_pos = {
379
+ top : pos.top,
380
+ left : pos.left,
381
+ width : wrap.width(),
382
+ height : wrap.height()
383
+ };
384
+
385
+ equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);
386
+
387
+ content.fadeTo(currentOpts.changeFade, 0.3, function() {
388
+ var finish_resizing = function() {
389
+ content.html( tmp.contents() ).fadeTo(currentOpts.changeFade, 1, _finish);
390
+ };
391
+
392
+ $.event.trigger('fancybox-change');
393
+
394
+ content
395
+ .empty()
396
+ .removeAttr('filter')
397
+ .css({
398
+ 'border-width' : currentOpts.padding,
399
+ 'width' : final_pos.width - currentOpts.padding * 2,
400
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
401
+ });
402
+
403
+ if (equal) {
404
+ finish_resizing();
405
+
406
+ } else {
407
+ fx.prop = 0;
408
+
409
+ $(fx).animate({prop: 1}, {
410
+ duration : currentOpts.changeSpeed,
411
+ easing : currentOpts.easingChange,
412
+ step : _draw,
413
+ complete : finish_resizing
414
+ });
415
+ }
416
+ });
417
+
418
+ return;
419
+ }
420
+
421
+ wrap.removeAttr("style");
422
+
423
+ content.css('border-width', currentOpts.padding);
424
+
425
+ if (currentOpts.transitionIn == 'elastic') {
426
+ start_pos = _get_zoom_from();
427
+
428
+ content.html( tmp.contents() );
429
+
430
+ wrap.show();
431
+
432
+ if (currentOpts.opacity) {
433
+ final_pos.opacity = 0;
434
+ }
435
+
436
+ fx.prop = 0;
437
+
438
+ $(fx).animate({prop: 1}, {
439
+ duration : currentOpts.speedIn,
440
+ easing : currentOpts.easingIn,
441
+ step : _draw,
442
+ complete : _finish
443
+ });
444
+
445
+ return;
446
+ }
447
+
448
+ if (currentOpts.titlePosition == 'inside' && titleHeight > 0) {
449
+ title.show();
450
+ }
451
+
452
+ content
453
+ .css({
454
+ 'width' : final_pos.width - currentOpts.padding * 2,
455
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
456
+ })
457
+ .html( tmp.contents() );
458
+
459
+ wrap
460
+ .css(final_pos)
461
+ .fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );
462
+ },
463
+
464
+ _format_title = function(title) {
465
+ if (title && title.length) {
466
+ if (currentOpts.titlePosition == 'float') {
467
+ return '<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">' + title + '</td><td id="fancybox-title-float-right"></td></tr></table>';
468
+ }
469
+
470
+ return '<div id="fancybox-title-' + currentOpts.titlePosition + '">' + title + '</div>';
471
+ }
472
+
473
+ return false;
474
+ },
475
+
476
+ _process_title = function() {
477
+ titleStr = currentOpts.title || '';
478
+ titleHeight = 0;
479
+
480
+ title
481
+ .empty()
482
+ .removeAttr('style')
483
+ .removeClass();
484
+
485
+ if (currentOpts.titleShow === false) {
486
+ title.hide();
487
+ return;
488
+ }
489
+
490
+ titleStr = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(titleStr, currentArray, currentIndex, currentOpts) : _format_title(titleStr);
491
+
492
+ if (!titleStr || titleStr === '') {
493
+ title.hide();
494
+ return;
495
+ }
496
+
497
+ title
498
+ .addClass('fancybox-title-' + currentOpts.titlePosition)
499
+ .html( titleStr )
500
+ .appendTo( 'body' )
501
+ .show();
502
+
503
+ switch (currentOpts.titlePosition) {
504
+ case 'inside':
505
+ title
506
+ .css({
507
+ 'width' : final_pos.width - (currentOpts.padding * 2),
508
+ 'marginLeft' : currentOpts.padding,
509
+ 'marginRight' : currentOpts.padding
510
+ });
511
+
512
+ titleHeight = title.outerHeight(true);
513
+
514
+ title.appendTo( outer );
515
+
516
+ final_pos.height += titleHeight;
517
+ break;
518
+
519
+ case 'over':
520
+ title
521
+ .css({
522
+ 'marginLeft' : currentOpts.padding,
523
+ 'width' : final_pos.width - (currentOpts.padding * 2),
524
+ 'bottom' : currentOpts.padding
525
+ })
526
+ .appendTo( outer );
527
+ break;
528
+
529
+ case 'float':
530
+ title
531
+ .css('left', parseInt((title.width() - final_pos.width - 40)/ 2, 10) * -1)
532
+ .appendTo( wrap );
533
+ break;
534
+
535
+ default:
536
+ title
537
+ .css({
538
+ 'width' : final_pos.width - (currentOpts.padding * 2),
539
+ 'paddingLeft' : currentOpts.padding,
540
+ 'paddingRight' : currentOpts.padding
541
+ })
542
+ .appendTo( wrap );
543
+ break;
544
+ }
545
+
546
+ title.hide();
547
+ },
548
+
549
+ _set_navigation = function() {
550
+ if (currentOpts.enableEscapeButton || currentOpts.enableKeyboardNav) {
551
+ $(document).bind('keydown.fb', function(e) {
552
+ if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
553
+ e.preventDefault();
554
+ $.fancybox.close();
555
+
556
+ } else if ((e.keyCode == 37 || e.keyCode == 39) && currentOpts.enableKeyboardNav && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {
557
+ e.preventDefault();
558
+ $.fancybox[ e.keyCode == 37 ? 'prev' : 'next']();
559
+ }
560
+ });
561
+ }
562
+
563
+ if (!currentOpts.showNavArrows) {
564
+ nav_left.hide();
565
+ nav_right.hide();
566
+ return;
567
+ }
568
+
569
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {
570
+ nav_left.show();
571
+ }
572
+
573
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {
574
+ nav_right.show();
575
+ }
576
+ },
577
+
578
+ _finish = function () {
579
+ if (!$.support.opacity) {
580
+ content.get(0).style.removeAttribute('filter');
581
+ wrap.get(0).style.removeAttribute('filter');
582
+ }
583
+
584
+ if (selectedOpts.autoDimensions) {
585
+ content.css('height', 'auto');
586
+ }
587
+
588
+ wrap.css('height', 'auto');
589
+
590
+ if (titleStr && titleStr.length) {
591
+ title.show();
592
+ }
593
+
594
+ if (currentOpts.showCloseButton) {
595
+ close.show();
596
+ }
597
+
598
+ _set_navigation();
599
+
600
+ if (currentOpts.hideOnContentClick) {
601
+ content.bind('click', $.fancybox.close);
602
+ }
603
+
604
+ if (currentOpts.hideOnOverlayClick) {
605
+ overlay.bind('click', $.fancybox.close);
606
+ }
607
+
608
+ $(window).bind("resize.fb", $.fancybox.resize);
609
+
610
+ if (currentOpts.centerOnScroll) {
611
+ $(window).bind("scroll.fb", $.fancybox.center);
612
+ }
613
+
614
+ if (currentOpts.type == 'iframe') {
615
+ $('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" ' + ($.browser.msie ? 'allowtransparency="true""' : '') + ' scrolling="' + selectedOpts.scrolling + '" src="' + currentOpts.href + '"></iframe>').appendTo(content);
616
+ }
617
+
618
+ wrap.show();
619
+
620
+ busy = false;
621
+
622
+ $.fancybox.center();
623
+
624
+ currentOpts.onComplete(currentArray, currentIndex, currentOpts);
625
+
626
+ _preload_images();
627
+ },
628
+
629
+ _preload_images = function() {
630
+ var href,
631
+ objNext;
632
+
633
+ if ((currentArray.length -1) > currentIndex) {
634
+ href = currentArray[ currentIndex + 1 ].href;
635
+
636
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
637
+ objNext = new Image();
638
+ objNext.src = href;
639
+ }
640
+ }
641
+
642
+ if (currentIndex > 0) {
643
+ href = currentArray[ currentIndex - 1 ].href;
644
+
645
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
646
+ objNext = new Image();
647
+ objNext.src = href;
648
+ }
649
+ }
650
+ },
651
+
652
+ _draw = function(pos) {
653
+ var dim = {
654
+ width : parseInt(start_pos.width + (final_pos.width - start_pos.width) * pos, 10),
655
+ height : parseInt(start_pos.height + (final_pos.height - start_pos.height) * pos, 10),
656
+
657
+ top : parseInt(start_pos.top + (final_pos.top - start_pos.top) * pos, 10),
658
+ left : parseInt(start_pos.left + (final_pos.left - start_pos.left) * pos, 10)
659
+ };
660
+
661
+ if (typeof final_pos.opacity !== 'undefined') {
662
+ dim.opacity = pos < 0.5 ? 0.5 : pos;
663
+ }
664
+
665
+ wrap.css(dim);
666
+
667
+ content.css({
668
+ 'width' : dim.width - currentOpts.padding * 2,
669
+ 'height' : dim.height - (titleHeight * pos) - currentOpts.padding * 2
670
+ });
671
+ },
672
+
673
+ _get_viewport = function() {
674
+ return [
675
+ $(window).width() - (currentOpts.margin * 2),
676
+ $(window).height() - (currentOpts.margin * 2),
677
+ $(document).scrollLeft() + currentOpts.margin,
678
+ $(document).scrollTop() + currentOpts.margin
679
+ ];
680
+ },
681
+
682
+ _get_zoom_to = function () {
683
+ var view = _get_viewport(),
684
+ to = {},
685
+ resize = currentOpts.autoScale,
686
+ double_padding = currentOpts.padding * 2,
687
+ ratio;
688
+
689
+ if (currentOpts.width.toString().indexOf('%') > -1) {
690
+ to.width = parseInt((view[0] * parseFloat(currentOpts.width)) / 100, 10);
691
+ } else {
692
+ to.width = currentOpts.width + double_padding;
693
+ }
694
+
695
+ if (currentOpts.height.toString().indexOf('%') > -1) {
696
+ to.height = parseInt((view[1] * parseFloat(currentOpts.height)) / 100, 10);
697
+ } else {
698
+ to.height = currentOpts.height + double_padding;
699
+ }
700
+
701
+ if (resize && (to.width > view[0] || to.height > view[1])) {
702
+ if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {
703
+ ratio = (currentOpts.width ) / (currentOpts.height );
704
+
705
+ if ((to.width ) > view[0]) {
706
+ to.width = view[0];
707
+ to.height = parseInt(((to.width - double_padding) / ratio) + double_padding, 10);
708
+ }
709
+
710
+ if ((to.height) > view[1]) {
711
+ to.height = view[1];
712
+ to.width = parseInt(((to.height - double_padding) * ratio) + double_padding, 10);
713
+ }
714
+
715
+ } else {
716
+ to.width = Math.min(to.width, view[0]);
717
+ to.height = Math.min(to.height, view[1]);
718
+ }
719
+ }
720
+
721
+ to.top = parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - to.height - 40) * 0.5)), 10);
722
+ to.left = parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - to.width - 40) * 0.5)), 10);
723
+
724
+ return to;
725
+ },
726
+
727
+ _get_obj_pos = function(obj) {
728
+ var pos = obj.offset();
729
+
730
+ pos.top += parseInt( obj.css('paddingTop'), 10 ) || 0;
731
+ pos.left += parseInt( obj.css('paddingLeft'), 10 ) || 0;
732
+
733
+ pos.top += parseInt( obj.css('border-top-width'), 10 ) || 0;
734
+ pos.left += parseInt( obj.css('border-left-width'), 10 ) || 0;
735
+
736
+ pos.width = obj.width();
737
+ pos.height = obj.height();
738
+
739
+ return pos;
740
+ },
741
+
742
+ _get_zoom_from = function() {
743
+ var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,
744
+ from = {},
745
+ pos,
746
+ view;
747
+
748
+ if (orig && orig.length) {
749
+ pos = _get_obj_pos(orig);
750
+
751
+ from = {
752
+ width : pos.width + (currentOpts.padding * 2),
753
+ height : pos.height + (currentOpts.padding * 2),
754
+ top : pos.top - currentOpts.padding - 20,
755
+ left : pos.left - currentOpts.padding - 20
756
+ };
757
+
758
+ } else {
759
+ view = _get_viewport();
760
+
761
+ from = {
762
+ width : currentOpts.padding * 2,
763
+ height : currentOpts.padding * 2,
764
+ top : parseInt(view[3] + view[1] * 0.5, 10),
765
+ left : parseInt(view[2] + view[0] * 0.5, 10)
766
+ };
767
+ }
768
+
769
+ return from;
770
+ },
771
+
772
+ _animate_loading = function() {
773
+ if (!loading.is(':visible')){
774
+ clearInterval(loadingTimer);
775
+ return;
776
+ }
777
+
778
+ $('div', loading).css('top', (loadingFrame * -40) + 'px');
779
+
780
+ loadingFrame = (loadingFrame + 1) % 12;
781
+ };
782
+
783
+ /*
784
+ * Public methods
785
+ */
786
+
787
+ $.fn.fancybox = function(options) {
788
+ if (!$(this).length) {
789
+ return this;
790
+ }
791
+
792
+ $(this)
793
+ .data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))
794
+ .unbind('click.fb')
795
+ .bind('click.fb', function(e) {
796
+ e.preventDefault();
797
+
798
+ if (busy) {
799
+ return;
800
+ }
801
+
802
+ busy = true;
803
+
804
+ $(this).blur();
805
+
806
+ selectedArray = [];
807
+ selectedIndex = 0;
808
+
809
+ var rel = $(this).attr('rel') || '';
810
+
811
+ if (!rel || rel == '' || rel === 'nofollow') {
812
+ selectedArray.push(this);
813
+
814
+ } else {
815
+ selectedArray = $("a[rel=" + rel + "], area[rel=" + rel + "]");
816
+ selectedIndex = selectedArray.index( this );
817
+ }
818
+
819
+ _start();
820
+
821
+ return;
822
+ });
823
+
824
+ return this;
825
+ };
826
+
827
+ $.fancybox = function(obj) {
828
+ var opts;
829
+
830
+ if (busy) {
831
+ return;
832
+ }
833
+
834
+ busy = true;
835
+ opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};
836
+
837
+ selectedArray = [];
838
+ selectedIndex = parseInt(opts.index, 10) || 0;
839
+
840
+ if ($.isArray(obj)) {
841
+ for (var i = 0, j = obj.length; i < j; i++) {
842
+ if (typeof obj[i] == 'object') {
843
+ $(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));
844
+ } else {
845
+ obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));
846
+ }
847
+ }
848
+
849
+ selectedArray = jQuery.merge(selectedArray, obj);
850
+
851
+ } else {
852
+ if (typeof obj == 'object') {
853
+ $(obj).data('fancybox', $.extend({}, opts, obj));
854
+ } else {
855
+ obj = $({}).data('fancybox', $.extend({content : obj}, opts));
856
+ }
857
+
858
+ selectedArray.push(obj);
859
+ }
860
+
861
+ if (selectedIndex > selectedArray.length || selectedIndex < 0) {
862
+ selectedIndex = 0;
863
+ }
864
+
865
+ _start();
866
+ };
867
+
868
+ $.fancybox.showActivity = function() {
869
+ clearInterval(loadingTimer);
870
+
871
+ loading.show();
872
+ loadingTimer = setInterval(_animate_loading, 66);
873
+ };
874
+
875
+ $.fancybox.hideActivity = function() {
876
+ loading.hide();
877
+ };
878
+
879
+ $.fancybox.next = function() {
880
+ return $.fancybox.pos( currentIndex + 1);
881
+ };
882
+
883
+ $.fancybox.prev = function() {
884
+ return $.fancybox.pos( currentIndex - 1);
885
+ };
886
+
887
+ $.fancybox.pos = function(pos) {
888
+ if (busy) {
889
+ return;
890
+ }
891
+
892
+ pos = parseInt(pos);
893
+
894
+ selectedArray = currentArray;
895
+
896
+ if (pos > -1 && pos < currentArray.length) {
897
+ selectedIndex = pos;
898
+ _start();
899
+
900
+ } else if (currentOpts.cyclic && currentArray.length > 1) {
901
+ selectedIndex = pos >= currentArray.length ? 0 : currentArray.length - 1;
902
+ _start();
903
+ }
904
+
905
+ return;
906
+ };
907
+
908
+ $.fancybox.cancel = function() {
909
+ if (busy) {
910
+ return;
911
+ }
912
+
913
+ busy = true;
914
+
915
+ $.event.trigger('fancybox-cancel');
916
+
917
+ _abort();
918
+
919
+ selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);
920
+
921
+ busy = false;
922
+ };
923
+
924
+ // Note: within an iframe use - parent.$.fancybox.close();
925
+ $.fancybox.close = function() {
926
+ if (busy || wrap.is(':hidden')) {
927
+ return;
928
+ }
929
+
930
+ busy = true;
931
+
932
+ if (currentOpts && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
933
+ busy = false;
934
+ return;
935
+ }
936
+
937
+ _abort();
938
+
939
+ $(close.add( nav_left ).add( nav_right )).hide();
940
+
941
+ $(content.add( overlay )).unbind();
942
+
943
+ $(window).unbind("resize.fb scroll.fb");
944
+ $(document).unbind('keydown.fb');
945
+
946
+ content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank');
947
+
948
+ if (currentOpts.titlePosition !== 'inside') {
949
+ title.empty();
950
+ }
951
+
952
+ wrap.stop();
953
+
954
+ function _cleanup() {
955
+ overlay.fadeOut('fast');
956
+
957
+ title.empty().hide();
958
+ wrap.hide();
959
+
960
+ $.event.trigger('fancybox-cleanup');
961
+
962
+ content.empty();
963
+
964
+ currentOpts.onClosed(currentArray, currentIndex, currentOpts);
965
+
966
+ currentArray = selectedOpts = [];
967
+ currentIndex = selectedIndex = 0;
968
+ currentOpts = selectedOpts = {};
969
+
970
+ busy = false;
971
+ }
972
+
973
+ if (currentOpts.transitionOut == 'elastic') {
974
+ start_pos = _get_zoom_from();
975
+
976
+ var pos = wrap.position();
977
+
978
+ final_pos = {
979
+ top : pos.top ,
980
+ left : pos.left,
981
+ width : wrap.width(),
982
+ height : wrap.height()
983
+ };
984
+
985
+ if (currentOpts.opacity) {
986
+ final_pos.opacity = 1;
987
+ }
988
+
989
+ title.empty().hide();
990
+
991
+ fx.prop = 1;
992
+
993
+ $(fx).animate({ prop: 0 }, {
994
+ duration : currentOpts.speedOut,
995
+ easing : currentOpts.easingOut,
996
+ step : _draw,
997
+ complete : _cleanup
998
+ });
999
+
1000
+ } else {
1001
+ wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);
1002
+ }
1003
+ };
1004
+
1005
+ $.fancybox.resize = function() {
1006
+ if (overlay.is(':visible')) {
1007
+ overlay.css('height', $(document).height());
1008
+ }
1009
+
1010
+ $.fancybox.center(true);
1011
+ };
1012
+
1013
+ $.fancybox.center = function() {
1014
+ var view, align;
1015
+
1016
+ if (busy) {
1017
+ return;
1018
+ }
1019
+
1020
+ align = arguments[0] === true ? 1 : 0;
1021
+ view = _get_viewport();
1022
+
1023
+ if (!align && (wrap.width() > view[0] || wrap.height() > view[1])) {
1024
+ return;
1025
+ }
1026
+
1027
+ wrap
1028
+ .stop()
1029
+ .animate({
1030
+ 'top' : parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - content.height() - 40) * 0.5) - currentOpts.padding)),
1031
+ 'left' : parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - content.width() - 40) * 0.5) - currentOpts.padding))
1032
+ }, typeof arguments[0] == 'number' ? arguments[0] : 200);
1033
+ };
1034
+
1035
+ $.fancybox.init = function() {
1036
+ if ($("#fancybox-wrap").length) {
1037
+ return;
1038
+ }
1039
+
1040
+ $('body').append(
1041
+ tmp = $('<div id="fancybox-tmp"></div>'),
1042
+ loading = $('<div id="fancybox-loading"><div></div></div>'),
1043
+ overlay = $('<div id="fancybox-overlay"></div>'),
1044
+ wrap = $('<div id="fancybox-wrap"></div>')
1045
+ );
1046
+
1047
+ outer = $('<div id="fancybox-outer"></div>')
1048
+ .append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>')
1049
+ .appendTo( wrap );
1050
+
1051
+ outer.append(
1052
+ content = $('<div id="fancybox-content"></div>'),
1053
+ close = $('<a id="fancybox-close"></a>'),
1054
+ title = $('<div id="fancybox-title"></div>'),
1055
+
1056
+ nav_left = $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),
1057
+ nav_right = $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>')
1058
+ );
1059
+
1060
+ close.click($.fancybox.close);
1061
+ loading.click($.fancybox.cancel);
1062
+
1063
+ nav_left.click(function(e) {
1064
+ e.preventDefault();
1065
+ $.fancybox.prev();
1066
+ });
1067
+
1068
+ nav_right.click(function(e) {
1069
+ e.preventDefault();
1070
+ $.fancybox.next();
1071
+ });
1072
+
1073
+ if ($.fn.mousewheel) {
1074
+ wrap.bind('mousewheel.fb', function(e, delta) {
1075
+ if (busy) {
1076
+ e.preventDefault();
1077
+
1078
+ } else if ($(e.target).get(0).clientHeight == 0 || $(e.target).get(0).scrollHeight === $(e.target).get(0).clientHeight) {
1079
+ e.preventDefault();
1080
+ $.fancybox[ delta > 0 ? 'prev' : 'next']();
1081
+ }
1082
+ });
1083
+ }
1084
+
1085
+ if (!$.support.opacity) {
1086
+ wrap.addClass('fancybox-ie');
1087
+ }
1088
+
1089
+ if (isIE6) {
1090
+ loading.addClass('fancybox-ie6');
1091
+ wrap.addClass('fancybox-ie6');
1092
+
1093
+ $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank' ) + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer);
1094
+ }
1095
+ };
1096
+
1097
+ $.fn.fancybox.defaults = {
1098
+ padding : 10,
1099
+ margin : 40,
1100
+ opacity : false,
1101
+ modal : false,
1102
+ cyclic : false,
1103
+ scrolling : 'auto', // 'auto', 'yes' or 'no'
1104
+
1105
+ width : 560,
1106
+ height : 340,
1107
+
1108
+ autoScale : true,
1109
+ autoDimensions : true,
1110
+ centerOnScroll : false,
1111
+
1112
+ ajax : {},
1113
+ swf : { wmode: 'transparent' },
1114
+
1115
+ hideOnOverlayClick : true,
1116
+ hideOnContentClick : false,
1117
+
1118
+ overlayShow : true,
1119
+ overlayOpacity : 0.7,
1120
+ overlayColor : '#777',
1121
+
1122
+ titleShow : true,
1123
+ titlePosition : 'float', // 'float', 'outside', 'inside' or 'over'
1124
+ titleFormat : null,
1125
+ titleFromAlt : false,
1126
+
1127
+ transitionIn : 'fade', // 'elastic', 'fade' or 'none'
1128
+ transitionOut : 'fade', // 'elastic', 'fade' or 'none'
1129
+
1130
+ speedIn : 300,
1131
+ speedOut : 300,
1132
+
1133
+ changeSpeed : 300,
1134
+ changeFade : 'fast',
1135
+
1136
+ easingIn : 'swing',
1137
+ easingOut : 'swing',
1138
+
1139
+ showCloseButton : true,
1140
+ showNavArrows : true,
1141
+ enableEscapeButton : true,
1142
+ enableKeyboardNav : true,
1143
+
1144
+ onStart : function(){},
1145
+ onCancel : function(){},
1146
+ onComplete : function(){},
1147
+ onCleanup : function(){},
1148
+ onClosed : function(){},
1149
+ onError : function(){}
1150
+ };
1151
+
1152
+ $(document).ready(function() {
1153
+ $.fancybox.init();
1154
+ });
1155
+
1156
+ })(jQuery);
products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.fancybox-1.3.4.pack.js ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * FancyBox - jQuery Plugin
3
+ * Simple and fancy lightbox alternative
4
+ *
5
+ * Examples and documentation at: http://fancybox.net
6
+ *
7
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
8
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
9
+ *
10
+ * Version: 1.3.4 (11/11/2010)
11
+ * Requires: jQuery v1.3+
12
+ *
13
+ * Dual licensed under the MIT and GPL licenses:
14
+ * http://www.opensource.org/licenses/mit-license.php
15
+ * http://www.gnu.org/licenses/gpl.html
16
+ */
17
+
18
+ ;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
19
+ F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
20
+ c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
21
+ false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel",
22
+ function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+
23
+ '"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win==
24
+ "function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+
25
+ ";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor,
26
+ opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?
27
+ d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
28
+ y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==
29
+ i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents());
30
+ f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==
31
+ 37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto");
32
+ s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j);
33
+ f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);
34
+ j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==
35
+ "image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"),
36
+ 10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};
37
+ b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
38
+ 0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
39
+ 1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
40
+ true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
41
+ b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
42
+ d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
43
+ D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
44
+ b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
45
+ b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
46
+ easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery);
products/photocrati_nextgen/modules/lightbox/static/fancybox/jquery.mousewheel-3.0.4.pack.js ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
2
+ * Licensed under the MIT License (LICENSE.txt).
3
+ *
4
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
5
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
6
+ * Thanks to: Seamus Leahy for adding deltaX and deltaY
7
+ *
8
+ * Version: 3.0.4
9
+ *
10
+ * Requires: 1.2.2+
11
+ */
12
+
13
+ (function(d){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),c=0,h=0,e=0;a=d.event.fix(b);a.type="mousewheel";if(a.wheelDelta)c=a.wheelDelta/120;if(a.detail)c=-a.detail/3;e=c;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){e=0;h=-1*c}if(b.wheelDeltaY!==undefined)e=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,c,h,e);return d.event.handle.apply(this,i)}var f=["DOMMouseScroll","mousewheel"];d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=
14
+ f.length;a;)this.addEventListener(f[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=f.length;a;)this.removeEventListener(f[--a],g,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);
products/photocrati_nextgen/modules/lightbox/static/fancybox/nextgen_fancybox_init.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(function($) {
2
+ var nextgen_fancybox_init = function() {
3
+ $(".ngg-fancybox").fancybox({
4
+ titlePosition: 'inside',
5
+ // Needed for twenty eleven
6
+ onComplete: function() {
7
+ $('#fancybox-wrap').css('z-index', 10000);
8
+ }
9
+ });
10
+ };
11
+ $(this).bind('refreshed', nextgen_fancybox_init);
12
+ nextgen_fancybox_init();
13
+ });
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/close.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/closeX.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar-black-border.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar-text-buttons.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar-white-small.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar-white.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar2.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar3.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar4-hover.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/controlbar4.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/fullexpand.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/geckodimmer.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/icon.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/loader.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/loader.white.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/Outlines.psd ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/beveled.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/drop-shadow.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/glossy-dark.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/outer-glow.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/rounded-black.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/outlines/rounded-white.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/resize.gif ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/scrollarrows.png ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/zoomin.cur ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/graphics/zoomout.cur ADDED
Binary file
products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-full.js ADDED
@@ -0,0 +1,3320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Name: Highslide JS
3
+ * Version: 4.1.13 (2011-10-06)
4
+ * Config: default +events +unobtrusive +imagemap +slideshow +positioning +transitions +viewport +thumbstrip +inline +ajax +iframe +flash
5
+ * Author: Torstein Hønsi
6
+ * Support: www.highslide.com/support
7
+ * License: www.highslide.com/#license
8
+ */
9
+ if (!hs) { var hs = {
10
+ // Language strings
11
+ lang : {
12
+ cssDirection: 'ltr',
13
+ loadingText : 'Loading...',
14
+ loadingTitle : 'Click to cancel',
15
+ focusTitle : 'Click to bring to front',
16
+ fullExpandTitle : 'Expand to actual size (f)',
17
+ creditsText : 'Powered by <i>Highslide JS</i>',
18
+ creditsTitle : 'Go to the Highslide JS homepage',
19
+ previousText : 'Previous',
20
+ nextText : 'Next',
21
+ moveText : 'Move',
22
+ closeText : 'Close',
23
+ closeTitle : 'Close (esc)',
24
+ resizeTitle : 'Resize',
25
+ playText : 'Play',
26
+ playTitle : 'Play slideshow (spacebar)',
27
+ pauseText : 'Pause',
28
+ pauseTitle : 'Pause slideshow (spacebar)',
29
+ previousTitle : 'Previous (arrow left)',
30
+ nextTitle : 'Next (arrow right)',
31
+ moveTitle : 'Move',
32
+ fullExpandText : '1:1',
33
+ number: 'Image %1 of %2',
34
+ restoreTitle : 'Click to close image, click and drag to move. Use arrow keys for next and previous.'
35
+ },
36
+ // See http://highslide.com/ref for examples of settings
37
+ graphicsDir : 'highslide/graphics/',
38
+ expandCursor : 'zoomin.cur', // null disables
39
+ restoreCursor : 'zoomout.cur', // null disables
40
+ expandDuration : 250, // milliseconds
41
+ restoreDuration : 250,
42
+ marginLeft : 15,
43
+ marginRight : 15,
44
+ marginTop : 15,
45
+ marginBottom : 15,
46
+ zIndexCounter : 10001, // adjust to other absolutely positioned elements
47
+ loadingOpacity : 0.75,
48
+ allowMultipleInstances: true,
49
+ numberOfImagesToPreload : 5,
50
+ outlineWhileAnimating : 2, // 0 = never, 1 = always, 2 = HTML only
51
+ outlineStartOffset : 3, // ends at 10
52
+ padToMinWidth : false, // pad the popup width to make room for wide caption
53
+ fullExpandPosition : 'bottom right',
54
+ fullExpandOpacity : 1,
55
+ showCredits : true, // you can set this to false if you want
56
+ creditsHref : 'http://highslide.com/',
57
+ creditsTarget : '_self',
58
+ enableKeyListener : true,
59
+ openerTagNames : ['a', 'area'], // Add more to allow slideshow indexing
60
+ transitions : [],
61
+ transitionDuration: 250,
62
+ dimmingOpacity: 0, // Lightbox style dimming background
63
+ dimmingDuration: 50, // 0 for instant dimming
64
+
65
+ allowWidthReduction : false,
66
+ allowHeightReduction : true,
67
+ preserveContent : true, // Preserve changes made to the content and position of HTML popups.
68
+ objectLoadTime : 'before', // Load iframes 'before' or 'after' expansion.
69
+ cacheAjax : true, // Cache ajax popups for instant display. Can be overridden for each popup.
70
+ anchor : 'auto', // where the image expands from
71
+ align : 'auto', // position in the client (overrides anchor)
72
+ targetX: null, // the id of a target element
73
+ targetY: null,
74
+ dragByHeading: true,
75
+ minWidth: 200,
76
+ minHeight: 200,
77
+ allowSizeReduction: true, // allow the image to reduce to fit client size. If false, this overrides minWidth and minHeight
78
+ outlineType : 'drop-shadow', // set null to disable outlines
79
+ skin : {
80
+ controls:
81
+ '<div class="highslide-controls"><ul>'+
82
+ '<li class="highslide-previous">'+
83
+ '<a href="#" title="{hs.lang.previousTitle}">'+
84
+ '<span>{hs.lang.previousText}</span></a>'+
85
+ '</li>'+
86
+ '<li class="highslide-play">'+
87
+ '<a href="#" title="{hs.lang.playTitle}">'+
88
+ '<span>{hs.lang.playText}</span></a>'+
89
+ '</li>'+
90
+ '<li class="highslide-pause">'+
91
+ '<a href="#" title="{hs.lang.pauseTitle}">'+
92
+ '<span>{hs.lang.pauseText}</span></a>'+
93
+ '</li>'+
94
+ '<li class="highslide-next">'+
95
+ '<a href="#" title="{hs.lang.nextTitle}">'+
96
+ '<span>{hs.lang.nextText}</span></a>'+
97
+ '</li>'+
98
+ '<li class="highslide-move">'+
99
+ '<a href="#" title="{hs.lang.moveTitle}">'+
100
+ '<span>{hs.lang.moveText}</span></a>'+
101
+ '</li>'+
102
+ '<li class="highslide-full-expand">'+
103
+ '<a href="#" title="{hs.lang.fullExpandTitle}">'+
104
+ '<span>{hs.lang.fullExpandText}</span></a>'+
105
+ '</li>'+
106
+ '<li class="highslide-close">'+
107
+ '<a href="#" title="{hs.lang.closeTitle}" >'+
108
+ '<span>{hs.lang.closeText}</span></a>'+
109
+ '</li>'+
110
+ '</ul></div>'
111
+ ,
112
+ contentWrapper:
113
+ '<div class="highslide-header"><ul>'+
114
+ '<li class="highslide-previous">'+
115
+ '<a href="#" title="{hs.lang.previousTitle}" onclick="return hs.previous(this)">'+
116
+ '<span>{hs.lang.previousText}</span></a>'+
117
+ '</li>'+
118
+ '<li class="highslide-next">'+
119
+ '<a href="#" title="{hs.lang.nextTitle}" onclick="return hs.next(this)">'+
120
+ '<span>{hs.lang.nextText}</span></a>'+
121
+ '</li>'+
122
+ '<li class="highslide-move">'+
123
+ '<a href="#" title="{hs.lang.moveTitle}" onclick="return false">'+
124
+ '<span>{hs.lang.moveText}</span></a>'+
125
+ '</li>'+
126
+ '<li class="highslide-close">'+
127
+ '<a href="#" title="{hs.lang.closeTitle}" onclick="return hs.close(this)">'+
128
+ '<span>{hs.lang.closeText}</span></a>'+
129
+ '</li>'+
130
+ '</ul></div>'+
131
+ '<div class="highslide-body"></div>'+
132
+ '<div class="highslide-footer"><div>'+
133
+ '<span class="highslide-resize" title="{hs.lang.resizeTitle}"><span></span></span>'+
134
+ '</div></div>'
135
+ },
136
+ // END OF YOUR SETTINGS
137
+
138
+
139
+ // declare internal properties
140
+ preloadTheseImages : [],
141
+ continuePreloading: true,
142
+ expanders : [],
143
+ overrides : [
144
+ 'allowSizeReduction',
145
+ 'useBox',
146
+ 'anchor',
147
+ 'align',
148
+ 'targetX',
149
+ 'targetY',
150
+ 'outlineType',
151
+ 'outlineWhileAnimating',
152
+ 'captionId',
153
+ 'captionText',
154
+ 'captionEval',
155
+ 'captionOverlay',
156
+ 'headingId',
157
+ 'headingText',
158
+ 'headingEval',
159
+ 'headingOverlay',
160
+ 'creditsPosition',
161
+ 'dragByHeading',
162
+ 'autoplay',
163
+ 'numberPosition',
164
+ 'transitions',
165
+ 'dimmingOpacity',
166
+
167
+ 'width',
168
+ 'height',
169
+
170
+ 'contentId',
171
+ 'allowWidthReduction',
172
+ 'allowHeightReduction',
173
+ 'preserveContent',
174
+ 'maincontentId',
175
+ 'maincontentText',
176
+ 'maincontentEval',
177
+ 'objectType',
178
+ 'cacheAjax',
179
+ 'objectWidth',
180
+ 'objectHeight',
181
+ 'objectLoadTime',
182
+ 'swfOptions',
183
+ 'wrapperClassName',
184
+ 'minWidth',
185
+ 'minHeight',
186
+ 'maxWidth',
187
+ 'maxHeight',
188
+ 'pageOrigin',
189
+ 'slideshowGroup',
190
+ 'easing',
191
+ 'easingClose',
192
+ 'fadeInOut',
193
+ 'src'
194
+ ],
195
+ overlays : [],
196
+ idCounter : 0,
197
+ oPos : {
198
+ x: ['leftpanel', 'left', 'center', 'right', 'rightpanel'],
199
+ y: ['above', 'top', 'middle', 'bottom', 'below']
200
+ },
201
+ mouse: {},
202
+ headingOverlay: {},
203
+ captionOverlay: {},
204
+ swfOptions: { flashvars: {}, params: {}, attributes: {} },
205
+ timers : [],
206
+
207
+ slideshows : [],
208
+
209
+ pendingOutlines : {},
210
+ sleeping : [],
211
+ preloadTheseAjax : [],
212
+ cacheBindings : [],
213
+ cachedGets : {},
214
+ clones : {},
215
+ onReady: [],
216
+ uaVersion: /Trident\/4\.0/.test(navigator.userAgent) ? 8 :
217
+ parseFloat((navigator.userAgent.toLowerCase().match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1]),
218
+ ie : (document.all && !window.opera),
219
+ //ie : navigator && /MSIE [678]/.test(navigator.userAgent), // ie9 compliant?
220
+ safari : /Safari/.test(navigator.userAgent),
221
+ geckoMac : /Macintosh.+rv:1\.[0-8].+Gecko/.test(navigator.userAgent),
222
+
223
+ $ : function (id) {
224
+ if (id) return document.getElementById(id);
225
+ },
226
+
227
+ push : function (arr, val) {
228
+ arr[arr.length] = val;
229
+ },
230
+
231
+ createElement : function (tag, attribs, styles, parent, nopad) {
232
+ var el = document.createElement(tag);
233
+ if (attribs) hs.extend(el, attribs);
234
+ if (nopad) hs.setStyles(el, {padding: 0, border: 'none', margin: 0});
235
+ if (styles) hs.setStyles(el, styles);
236
+ if (parent) parent.appendChild(el);
237
+ return el;
238
+ },
239
+
240
+ extend : function (el, attribs) {
241
+ for (var x in attribs) el[x] = attribs[x];
242
+ return el;
243
+ },
244
+
245
+ setStyles : function (el, styles) {
246
+ for (var x in styles) {
247
+ if (hs.ieLt9 && x == 'opacity') {
248
+ if (styles[x] > 0.99) el.style.removeAttribute('filter');
249
+ else el.style.filter = 'alpha(opacity='+ (styles[x] * 100) +')';
250
+ }
251
+ else el.style[x] = styles[x];
252
+ }
253
+ },
254
+ animate: function(el, prop, opt) {
255
+ var start,
256
+ end,
257
+ unit;
258
+ if (typeof opt != 'object' || opt === null) {
259
+ var args = arguments;
260
+ opt = {
261
+ duration: args[2],
262
+ easing: args[3],
263
+ complete: args[4]
264
+ };
265
+ }
266
+ if (typeof opt.duration != 'number') opt.duration = 250;
267
+ opt.easing = Math[opt.easing] || Math.easeInQuad;
268
+ opt.curAnim = hs.extend({}, prop);
269
+ for (var name in prop) {
270
+ var e = new hs.fx(el, opt , name );
271
+
272
+ start = parseFloat(hs.css(el, name)) || 0;
273
+ end = parseFloat(prop[name]);
274
+ unit = name != 'opacity' ? 'px' : '';
275
+
276
+ e.custom( start, end, unit );
277
+ }
278
+ },
279
+ css: function(el, prop) {
280
+ if (el.style[prop]) {
281
+ return el.style[prop];
282
+ } else if (document.defaultView) {
283
+ return document.defaultView.getComputedStyle(el, null).getPropertyValue(prop);
284
+
285
+ } else {
286
+ if (prop == 'opacity') prop = 'filter';
287
+ var val = el.currentStyle[prop.replace(/\-(\w)/g, function (a, b){ return b.toUpperCase(); })];
288
+ if (prop == 'filter')
289
+ val = val.replace(/alpha\(opacity=([0-9]+)\)/,
290
+ function (a, b) { return b / 100 });
291
+ return val === '' ? 1 : val;
292
+ }
293
+ },
294
+
295
+ getPageSize : function () {
296
+ var d = document, w = window, iebody = d.compatMode && d.compatMode != 'BackCompat'
297
+ ? d.documentElement : d.body,
298
+ ieLt9 = hs.ie && (hs.uaVersion < 9 || typeof pageXOffset == 'undefined');
299
+
300
+ var width = ieLt9 ? iebody.clientWidth :
301
+ (d.documentElement.clientWidth || self.innerWidth),
302
+ height = ieLt9 ? iebody.clientHeight : self.innerHeight;
303
+ hs.page = {
304
+ width: width,
305
+ height: height,
306
+ scrollLeft: ieLt9 ? iebody.scrollLeft : pageXOffset,
307
+ scrollTop: ieLt9 ? iebody.scrollTop : pageYOffset
308
+ };
309
+ return hs.page;
310
+ },
311
+
312
+ getPosition : function(el) {
313
+ if (/area/i.test(el.tagName)) {
314
+ var imgs = document.getElementsByTagName('img');
315
+ for (var i = 0; i < imgs.length; i++) {
316
+ var u = imgs[i].useMap;
317
+ if (u && u.replace(/^.*?#/, '') == el.parentNode.name) {
318
+ el = imgs[i];
319
+ break;
320
+ }
321
+ }
322
+ }
323
+ var p = { x: el.offsetLeft, y: el.offsetTop };
324
+ while (el.offsetParent) {
325
+ el = el.offsetParent;
326
+ p.x += el.offsetLeft;
327
+ p.y += el.offsetTop;
328
+ if (el != document.body && el != document.documentElement) {
329
+ p.x -= el.scrollLeft;
330
+ p.y -= el.scrollTop;
331
+ }
332
+ }
333
+ return p;
334
+ },
335
+
336
+ expand : function(a, params, custom, type) {
337
+ if (!a) a = hs.createElement('a', null, { display: 'none' }, hs.container);
338
+ if (typeof a.getParams == 'function') return params;
339
+ if (type == 'html') {
340
+ for (var i = 0; i < hs.sleeping.length; i++) {
341
+ if (hs.sleeping[i] && hs.sleeping[i].a == a) {
342
+ hs.sleeping[i].awake();
343
+ hs.sleeping[i] = null;
344
+ return false;
345
+ }
346
+ }
347
+ hs.hasHtmlExpanders = true;
348
+ }
349
+ try {
350
+ new hs.Expander(a, params, custom, type);
351
+ return false;
352
+ } catch (e) { return true; }
353
+ },
354
+
355
+ htmlExpand : function(a, params, custom) {
356
+ return hs.expand(a, params, custom, 'html');
357
+ },
358
+
359
+ getSelfRendered : function() {
360
+ return hs.createElement('div', {
361
+ className: 'highslide-html-content',
362
+ innerHTML: hs.replaceLang(hs.skin.contentWrapper)
363
+ });
364
+ },
365
+ getElementByClass : function (el, tagName, className) {
366
+ var els = el.getElementsByTagName(tagName);
367
+ for (var i = 0; i < els.length; i++) {
368
+ if ((new RegExp(className)).test(els[i].className)) {
369
+ return els[i];
370
+ }
371
+ }
372
+ return null;
373
+ },
374
+ replaceLang : function(s) {
375
+ s = s.replace(/\s/g, ' ');
376
+ var re = /{hs\.lang\.([^}]+)\}/g,
377
+ matches = s.match(re),
378
+ lang;
379
+ if (matches) for (var i = 0; i < matches.length; i++) {
380
+ lang = matches[i].replace(re, "$1");
381
+ if (typeof hs.lang[lang] != 'undefined') s = s.replace(matches[i], hs.lang[lang]);
382
+ }
383
+ return s;
384
+ },
385
+
386
+
387
+ setClickEvents : function () {
388
+ var els = document.getElementsByTagName('a');
389
+ for (var i = 0; i < els.length; i++) {
390
+ var type = hs.isUnobtrusiveAnchor(els[i]);
391
+ if (type && !els[i].hsHasSetClick) {
392
+ (function(){
393
+ var t = type;
394
+ if (hs.fireEvent(hs, 'onSetClickEvent', { element: els[i], type: t })) {
395
+ els[i].onclick =(type == 'image') ?function() { return hs.expand(this) }:
396
+ function() { return hs.htmlExpand(this, { objectType: t } );};
397
+ }
398
+ })();
399
+ els[i].hsHasSetClick = true;
400
+ }
401
+ }
402
+ hs.getAnchors();
403
+ },
404
+ isUnobtrusiveAnchor: function(el) {
405
+ if (el.rel == 'highslide') return 'image';
406
+ else if (el.rel == 'highslide-ajax') return 'ajax';
407
+ else if (el.rel == 'highslide-iframe') return 'iframe';
408
+ else if (el.rel == 'highslide-swf') return 'swf';
409
+ },
410
+
411
+ getCacheBinding : function (a) {
412
+ for (var i = 0; i < hs.cacheBindings.length; i++) {
413
+ if (hs.cacheBindings[i][0] == a) {
414
+ var c = hs.cacheBindings[i][1];
415
+ hs.cacheBindings[i][1] = c.cloneNode(1);
416
+ return c;
417
+ }
418
+ }
419
+ return null;
420
+ },
421
+
422
+ preloadAjax : function (e) {
423
+ var arr = hs.getAnchors();
424
+ for (var i = 0; i < arr.htmls.length; i++) {
425
+ var a = arr.htmls[i];
426
+ if (hs.getParam(a, 'objectType') == 'ajax' && hs.getParam(a, 'cacheAjax'))
427
+ hs.push(hs.preloadTheseAjax, a);
428
+ }
429
+
430
+ hs.preloadAjaxElement(0);
431
+ },
432
+
433
+ preloadAjaxElement : function (i) {
434
+ if (!hs.preloadTheseAjax[i]) return;
435
+ var a = hs.preloadTheseAjax[i];
436
+ var cache = hs.getNode(hs.getParam(a, 'contentId'));
437
+ if (!cache) cache = hs.getSelfRendered();
438
+ var ajax = new hs.Ajax(a, cache, 1);
439
+ ajax.onError = function () { };
440
+ ajax.onLoad = function () {
441
+ hs.push(hs.cacheBindings, [a, cache]);
442
+ hs.preloadAjaxElement(i + 1);
443
+ };
444
+ ajax.run();
445
+ },
446
+
447
+ focusTopmost : function() {
448
+ var topZ = 0,
449
+ topmostKey = -1,
450
+ expanders = hs.expanders,
451
+ exp,
452
+ zIndex;
453
+ for (var i = 0; i < expanders.length; i++) {
454
+ exp = expanders[i];
455
+ if (exp) {
456
+ zIndex = exp.wrapper.style.zIndex;
457
+ if (zIndex && zIndex > topZ) {
458
+ topZ = zIndex;
459
+ topmostKey = i;
460
+ }
461
+ }
462
+ }
463
+ if (topmostKey == -1) hs.focusKey = -1;
464
+ else expanders[topmostKey].focus();
465
+ },
466
+
467
+ getParam : function (a, param) {
468
+ a.getParams = a.onclick;
469
+ var p = a.getParams ? a.getParams() : null;
470
+ a.getParams = null;
471
+
472
+ return (p && typeof p[param] != 'undefined') ? p[param] :
473
+ (typeof hs[param] != 'undefined' ? hs[param] : null);
474
+ },
475
+
476
+ getSrc : function (a) {
477
+ var src = hs.getParam(a, 'src');
478
+ if (src) return src;
479
+ return a.href;
480
+ },
481
+
482
+ getNode : function (id) {
483
+ var node = hs.$(id), clone = hs.clones[id], a = {};
484
+ if (!node && !clone) return null;
485
+ if (!clone) {
486
+ clone = node.cloneNode(true);
487
+ clone.id = '';
488
+ hs.clones[id] = clone;
489
+ return node;
490
+ } else {
491
+ return clone.cloneNode(true);
492
+ }
493
+ },
494
+
495
+ discardElement : function(d) {
496
+ if (d) hs.garbageBin.appendChild(d);
497
+ hs.garbageBin.innerHTML = '';
498
+ },
499
+ dim : function(exp) {
500
+ if (!hs.dimmer) {
501
+ isNew = true;
502
+ hs.dimmer = hs.createElement ('div', {
503
+ className: 'highslide-dimming highslide-viewport-size',
504
+ owner: '',
505
+ onclick: function() {
506
+ if (hs.fireEvent(hs, 'onDimmerClick'))
507
+
508
+ hs.close();
509
+ }
510
+ }, {
511
+ visibility: 'visible',
512
+ opacity: 0
513
+ }, hs.container, true);
514
+
515
+ if (/(Android|iPad|iPhone|iPod)/.test(navigator.userAgent)) {
516
+ var body = document.body;
517
+ function pixDimmerSize() {
518
+ hs.setStyles(hs.dimmer, {
519
+ width: body.scrollWidth +'px',
520
+ height: body.scrollHeight +'px'
521
+ });
522
+ }
523
+ pixDimmerSize();
524
+ hs.addEventListener(window, 'resize', pixDimmerSize);
525
+ }
526
+ }
527
+ hs.dimmer.style.display = '';
528
+
529
+ var isNew = hs.dimmer.owner == '';
530
+ hs.dimmer.owner += '|'+ exp.key;
531
+
532
+ if (isNew) {
533
+ if (hs.geckoMac && hs.dimmingGeckoFix)
534
+ hs.setStyles(hs.dimmer, {
535
+ background: 'url('+ hs.graphicsDir + 'geckodimmer.png)',
536
+ opacity: 1
537
+ });
538
+ else
539
+ hs.animate(hs.dimmer, { opacity: exp.dimmingOpacity }, hs.dimmingDuration);
540
+ }
541
+ },
542
+ undim : function(key) {
543
+ if (!hs.dimmer) return;
544
+ if (typeof key != 'undefined') hs.dimmer.owner = hs.dimmer.owner.replace('|'+ key, '');
545
+
546
+ if (
547
+ (typeof key != 'undefined' && hs.dimmer.owner != '')
548
+ || (hs.upcoming && hs.getParam(hs.upcoming, 'dimmingOpacity'))
549
+ ) return;
550
+
551
+ if (hs.geckoMac && hs.dimmingGeckoFix) hs.dimmer.style.display = 'none';
552
+ else hs.animate(hs.dimmer, { opacity: 0 }, hs.dimmingDuration, null, function() {
553
+ hs.dimmer.style.display = 'none';
554
+ });
555
+ },
556
+ transit : function (adj, exp) {
557
+ var last = exp || hs.getExpander();
558
+ exp = last;
559
+ if (hs.upcoming) return false;
560
+ else hs.last = last;
561
+ hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);
562
+ try {
563
+ hs.upcoming = adj;
564
+ adj.onclick();
565
+ } catch (e){
566
+ hs.last = hs.upcoming = null;
567
+ }
568
+ try {
569
+ if (!adj || exp.transitions[1] != 'crossfade')
570
+ exp.close();
571
+ } catch (e) {}
572
+ return false;
573
+ },
574
+
575
+ previousOrNext : function (el, op) {
576
+ var exp = hs.getExpander(el);
577
+ if (exp) return hs.transit(exp.getAdjacentAnchor(op), exp);
578
+ else return false;
579
+ },
580
+
581
+ previous : function (el) {
582
+ return hs.previousOrNext(el, -1);
583
+ },
584
+
585
+ next : function (el) {
586
+ return hs.previousOrNext(el, 1);
587
+ },
588
+
589
+ keyHandler : function(e) {
590
+ if (!e) e = window.event;
591
+ if (!e.target) e.target = e.srcElement; // ie
592
+ if (typeof e.target.form != 'undefined') return true; // form element has focus
593
+ if (!hs.fireEvent(hs, 'onKeyDown', e)) return true;
594
+ var exp = hs.getExpander();
595
+
596
+ var op = null;
597
+ switch (e.keyCode) {
598
+ case 70: // f
599
+ if (exp) exp.doFullExpand();
600
+ return true;
601
+ case 32: // Space
602
+ op = 2;
603
+ break;
604
+ case 34: // Page Down
605
+ case 39: // Arrow right
606
+ case 40: // Arrow down
607
+ op = 1;
608
+ break;
609
+ case 8: // Backspace
610
+ case 33: // Page Up
611
+ case 37: // Arrow left
612
+ case 38: // Arrow up
613
+ op = -1;
614
+ break;
615
+ case 27: // Escape
616
+ case 13: // Enter
617
+ op = 0;
618
+ }
619
+ if (op !== null) {if (op != 2)hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);
620
+ if (!hs.enableKeyListener) return true;
621
+
622
+ if (e.preventDefault) e.preventDefault();
623
+ else e.returnValue = false;
624
+ if (exp) {
625
+ if (op == 0) {
626
+ exp.close();
627
+ } else if (op == 2) {
628
+ if (exp.slideshow) exp.slideshow.hitSpace();
629
+ } else {
630
+ if (exp.slideshow) exp.slideshow.pause();
631
+ hs.previousOrNext(exp.key, op);
632
+ }
633
+ return false;
634
+ }
635
+ }
636
+ return true;
637
+ },
638
+
639
+
640
+ registerOverlay : function (overlay) {
641
+ hs.push(hs.overlays, hs.extend(overlay, { hsId: 'hsId'+ hs.idCounter++ } ));
642
+ },
643
+
644
+
645
+ addSlideshow : function (options) {
646
+ var sg = options.slideshowGroup;
647
+ if (typeof sg == 'object') {
648
+ for (var i = 0; i < sg.length; i++) {
649
+ var o = {};
650
+ for (var x in options) o[x] = options[x];
651
+ o.slideshowGroup = sg[i];
652
+ hs.push(hs.slideshows, o);
653
+ }
654
+ } else {
655
+ hs.push(hs.slideshows, options);
656
+ }
657
+ },
658
+
659
+ getWrapperKey : function (element, expOnly) {
660
+ var el, re = /^highslide-wrapper-([0-9]+)$/;
661
+ // 1. look in open expanders
662
+ el = element;
663
+ while (el.parentNode) {
664
+ if (el.hsKey !== undefined) return el.hsKey;
665
+ if (el.id && re.test(el.id)) return el.id.replace(re, "$1");
666
+ el = el.parentNode;
667
+ }
668
+ // 2. look in thumbnail
669
+ if (!expOnly) {
670
+ el = element;
671
+ while (el.parentNode) {
672
+ if (el.tagName && hs.isHsAnchor(el)) {
673
+ for (var key = 0; key < hs.expanders.length; key++) {
674
+ var exp = hs.expanders[key];
675
+ if (exp && exp.a == el) return key;
676
+ }
677
+ }
678
+ el = el.parentNode;
679
+ }
680
+ }
681
+ return null;
682
+ },
683
+
684
+ getExpander : function (el, expOnly) {
685
+ if (typeof el == 'undefined') return hs.expanders[hs.focusKey] || null;
686
+ if (typeof el == 'number') return hs.expanders[el] || null;
687
+ if (typeof el == 'string') el = hs.$(el);
688
+ return hs.expanders[hs.getWrapperKey(el, expOnly)] || null;
689
+ },
690
+
691
+ isHsAnchor : function (a) {
692
+ return (a.onclick && a.onclick.toString().replace(/\s/g, ' ').match(/hs.(htmlE|e)xpand/));
693
+ },
694
+
695
+ reOrder : function () {
696
+ for (var i = 0; i < hs.expanders.length; i++)
697
+ if (hs.expanders[i] && hs.expanders[i].isExpanded) hs.focusTopmost();
698
+ },
699
+ fireEvent : function (obj, evt, args) {
700
+ return obj && obj[evt] ? (obj[evt](obj, args) !== false) : true;
701
+ },
702
+
703
+ mouseClickHandler : function(e)
704
+ {
705
+ if (!e) e = window.event;
706
+ if (e.button > 1) return true;
707
+ if (!e.target) e.target = e.srcElement;
708
+
709
+ var el = e.target;
710
+ while (el.parentNode
711
+ && !(/highslide-(image|move|html|resize)/.test(el.className)))
712
+ {
713
+ el = el.parentNode;
714
+ }
715
+ var exp = hs.getExpander(el);
716
+ if (exp && (exp.isClosing || !exp.isExpanded)) return true;
717
+
718
+ if (exp && e.type == 'mousedown') {
719
+ if (e.target.form) return true;
720
+ var match = el.className.match(/highslide-(image|move|resize)/);
721
+ if (match) {
722
+ hs.dragArgs = {
723
+ exp: exp ,
724
+ type: match[1],
725
+ left: exp.x.pos,
726
+ width: exp.x.size,
727
+ top: exp.y.pos,
728
+ height: exp.y.size,
729
+ clickX: e.clientX,
730
+ clickY: e.clientY
731
+ };
732
+
733
+
734
+ hs.addEventListener(document, 'mousemove', hs.dragHandler);
735
+ if (e.preventDefault) e.preventDefault(); // FF
736
+
737
+ if (/highslide-(image|html)-blur/.test(exp.content.className)) {
738
+ exp.focus();
739
+ hs.hasFocused = true;
740
+ }
741
+ return false;
742
+ }
743
+ else if (/highslide-html/.test(el.className) && hs.focusKey != exp.key) {
744
+ exp.focus();
745
+ exp.doShowHide('hidden');
746
+ }
747
+ } else if (e.type == 'mouseup') {
748
+
749
+ hs.removeEventListener(document, 'mousemove', hs.dragHandler);
750
+
751
+ if (hs.dragArgs) {
752
+ if (hs.styleRestoreCursor && hs.dragArgs.type == 'image')
753
+ hs.dragArgs.exp.content.style.cursor = hs.styleRestoreCursor;
754
+ var hasDragged = hs.dragArgs.hasDragged;
755
+
756
+ if (!hasDragged &&!hs.hasFocused && !/(move|resize)/.test(hs.dragArgs.type)) {
757
+ if (hs.fireEvent(exp, 'onImageClick'))
758
+ exp.close();
759
+ }
760
+ else if (hasDragged || (!hasDragged && hs.hasHtmlExpanders)) {
761
+ hs.dragArgs.exp.doShowHide('hidden');
762
+ }
763
+
764
+ if (hs.dragArgs.exp.releaseMask)
765
+ hs.dragArgs.exp.releaseMask.style.display = 'none';
766
+
767
+ if (hasDragged) hs.fireEvent(hs.dragArgs.exp, 'onDrop', hs.dragArgs);
768
+ hs.hasFocused = false;
769
+ hs.dragArgs = null;
770
+
771
+ } else if (/highslide-image-blur/.test(el.className)) {
772
+ el.style.cursor = hs.styleRestoreCursor;
773
+ }
774
+ }
775
+ return false;
776
+ },
777
+
778
+ dragHandler : function(e)
779
+ {
780
+ if (!hs.dragArgs) return true;
781
+ if (!e) e = window.event;
782
+ var a = hs.dragArgs, exp = a.exp;
783
+ if (exp.iframe) {
784
+ if (!exp.releaseMask) exp.releaseMask = hs.createElement('div', null,
785
+ { position: 'absolute', width: exp.x.size+'px', height: exp.y.size+'px',
786
+ left: exp.x.cb+'px', top: exp.y.cb+'px', zIndex: 4, background: (hs.ieLt9 ? 'white' : 'none'),
787
+ opacity: 0.01 },
788
+ exp.wrapper, true);
789
+ if (exp.releaseMask.style.display == 'none')
790
+ exp.releaseMask.style.display = '';
791
+ }
792
+
793
+ a.dX = e.clientX - a.clickX;
794
+ a.dY = e.clientY - a.clickY;
795
+
796
+ var distance = Math.sqrt(Math.pow(a.dX, 2) + Math.pow(a.dY, 2));
797
+ if (!a.hasDragged) a.hasDragged = (a.type != 'image' && distance > 0)
798
+ || (distance > (hs.dragSensitivity || 5));
799
+
800
+ if (a.hasDragged && e.clientX > 5 && e.clientY > 5) {
801
+ if (!hs.fireEvent(exp, 'onDrag', a)) return false;
802
+
803
+ if (a.type == 'resize') exp.resize(a);
804
+ else {
805
+ exp.moveTo(a.left + a.dX, a.top + a.dY);
806
+ if (a.type == 'image') exp.content.style.cursor = 'move';
807
+ }
808
+ }
809
+ return false;
810
+ },
811
+
812
+ wrapperMouseHandler : function (e) {
813
+ try {
814
+ if (!e) e = window.event;
815
+ var over = /mouseover/i.test(e.type);
816
+ if (!e.target) e.target = e.srcElement; // ie
817
+ if (!e.relatedTarget) e.relatedTarget =
818
+ over ? e.fromElement : e.toElement; // ie
819
+ var exp = hs.getExpander(e.target);
820
+ if (!exp.isExpanded) return;
821
+ if (!exp || !e.relatedTarget || hs.getExpander(e.relatedTarget, true) == exp
822
+ || hs.dragArgs) return;
823
+ hs.fireEvent(exp, over ? 'onMouseOver' : 'onMouseOut', e);
824
+ for (var i = 0; i < exp.overlays.length; i++) (function() {
825
+ var o = hs.$('hsId'+ exp.overlays[i]);
826
+ if (o && o.hideOnMouseOut) {
827
+ if (over) hs.setStyles(o, { visibility: 'visible', display: '' });
828
+ hs.animate(o, { opacity: over ? o.opacity : 0 }, o.dur);
829
+ }
830
+ })();
831
+ } catch (e) {}
832
+ },
833
+ addEventListener : function (el, event, func) {
834
+ if (el == document && event == 'ready') {
835
+ hs.push(hs.onReady, func);
836
+ }
837
+ try {
838
+ el.addEventListener(event, func, false);
839
+ } catch (e) {
840
+ try {
841
+ el.detachEvent('on'+ event, func);
842
+ el.attachEvent('on'+ event, func);
843
+ } catch (e) {
844
+ el['on'+ event] = func;
845
+ }
846
+ }
847
+ },
848
+
849
+ removeEventListener : function (el, event, func) {
850
+ try {
851
+ el.removeEventListener(event, func, false);
852
+ } catch (e) {
853
+ try {
854
+ el.detachEvent('on'+ event, func);
855
+ } catch (e) {
856
+ el['on'+ event] = null;
857
+ }
858
+ }
859
+ },
860
+
861
+ preloadFullImage : function (i) {
862
+ if (hs.continuePreloading && hs.preloadTheseImages[i] && hs.preloadTheseImages[i] != 'undefined') {
863
+ var img = document.createElement('img');
864
+ img.onload = function() {
865
+ img = null;
866
+ hs.preloadFullImage(i + 1);
867
+ };
868
+ img.src = hs.preloadTheseImages[i];
869
+ }
870
+ },
871
+ preloadImages : function (number) {
872
+ if (number && typeof number != 'object') hs.numberOfImagesToPreload = number;
873
+
874
+ var arr = hs.getAnchors();
875
+ for (var i = 0; i < arr.images.length && i < hs.numberOfImagesToPreload; i++) {
876
+ hs.push(hs.preloadTheseImages, hs.getSrc(arr.images[i]));
877
+ }
878
+
879
+ // preload outlines
880
+ if (hs.outlineType) new hs.Outline(hs.outlineType, function () { hs.preloadFullImage(0)} );
881
+ else
882
+
883
+ hs.preloadFullImage(0);
884
+
885
+ // preload cursor
886
+ if (hs.restoreCursor) var cur = hs.createElement('img', { src: hs.graphicsDir + hs.restoreCursor });
887
+ },
888
+
889
+
890
+ init : function () {
891
+ if (!hs.container) {
892
+
893
+ hs.ieLt7 = hs.ie && hs.uaVersion < 7;
894
+ hs.ieLt9 = hs.ie && hs.uaVersion < 9;
895
+
896
+ hs.getPageSize();
897
+ hs.ie6SSL = hs.ieLt7 && location.protocol == 'https:';
898
+ for (var x in hs.langDefaults) {
899
+ if (typeof hs[x] != 'undefined') hs.lang[x] = hs[x];
900
+ else if (typeof hs.lang[x] == 'undefined' && typeof hs.langDefaults[x] != 'undefined')
901
+ hs.lang[x] = hs.langDefaults[x];
902
+ }
903
+
904
+ hs.container = hs.createElement('div', {
905
+ className: 'highslide-container'
906
+ }, {
907
+ position: 'absolute',
908
+ left: 0,
909
+ top: 0,
910
+ width: '100%',
911
+ zIndex: hs.zIndexCounter,
912
+ direction: 'ltr'
913
+ },
914
+ document.body,
915
+ true
916
+ );
917
+ hs.loading = hs.createElement('a', {
918
+ className: 'highslide-loading',
919
+ title: hs.lang.loadingTitle,
920
+ innerHTML: hs.lang.loadingText,
921
+ href: 'javascript:;'
922
+ }, {
923
+ position: 'absolute',
924
+ top: '-9999px',
925
+ opacity: hs.loadingOpacity,
926
+ zIndex: 1
927
+ }, hs.container
928
+ );
929
+ hs.garbageBin = hs.createElement('div', null, { display: 'none' }, hs.container);
930
+ hs.viewport = hs.createElement('div', {
931
+ className: 'highslide-viewport highslide-viewport-size'
932
+ }, {
933
+ visibility: (hs.safari && hs.uaVersion < 525) ? 'visible' : 'hidden'
934
+ }, hs.container, 1
935
+ );
936
+ hs.clearing = hs.createElement('div', null,
937
+ { clear: 'both', paddingTop: '1px' }, null, true);
938
+
939
+ // http://www.robertpenner.com/easing/
940
+ Math.linearTween = function (t, b, c, d) {
941
+ return c*t/d + b;
942
+ };
943
+ Math.easeInQuad = function (t, b, c, d) {
944
+ return c*(t/=d)*t + b;
945
+ };
946
+ Math.easeOutQuad = function (t, b, c, d) {
947
+ return -c *(t/=d)*(t-2) + b;
948
+ };
949
+
950
+ hs.hideSelects = hs.ieLt7;
951
+ hs.hideIframes = ((window.opera && hs.uaVersion < 9) || navigator.vendor == 'KDE'
952
+ || (hs.ieLt7 && hs.uaVersion < 5.5));
953
+ hs.fireEvent(this, 'onActivate');
954
+ }
955
+ },
956
+ ready : function() {
957
+ if (hs.isReady) return;
958
+ hs.isReady = true;
959
+ for (var i = 0; i < hs.onReady.length; i++) hs.onReady[i]();
960
+ },
961
+
962
+ updateAnchors : function() {
963
+ var el, els, all = [], images = [], htmls = [],groups = {}, re;
964
+
965
+ for (var i = 0; i < hs.openerTagNames.length; i++) {
966
+ els = document.getElementsByTagName(hs.openerTagNames[i]);
967
+ for (var j = 0; j < els.length; j++) {
968
+ el = els[j];
969
+ re = hs.isHsAnchor(el);
970
+ if (re) {
971
+ hs.push(all, el);
972
+ if (re[0] == 'hs.expand') hs.push(images, el);
973
+ else if (re[0] == 'hs.htmlExpand') hs.push(htmls, el);
974
+ var g = hs.getParam(el, 'slideshowGroup') || 'none';
975
+ if (!groups[g]) groups[g] = [];
976
+ hs.push(groups[g], el);
977
+ }
978
+ }
979
+ }
980
+ hs.anchors = { all: all, groups: groups, images: images, htmls: htmls };
981
+ return hs.anchors;
982
+
983
+ },
984
+
985
+ getAnchors : function() {
986
+ return hs.anchors || hs.updateAnchors();
987
+ },
988
+
989
+
990
+ close : function(el) {
991
+ var exp = hs.getExpander(el);
992
+ if (exp) exp.close();
993
+ return false;
994
+ }
995
+ }; // end hs object
996
+ hs.fx = function( elem, options, prop ){
997
+ this.options = options;
998
+ this.elem = elem;
999
+ this.prop = prop;
1000
+
1001
+ if (!options.orig) options.orig = {};
1002
+ };
1003
+ hs.fx.prototype = {
1004
+ update: function(){
1005
+ (hs.fx.step[this.prop] || hs.fx.step._default)(this);
1006
+
1007
+ if (this.options.step)
1008
+ this.options.step.call(this.elem, this.now, this);
1009
+
1010
+ },
1011
+ custom: function(from, to, unit){
1012
+ this.startTime = (new Date()).getTime();
1013
+ this.start = from;
1014
+ this.end = to;
1015
+ this.unit = unit;// || this.unit || "px";
1016
+ this.now = this.start;
1017
+ this.pos = this.state = 0;
1018
+
1019
+ var self = this;
1020
+ function t(gotoEnd){
1021
+ return self.step(gotoEnd);
1022
+ }
1023
+
1024
+ t.elem = this.elem;
1025
+
1026
+ if ( t() && hs.timers.push(t) == 1 ) {
1027
+ hs.timerId = setInterval(function(){
1028
+ var timers = hs.timers;
1029
+
1030
+ for ( var i = 0; i < timers.length; i++ )
1031
+ if ( !timers[i]() )
1032
+ timers.splice(i--, 1);
1033
+
1034
+ if ( !timers.length ) {
1035
+ clearInterval(hs.timerId);
1036
+ }
1037
+ }, 13);
1038
+ }
1039
+ },
1040
+ step: function(gotoEnd){
1041
+ var t = (new Date()).getTime();
1042
+ if ( gotoEnd || t >= this.options.duration + this.startTime ) {
1043
+ this.now = this.end;
1044
+ this.pos = this.state = 1;
1045
+ this.update();
1046
+
1047
+ this.options.curAnim[ this.prop ] = true;
1048
+
1049
+ var done = true;
1050
+ for ( var i in this.options.curAnim )
1051
+ if ( this.options.curAnim[i] !== true )
1052
+ done = false;
1053
+
1054
+ if ( done ) {
1055
+ if (this.options.complete) this.options.complete.call(this.elem);
1056
+ }
1057
+ return false;
1058
+ } else {
1059
+ var n = t - this.startTime;
1060
+ this.state = n / this.options.duration;
1061
+ this.pos = this.options.easing(n, 0, 1, this.options.duration);
1062
+ this.now = this.start + ((this.end - this.start) * this.pos);
1063
+ this.update();
1064
+ }
1065
+ return true;
1066
+ }
1067
+
1068
+ };
1069
+
1070
+ hs.extend( hs.fx, {
1071
+ step: {
1072
+
1073
+ opacity: function(fx){
1074
+ hs.setStyles(fx.elem, { opacity: fx.now });
1075
+ },
1076
+
1077
+ _default: function(fx){
1078
+ try {
1079
+ if ( fx.elem.style && fx.elem.style[ fx.prop ] != null )
1080
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
1081
+ else
1082
+ fx.elem[ fx.prop ] = fx.now;
1083
+ } catch (e) {}
1084
+ }
1085
+ }
1086
+ });
1087
+
1088
+ hs.Outline = function (outlineType, onLoad) {
1089
+ this.onLoad = onLoad;
1090
+ this.outlineType = outlineType;
1091
+ var v = hs.uaVersion, tr;
1092
+
1093
+ this.hasAlphaImageLoader = hs.ie && hs.uaVersion < 7;
1094
+ if (!outlineType) {
1095
+ if (onLoad) onLoad();
1096
+ return;
1097
+ }
1098
+
1099
+ hs.init();
1100
+ this.table = hs.createElement(
1101
+ 'table', {
1102
+ cellSpacing: 0
1103
+ }, {
1104
+ visibility: 'hidden',
1105
+ position: 'absolute',
1106
+ borderCollapse: 'collapse',
1107
+ width: 0
1108
+ },
1109
+ hs.container,
1110
+ true
1111
+ );
1112
+ var tbody = hs.createElement('tbody', null, null, this.table, 1);
1113
+
1114
+ this.td = [];
1115
+ for (var i = 0; i <= 8; i++) {
1116
+ if (i % 3 == 0) tr = hs.createElement('tr', null, { height: 'auto' }, tbody, true);
1117
+ this.td[i] = hs.createElement('td', null, null, tr, true);
1118
+ var style = i != 4 ? { lineHeight: 0, fontSize: 0} : { position : 'relative' };
1119
+ hs.setStyles(this.td[i], style);
1120
+ }
1121
+ this.td[4].className = outlineType +' highslide-outline';
1122
+
1123
+ this.preloadGraphic();
1124
+ };
1125
+
1126
+ hs.Outline.prototype = {
1127
+ preloadGraphic : function () {
1128
+ var src = hs.graphicsDir + (hs.outlinesDir || "outlines/")+ this.outlineType +".png";
1129
+
1130
+ var appendTo = hs.safari && hs.uaVersion < 525 ? hs.container : null;
1131
+ this.graphic = hs.createElement('img', null, { position: 'absolute',
1132
+ top: '-9999px' }, appendTo, true); // for onload trigger
1133
+
1134
+ var pThis = this;
1135
+ this.graphic.onload = function() { pThis.onGraphicLoad(); };
1136
+
1137
+ this.graphic.src = src;
1138
+ },
1139
+
1140
+ onGraphicLoad : function () {
1141
+ var o = this.offset = this.graphic.width / 4,
1142
+ pos = [[0,0],[0,-4],[-2,0],[0,-8],0,[-2,-8],[0,-2],[0,-6],[-2,-2]],
1143
+ dim = { height: (2*o) +'px', width: (2*o) +'px' };
1144
+ for (var i = 0; i <= 8; i++) {
1145
+ if (pos[i]) {
1146
+ if (this.hasAlphaImageLoader) {
1147
+ var w = (i == 1 || i == 7) ? '100%' : this.graphic.width +'px';
1148
+ var div = hs.createElement('div', null, { width: '100%', height: '100%', position: 'relative', overflow: 'hidden'}, this.td[i], true);
1149
+ hs.createElement ('div', null, {
1150
+ filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale, src='"+ this.graphic.src + "')",
1151
+ position: 'absolute',
1152
+ width: w,
1153
+ height: this.graphic.height +'px',
1154
+ left: (pos[i][0]*o)+'px',
1155
+ top: (pos[i][1]*o)+'px'
1156
+ },
1157
+ div,
1158
+ true);
1159
+ } else {
1160
+ hs.setStyles(this.td[i], { background: 'url('+ this.graphic.src +') '+ (pos[i][0]*o)+'px '+(pos[i][1]*o)+'px'});
1161
+ }
1162
+
1163
+ if (window.opera && (i == 3 || i ==5))
1164
+ hs.createElement('div', null, dim, this.td[i], true);
1165
+
1166
+ hs.setStyles (this.td[i], dim);
1167
+ }
1168
+ }
1169
+ this.graphic = null;
1170
+ if (hs.pendingOutlines[this.outlineType]) hs.pendingOutlines[this.outlineType].destroy();
1171
+ hs.pendingOutlines[this.outlineType] = this;
1172
+ if (this.onLoad) this.onLoad();
1173
+ },
1174
+
1175
+ setPosition : function (pos, offset, vis, dur, easing) {
1176
+ var exp = this.exp,
1177
+ stl = exp.wrapper.style,
1178
+ offset = offset || 0,
1179
+ pos = pos || {
1180
+ x: exp.x.pos + offset,
1181
+ y: exp.y.pos + offset,
1182
+ w: exp.x.get('wsize') - 2 * offset,
1183
+ h: exp.y.get('wsize') - 2 * offset
1184
+ };
1185
+ if (vis) this.table.style.visibility = (pos.h >= 4 * this.offset)
1186
+ ? 'visible' : 'hidden';
1187
+ hs.setStyles(this.table, {
1188
+ left: (pos.x - this.offset) +'px',
1189
+ top: (pos.y - this.offset) +'px',
1190
+ width: (pos.w + 2 * this.offset) +'px'
1191
+ });
1192
+
1193
+ pos.w -= 2 * this.offset;
1194
+ pos.h -= 2 * this.offset;
1195
+ hs.setStyles (this.td[4], {
1196
+ width: pos.w >= 0 ? pos.w +'px' : 0,
1197
+ height: pos.h >= 0 ? pos.h +'px' : 0
1198
+ });
1199
+ if (this.hasAlphaImageLoader) this.td[3].style.height
1200
+ = this.td[5].style.height = this.td[4].style.height;
1201
+
1202
+ },
1203
+
1204
+ destroy : function(hide) {
1205
+ if (hide) this.table.style.visibility = 'hidden';
1206
+ else hs.discardElement(this.table);
1207
+ }
1208
+ };
1209
+
1210
+ hs.Dimension = function(exp, dim) {
1211
+ this.exp = exp;
1212
+ this.dim = dim;
1213
+ this.ucwh = dim == 'x' ? 'Width' : 'Height';
1214
+ this.wh = this.ucwh.toLowerCase();
1215
+ this.uclt = dim == 'x' ? 'Left' : 'Top';
1216
+ this.lt = this.uclt.toLowerCase();
1217
+ this.ucrb = dim == 'x' ? 'Right' : 'Bottom';
1218
+ this.rb = this.ucrb.toLowerCase();
1219
+ this.p1 = this.p2 = 0;
1220
+ };
1221
+ hs.Dimension.prototype = {
1222
+ get : function(key) {
1223
+ switch (key) {
1224
+ case 'loadingPos':
1225
+ return this.tpos + this.tb + (this.t - hs.loading['offset'+ this.ucwh]) / 2;
1226
+ case 'loadingPosXfade':
1227
+ return this.pos + this.cb+ this.p1 + (this.size - hs.loading['offset'+ this.ucwh]) / 2;
1228
+ case 'wsize':
1229
+ return this.size + 2 * this.cb + this.p1 + this.p2;
1230
+ case 'fitsize':
1231
+ return this.clientSize - this.marginMin - this.marginMax;
1232
+ case 'maxsize':
1233
+ return this.get('fitsize') - 2 * this.cb - this.p1 - this.p2 ;
1234
+ case 'opos':
1235
+ return this.pos - (this.exp.outline ? this.exp.outline.offset : 0);
1236
+ case 'osize':
1237
+ return this.get('wsize') + (this.exp.outline ? 2*this.exp.outline.offset : 0);
1238
+ case 'imgPad':
1239
+ return this.imgSize ? Math.round((this.size - this.imgSize) / 2) : 0;
1240
+
1241
+ }
1242
+ },
1243
+ calcBorders: function() {
1244
+ // correct for borders
1245
+ this.cb = (this.exp.content['offset'+ this.ucwh] - this.t) / 2;
1246
+
1247
+ this.marginMax = hs['margin'+ this.ucrb];
1248
+ },
1249
+ calcThumb: function() {
1250
+ this.t = this.exp.el[this.wh] ? parseInt(this.exp.el[this.wh]) :
1251
+ this.exp.el['offset'+ this.ucwh];
1252
+ this.tpos = this.exp.tpos[this.dim];
1253
+ this.tb = (this.exp.el['offset'+ this.ucwh] - this.t) / 2;
1254
+ if (this.tpos == 0 || this.tpos == -1) {
1255
+ this.tpos = (hs.page[this.wh] / 2) + hs.page['scroll'+ this.uclt];
1256
+ };
1257
+ },
1258
+ calcExpanded: function() {
1259
+ var exp = this.exp;
1260
+ this.justify = 'auto';
1261
+
1262
+ // get alignment
1263
+ if (exp.align == 'center') this.justify = 'center';
1264
+ else if (new RegExp(this.lt).test(exp.anchor)) this.justify = null;
1265
+ else if (new RegExp(this.rb).test(exp.anchor)) this.justify = 'max';
1266
+
1267
+
1268
+ // size and position
1269
+ this.pos = this.tpos - this.cb + this.tb;
1270
+
1271
+ if (this.maxHeight && this.dim == 'x')
1272
+ exp.maxWidth = Math.min(exp.maxWidth || this.full, exp.maxHeight * this.full / exp.y.full);
1273
+
1274
+ this.size = Math.min(this.full, exp['max'+ this.ucwh] || this.full);
1275
+ this.minSize = exp.allowSizeReduction ?
1276
+ Math.min(exp['min'+ this.ucwh], this.full) :this.full;
1277
+ if (exp.isImage && exp.useBox) {
1278
+ this.size = exp[this.wh];
1279
+ this.imgSize = this.full;
1280
+ }
1281
+ if (this.dim == 'x' && hs.padToMinWidth) this.minSize = exp.minWidth;
1282
+ this.target = exp['target'+ this.dim.toUpperCase()];
1283
+ this.marginMin = hs['margin'+ this.uclt];
1284
+ this.scroll = hs.page['scroll'+ this.uclt];
1285
+ this.clientSize = hs.page[this.wh];
1286
+ },
1287
+ setSize: function(i) {
1288
+ var exp = this.exp;
1289
+ if (exp.isImage && (exp.useBox || hs.padToMinWidth)) {
1290
+ this.imgSize = i;
1291
+ this.size = Math.max(this.size, this.imgSize);
1292
+ exp.content.style[this.lt] = this.get('imgPad')+'px';
1293
+ } else
1294
+ this.size = i;
1295
+
1296
+ exp.content.style[this.wh] = i +'px';
1297
+ exp.wrapper.style[this.wh] = this.get('wsize') +'px';
1298
+ if (exp.outline) exp.outline.setPosition();
1299
+ if (exp.releaseMask) exp.releaseMask.style[this.wh] = i +'px';
1300
+ if (this.dim == 'y' && exp.iDoc && exp.body.style.height != 'auto') try {
1301
+ exp.iDoc.body.style.overflow = 'auto';
1302
+ } catch (e) {}
1303
+ if (exp.isHtml) {
1304
+ var d = exp.scrollerDiv;
1305
+ if (this.sizeDiff === undefined)
1306
+ this.sizeDiff = exp.innerContent['offset'+ this.ucwh] - d['offset'+ this.ucwh];
1307
+ d.style[this.wh] = (this.size - this.sizeDiff) +'px';
1308
+
1309
+ if (this.dim == 'x') exp.mediumContent.style.width = 'auto';
1310
+ if (exp.body) exp.body.style[this.wh] = 'auto';
1311
+ }
1312
+ if (this.dim == 'x' && exp.overlayBox) exp.sizeOverlayBox(true);
1313
+ if (this.dim == 'x' && exp.slideshow && exp.isImage) {
1314
+ if (i == this.full) exp.slideshow.disable('full-expand');
1315
+ else exp.slideshow.enable('full-expand');
1316
+ }
1317
+ },
1318
+ setPos: function(i) {
1319
+ this.pos = i;
1320
+ this.exp.wrapper.style[this.lt] = i +'px';
1321
+
1322
+ if (this.exp.outline) this.exp.outline.setPosition();
1323
+
1324
+ }
1325
+ };
1326
+
1327
+ hs.Expander = function(a, params, custom, contentType) {
1328
+ if (document.readyState && hs.ie && !hs.isReady) {
1329
+ hs.addEventListener(document, 'ready', function() {
1330
+ new hs.Expander(a, params, custom, contentType);
1331
+ });
1332
+ return;
1333
+ }
1334
+ this.a = a;
1335
+ this.custom = custom;
1336
+ this.contentType = contentType || 'image';
1337
+ this.isHtml = (contentType == 'html');
1338
+ this.isImage = !this.isHtml;
1339
+
1340
+ hs.continuePreloading = false;
1341
+ this.overlays = [];
1342
+ this.last = hs.last;
1343
+ hs.last = null;
1344
+ hs.init();
1345
+ var key = this.key = hs.expanders.length;
1346
+ // override inline parameters
1347
+ for (var i = 0; i < hs.overrides.length; i++) {
1348
+ var name = hs.overrides[i];
1349
+ this[name] = params && typeof params[name] != 'undefined' ?
1350
+ params[name] : hs[name];
1351
+ }
1352
+ if (!this.src) this.src = a.href;
1353
+
1354
+ // get thumb
1355
+ var el = (params && params.thumbnailId) ? hs.$(params.thumbnailId) : a;
1356
+ el = this.thumb = el.getElementsByTagName('img')[0] || el;
1357
+ this.thumbsUserSetId = el.id || a.id;
1358
+ if (!hs.fireEvent(this, 'onInit')) return true;
1359
+
1360
+ // check if already open
1361
+ for (var i = 0; i < hs.expanders.length; i++) {
1362
+ if (hs.expanders[i] && hs.expanders[i].a == a
1363
+ && !(this.last && this.transitions[1] == 'crossfade')) {
1364
+ hs.expanders[i].focus();
1365
+ return false;
1366
+ }
1367
+ }
1368
+
1369
+ // cancel other
1370
+ if (!hs.allowSimultaneousLoading) for (var i = 0; i < hs.expanders.length; i++) {
1371
+ if (hs.expanders[i] && hs.expanders[i].thumb != el && !hs.expanders[i].onLoadStarted) {
1372
+ hs.expanders[i].cancelLoading();
1373
+ }
1374
+ }
1375
+ hs.expanders[key] = this;
1376
+ if (!hs.allowMultipleInstances && !hs.upcoming) {
1377
+ if (hs.expanders[key-1]) hs.expanders[key-1].close();
1378
+ if (typeof hs.focusKey != 'undefined' && hs.expanders[hs.focusKey])
1379
+ hs.expanders[hs.focusKey].close();
1380
+ }
1381
+
1382
+ // initiate metrics
1383
+ this.el = el;
1384
+ this.tpos = this.pageOrigin || hs.getPosition(el);
1385
+ hs.getPageSize();
1386
+ var x = this.x = new hs.Dimension(this, 'x');
1387
+ x.calcThumb();
1388
+ var y = this.y = new hs.Dimension(this, 'y');
1389
+ y.calcThumb();
1390
+ if (/area/i.test(el.tagName)) this.getImageMapAreaCorrection(el);
1391
+ this.wrapper = hs.createElement(
1392
+ 'div', {
1393
+ id: 'highslide-wrapper-'+ this.key,
1394
+ className: 'highslide-wrapper '+ this.wrapperClassName
1395
+ }, {
1396
+ visibility: 'hidden',
1397
+ position: 'absolute',
1398
+ zIndex: hs.zIndexCounter += 2
1399
+ }, null, true );
1400
+
1401
+ this.wrapper.onmouseover = this.wrapper.onmouseout = hs.wrapperMouseHandler;
1402
+ if (this.contentType == 'image' && this.outlineWhileAnimating == 2)
1403
+ this.outlineWhileAnimating = 0;
1404
+
1405
+ // get the outline
1406
+ if (!this.outlineType
1407
+ || (this.last && this.isImage && this.transitions[1] == 'crossfade')) {
1408
+ this[this.contentType +'Create']();
1409
+
1410
+ } else if (hs.pendingOutlines[this.outlineType]) {
1411
+ this.connectOutline();
1412
+ this[this.contentType +'Create']();
1413
+
1414
+ } else {
1415
+ this.showLoading();
1416
+ var exp = this;
1417
+ new hs.Outline(this.outlineType,
1418
+ function () {
1419
+ exp.connectOutline();
1420
+ exp[exp.contentType +'Create']();
1421
+ }
1422
+ );
1423
+ }
1424
+ return true;
1425
+ };
1426
+
1427
+ hs.Expander.prototype = {
1428
+ error : function(e) {
1429
+ if (hs.debug) alert ('Line '+ e.lineNumber +': '+ e.message);
1430
+ else window.location.href = this.src;
1431
+ },
1432
+
1433
+ connectOutline : function() {
1434
+ var outline = this.outline = hs.pendingOutlines[this.outlineType];
1435
+ outline.exp = this;
1436
+ outline.table.style.zIndex = this.wrapper.style.zIndex - 1;
1437
+ hs.pendingOutlines[this.outlineType] = null;
1438
+ },
1439
+
1440
+ showLoading : function() {
1441
+ if (this.onLoadStarted || this.loading) return;
1442
+
1443
+ this.loading = hs.loading;
1444
+ var exp = this;
1445
+ this.loading.onclick = function() {
1446
+ exp.cancelLoading();
1447
+ };
1448
+
1449
+
1450
+ if (!hs.fireEvent(this, 'onShowLoading')) return;
1451
+ var exp = this,
1452
+ l = this.x.get('loadingPos') +'px',
1453
+ t = this.y.get('loadingPos') +'px';
1454
+ if (!tgt && this.last && this.transitions[1] == 'crossfade')
1455
+ var tgt = this.last;
1456
+ if (tgt) {
1457
+ l = tgt.x.get('loadingPosXfade') +'px';
1458
+ t = tgt.y.get('loadingPosXfade') +'px';
1459
+ this.loading.style.zIndex = hs.zIndexCounter++;
1460
+ }
1461
+ setTimeout(function () {
1462
+ if (exp.loading) hs.setStyles(exp.loading, { left: l, top: t, zIndex: hs.zIndexCounter++ })}
1463
+ , 100);
1464
+ },
1465
+
1466
+ imageCreate : function() {
1467
+ var exp = this;
1468
+
1469
+ var img = document.createElement('img');
1470
+ this.content = img;
1471
+ img.onload = function () {
1472
+ if (hs.expanders[exp.key]) exp.contentLoaded();
1473
+ };
1474
+ if (hs.blockRightClick) img.oncontextmenu = function() { return false; };
1475
+ img.className = 'highslide-image';
1476
+ hs.setStyles(img, {
1477
+ visibility: 'hidden',
1478
+ display: 'block',
1479
+ position: 'absolute',
1480
+ maxWidth: '9999px',
1481
+ zIndex: 3
1482
+ });
1483
+ img.title = hs.lang.restoreTitle;
1484
+ if (hs.safari && hs.uaVersion < 525) hs.container.appendChild(img);
1485
+ if (hs.ie && hs.flushImgSize) img.src = null;
1486
+ img.src = this.src;
1487
+
1488
+ this.showLoading();
1489
+ },
1490
+
1491
+ htmlCreate : function () {
1492
+ if (!hs.fireEvent(this, 'onBeforeGetContent')) return;
1493
+
1494
+ this.content = hs.getCacheBinding(this.a);
1495
+ if (!this.content)
1496
+ this.content = hs.getNode(this.contentId);
1497
+ if (!this.content)
1498
+ this.content = hs.getSelfRendered();
1499
+ this.getInline(['maincontent']);
1500
+ if (this.maincontent) {
1501
+ var body = hs.getElementByClass(this.content, 'div', 'highslide-body');
1502
+ if (body) body.appendChild(this.maincontent);
1503
+ this.maincontent.style.display = 'block';
1504
+ }
1505
+ hs.fireEvent(this, 'onAfterGetContent');
1506
+
1507
+ var innerContent = this.innerContent = this.content;
1508
+
1509
+ if (/(swf|iframe)/.test(this.objectType)) this.setObjContainerSize(innerContent);
1510
+
1511
+ // the content tree
1512
+ hs.container.appendChild(this.wrapper);
1513
+ hs.setStyles( this.wrapper, {
1514
+ position: 'static',
1515
+ padding: '0 '+ hs.marginRight +'px 0 '+ hs.marginLeft +'px'
1516
+ });
1517
+ this.content = hs.createElement(
1518
+ 'div', {
1519
+ className: 'highslide-html'
1520
+ }, {
1521
+ position: 'relative',
1522
+ zIndex: 3,
1523
+ height: 0,
1524
+ overflow: 'hidden'
1525
+ },
1526
+ this.wrapper
1527
+ );
1528
+ this.mediumContent = hs.createElement('div', null, null, this.content, 1);
1529
+ this.mediumContent.appendChild(innerContent);
1530
+
1531
+ hs.setStyles (innerContent, {
1532
+ position: 'relative',
1533
+ display: 'block',
1534
+ direction: hs.lang.cssDirection || ''
1535
+ });
1536
+ if (this.width) innerContent.style.width = this.width +'px';
1537
+ if (this.height) hs.setStyles(innerContent, {
1538
+ height: this.height +'px',
1539
+ overflow: 'hidden'
1540
+ });
1541
+ if (innerContent.offsetWidth < this.minWidth)
1542
+ innerContent.style.width = this.minWidth +'px';
1543
+
1544
+
1545
+
1546
+ if (this.objectType == 'ajax' && !hs.getCacheBinding(this.a)) {
1547
+ this.showLoading();
1548
+ var exp = this;
1549
+ var ajax = new hs.Ajax(this.a, innerContent);
1550
+ ajax.src = this.src;
1551
+ ajax.onLoad = function () { if (hs.expanders[exp.key]) exp.contentLoaded(); };
1552
+ ajax.onError = function () { location.href = exp.src; };
1553
+ ajax.run();
1554
+ }
1555
+ else
1556
+
1557
+ if (this.objectType == 'iframe' && this.objectLoadTime == 'before') {
1558
+ this.writeExtendedContent();
1559
+ }
1560
+ else
1561
+ this.contentLoaded();
1562
+ },
1563
+
1564
+ contentLoaded : function() {
1565
+ try {
1566
+ if (!this.content) return;
1567
+ this.content.onload = null;
1568
+ if (this.onLoadStarted) return;
1569
+ else this.onLoadStarted = true;
1570
+
1571
+ var x = this.x, y = this.y;
1572
+
1573
+ if (this.loading) {
1574
+ hs.setStyles(this.loading, { top: '-9999px' });
1575
+ this.loading = null;
1576
+ hs.fireEvent(this, 'onHideLoading');
1577
+ }
1578
+ if (this.isImage) {
1579
+ x.full = this.content.width;
1580
+ y.full = this.content.height;
1581
+
1582
+ hs.setStyles(this.content, {
1583
+ width: x.t +'px',
1584
+ height: y.t +'px'
1585
+ });
1586
+ this.wrapper.appendChild(this.content);
1587
+ hs.container.appendChild(this.wrapper);
1588
+ } else if (this.htmlGetSize) this.htmlGetSize();
1589
+
1590
+ x.calcBorders();
1591
+ y.calcBorders();
1592
+
1593
+ hs.setStyles (this.wrapper, {
1594
+ left: (x.tpos + x.tb - x.cb) +'px',
1595
+ top: (y.tpos + x.tb - y.cb) +'px'
1596
+ });
1597
+
1598
+
1599
+ this.initSlideshow();
1600
+ this.getOverlays();
1601
+
1602
+ var ratio = x.full / y.full;
1603
+ x.calcExpanded();
1604
+ this.justify(x);
1605
+
1606
+ y.calcExpanded();
1607
+ this.justify(y);
1608
+ if (this.isHtml) this.htmlSizeOperations();
1609
+ if (this.overlayBox) this.sizeOverlayBox(0, 1);
1610
+
1611
+
1612
+ if (this.allowSizeReduction) {
1613
+ if (this.isImage)
1614
+ this.correctRatio(ratio);
1615
+ else this.fitOverlayBox();
1616
+ var ss = this.slideshow;
1617
+ if (ss && this.last && ss.controls && ss.fixedControls) {
1618
+ var pos = ss.overlayOptions.position || '', p;
1619
+ for (var dim in hs.oPos) for (var i = 0; i < 5; i++) {
1620
+ p = this[dim];
1621
+ if (pos.match(hs.oPos[dim][i])) {
1622
+ p.pos = this.last[dim].pos
1623
+ + (this.last[dim].p1 - p.p1)
1624
+ + (this.last[dim].size - p.size) * [0, 0, .5, 1, 1][i];
1625
+ if (ss.fixedControls == 'fit') {
1626
+ if (p.pos + p.size + p.p1 + p.p2 > p.scroll + p.clientSize - p.marginMax)
1627
+ p.pos = p.scroll + p.clientSize - p.size - p.marginMin - p.marginMax - p.p1 - p.p2;
1628
+ if (p.pos < p.scroll + p.marginMin) p.pos = p.scroll + p.marginMin;
1629
+ }
1630
+ }
1631
+ }
1632
+ }
1633
+ if (this.isImage && this.x.full > (this.x.imgSize || this.x.size)) {
1634
+ this.createFullExpand();
1635
+ if (this.overlays.length == 1) this.sizeOverlayBox();
1636
+ }
1637
+ }
1638
+ this.show();
1639
+
1640
+ } catch (e) {
1641
+ this.error(e);
1642
+ }
1643
+ },
1644
+
1645
+
1646
+ setObjContainerSize : function(parent, auto) {
1647
+ var c = hs.getElementByClass(parent, 'DIV', 'highslide-body');
1648
+ if (/(iframe|swf)/.test(this.objectType)) {
1649
+ if (this.objectWidth) c.style.width = this.objectWidth +'px';
1650
+ if (this.objectHeight) c.style.height = this.objectHeight +'px';
1651
+ }
1652
+ },
1653
+
1654
+ writeExtendedContent : function () {
1655
+ if (this.hasExtendedContent) return;
1656
+ var exp = this;
1657
+ this.body = hs.getElementByClass(this.innerContent, 'DIV', 'highslide-body');
1658
+ if (this.objectType == 'iframe') {
1659
+ this.showLoading();
1660
+ var ruler = hs.clearing.cloneNode(1);
1661
+ this.body.appendChild(ruler);
1662
+ this.newWidth = this.innerContent.offsetWidth;
1663
+ if (!this.objectWidth) this.objectWidth = ruler.offsetWidth;
1664
+ var hDiff = this.innerContent.offsetHeight - this.body.offsetHeight,
1665
+ h = this.objectHeight || hs.page.height - hDiff - hs.marginTop - hs.marginBottom,
1666
+ onload = this.objectLoadTime == 'before' ?
1667
+ ' onload="if (hs.expanders['+ this.key +']) hs.expanders['+ this.key +'].contentLoaded()" ' : '';
1668
+ this.body.innerHTML += '<iframe name="hs'+ (new Date()).getTime() +'" frameborder="0" key="'+ this.key +'" '
1669
+ +' style="width:'+ this.objectWidth +'px; height:'+ h +'px" '
1670
+ + onload +' src="'+ this.src +'" ></iframe>';
1671
+ this.ruler = this.body.getElementsByTagName('div')[0];
1672
+ this.iframe = this.body.getElementsByTagName('iframe')[0];
1673
+
1674
+ if (this.objectLoadTime == 'after') this.correctIframeSize();
1675
+
1676
+ }
1677
+ if (this.objectType == 'swf') {
1678
+ this.body.id = this.body.id || 'hs-flash-id-' + this.key;
1679
+ var a = this.swfOptions;
1680
+ if (!a.params) a.params = {};
1681
+ if (typeof a.params.wmode == 'undefined') a.params.wmode = 'transparent';
1682
+ if (swfobject) swfobject.embedSWF(this.src, this.body.id, this.objectWidth, this.objectHeight,
1683
+ a.version || '7', a.expressInstallSwfurl, a.flashvars, a.params, a.attributes);
1684
+ }
1685
+ this.hasExtendedContent = true;
1686
+ },
1687
+ htmlGetSize : function() {
1688
+ if (this.iframe && !this.objectHeight) { // loadtime before
1689
+ this.iframe.style.height = this.body.style.height = this.getIframePageHeight() +'px';
1690
+ }
1691
+ this.innerContent.appendChild(hs.clearing);
1692
+ if (!this.x.full) this.x.full = this.innerContent.offsetWidth;
1693
+ this.y.full = this.innerContent.offsetHeight;
1694
+ this.innerContent.removeChild(hs.clearing);
1695
+ if (hs.ie && this.newHeight > parseInt(this.innerContent.currentStyle.height)) { // ie css bug
1696
+ this.newHeight = parseInt(this.innerContent.currentStyle.height);
1697
+ }
1698
+ hs.setStyles( this.wrapper, { position: 'absolute', padding: '0'});
1699
+ hs.setStyles( this.content, { width: this.x.t +'px', height: this.y.t +'px'});
1700
+
1701
+ },
1702
+
1703
+ getIframePageHeight : function() {
1704
+ var h;
1705
+ try {
1706
+ var doc = this.iDoc = this.iframe.contentDocument || this.iframe.contentWindow.document;
1707
+ var clearing = doc.createElement('div');
1708
+ clearing.style.clear = 'both';
1709
+ doc.body.appendChild(clearing);
1710
+ h = clearing.offsetTop;
1711
+ if (hs.ie) h += parseInt(doc.body.currentStyle.marginTop)
1712
+ + parseInt(doc.body.currentStyle.marginBottom) - 1;
1713
+ } catch (e) { // other domain
1714
+ h = 300;
1715
+ }
1716
+ return h;
1717
+ },
1718
+ correctIframeSize : function () {
1719
+ var wDiff = this.innerContent.offsetWidth - this.ruler.offsetWidth;
1720
+ hs.discardElement(this.ruler);
1721
+ if (wDiff < 0) wDiff = 0;
1722
+
1723
+ var hDiff = this.innerContent.offsetHeight - this.iframe.offsetHeight;
1724
+ if (this.iDoc && !this.objectHeight && !this.height && this.y.size == this.y.full) try {
1725
+ this.iDoc.body.style.overflow = 'hidden';
1726
+ } catch (e) {}
1727
+ hs.setStyles(this.iframe, {
1728
+ width: Math.abs(this.x.size - wDiff) +'px',
1729
+ height: Math.abs(this.y.size - hDiff) +'px'
1730
+ });
1731
+ hs.setStyles(this.body, {
1732
+ width: this.iframe.style.width,
1733
+ height: this.iframe.style.height
1734
+ });
1735
+
1736
+ this.scrollingContent = this.iframe;
1737
+ this.scrollerDiv = this.scrollingContent;
1738
+
1739
+ },
1740
+ htmlSizeOperations : function () {
1741
+
1742
+ this.setObjContainerSize(this.innerContent);
1743
+
1744
+
1745
+ if (this.objectType == 'swf' && this.objectLoadTime == 'before') this.writeExtendedContent();
1746
+
1747
+ // handle minimum size
1748
+ if (this.x.size < this.x.full && !this.allowWidthReduction) this.x.size = this.x.full;
1749
+ if (this.y.size < this.y.full && !this.allowHeightReduction) this.y.size = this.y.full;
1750
+ this.scrollerDiv = this.innerContent;
1751
+ hs.setStyles(this.mediumContent, {
1752
+ position: 'relative',
1753
+ width: this.x.size +'px'
1754
+ });
1755
+ hs.setStyles(this.innerContent, {
1756
+ border: 'none',
1757
+ width: 'auto',
1758
+ height: 'auto'
1759
+ });
1760
+ var node = hs.getElementByClass(this.innerContent, 'DIV', 'highslide-body');
1761
+ if (node && !/(iframe|swf)/.test(this.objectType)) {
1762
+ var cNode = node; // wrap to get true size
1763
+ node = hs.createElement(cNode.nodeName, null, {overflow: 'hidden'}, null, true);
1764
+ cNode.parentNode.insertBefore(node, cNode);
1765
+ node.appendChild(hs.clearing); // IE6
1766
+ node.appendChild(cNode);
1767
+
1768
+ var wDiff = this.innerContent.offsetWidth - node.offsetWidth;
1769
+ var hDiff = this.innerContent.offsetHeight - node.offsetHeight;
1770
+ node.removeChild(hs.clearing);
1771
+
1772
+ var kdeBugCorr = hs.safari || navigator.vendor == 'KDE' ? 1 : 0; // KDE repainting bug
1773
+ hs.setStyles(node, {
1774
+ width: (this.x.size - wDiff - kdeBugCorr) +'px',
1775
+ height: (this.y.size - hDiff) +'px',
1776
+ overflow: 'auto',
1777
+ position: 'relative'
1778
+ }
1779
+ );
1780
+ if (kdeBugCorr && cNode.offsetHeight > node.offsetHeight) {
1781
+ node.style.width = (parseInt(node.style.width) + kdeBugCorr) + 'px';
1782
+ }
1783
+ this.scrollingContent = node;
1784
+ this.scrollerDiv = this.scrollingContent;
1785
+ }
1786
+ if (this.iframe && this.objectLoadTime == 'before') this.correctIframeSize();
1787
+ if (!this.scrollingContent && this.y.size < this.mediumContent.offsetHeight) this.scrollerDiv = this.content;
1788
+
1789
+ if (this.scrollerDiv == this.content && !this.allowWidthReduction && !/(iframe|swf)/.test(this.objectType)) {
1790
+ this.x.size += 17; // room for scrollbars
1791
+ }
1792
+ if (this.scrollerDiv && this.scrollerDiv.offsetHeight > this.scrollerDiv.parentNode.offsetHeight) {
1793
+ setTimeout("try { hs.expanders["+ this.key +"].scrollerDiv.style.overflow = 'auto'; } catch(e) {}",
1794
+ hs.expandDuration);
1795
+ }
1796
+ },
1797
+
1798
+ getImageMapAreaCorrection : function(area) {
1799
+ var c = area.coords.split(',');
1800
+ for (var i = 0; i < c.length; i++) c[i] = parseInt(c[i]);
1801
+
1802
+ if (area.shape.toLowerCase() == 'circle') {
1803
+ this.x.tpos += c[0] - c[2];
1804
+ this.y.tpos += c[1] - c[2];
1805
+ this.x.t = this.y.t = 2 * c[2];
1806
+ } else {
1807
+ var maxX, maxY, minX = maxX = c[0], minY = maxY = c[1];
1808
+ for (var i = 0; i < c.length; i++) {
1809
+ if (i % 2 == 0) {
1810
+ minX = Math.min(minX, c[i]);
1811
+ maxX = Math.max(maxX, c[i]);
1812
+ } else {
1813
+ minY = Math.min(minY, c[i]);
1814
+ maxY = Math.max(maxY, c[i]);
1815
+ }
1816
+ }
1817
+ this.x.tpos += minX;
1818
+ this.x.t = maxX - minX;
1819
+ this.y.tpos += minY;
1820
+ this.y.t = maxY - minY;
1821
+ }
1822
+ },
1823
+ justify : function (p, moveOnly) {
1824
+ var tgtArr, tgt = p.target, dim = p == this.x ? 'x' : 'y';
1825
+
1826
+ if (tgt && tgt.match(/ /)) {
1827
+ tgtArr = tgt.split(' ');
1828
+ tgt = tgtArr[0];
1829
+ }
1830
+ if (tgt && hs.$(tgt)) {
1831
+ p.pos = hs.getPosition(hs.$(tgt))[dim];
1832
+ if (tgtArr && tgtArr[1] && tgtArr[1].match(/^[-]?[0-9]+px$/))
1833
+ p.pos += parseInt(tgtArr[1]);
1834
+ if (p.size < p.minSize) p.size = p.minSize;
1835
+
1836
+ } else if (p.justify == 'auto' || p.justify == 'center') {
1837
+
1838
+ var hasMovedMin = false;
1839
+
1840
+ var allowReduce = p.exp.allowSizeReduction;
1841
+ if (p.justify == 'center')
1842
+ p.pos = Math.round(p.scroll + (p.clientSize + p.marginMin - p.marginMax - p.get('wsize')) / 2);
1843
+ else
1844
+ p.pos = Math.round(p.pos - ((p.get('wsize') - p.t) / 2));
1845
+ if (p.pos < p.scroll + p.marginMin) {
1846
+ p.pos = p.scroll + p.marginMin;
1847
+ hasMovedMin = true;
1848
+ }
1849
+ if (!moveOnly && p.size < p.minSize) {
1850
+ p.size = p.minSize;
1851
+ allowReduce = false;
1852
+ }
1853
+ if (p.pos + p.get('wsize') > p.scroll + p.clientSize - p.marginMax) {
1854
+ if (!moveOnly && hasMovedMin && allowReduce) {
1855
+ p.size = Math.min(p.size, p.get(dim == 'y' ? 'fitsize' : 'maxsize'));
1856
+ } else if (p.get('wsize') < p.get('fitsize')) {
1857
+ p.pos = p.scroll + p.clientSize - p.marginMax - p.get('wsize');
1858
+ } else { // image larger than viewport
1859
+ p.pos = p.scroll + p.marginMin;
1860
+ if (!moveOnly && allowReduce) p.size = p.get(dim == 'y' ? 'fitsize' : 'maxsize');
1861
+ }
1862
+ }
1863
+
1864
+ if (!moveOnly && p.size < p.minSize) {
1865
+ p.size = p.minSize;
1866
+ allowReduce = false;
1867
+ }
1868
+
1869
+
1870
+ } else if (p.justify == 'max') {
1871
+ p.pos = Math.floor(p.pos - p.size + p.t);
1872
+ }
1873
+
1874
+
1875
+ if (p.pos < p.marginMin) {
1876
+ var tmpMin = p.pos;
1877
+ p.pos = p.marginMin;
1878
+
1879
+ if (allowReduce && !moveOnly) p.size = p.size - (p.pos - tmpMin);
1880
+
1881
+ }
1882
+ },
1883
+
1884
+ correctRatio : function(ratio) {
1885
+ var x = this.x,
1886
+ y = this.y,
1887
+ changed = false,
1888
+ xSize = Math.min(x.full, x.size),
1889
+ ySize = Math.min(y.full, y.size),
1890
+ useBox = (this.useBox || hs.padToMinWidth);
1891
+
1892
+ if (xSize / ySize > ratio) { // width greater
1893
+ xSize = ySize * ratio;
1894
+ if (xSize < x.minSize) { // below minWidth
1895
+ xSize = x.minSize;
1896
+ ySize = xSize / ratio;
1897
+ }
1898
+ changed = true;
1899
+
1900
+ } else if (xSize / ySize < ratio) { // height greater
1901
+ ySize = xSize / ratio;
1902
+ changed = true;
1903
+ }
1904
+
1905
+ if (hs.padToMinWidth && x.full < x.minSize) {
1906
+ x.imgSize = x.full;
1907
+ y.size = y.imgSize = y.full;
1908
+ } else if (this.useBox) {
1909
+ x.imgSize = xSize;
1910
+ y.imgSize = ySize;
1911
+ } else {
1912
+ x.size = xSize;
1913
+ y.size = ySize;
1914
+ }
1915
+ changed = this.fitOverlayBox(this.useBox ? null : ratio, changed);
1916
+ if (useBox && y.size < y.imgSize) {
1917
+ y.imgSize = y.size;
1918
+ x.imgSize = y.size * ratio;
1919
+ }
1920
+ if (changed || useBox) {
1921
+ x.pos = x.tpos - x.cb + x.tb;
1922
+ x.minSize = x.size;
1923
+ this.justify(x, true);
1924
+
1925
+ y.pos = y.tpos - y.cb + y.tb;
1926
+ y.minSize = y.size;
1927
+ this.justify(y, true);
1928
+ if (this.overlayBox) this.sizeOverlayBox();
1929
+ }
1930
+
1931
+
1932
+ },
1933
+ fitOverlayBox : function(ratio, changed) {
1934
+ var x = this.x, y = this.y;
1935
+ if (this.overlayBox && (this.isImage || this.allowHeightReduction)) {
1936
+ while (y.size > this.minHeight && x.size > this.minWidth
1937
+ && y.get('wsize') > y.get('fitsize')) {
1938
+ y.size -= 10;
1939
+ if (ratio) x.size = y.size * ratio;
1940
+ this.sizeOverlayBox(0, 1);
1941
+ changed = true;
1942
+ }
1943
+ }
1944
+ return changed;
1945
+ },
1946
+
1947
+ reflow : function () {
1948
+ if (this.scrollerDiv) {
1949
+ var h = /iframe/i.test(this.scrollerDiv.tagName) ? (this.getIframePageHeight() + 1) +'px' : 'auto';
1950
+ if (this.body) this.body.style.height = h;
1951
+ this.scrollerDiv.style.height = h;
1952
+ this.y.setSize(this.innerContent.offsetHeight);
1953
+ }
1954
+ },
1955
+
1956
+ show : function () {
1957
+ var x = this.x, y = this.y;
1958
+ this.doShowHide('hidden');
1959
+ hs.fireEvent(this, 'onBeforeExpand');
1960
+ if (this.slideshow && this.slideshow.thumbstrip) this.slideshow.thumbstrip.selectThumb();
1961
+
1962
+ // Apply size change
1963
+ this.changeSize(
1964
+ 1, {
1965
+ wrapper: {
1966
+ width : x.get('wsize'),
1967
+ height : y.get('wsize'),
1968
+ left: x.pos,
1969
+ top: y.pos
1970
+ },
1971
+ content: {
1972
+ left: x.p1 + x.get('imgPad'),
1973
+ top: y.p1 + y.get('imgPad'),
1974
+ width:x.imgSize ||x.size,
1975
+ height:y.imgSize ||y.size
1976
+ }
1977
+ },
1978
+ hs.expandDuration
1979
+ );
1980
+ },
1981
+
1982
+ changeSize : function(up, to, dur) {
1983
+ // transition
1984
+ var trans = this.transitions,
1985
+ other = up ? (this.last ? this.last.a : null) : hs.upcoming,
1986
+ t = (trans[1] && other
1987
+ && hs.getParam(other, 'transitions')[1] == trans[1]) ?
1988
+ trans[1] : trans[0];
1989
+
1990
+ if (this[t] && t != 'expand') {
1991
+ this[t](up, to);
1992
+ return;
1993
+ }
1994
+
1995
+ if (this.outline && !this.outlineWhileAnimating) {
1996
+ if (up) this.outline.setPosition();
1997
+ else this.outline.destroy(
1998
+ (this.isHtml && this.preserveContent));
1999
+ }
2000
+
2001
+
2002
+ if (!up) this.destroyOverlays();
2003
+
2004
+ var exp = this,
2005
+ x = exp.x,
2006
+ y = exp.y,
2007
+ easing = this.easing;
2008
+ if (!up) easing = this.easingClose || easing;
2009
+ var after = up ?
2010
+ function() {
2011
+
2012
+ if (exp.outline) exp.outline.table.style.visibility = "visible";
2013
+ setTimeout(function() {
2014
+ exp.afterExpand();
2015
+ }, 50);
2016
+ } :
2017
+ function() {
2018
+ exp.afterClose();
2019
+ };
2020
+ if (up) hs.setStyles( this.wrapper, {
2021
+ width: x.t +'px',
2022
+ height: y.t +'px'
2023
+ });
2024
+ if (up && this.isHtml) {
2025
+ hs.setStyles(this.wrapper, {
2026
+ left: (x.tpos - x.cb + x.tb) +'px',
2027
+ top: (y.tpos - y.cb + y.tb) +'px'
2028
+ });
2029
+ }
2030
+ if (this.fadeInOut) {
2031
+ hs.setStyles(this.wrapper, { opacity: up ? 0 : 1 });
2032
+ hs.extend(to.wrapper, { opacity: up });
2033
+ }
2034
+ hs.animate( this.wrapper, to.wrapper, {
2035
+ duration: dur,
2036
+ easing: easing,
2037
+ step: function(val, args) {
2038
+ if (exp.outline && exp.outlineWhileAnimating && args.prop == 'top') {
2039
+ var fac = up ? args.pos : 1 - args.pos;
2040
+ var pos = {
2041
+ w: x.t + (x.get('wsize') - x.t) * fac,
2042
+ h: y.t + (y.get('wsize') - y.t) * fac,
2043
+ x: x.tpos + (x.pos - x.tpos) * fac,
2044
+ y: y.tpos + (y.pos - y.tpos) * fac
2045
+ };
2046
+ exp.outline.setPosition(pos, 0, 1);
2047
+ }
2048
+ if (exp.isHtml) {
2049
+ if (args.prop == 'left')
2050
+ exp.mediumContent.style.left = (x.pos - val) +'px';
2051
+ if (args.prop == 'top')
2052
+ exp.mediumContent.style.top = (y.pos - val) +'px';
2053
+ }
2054
+ }
2055
+ });
2056
+ hs.animate( this.content, to.content, dur, easing, after);
2057
+ if (up) {
2058
+ this.wrapper.style.visibility = 'visible';
2059
+ this.content.style.visibility = 'visible';
2060
+ if (this.isHtml) this.innerContent.style.visibility = 'visible';
2061
+ this.a.className += ' highslide-active-anchor';
2062
+ }
2063
+ },
2064
+
2065
+
2066
+
2067
+ fade : function(up, to) {
2068
+ this.outlineWhileAnimating = false;
2069
+ var exp = this, t = up ? hs.expandDuration : 0;
2070
+
2071
+ if (up) {
2072
+ hs.animate(this.wrapper, to.wrapper, 0);
2073
+ hs.setStyles(this.wrapper, { opacity: 0, visibility: 'visible' });
2074
+ hs.animate(this.content, to.content, 0);
2075
+ this.content.style.visibility = 'visible';
2076
+
2077
+ hs.animate(this.wrapper, { opacity: 1 }, t, null,
2078
+ function() { exp.afterExpand(); });
2079
+ }
2080
+
2081
+ if (this.outline) {
2082
+ this.outline.table.style.zIndex = this.wrapper.style.zIndex;
2083
+ var dir = up || -1,
2084
+ offset = this.outline.offset,
2085
+ startOff = up ? 3 : offset,
2086
+ endOff = up? offset : 3;
2087
+ for (var i = startOff; dir * i <= dir * endOff; i += dir, t += 25) {
2088
+ (function() {
2089
+ var o = up ? endOff - i : startOff - i;
2090
+ setTimeout(function() {
2091
+ exp.outline.setPosition(0, o, 1);
2092
+ }, t);
2093
+ })();
2094
+ }
2095
+ }
2096
+
2097
+
2098
+ if (up) {}//setTimeout(function() { exp.afterExpand(); }, t+50);
2099
+ else {
2100
+ setTimeout( function() {
2101
+ if (exp.outline) exp.outline.destroy(exp.preserveContent);
2102
+
2103
+ exp.destroyOverlays();
2104
+
2105
+ hs.animate( exp.wrapper, { opacity: 0 }, hs.restoreDuration, null, function(){
2106
+ exp.afterClose();
2107
+ });
2108
+ }, t);
2109
+ }
2110
+ },
2111
+ crossfade : function (up, to, from) {
2112
+ if (!up) return;
2113
+ var exp = this,
2114
+ last = this.last,
2115
+ x = this.x,
2116
+ y = this.y,
2117
+ lastX = last.x,
2118
+ lastY = last.y,
2119
+ wrapper = this.wrapper,
2120
+ content = this.content,
2121
+ overlayBox = this.overlayBox;
2122
+ hs.removeEventListener(document, 'mousemove', hs.dragHandler);
2123
+
2124
+ hs.setStyles(content, {
2125
+ width: (x.imgSize || x.size) +'px',
2126
+ height: (y.imgSize || y.size) +'px'
2127
+ });
2128
+ if (overlayBox) overlayBox.style.overflow = 'visible';
2129
+ this.outline = last.outline;
2130
+ if (this.outline) this.outline.exp = exp;
2131
+ last.outline = null;
2132
+ var fadeBox = hs.createElement('div', {
2133
+ className: 'highslide-'+ this.contentType
2134
+ }, {
2135
+ position: 'absolute',
2136
+ zIndex: 4,
2137
+ overflow: 'hidden',
2138
+ display: 'none'
2139
+ }
2140
+ );
2141
+ var names = { oldImg: last, newImg: this };
2142
+ for (var n in names) {
2143
+ this[n] = names[n].content.cloneNode(1);
2144
+ hs.setStyles(this[n], {
2145
+ position: 'absolute',
2146
+ border: 0,
2147
+ visibility: 'visible'
2148
+ });
2149
+ fadeBox.appendChild(this[n]);
2150
+ }
2151
+ wrapper.appendChild(fadeBox);
2152
+ if (this.isHtml) hs.setStyles(this.mediumContent, {
2153
+ left: 0,
2154
+ top: 0
2155
+ });
2156
+ if (overlayBox) {
2157
+ overlayBox.className = '';
2158
+ wrapper.appendChild(overlayBox);
2159
+ }
2160
+ fadeBox.style.display = '';
2161
+ last.content.style.display = 'none';
2162
+
2163
+
2164
+ if (hs.safari && hs.uaVersion < 525) {
2165
+ this.wrapper.style.visibility = 'visible';
2166
+ }
2167
+ hs.animate(wrapper, {
2168
+ width: x.size
2169
+ }, {
2170
+ duration: hs.transitionDuration,
2171
+ step: function(val, args) {
2172
+ var pos = args.pos,
2173
+ invPos = 1 - pos;
2174
+ var prop,
2175
+ size = {},
2176
+ props = ['pos', 'size', 'p1', 'p2'];
2177
+ for (var n in props) {
2178
+ prop = props[n];
2179
+ size['x'+ prop] = Math.round(invPos * lastX[prop] + pos * x[prop]);
2180
+ size['y'+ prop] = Math.round(invPos * lastY[prop] + pos * y[prop]);
2181
+ size.ximgSize = Math.round(
2182
+ invPos * (lastX.imgSize || lastX.size) + pos * (x.imgSize || x.size));
2183
+ size.ximgPad = Math.round(invPos * lastX.get('imgPad') + pos * x.get('imgPad'));
2184
+ size.yimgSize = Math.round(
2185
+ invPos * (lastY.imgSize || lastY.size) + pos * (y.imgSize || y.size));
2186
+ size.yimgPad = Math.round(invPos * lastY.get('imgPad') + pos * y.get('imgPad'));
2187
+ }
2188
+ if (exp.outline) exp.outline.setPosition({
2189
+ x: size.xpos,
2190
+ y: size.ypos,
2191
+ w: size.xsize + size.xp1 + size.xp2 + 2 * x.cb,
2192
+ h: size.ysize + size.yp1 + size.yp2 + 2 * y.cb
2193
+ });
2194
+ last.wrapper.style.clip = 'rect('
2195
+ + (size.ypos - lastY.pos)+'px, '
2196
+ + (size.xsize + size.xp1 + size.xp2 + size.xpos + 2 * lastX.cb - lastX.pos) +'px, '
2197
+ + (size.ysize + size.yp1 + size.yp2 + size.ypos + 2 * lastY.cb - lastY.pos) +'px, '
2198
+ + (size.xpos - lastX.pos)+'px)';
2199
+
2200
+ hs.setStyles(content, {
2201
+ top: (size.yp1 + y.get('imgPad')) +'px',
2202
+ left: (size.xp1 + x.get('imgPad')) +'px',
2203
+ marginTop: (y.pos - size.ypos) +'px',
2204
+ marginLeft: (x.pos - size.xpos) +'px'
2205
+ });
2206
+ hs.setStyles(wrapper, {
2207
+ top: size.ypos +'px',
2208
+ left: size.xpos +'px',
2209
+ width: (size.xp1 + size.xp2 + size.xsize + 2 * x.cb)+ 'px',
2210
+ height: (size.yp1 + size.yp2 + size.ysize + 2 * y.cb) + 'px'
2211
+ });
2212
+ hs.setStyles(fadeBox, {
2213
+ width: (size.ximgSize || size.xsize) + 'px',
2214
+ height: (size.yimgSize || size.ysize) +'px',
2215
+ left: (size.xp1 + size.ximgPad) +'px',
2216
+ top: (size.yp1 + size.yimgPad) +'px',
2217
+ visibility: 'visible'
2218
+ });
2219
+
2220
+ hs.setStyles(exp.oldImg, {
2221
+ top: (lastY.pos - size.ypos + lastY.p1 - size.yp1 + lastY.get('imgPad') - size.yimgPad)+'px',
2222
+ left: (lastX.pos - size.xpos + lastX.p1 - size.xp1 + lastX.get('imgPad') - size.ximgPad)+'px'
2223
+ });
2224
+
2225
+ hs.setStyles(exp.newImg, {
2226
+ opacity: pos,
2227
+ top: (y.pos - size.ypos + y.p1 - size.yp1 + y.get('imgPad') - size.yimgPad) +'px',
2228
+ left: (x.pos - size.xpos + x.p1 - size.xp1 + x.get('imgPad') - size.ximgPad) +'px'
2229
+ });
2230
+ if (overlayBox) hs.setStyles(overlayBox, {
2231
+ width: size.xsize + 'px',
2232
+ height: size.ysize +'px',
2233
+ left: (size.xp1 + x.cb) +'px',
2234
+ top: (size.yp1 + y.cb) +'px'
2235
+ });
2236
+ },
2237
+ complete: function () {
2238
+ wrapper.style.visibility = content.style.visibility = 'visible';
2239
+ content.style.display = 'block';
2240
+ hs.discardElement(fadeBox);
2241
+ exp.afterExpand();
2242
+ last.afterClose();
2243
+ exp.last = null;
2244
+ }
2245
+
2246
+ });
2247
+ },
2248
+ reuseOverlay : function(o, el) {
2249
+ if (!this.last) return false;
2250
+ for (var i = 0; i < this.last.overlays.length; i++) {
2251
+ var oDiv = hs.$('hsId'+ this.last.overlays[i]);
2252
+ if (oDiv && oDiv.hsId == o.hsId) {
2253
+ this.genOverlayBox();
2254
+ oDiv.reuse = this.key;
2255
+ hs.push(this.overlays, this.last.overlays[i]);
2256
+ return true;
2257
+ }
2258
+ }
2259
+ return false;
2260
+ },
2261
+
2262
+
2263
+ afterExpand : function() {
2264
+ this.isExpanded = true;
2265
+ this.focus();
2266
+
2267
+ if (this.isHtml && this.objectLoadTime == 'after') this.writeExtendedContent();
2268
+ if (this.iframe) {
2269
+ try {
2270
+ var exp = this,
2271
+ doc = this.iframe.contentDocument || this.iframe.contentWindow.document;
2272
+ hs.addEventListener(doc, 'mousedown', function () {
2273
+ if (hs.focusKey != exp.key) exp.focus();
2274
+ });
2275
+ } catch(e) {}
2276
+ if (hs.ie && typeof this.isClosing != 'boolean') // first open
2277
+ this.iframe.style.width = (this.objectWidth - 1) +'px'; // hasLayout
2278
+ }
2279
+ if (this.dimmingOpacity) hs.dim(this);
2280
+ if (hs.upcoming && hs.upcoming == this.a) hs.upcoming = null;
2281
+ this.prepareNextOutline();
2282
+ var p = hs.page, mX = hs.mouse.x + p.scrollLeft, mY = hs.mouse.y + p.scrollTop;
2283
+ this.mouseIsOver = this.x.pos < mX && mX < this.x.pos + this.x.get('wsize')
2284
+ && this.y.pos < mY && mY < this.y.pos + this.y.get('wsize');
2285
+ if (this.overlayBox) this.showOverlays();
2286
+ hs.fireEvent(this, 'onAfterExpand');
2287
+
2288
+ },
2289
+
2290
+
2291
+ prepareNextOutline : function() {
2292
+ var key = this.key;
2293
+ var outlineType = this.outlineType;
2294
+ new hs.Outline(outlineType,
2295
+ function () { try { hs.expanders[key].preloadNext(); } catch (e) {} });
2296
+ },
2297
+
2298
+
2299
+ preloadNext : function() {
2300
+ var next = this.getAdjacentAnchor(1);
2301
+ if (next && next.onclick.toString().match(/hs\.expand/))
2302
+ var img = hs.createElement('img', { src: hs.getSrc(next) });
2303
+ },
2304
+
2305
+
2306
+ getAdjacentAnchor : function(op) {
2307
+ var current = this.getAnchorIndex(), as = hs.anchors.groups[this.slideshowGroup || 'none'];
2308
+ if (as && !as[current + op] && this.slideshow && this.slideshow.repeat) {
2309
+ if (op == 1) return as[0];
2310
+ else if (op == -1) return as[as.length-1];
2311
+ }
2312
+ return (as && as[current + op]) || null;
2313
+ },
2314
+
2315
+ getAnchorIndex : function() {
2316
+ var arr = hs.getAnchors().groups[this.slideshowGroup || 'none'];
2317
+ if (arr) for (var i = 0; i < arr.length; i++) {
2318
+ if (arr[i] == this.a) return i;
2319
+ }
2320
+ return null;
2321
+ },
2322
+
2323
+
2324
+ getNumber : function() {
2325
+ if (this[this.numberPosition]) {
2326
+ var arr = hs.anchors.groups[this.slideshowGroup || 'none'];
2327
+ if (arr) {
2328
+ var s = hs.lang.number.replace('%1', this.getAnchorIndex() + 1).replace('%2', arr.length);
2329
+ this[this.numberPosition].innerHTML =
2330
+ '<div class="highslide-number">'+ s +'</div>'+ this[this.numberPosition].innerHTML;
2331
+ }
2332
+ }
2333
+ },
2334
+ initSlideshow : function() {
2335
+ if (!this.last) {
2336
+ for (var i = 0; i < hs.slideshows.length; i++) {
2337
+ var ss = hs.slideshows[i], sg = ss.slideshowGroup;
2338
+ if (typeof sg == 'undefined' || sg === null || sg === this.slideshowGroup)
2339
+ this.slideshow = new hs.Slideshow(this.key, ss);
2340
+ }
2341
+ } else {
2342
+ this.slideshow = this.last.slideshow;
2343
+ }
2344
+ var ss = this.slideshow;
2345
+ if (!ss) return;
2346
+ var key = ss.expKey = this.key;
2347
+
2348
+ ss.checkFirstAndLast();
2349
+ ss.disable('full-expand');
2350
+ if (ss.controls) {
2351
+ this.createOverlay(hs.extend(ss.overlayOptions || {}, {
2352
+ overlayId: ss.controls,
2353
+ hsId: 'controls',
2354
+ zIndex: 5
2355
+ }));
2356
+ }
2357
+ if (ss.thumbstrip) ss.thumbstrip.add(this);
2358
+ if (!this.last && this.autoplay) ss.play(true);
2359
+ if (ss.autoplay) {
2360
+ ss.autoplay = setTimeout(function() {
2361
+ hs.next(key);
2362
+ }, (ss.interval || 500));
2363
+ }
2364
+ },
2365
+
2366
+ cancelLoading : function() {
2367
+ hs.discardElement (this.wrapper);
2368
+ hs.expanders[this.key] = null;
2369
+ if (hs.upcoming == this.a) hs.upcoming = null;
2370
+ hs.undim(this.key);
2371
+ if (this.loading) hs.loading.style.left = '-9999px';
2372
+ hs.fireEvent(this, 'onHideLoading');
2373
+ },
2374
+
2375
+ writeCredits : function () {
2376
+ if (this.credits) return;
2377
+ this.credits = hs.createElement('a', {
2378
+ href: hs.creditsHref,
2379
+ target: hs.creditsTarget,
2380
+ className: 'highslide-credits',
2381
+ innerHTML: hs.lang.creditsText,
2382
+ title: hs.lang.creditsTitle
2383
+ });
2384
+ this.createOverlay({
2385
+ overlayId: this.credits,
2386
+ position: this.creditsPosition || 'top left',
2387
+ hsId: 'credits'
2388
+ });
2389
+ },
2390
+
2391
+ getInline : function(types, addOverlay) {
2392
+ for (var i = 0; i < types.length; i++) {
2393
+ var type = types[i], s = null;
2394
+ if (type == 'caption' && !hs.fireEvent(this, 'onBeforeGetCaption')) return;
2395
+ else if (type == 'heading' && !hs.fireEvent(this, 'onBeforeGetHeading')) return;
2396
+ if (!this[type +'Id'] && this.thumbsUserSetId)
2397
+ this[type +'Id'] = type +'-for-'+ this.thumbsUserSetId;
2398
+ if (this[type +'Id']) this[type] = hs.getNode(this[type +'Id']);
2399
+ if (!this[type] && !this[type +'Text'] && this[type +'Eval']) try {
2400
+ s = eval(this[type +'Eval']);
2401
+ } catch (e) {}
2402
+ if (!this[type] && this[type +'Text']) {
2403
+ s = this[type +'Text'];
2404
+ }
2405
+ if (!this[type] && !s) {
2406
+ this[type] = hs.getNode(this.a['_'+ type + 'Id']);
2407
+ if (!this[type]) {
2408
+ var next = this.a.nextSibling;
2409
+ while (next && !hs.isHsAnchor(next)) {
2410
+ if ((new RegExp('highslide-'+ type)).test(next.className || null)) {
2411
+ if (!next.id) this.a['_'+ type + 'Id'] = next.id = 'hsId'+ hs.idCounter++;
2412
+ this[type] = hs.getNode(next.id);
2413
+ break;
2414
+ }
2415
+ next = next.nextSibling;
2416
+ }
2417
+ }
2418
+ }
2419
+ if (!this[type] && !s && this.numberPosition == type) s = '\n';
2420
+
2421
+ if (!this[type] && s) this[type] = hs.createElement('div',
2422
+ { className: 'highslide-'+ type, innerHTML: s } );
2423
+
2424
+ if (addOverlay && this[type]) {
2425
+ var o = { position: (type == 'heading') ? 'above' : 'below' };
2426
+ for (var x in this[type+'Overlay']) o[x] = this[type+'Overlay'][x];
2427
+ o.overlayId = this[type];
2428
+ this.createOverlay(o);
2429
+ }
2430
+ }
2431
+ },
2432
+
2433
+
2434
+ // on end move and resize
2435
+ doShowHide : function(visibility) {
2436
+ if (hs.hideSelects) this.showHideElements('SELECT', visibility);
2437
+ if (hs.hideIframes) this.showHideElements('IFRAME', visibility);
2438
+ if (hs.geckoMac) this.showHideElements('*', visibility);
2439
+ },
2440
+ showHideElements : function (tagName, visibility) {
2441
+ var els = document.getElementsByTagName(tagName);
2442
+ var prop = tagName == '*' ? 'overflow' : 'visibility';
2443
+ for (var i = 0; i < els.length; i++) {
2444
+ if (prop == 'visibility' || (document.defaultView.getComputedStyle(
2445
+ els[i], "").getPropertyValue('overflow') == 'auto'
2446
+ || els[i].getAttribute('hidden-by') != null)) {
2447
+ var hiddenBy = els[i].getAttribute('hidden-by');
2448
+ if (visibility == 'visible' && hiddenBy) {
2449
+ hiddenBy = hiddenBy.replace('['+ this.key +']', '');
2450
+ els[i].setAttribute('hidden-by', hiddenBy);
2451
+ if (!hiddenBy) els[i].style[prop] = els[i].origProp;
2452
+ } else if (visibility == 'hidden') { // hide if behind
2453
+ var elPos = hs.getPosition(els[i]);
2454
+ elPos.w = els[i].offsetWidth;
2455
+ elPos.h = els[i].offsetHeight;
2456
+ if (!this.dimmingOpacity) { // hide all if dimming
2457
+
2458
+ var clearsX = (elPos.x + elPos.w < this.x.get('opos')
2459
+ || elPos.x > this.x.get('opos') + this.x.get('osize'));
2460
+ var clearsY = (elPos.y + elPos.h < this.y.get('opos')
2461
+ || elPos.y > this.y.get('opos') + this.y.get('osize'));
2462
+ }
2463
+ var wrapperKey = hs.getWrapperKey(els[i]);
2464
+ if (!clearsX && !clearsY && wrapperKey != this.key) { // element falls behind image
2465
+ if (!hiddenBy) {
2466
+ els[i].setAttribute('hidden-by', '['+ this.key +']');
2467
+ els[i].origProp = els[i].style[prop];
2468
+ els[i].style[prop] = 'hidden';
2469
+
2470
+ } else if (hiddenBy.indexOf('['+ this.key +']') == -1) {
2471
+ els[i].setAttribute('hidden-by', hiddenBy + '['+ this.key +']');
2472
+ }
2473
+ } else if ((hiddenBy == '['+ this.key +']' || hs.focusKey == wrapperKey)
2474
+ && wrapperKey != this.key) { // on move
2475
+ els[i].setAttribute('hidden-by', '');
2476
+ els[i].style[prop] = els[i].origProp || '';
2477
+ } else if (hiddenBy && hiddenBy.indexOf('['+ this.key +']') > -1) {
2478
+ els[i].setAttribute('hidden-by', hiddenBy.replace('['+ this.key +']', ''));
2479
+ }
2480
+
2481
+ }
2482
+ }
2483
+ }
2484
+ },
2485
+
2486
+ focus : function() {
2487
+ this.wrapper.style.zIndex = hs.zIndexCounter += 2;
2488
+ // blur others
2489
+ for (var i = 0; i < hs.expanders.length; i++) {
2490
+ if (hs.expanders[i] && i == hs.focusKey) {
2491
+ var blurExp = hs.expanders[i];
2492
+ blurExp.content.className += ' highslide-'+ blurExp.contentType +'-blur';
2493
+ if (blurExp.isImage) {
2494
+ blurExp.content.style.cursor = hs.ieLt7 ? 'hand' : 'pointer';
2495
+ blurExp.content.title = hs.lang.focusTitle;
2496
+ }
2497
+ hs.fireEvent(blurExp, 'onBlur');
2498
+ }
2499
+ }
2500
+
2501
+ // focus this
2502
+ if (this.outline) this.outline.table.style.zIndex
2503
+ = this.wrapper.style.zIndex - 1;
2504
+ this.content.className = 'highslide-'+ this.contentType;
2505
+ if (this.isImage) {
2506
+ this.content.title = hs.lang.restoreTitle;
2507
+
2508
+ if (hs.restoreCursor) {
2509
+ hs.styleRestoreCursor = window.opera ? 'pointer' : 'url('+ hs.graphicsDir + hs.restoreCursor +'), pointer';
2510
+ if (hs.ieLt7 && hs.uaVersion < 6) hs.styleRestoreCursor = 'hand';
2511
+ this.content.style.cursor = hs.styleRestoreCursor;
2512
+ }
2513
+ }
2514
+ hs.focusKey = this.key;
2515
+ hs.addEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);
2516
+ hs.fireEvent(this, 'onFocus');
2517
+ },
2518
+ moveTo: function(x, y) {
2519
+ this.x.setPos(x);
2520
+ this.y.setPos(y);
2521
+ },
2522
+ resize : function (e) {
2523
+ var w, h, r = e.width / e.height;
2524
+ w = Math.max(e.width + e.dX, Math.min(this.minWidth, this.x.full));
2525
+ if (this.isImage && Math.abs(w - this.x.full) < 12) w = this.x.full;
2526
+ h = this.isHtml ? e.height + e.dY : w / r;
2527
+ if (h < Math.min(this.minHeight, this.y.full)) {
2528
+ h = Math.min(this.minHeight, this.y.full);
2529
+ if (this.isImage) w = h * r;
2530
+ }
2531
+ this.resizeTo(w, h);
2532
+ },
2533
+ resizeTo: function(w, h) {
2534
+ this.y.setSize(h);
2535
+ this.x.setSize(w);
2536
+ this.wrapper.style.height = this.y.get('wsize') +'px';
2537
+ },
2538
+
2539
+ close : function() {
2540
+ if (this.isClosing || !this.isExpanded) return;
2541
+ if (this.transitions[1] == 'crossfade' && hs.upcoming) {
2542
+ hs.getExpander(hs.upcoming).cancelLoading();
2543
+ hs.upcoming = null;
2544
+ }
2545
+ if (!hs.fireEvent(this, 'onBeforeClose')) return;
2546
+ this.isClosing = true;
2547
+ if (this.slideshow && !hs.upcoming) this.slideshow.pause();
2548
+
2549
+ hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);
2550
+
2551
+ try {
2552
+ if (this.isHtml) this.htmlPrepareClose();
2553
+ this.content.style.cursor = 'default';
2554
+ this.changeSize(
2555
+ 0, {
2556
+ wrapper: {
2557
+ width : this.x.t,
2558
+ height : this.y.t,
2559
+ left: this.x.tpos - this.x.cb + this.x.tb,
2560
+ top: this.y.tpos - this.y.cb + this.y.tb
2561
+ },
2562
+ content: {
2563
+ left: 0,
2564
+ top: 0,
2565
+ width: this.x.t,
2566
+ height: this.y.t
2567
+ }
2568
+ }, hs.restoreDuration
2569
+ );
2570
+ } catch (e) { this.afterClose(); }
2571
+ },
2572
+
2573
+ htmlPrepareClose : function() {
2574
+ if (hs.geckoMac) { // bad redraws
2575
+ if (!hs.mask) hs.mask = hs.createElement('div', null,
2576
+ { position: 'absolute' }, hs.container);
2577
+ hs.setStyles(hs.mask, { width: this.x.size +'px', height: this.y.size +'px',
2578
+ left: this.x.pos +'px', top: this.y.pos +'px', display: 'block' });
2579
+ }
2580
+ if (this.objectType == 'swf') try { hs.$(this.body.id).StopPlay(); } catch (e) {}
2581
+
2582
+ if (this.objectLoadTime == 'after' && !this.preserveContent) this.destroyObject();
2583
+ if (this.scrollerDiv && this.scrollerDiv != this.scrollingContent)
2584
+ this.scrollerDiv.style.overflow = 'hidden';
2585
+ },
2586
+
2587
+ destroyObject : function () {
2588
+ if (hs.ie && this.iframe)
2589
+ try { this.iframe.contentWindow.document.body.innerHTML = ''; } catch (e) {}
2590
+ if (this.objectType == 'swf') swfobject.removeSWF(this.body.id);
2591
+ this.body.innerHTML = '';
2592
+ },
2593
+
2594
+ sleep : function() {
2595
+ if (this.outline) this.outline.table.style.display = 'none';
2596
+ this.releaseMask = null;
2597
+ this.wrapper.style.display = 'none';
2598
+ this.isExpanded = false;
2599
+ hs.push(hs.sleeping, this);
2600
+ },
2601
+
2602
+ awake : function() {try {
2603
+
2604
+ hs.expanders[this.key] = this;
2605
+
2606
+ if (!hs.allowMultipleInstances &&hs.focusKey != this.key) {
2607
+ try { hs.expanders[hs.focusKey].close(); } catch (e){}
2608
+ }
2609
+
2610
+ var z = hs.zIndexCounter++, stl = { display: '', zIndex: z };
2611
+ hs.setStyles (this.wrapper, stl);
2612
+ this.isClosing = false;
2613
+
2614
+ var o = this.outline || 0;
2615
+ if (o) {
2616
+ if (!this.outlineWhileAnimating) stl.visibility = 'hidden';
2617
+ hs.setStyles (o.table, stl);
2618
+ }
2619
+ if (this.slideshow) {
2620
+ this.initSlideshow();
2621
+ }
2622
+
2623
+ this.show();
2624
+ } catch (e) {}
2625
+
2626
+
2627
+ },
2628
+
2629
+ createOverlay : function (o) {
2630
+ var el = o.overlayId,
2631
+ relToVP = (o.relativeTo == 'viewport' && !/panel$/.test(o.position));
2632
+ if (typeof el == 'string') el = hs.getNode(el);
2633
+ if (o.html) el = hs.createElement('div', { innerHTML: o.html });
2634
+ if (!el || typeof el == 'string') return;
2635
+ if (!hs.fireEvent(this, 'onCreateOverlay', { overlay: el })) return;
2636
+ el.style.display = 'block';
2637
+ o.hsId = o.hsId || o.overlayId;
2638
+ if (this.transitions[1] == 'crossfade' && this.reuseOverlay(o, el)) return;
2639
+ this.genOverlayBox();
2640
+ var width = o.width && /^[0-9]+(px|%)$/.test(o.width) ? o.width : 'auto';
2641
+ if (/^(left|right)panel$/.test(o.position) && !/^[0-9]+px$/.test(o.width)) width = '200px';
2642
+ var overlay = hs.createElement(
2643
+ 'div', {
2644
+ id: 'hsId'+ hs.idCounter++,
2645
+ hsId: o.hsId
2646
+ }, {
2647
+ position: 'absolute',
2648
+ visibility: 'hidden',
2649
+ width: width,
2650
+ direction: hs.lang.cssDirection || '',
2651
+ opacity: 0
2652
+ },
2653
+ relToVP ? hs.viewport :this.overlayBox,
2654
+ true
2655
+ );
2656
+ if (relToVP) overlay.hsKey = this.key;
2657
+
2658
+ overlay.appendChild(el);
2659
+ hs.extend(overlay, {
2660
+ opacity: 1,
2661
+ offsetX: 0,
2662
+ offsetY: 0,
2663
+ dur: (o.fade === 0 || o.fade === false || (o.fade == 2 && hs.ie)) ? 0 : 250
2664
+ });
2665
+ hs.extend(overlay, o);
2666
+
2667
+
2668
+ if (this.gotOverlays) {
2669
+ this.positionOverlay(overlay);
2670
+ if (!overlay.hideOnMouseOut || this.mouseIsOver)
2671
+ hs.animate(overlay, { opacity: overlay.opacity }, overlay.dur);
2672
+ }
2673
+ hs.push(this.overlays, hs.idCounter - 1);
2674
+ },
2675
+ positionOverlay : function(overlay) {
2676
+ var p = overlay.position || 'middle center',
2677
+ relToVP = (overlay.relativeTo == 'viewport'),
2678
+ offX = overlay.offsetX,
2679
+ offY = overlay.offsetY;
2680
+ if (relToVP) {
2681
+ hs.viewport.style.display = 'block';
2682
+ overlay.hsKey = this.key;
2683
+ if (overlay.offsetWidth > overlay.parentNode.offsetWidth)
2684
+ overlay.style.width = '100%';
2685
+ } else
2686
+ if (overlay.parentNode != this.overlayBox) this.overlayBox.appendChild(overlay);
2687
+ if (/left$/.test(p)) overlay.style.left = offX +'px';
2688
+
2689
+ if (/center$/.test(p)) hs.setStyles (overlay, {
2690
+ left: '50%',
2691
+ marginLeft: (offX - Math.round(overlay.offsetWidth / 2)) +'px'
2692
+ });
2693
+
2694
+ if (/right$/.test(p)) overlay.style.right = - offX +'px';
2695
+
2696
+ if (/^leftpanel$/.test(p)) {
2697
+ hs.setStyles(overlay, {
2698
+ right: '100%',
2699
+ marginRight: this.x.cb +'px',
2700
+ top: - this.y.cb +'px',
2701
+ bottom: - this.y.cb +'px',
2702
+ overflow: 'auto'
2703
+ });
2704
+ this.x.p1 = overlay.offsetWidth;
2705
+
2706
+ } else if (/^rightpanel$/.test(p)) {
2707
+ hs.setStyles(overlay, {
2708
+ left: '100%',
2709
+ marginLeft: this.x.cb +'px',
2710
+ top: - this.y.cb +'px',
2711
+ bottom: - this.y.cb +'px',
2712
+ overflow: 'auto'
2713
+ });
2714
+ this.x.p2 = overlay.offsetWidth;
2715
+ }
2716
+ var parOff = overlay.parentNode.offsetHeight;
2717
+ overlay.style.height = 'auto';
2718
+ if (relToVP && overlay.offsetHeight > parOff)
2719
+ overlay.style.height = hs.ieLt7 ? parOff +'px' : '100%';
2720
+
2721
+ if (/^top/.test(p)) overlay.style.top = offY +'px';
2722
+ if (/^middle/.test(p)) hs.setStyles (overlay, {
2723
+ top: '50%',
2724
+ marginTop: (offY - Math.round(overlay.offsetHeight / 2)) +'px'
2725
+ });
2726
+ if (/^bottom/.test(p)) overlay.style.bottom = - offY +'px';
2727
+ if (/^above$/.test(p)) {
2728
+ hs.setStyles(overlay, {
2729
+ left: (- this.x.p1 - this.x.cb) +'px',
2730
+ right: (- this.x.p2 - this.x.cb) +'px',
2731
+ bottom: '100%',
2732
+ marginBottom: this.y.cb +'px',
2733
+ width: 'auto'
2734
+ });
2735
+ this.y.p1 = overlay.offsetHeight;
2736
+
2737
+ } else if (/^below$/.test(p)) {
2738
+ hs.setStyles(overlay, {
2739
+ position: 'relative',
2740
+ left: (- this.x.p1 - this.x.cb) +'px',
2741
+ right: (- this.x.p2 - this.x.cb) +'px',
2742
+ top: '100%',
2743
+ marginTop: this.y.cb +'px',
2744
+ width: 'auto'
2745
+ });
2746
+ this.y.p2 = overlay.offsetHeight;
2747
+ overlay.style.position = 'absolute';
2748
+ }
2749
+ },
2750
+
2751
+ getOverlays : function() {
2752
+ this.getInline(['heading', 'caption'], true);
2753
+ this.getNumber();
2754
+ if (this.caption) hs.fireEvent(this, 'onAfterGetCaption');
2755
+ if (this.heading) hs.fireEvent(this, 'onAfterGetHeading');
2756
+ if (this.heading && this.dragByHeading) this.heading.className += ' highslide-move';
2757
+ if (hs.showCredits) this.writeCredits();
2758
+ for (var i = 0; i < hs.overlays.length; i++) {
2759
+ var o = hs.overlays[i], tId = o.thumbnailId, sg = o.slideshowGroup;
2760
+ if ((!tId && !sg) || (tId && tId == this.thumbsUserSetId)
2761
+ || (sg && sg === this.slideshowGroup)) {
2762
+ if (this.isImage || (this.isHtml && o.useOnHtml))
2763
+ this.createOverlay(o);
2764
+ }
2765
+ }
2766
+ var os = [];
2767
+ for (var i = 0; i < this.overlays.length; i++) {
2768
+ var o = hs.$('hsId'+ this.overlays[i]);
2769
+ if (/panel$/.test(o.position)) this.positionOverlay(o);
2770
+ else hs.push(os, o);
2771
+ }
2772
+ for (var i = 0; i < os.length; i++) this.positionOverlay(os[i]);
2773
+ this.gotOverlays = true;
2774
+ },
2775
+ genOverlayBox : function() {
2776
+ if (!this.overlayBox) this.overlayBox = hs.createElement (
2777
+ 'div', {
2778
+ className: this.wrapperClassName
2779
+ }, {
2780
+ position : 'absolute',
2781
+ width: (this.x.size || (this.useBox ? this.width : null)
2782
+ || this.x.full) +'px',
2783
+ height: (this.y.size || this.y.full) +'px',
2784
+ visibility : 'hidden',
2785
+ overflow : 'hidden',
2786
+ zIndex : hs.ie ? 4 : 'auto'
2787
+ },
2788
+ hs.container,
2789
+ true
2790
+ );
2791
+ },
2792
+ sizeOverlayBox : function(doWrapper, doPanels) {
2793
+ var overlayBox = this.overlayBox,
2794
+ x = this.x,
2795
+ y = this.y;
2796
+ hs.setStyles( overlayBox, {
2797
+ width: x.size +'px',
2798
+ height: y.size +'px'
2799
+ });
2800
+ if (doWrapper || doPanels) {
2801
+ for (var i = 0; i < this.overlays.length; i++) {
2802
+ var o = hs.$('hsId'+ this.overlays[i]);
2803
+ var ie6 = (hs.ieLt7 || document.compatMode == 'BackCompat');
2804
+ if (o && /^(above|below)$/.test(o.position)) {
2805
+ if (ie6) {
2806
+ o.style.width = (overlayBox.offsetWidth + 2 * x.cb
2807
+ + x.p1 + x.p2) +'px';
2808
+ }
2809
+ y[o.position == 'above' ? 'p1' : 'p2'] = o.offsetHeight;
2810
+ }
2811
+ if (o && ie6 && /^(left|right)panel$/.test(o.position)) {
2812
+ o.style.height = (overlayBox.offsetHeight + 2* y.cb) +'px';
2813
+ }
2814
+ }
2815
+ }
2816
+ if (doWrapper) {
2817
+ hs.setStyles(this.content, {
2818
+ top: y.p1 +'px'
2819
+ });
2820
+ hs.setStyles(overlayBox, {
2821
+ top: (y.p1 + y.cb) +'px'
2822
+ });
2823
+ }
2824
+ },
2825
+
2826
+ showOverlays : function() {
2827
+ var b = this.overlayBox;
2828
+ b.className = '';
2829
+ hs.setStyles(b, {
2830
+ top: (this.y.p1 + this.y.cb) +'px',
2831
+ left: (this.x.p1 + this.x.cb) +'px',
2832
+ overflow : 'visible'
2833
+ });
2834
+ if (hs.safari) b.style.visibility = 'visible';
2835
+ this.wrapper.appendChild (b);
2836
+ for (var i = 0; i < this.overlays.length; i++) {
2837
+ var o = hs.$('hsId'+ this.overlays[i]);
2838
+ o.style.zIndex = o.zIndex || 4;
2839
+ if (!o.hideOnMouseOut || this.mouseIsOver) {
2840
+ o.style.visibility = 'visible';
2841
+ hs.setStyles(o, { visibility: 'visible', display: '' });
2842
+ hs.animate(o, { opacity: o.opacity }, o.dur);
2843
+ }
2844
+ }
2845
+ },
2846
+
2847
+ destroyOverlays : function() {
2848
+ if (!this.overlays.length) return;
2849
+ if (this.slideshow) {
2850
+ var c = this.slideshow.controls;
2851
+ if (c && hs.getExpander(c) == this) c.parentNode.removeChild(c);
2852
+ }
2853
+ for (var i = 0; i < this.overlays.length; i++) {
2854
+ var o = hs.$('hsId'+ this.overlays[i]);
2855
+ if (o && o.parentNode == hs.viewport && hs.getExpander(o) == this) hs.discardElement(o);
2856
+ }
2857
+ if (this.isHtml && this.preserveContent) {
2858
+ this.overlayBox.style.top = '-9999px';
2859
+ hs.container.appendChild(this.overlayBox);
2860
+ } else
2861
+ hs.discardElement(this.overlayBox);
2862
+ },
2863
+
2864
+
2865
+
2866
+ createFullExpand : function () {
2867
+ if (this.slideshow && this.slideshow.controls) {
2868
+ this.slideshow.enable('full-expand');
2869
+ return;
2870
+ }
2871
+ this.fullExpandLabel = hs.createElement(
2872
+ 'a', {
2873
+ href: 'javascript:hs.expanders['+ this.key +'].doFullExpand();',
2874
+ title: hs.lang.fullExpandTitle,
2875
+ className: 'highslide-full-expand'
2876
+ }
2877
+ );
2878
+ if (!hs.fireEvent(this, 'onCreateFullExpand')) return;
2879
+
2880
+ this.createOverlay({
2881
+ overlayId: this.fullExpandLabel,
2882
+ position: hs.fullExpandPosition,
2883
+ hideOnMouseOut: true,
2884
+ opacity: hs.fullExpandOpacity
2885
+ });
2886
+ },
2887
+
2888
+ doFullExpand : function () {
2889
+ try {
2890
+ if (!hs.fireEvent(this, 'onDoFullExpand')) return;
2891
+ if (this.fullExpandLabel) hs.discardElement(this.fullExpandLabel);
2892
+
2893
+ this.focus();
2894
+ var xSize = this.x.size,
2895
+ ySize = this.y.size;
2896
+ this.resizeTo(this.x.full, this.y.full);
2897
+
2898
+ var xpos = this.x.pos - (this.x.size - xSize) / 2;
2899
+ if (xpos < hs.marginLeft) xpos = hs.marginLeft;
2900
+
2901
+ var ypos = this.y.pos - (this.y.size - ySize) / 2;
2902
+ if (ypos < hs.marginTop) ypos = hs.marginTop;
2903
+
2904
+ this.moveTo(xpos, ypos);
2905
+ this.doShowHide('hidden');
2906
+
2907
+ } catch (e) {
2908
+ this.error(e);
2909
+ }
2910
+ },
2911
+
2912
+
2913
+ afterClose : function () {
2914
+ this.a.className = this.a.className.replace('highslide-active-anchor', '');
2915
+
2916
+ this.doShowHide('visible');
2917
+
2918
+ if (this.isHtml && this.preserveContent
2919
+ && this.transitions[1] != 'crossfade') {
2920
+ this.sleep();
2921
+ } else {
2922
+ if (this.outline && this.outlineWhileAnimating) this.outline.destroy();
2923
+
2924
+ hs.discardElement(this.wrapper);
2925
+ }
2926
+ if (hs.mask) hs.mask.style.display = 'none';
2927
+ this.destroyOverlays();
2928
+ if (!hs.viewport.childNodes.length) hs.viewport.style.display = 'none';
2929
+
2930
+ if (this.dimmingOpacity) hs.undim(this.key);
2931
+ hs.fireEvent(this, 'onAfterClose');
2932
+ hs.expanders[this.key] = null;
2933
+ hs.reOrder();
2934
+ }
2935
+
2936
+ };
2937
+
2938
+
2939
+ // hs.Ajax object prototype
2940
+ hs.Ajax = function (a, content, pre) {
2941
+ this.a = a;
2942
+ this.content = content;
2943
+ this.pre = pre;
2944
+ };
2945
+
2946
+ hs.Ajax.prototype = {
2947
+ run : function () {
2948
+ var xhr;
2949
+ if (!this.src) this.src = hs.getSrc(this.a);
2950
+ if (this.src.match('#')) {
2951
+ var arr = this.src.split('#');
2952
+ this.src = arr[0];
2953
+ this.id = arr[1];
2954
+ }
2955
+ if (hs.cachedGets[this.src]) {
2956
+ this.cachedGet = hs.cachedGets[this.src];
2957
+ if (this.id) this.getElementContent();
2958
+ else this.loadHTML();
2959
+ return;
2960
+ }
2961
+ try { xhr = new XMLHttpRequest(); }
2962
+ catch (e) {
2963
+ try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); }
2964
+ catch (e) {
2965
+ try { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
2966
+ catch (e) { this.onError(); }
2967
+ }
2968
+ }
2969
+ var pThis = this;
2970
+ xhr.onreadystatechange = function() {
2971
+ if(pThis.xhr.readyState == 4) {
2972
+ if (pThis.id) pThis.getElementContent();
2973
+ else pThis.loadHTML();
2974
+ }
2975
+ };
2976
+ var src = this.src;
2977
+ this.xhr = xhr;
2978
+ if (hs.forceAjaxReload)
2979
+ src = src.replace(/$/, (/\?/.test(src) ? '&' : '?') +'dummy='+ (new Date()).getTime());
2980
+ xhr.open('GET', src, true);
2981
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
2982
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2983
+ xhr.send(null);
2984
+ },
2985
+
2986
+ getElementContent : function() {
2987
+ hs.init();
2988
+ var attribs = window.opera || hs.ie6SSL ? { src: 'about:blank' } : null;
2989
+
2990
+ this.iframe = hs.createElement('iframe', attribs,
2991
+ { position: 'absolute', top: '-9999px' }, hs.container);
2992
+
2993
+ this.loadHTML();
2994
+ },
2995
+
2996
+ loadHTML : function() {
2997
+ var s = this.cachedGet || this.xhr.responseText,
2998
+ regBody;
2999
+ if (this.pre) hs.cachedGets[this.src] = s;
3000
+ if (!hs.ie || hs.uaVersion >= 5.5) {
3001
+ s = s.replace(new RegExp('<link[^>]*>', 'gi'), '')
3002
+ .replace(new RegExp('<script[^>]*>.*?</script>', 'gi'), '');
3003
+ if (this.iframe) {
3004
+ var doc = this.iframe.contentDocument;
3005
+ if (!doc && this.iframe.contentWindow) doc = this.iframe.contentWindow.document;
3006
+ if (!doc) { // Opera
3007
+ var pThis = this;
3008
+ setTimeout(function() { pThis.loadHTML(); }, 25);
3009
+ return;
3010
+ }
3011
+ doc.open();
3012
+ doc.write(s);
3013
+ doc.close();
3014
+ try { s = doc.getElementById(this.id).innerHTML; } catch (e) {
3015
+ try { s = this.iframe.document.getElementById(this.id).innerHTML; } catch (e) {} // opera
3016
+ }
3017
+ hs.discardElement(this.iframe);
3018
+ } else {
3019
+ regBody = /(<body[^>]*>|<\/body>)/ig;
3020
+ if (regBody.test(s)) s = s.split(regBody)[hs.ieLt9 ? 1 : 2];
3021
+
3022
+ }
3023
+ }
3024
+ hs.getElementByClass(this.content, 'DIV', 'highslide-body').innerHTML = s;
3025
+ this.onLoad();
3026
+ for (var x in this) this[x] = null;
3027
+ }
3028
+ };
3029
+
3030
+
3031
+ hs.Slideshow = function (expKey, options) {
3032
+ if (hs.dynamicallyUpdateAnchors !== false) hs.updateAnchors();
3033
+ this.expKey = expKey;
3034
+ for (var x in options) this[x] = options[x];
3035
+ if (this.useControls) this.getControls();
3036
+ if (this.thumbstrip) this.thumbstrip = hs.Thumbstrip(this);
3037
+ };
3038
+ hs.Slideshow.prototype = {
3039
+ getControls: function() {
3040
+ this.controls = hs.createElement('div', { innerHTML: hs.replaceLang(hs.skin.controls) },
3041
+ null, hs.container);
3042
+
3043
+ var buttons = ['play', 'pause', 'previous', 'next', 'move', 'full-expand', 'close'];
3044
+ this.btn = {};
3045
+ var pThis = this;
3046
+ for (var i = 0; i < buttons.length; i++) {
3047
+ this.btn[buttons[i]] = hs.getElementByClass(this.controls, 'li', 'highslide-'+ buttons[i]);
3048
+ this.enable(buttons[i]);
3049
+ }
3050
+ this.btn.pause.style.display = 'none';
3051
+ //this.disable('full-expand');
3052
+ },
3053
+ checkFirstAndLast: function() {
3054
+ if (this.repeat || !this.controls) return;
3055
+ var exp = hs.expanders[this.expKey],
3056
+ cur = exp.getAnchorIndex(),
3057
+ re = /disabled$/;
3058
+ if (cur == 0)
3059
+ this.disable('previous');
3060
+ else if (re.test(this.btn.previous.getElementsByTagName('a')[0].className))
3061
+ this.enable('previous');
3062
+ if (cur + 1 == hs.anchors.groups[exp.slideshowGroup || 'none'].length) {
3063
+ this.disable('next');
3064
+ this.disable('play');
3065
+ } else if (re.test(this.btn.next.getElementsByTagName('a')[0].className)) {
3066
+ this.enable('next');
3067
+ this.enable('play');
3068
+ }
3069
+ },
3070
+ enable: function(btn) {
3071
+ if (!this.btn) return;
3072
+ var sls = this, a = this.btn[btn].getElementsByTagName('a')[0], re = /disabled$/;
3073
+ a.onclick = function() {
3074
+ sls[btn]();
3075
+ return false;
3076
+ };
3077
+ if (re.test(a.className)) a.className = a.className.replace(re, '');
3078
+ },
3079
+ disable: function(btn) {
3080
+ if (!this.btn) return;
3081
+ var a = this.btn[btn].getElementsByTagName('a')[0];
3082
+ a.onclick = function() { return false; };
3083
+ if (!/disabled$/.test(a.className)) a.className += ' disabled';
3084
+ },
3085
+ hitSpace: function() {
3086
+ if (this.autoplay) this.pause();
3087
+ else this.play();
3088
+ },
3089
+ play: function(wait) {
3090
+ if (this.btn) {
3091
+ this.btn.play.style.display = 'none';
3092
+ this.btn.pause.style.display = '';
3093
+ }
3094
+
3095
+ this.autoplay = true;
3096
+ if (!wait) hs.next(this.expKey);
3097
+ },
3098
+ pause: function() {
3099
+ if (this.btn) {
3100
+ this.btn.pause.style.display = 'none';
3101
+ this.btn.play.style.display = '';
3102
+ }
3103
+
3104
+ clearTimeout(this.autoplay);
3105
+ this.autoplay = null;
3106
+ },
3107
+ previous: function() {
3108
+ this.pause();
3109
+ hs.previous(this.btn.previous);
3110
+ },
3111
+ next: function() {
3112
+ this.pause();
3113
+ hs.next(this.btn.next);
3114
+ },
3115
+ move: function() {},
3116
+ 'full-expand': function() {
3117
+ hs.getExpander().doFullExpand();
3118
+ },
3119
+ close: function() {
3120
+ hs.close(this.btn.close);
3121
+ }
3122
+ };
3123
+ hs.Thumbstrip = function(slideshow) {
3124
+ function add (exp) {
3125
+ hs.extend(options || {}, {
3126
+ overlayId: dom,
3127
+ hsId: 'thumbstrip',
3128
+ className: 'highslide-thumbstrip-'+ mode +'-overlay ' + (options.className || '')
3129
+ });
3130
+ if (hs.ieLt7) options.fade = 0;
3131
+ exp.createOverlay(options);
3132
+ hs.setStyles(dom.parentNode, { overflow: 'hidden' });
3133
+ };
3134
+
3135
+ function scroll (delta) {
3136
+ selectThumb(undefined, Math.round(delta * dom[isX ? 'offsetWidth' : 'offsetHeight'] * 0.7));
3137
+ };
3138
+
3139
+ function selectThumb (i, scrollBy) {
3140
+ if (i === undefined) for (var j = 0; j < group.length; j++) {
3141
+ if (group[j] == hs.expanders[slideshow.expKey].a) {
3142
+ i = j;
3143
+ break;
3144
+ }
3145
+ }
3146
+ if (i === undefined) return;
3147
+ var as = dom.getElementsByTagName('a'),
3148
+ active = as[i],
3149
+ cell = active.parentNode,
3150
+ left = isX ? 'Left' : 'Top',
3151
+ right = isX ? 'Right' : 'Bottom',
3152
+ width = isX ? 'Width' : 'Height',
3153
+ offsetLeft = 'offset' + left,
3154
+ offsetWidth = 'offset' + width,
3155
+ overlayWidth = div.parentNode.parentNode[offsetWidth],
3156
+ minTblPos = overlayWidth - table[offsetWidth],
3157
+ curTblPos = parseInt(table.style[isX ? 'left' : 'top']) || 0,
3158
+ tblPos = curTblPos,
3159
+ mgnRight = 20;
3160
+ if (scrollBy !== undefined) {
3161
+ tblPos = curTblPos - scrollBy;
3162
+
3163
+ if (minTblPos > 0) minTblPos = 0;
3164
+ if (tblPos > 0) tblPos = 0;
3165
+ if (tblPos < minTblPos) tblPos = minTblPos;
3166
+
3167
+
3168
+ } else {
3169
+ for (var j = 0; j < as.length; j++) as[j].className = '';
3170
+ active.className = 'highslide-active-anchor';
3171
+ var activeLeft = i > 0 ? as[i - 1].parentNode[offsetLeft] : cell[offsetLeft],
3172
+ activeRight = cell[offsetLeft] + cell[offsetWidth] +
3173
+ (as[i + 1] ? as[i + 1].parentNode[offsetWidth] : 0);
3174
+ if (activeRight > overlayWidth - curTblPos) tblPos = overlayWidth - activeRight;
3175
+ else if (activeLeft < -curTblPos) tblPos = -activeLeft;
3176
+ }
3177
+ var markerPos = cell[offsetLeft] + (cell[offsetWidth] - marker[offsetWidth]) / 2 + tblPos;
3178
+ hs.animate(table, isX ? { left: tblPos } : { top: tblPos }, null, 'easeOutQuad');
3179
+ hs.animate(marker, isX ? { left: markerPos } : { top: markerPos }, null, 'easeOutQuad');
3180
+ scrollUp.style.display = tblPos < 0 ? 'block' : 'none';
3181
+ scrollDown.style.display = (tblPos > minTblPos) ? 'block' : 'none';
3182
+
3183
+ };
3184
+
3185
+
3186
+ // initialize
3187
+ var group = hs.anchors.groups[hs.expanders[slideshow.expKey].slideshowGroup || 'none'],
3188
+ options = slideshow.thumbstrip,
3189
+ mode = options.mode || 'horizontal',
3190
+ floatMode = (mode == 'float'),
3191
+ tree = floatMode ? ['div', 'ul', 'li', 'span'] : ['table', 'tbody', 'tr', 'td'],
3192
+ isX = (mode == 'horizontal'),
3193
+ dom = hs.createElement('div', {
3194
+ className: 'highslide-thumbstrip highslide-thumbstrip-'+ mode,
3195
+ innerHTML:
3196
+ '<div class="highslide-thumbstrip-inner">'+
3197
+ '<'+ tree[0] +'><'+ tree[1] +'></'+ tree[1] +'></'+ tree[0] +'></div>'+
3198
+ '<div class="highslide-scroll-up"><div></div></div>'+
3199
+ '<div class="highslide-scroll-down"><div></div></div>'+
3200
+ '<div class="highslide-marker"><div></div></div>'
3201
+ }, {
3202
+ display: 'none'
3203
+ }, hs.container),
3204
+ domCh = dom.childNodes,
3205
+ div = domCh[0],
3206
+ scrollUp = domCh[1],
3207
+ scrollDown = domCh[2],
3208
+ marker = domCh[3],
3209
+ table = div.firstChild,
3210
+ tbody = dom.getElementsByTagName(tree[1])[0],
3211
+ tr;
3212
+ for (var i = 0; i < group.length; i++) {
3213
+ if (i == 0 || !isX) tr = hs.createElement(tree[2], null, null, tbody);
3214
+ (function(){
3215
+ var a = group[i],
3216
+ cell = hs.createElement(tree[3], null, null, tr),
3217
+ pI = i;
3218
+ hs.createElement('a', {
3219
+ href: a.href,
3220
+ title: a.title,
3221
+ onclick: function() {
3222
+ if (/highslide-active-anchor/.test(this.className)) return false;
3223
+ hs.getExpander(this).focus();
3224
+ return hs.transit(a);
3225
+ },
3226
+ innerHTML: hs.stripItemFormatter ? hs.stripItemFormatter(a) : a.innerHTML
3227
+ }, null, cell);
3228
+ })();
3229
+ }
3230
+ if (!floatMode) {
3231
+ scrollUp.onclick = function () { scroll(-1); };
3232
+ scrollDown.onclick = function() { scroll(1); };
3233
+ hs.addEventListener(tbody, document.onmousewheel !== undefined ?
3234
+ 'mousewheel' : 'DOMMouseScroll', function(e) {
3235
+ var delta = 0;
3236
+ e = e || window.event;
3237
+ if (e.wheelDelta) {
3238
+ delta = e.wheelDelta/120;
3239
+ if (hs.opera) delta = -delta;
3240
+ } else if (e.detail) {
3241
+ delta = -e.detail/3;
3242
+ }
3243
+ if (delta) scroll(-delta * 0.2);
3244
+ if (e.preventDefault) e.preventDefault();
3245
+ e.returnValue = false;
3246
+ });
3247
+ }
3248
+
3249
+ return {
3250
+ add: add,
3251
+ selectThumb: selectThumb
3252
+ }
3253
+ };
3254
+ hs.langDefaults = hs.lang;
3255
+ // history
3256
+ var HsExpander = hs.Expander;
3257
+ if (hs.ie && window == window.top) {
3258
+ (function () {
3259
+ try {
3260
+ document.documentElement.doScroll('left');
3261
+ } catch (e) {
3262
+ setTimeout(arguments.callee, 50);
3263
+ return;
3264
+ }
3265
+ hs.ready();
3266
+ })();
3267
+ }
3268
+ hs.addEventListener(document, 'DOMContentLoaded', hs.ready);
3269
+ hs.addEventListener(window, 'load', hs.ready);
3270
+
3271
+ // set handlers
3272
+ hs.addEventListener(document, 'ready', function() {
3273
+ if (hs.expandCursor || hs.dimmingOpacity) {
3274
+ var style = hs.createElement('style', { type: 'text/css' }, null,
3275
+ document.getElementsByTagName('HEAD')[0]),
3276
+ backCompat = document.compatMode == 'BackCompat';
3277
+
3278
+
3279
+ function addRule(sel, dec) {
3280
+ if (hs.ie && (hs.uaVersion < 9 || backCompat)) {
3281
+ var last = document.styleSheets[document.styleSheets.length - 1];
3282
+ if (typeof(last.addRule) == "object") last.addRule(sel, dec);
3283
+ } else {
3284
+ style.appendChild(document.createTextNode(sel + " {" + dec + "}"));
3285
+ }
3286
+ }
3287
+ function fix(prop) {
3288
+ return 'expression( ( ( ignoreMe = document.documentElement.'+ prop +
3289
+ ' ? document.documentElement.'+ prop +' : document.body.'+ prop +' ) ) + \'px\' );';
3290
+ }
3291
+ if (hs.expandCursor) addRule ('.highslide img',
3292
+ 'cursor: url('+ hs.graphicsDir + hs.expandCursor +'), pointer !important;');
3293
+ addRule ('.highslide-viewport-size',
3294
+ hs.ie && (hs.uaVersion < 7 || backCompat) ?
3295
+ 'position: absolute; '+
3296
+ 'left:'+ fix('scrollLeft') +
3297
+ 'top:'+ fix('scrollTop') +
3298
+ 'width:'+ fix('clientWidth') +
3299
+ 'height:'+ fix('clientHeight') :
3300
+ 'position: fixed; width: 100%; height: 100%; left: 0; top: 0');
3301
+ }
3302
+ });
3303
+ hs.addEventListener(window, 'resize', function() {
3304
+ hs.getPageSize();
3305
+ if (hs.viewport) for (var i = 0; i < hs.viewport.childNodes.length; i++) {
3306
+ var node = hs.viewport.childNodes[i],
3307
+ exp = hs.getExpander(node);
3308
+ exp.positionOverlay(node);
3309
+ if (node.hsId == 'thumbstrip') exp.slideshow.thumbstrip.selectThumb();
3310
+ }
3311
+ });
3312
+ hs.addEventListener(document, 'mousemove', function(e) {
3313
+ hs.mouse = { x: e.clientX, y: e.clientY };
3314
+ });
3315
+ hs.addEventListener(document, 'mousedown', hs.mouseClickHandler);
3316
+ hs.addEventListener(document, 'mouseup', hs.mouseClickHandler);
3317
+ hs.addEventListener(document, 'ready', hs.setClickEvents);
3318
+ hs.addEventListener(window, 'load', hs.preloadImages);
3319
+ hs.addEventListener(window, 'load', hs.preloadAjax);
3320
+ }
products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-full.min.js ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Name: Highslide JS
3
+ * Version: 4.1.13 (2011-10-06)
4
+ * Config: default +events +unobtrusive +imagemap +slideshow +positioning +transitions +viewport +thumbstrip +inline +ajax +iframe +flash
5
+ * Author: Torstein Hønsi
6
+ * Support: www.highslide.com/support
7
+ * License: www.highslide.com/#license
8
+ */
9
+ if(!hs){var hs={lang:{cssDirection:"ltr",loadingText:"Loading...",loadingTitle:"Click to cancel",focusTitle:"Click to bring to front",fullExpandTitle:"Expand to actual size (f)",creditsText:"Powered by <i>Highslide JS</i>",creditsTitle:"Go to the Highslide JS homepage",previousText:"Previous",nextText:"Next",moveText:"Move",closeText:"Close",closeTitle:"Close (esc)",resizeTitle:"Resize",playText:"Play",playTitle:"Play slideshow (spacebar)",pauseText:"Pause",pauseTitle:"Pause slideshow (spacebar)",previousTitle:"Previous (arrow left)",nextTitle:"Next (arrow right)",moveTitle:"Move",fullExpandText:"1:1",number:"Image %1 of %2",restoreTitle:"Click to close image, click and drag to move. Use arrow keys for next and previous."},graphicsDir:"highslide/graphics/",expandCursor:"zoomin.cur",restoreCursor:"zoomout.cur",expandDuration:250,restoreDuration:250,marginLeft:15,marginRight:15,marginTop:15,marginBottom:15,zIndexCounter:10001,loadingOpacity:0.75,allowMultipleInstances:true,numberOfImagesToPreload:5,outlineWhileAnimating:2,outlineStartOffset:3,padToMinWidth:false,fullExpandPosition:"bottom right",fullExpandOpacity:1,showCredits:true,creditsHref:"http://highslide.com/",creditsTarget:"_self",enableKeyListener:true,openerTagNames:["a","area"],transitions:[],transitionDuration:250,dimmingOpacity:0,dimmingDuration:50,allowWidthReduction:false,allowHeightReduction:true,preserveContent:true,objectLoadTime:"before",cacheAjax:true,anchor:"auto",align:"auto",targetX:null,targetY:null,dragByHeading:true,minWidth:200,minHeight:200,allowSizeReduction:true,outlineType:"drop-shadow",skin:{controls:'<div class="highslide-controls"><ul><li class="highslide-previous"><a href="#" title="{hs.lang.previousTitle}"><span>{hs.lang.previousText}</span></a></li><li class="highslide-play"><a href="#" title="{hs.lang.playTitle}"><span>{hs.lang.playText}</span></a></li><li class="highslide-pause"><a href="#" title="{hs.lang.pauseTitle}"><span>{hs.lang.pauseText}</span></a></li><li class="highslide-next"><a href="#" title="{hs.lang.nextTitle}"><span>{hs.lang.nextText}</span></a></li><li class="highslide-move"><a href="#" title="{hs.lang.moveTitle}"><span>{hs.lang.moveText}</span></a></li><li class="highslide-full-expand"><a href="#" title="{hs.lang.fullExpandTitle}"><span>{hs.lang.fullExpandText}</span></a></li><li class="highslide-close"><a href="#" title="{hs.lang.closeTitle}" ><span>{hs.lang.closeText}</span></a></li></ul></div>',contentWrapper:'<div class="highslide-header"><ul><li class="highslide-previous"><a href="#" title="{hs.lang.previousTitle}" onclick="return hs.previous(this)"><span>{hs.lang.previousText}</span></a></li><li class="highslide-next"><a href="#" title="{hs.lang.nextTitle}" onclick="return hs.next(this)"><span>{hs.lang.nextText}</span></a></li><li class="highslide-move"><a href="#" title="{hs.lang.moveTitle}" onclick="return false"><span>{hs.lang.moveText}</span></a></li><li class="highslide-close"><a href="#" title="{hs.lang.closeTitle}" onclick="return hs.close(this)"><span>{hs.lang.closeText}</span></a></li></ul></div><div class="highslide-body"></div><div class="highslide-footer"><div><span class="highslide-resize" title="{hs.lang.resizeTitle}"><span></span></span></div></div>'},preloadTheseImages:[],continuePreloading:true,expanders:[],overrides:["allowSizeReduction","useBox","anchor","align","targetX","targetY","outlineType","outlineWhileAnimating","captionId","captionText","captionEval","captionOverlay","headingId","headingText","headingEval","headingOverlay","creditsPosition","dragByHeading","autoplay","numberPosition","transitions","dimmingOpacity","width","height","contentId","allowWidthReduction","allowHeightReduction","preserveContent","maincontentId","maincontentText","maincontentEval","objectType","cacheAjax","objectWidth","objectHeight","objectLoadTime","swfOptions","wrapperClassName","minWidth","minHeight","maxWidth","maxHeight","pageOrigin","slideshowGroup","easing","easingClose","fadeInOut","src"],overlays:[],idCounter:0,oPos:{x:["leftpanel","left","center","right","rightpanel"],y:["above","top","middle","bottom","below"]},mouse:{},headingOverlay:{},captionOverlay:{},swfOptions:{flashvars:{},params:{},attributes:{}},timers:[],slideshows:[],pendingOutlines:{},sleeping:[],preloadTheseAjax:[],cacheBindings:[],cachedGets:{},clones:{},onReady:[],uaVersion:/Trident\/4\.0/.test(navigator.userAgent)?8:parseFloat((navigator.userAgent.toLowerCase().match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1]),ie:(document.all&&!window.opera),safari:/Safari/.test(navigator.userAgent),geckoMac:/Macintosh.+rv:1\.[0-8].+Gecko/.test(navigator.userAgent),$:function(a){if(a){return document.getElementById(a)}},push:function(a,b){a[a.length]=b},createElement:function(a,f,e,d,c){var b=document.createElement(a);if(f){hs.extend(b,f)}if(c){hs.setStyles(b,{padding:0,border:"none",margin:0})}if(e){hs.setStyles(b,e)}if(d){d.appendChild(b)}return b},extend:function(b,c){for(var a in c){b[a]=c[a]}return b},setStyles:function(b,c){for(var a in c){if(hs.ieLt9&&a=="opacity"){if(c[a]>0.99){b.style.removeAttribute("filter")}else{b.style.filter="alpha(opacity="+(c[a]*100)+")"}}else{b.style[a]=c[a]}}},animate:function(f,a,d){var c,g,j;if(typeof d!="object"||d===null){var i=arguments;d={duration:i[2],easing:i[3],complete:i[4]}}if(typeof d.duration!="number"){d.duration=250}d.easing=Math[d.easing]||Math.easeInQuad;d.curAnim=hs.extend({},a);for(var b in a){var h=new hs.fx(f,d,b);c=parseFloat(hs.css(f,b))||0;g=parseFloat(a[b]);j=b!="opacity"?"px":"";h.custom(c,g,j)}},css:function(a,c){if(a.style[c]){return a.style[c]}else{if(document.defaultView){return document.defaultView.getComputedStyle(a,null).getPropertyValue(c)}else{if(c=="opacity"){c="filter"}var b=a.currentStyle[c.replace(/\-(\w)/g,function(e,d){return d.toUpperCase()})];if(c=="filter"){b=b.replace(/alpha\(opacity=([0-9]+)\)/,function(e,d){return d/100})}return b===""?1:b}}},getPageSize:function(){var f=document,b=window,e=f.compatMode&&f.compatMode!="BackCompat"?f.documentElement:f.body,g=hs.ie&&(hs.uaVersion<9||typeof pageXOffset=="undefined");var c=g?e.clientWidth:(f.documentElement.clientWidth||self.innerWidth),a=g?e.clientHeight:self.innerHeight;hs.page={width:c,height:a,scrollLeft:g?e.scrollLeft:pageXOffset,scrollTop:g?e.scrollTop:pageYOffset};return hs.page},getPosition:function(c){if(/area/i.test(c.tagName)){var e=document.getElementsByTagName("img");for(var b=0;b<e.length;b++){var a=e[b].useMap;if(a&&a.replace(/^.*?#/,"")==c.parentNode.name){c=e[b];break}}}var d={x:c.offsetLeft,y:c.offsetTop};while(c.offsetParent){c=c.offsetParent;d.x+=c.offsetLeft;d.y+=c.offsetTop;if(c!=document.body&&c!=document.documentElement){d.x-=c.scrollLeft;d.y-=c.scrollTop}}return d},expand:function(b,h,f,d){if(!b){b=hs.createElement("a",null,{display:"none"},hs.container)}if(typeof b.getParams=="function"){return h}if(d=="html"){for(var c=0;c<hs.sleeping.length;c++){if(hs.sleeping[c]&&hs.sleeping[c].a==b){hs.sleeping[c].awake();hs.sleeping[c]=null;return false}}hs.hasHtmlExpanders=true}try{new hs.Expander(b,h,f,d);return false}catch(g){return true}},htmlExpand:function(b,d,c){return hs.expand(b,d,c,"html")},getSelfRendered:function(){return hs.createElement("div",{className:"highslide-html-content",innerHTML:hs.replaceLang(hs.skin.contentWrapper)})},getElementByClass:function(e,c,d){var b=e.getElementsByTagName(c);for(var a=0;a<b.length;a++){if((new RegExp(d)).test(b[a].className)){return b[a]}}return null},replaceLang:function(c){c=c.replace(/\s/g," ");var b=/{hs\.lang\.([^}]+)\}/g,d=c.match(b),e;if(d){for(var a=0;a<d.length;a++){e=d[a].replace(b,"$1");if(typeof hs.lang[e]!="undefined"){c=c.replace(d[a],hs.lang[e])}}}return c},setClickEvents:function(){var b=document.getElementsByTagName("a");for(var a=0;a<b.length;a++){var c=hs.isUnobtrusiveAnchor(b[a]);if(c&&!b[a].hsHasSetClick){(function(){var d=c;if(hs.fireEvent(hs,"onSetClickEvent",{element:b[a],type:d})){b[a].onclick=(c=="image")?function(){return hs.expand(this)}:function(){return hs.htmlExpand(this,{objectType:d})}}})();b[a].hsHasSetClick=true}}hs.getAnchors()},isUnobtrusiveAnchor:function(a){if(a.rel=="highslide"){return"image"}else{if(a.rel=="highslide-ajax"){return"ajax"}else{if(a.rel=="highslide-iframe"){return"iframe"}else{if(a.rel=="highslide-swf"){return"swf"}}}}},getCacheBinding:function(b){for(var d=0;d<hs.cacheBindings.length;d++){if(hs.cacheBindings[d][0]==b){var e=hs.cacheBindings[d][1];hs.cacheBindings[d][1]=e.cloneNode(1);return e}}return null},preloadAjax:function(f){var b=hs.getAnchors();for(var d=0;d<b.htmls.length;d++){var c=b.htmls[d];if(hs.getParam(c,"objectType")=="ajax"&&hs.getParam(c,"cacheAjax")){hs.push(hs.preloadTheseAjax,c)}}hs.preloadAjaxElement(0)},preloadAjaxElement:function(d){if(!hs.preloadTheseAjax[d]){return}var b=hs.preloadTheseAjax[d];var c=hs.getNode(hs.getParam(b,"contentId"));if(!c){c=hs.getSelfRendered()}var e=new hs.Ajax(b,c,1);e.onError=function(){};e.onLoad=function(){hs.push(hs.cacheBindings,[b,c]);hs.preloadAjaxElement(d+1)};e.run()},focusTopmost:function(){var c=0,b=-1,a=hs.expanders,e,f;for(var d=0;d<a.length;d++){e=a[d];if(e){f=e.wrapper.style.zIndex;if(f&&f>c){c=f;b=d}}}if(b==-1){hs.focusKey=-1}else{a[b].focus()}},getParam:function(b,d){b.getParams=b.onclick;var c=b.getParams?b.getParams():null;b.getParams=null;return(c&&typeof c[d]!="undefined")?c[d]:(typeof hs[d]!="undefined"?hs[d]:null)},getSrc:function(b){var c=hs.getParam(b,"src");if(c){return c}return b.href},getNode:function(e){var c=hs.$(e),d=hs.clones[e],b={};if(!c&&!d){return null}if(!d){d=c.cloneNode(true);d.id="";hs.clones[e]=d;return c}else{return d.cloneNode(true)}},discardElement:function(a){if(a){hs.garbageBin.appendChild(a)}hs.garbageBin.innerHTML=""},dim:function(d){if(!hs.dimmer){a=true;hs.dimmer=hs.createElement("div",{className:"highslide-dimming highslide-viewport-size",owner:"",onclick:function(){if(hs.fireEvent(hs,"onDimmerClick")){hs.close()}}},{visibility:"visible",opacity:0},hs.container,true);if(/(Android|iPad|iPhone|iPod)/.test(navigator.userAgent)){var b=document.body;function c(){hs.setStyles(hs.dimmer,{width:b.scrollWidth+"px",height:b.scrollHeight+"px"})}c();hs.addEventListener(window,"resize",c)}}hs.dimmer.style.display="";var a=hs.dimmer.owner=="";hs.dimmer.owner+="|"+d.key;if(a){if(hs.geckoMac&&hs.dimmingGeckoFix){hs.setStyles(hs.dimmer,{background:"url("+hs.graphicsDir+"geckodimmer.png)",opacity:1})}else{hs.animate(hs.dimmer,{opacity:d.dimmingOpacity},hs.dimmingDuration)}}},undim:function(a){if(!hs.dimmer){return}if(typeof a!="undefined"){hs.dimmer.owner=hs.dimmer.owner.replace("|"+a,"")}if((typeof a!="undefined"&&hs.dimmer.owner!="")||(hs.upcoming&&hs.getParam(hs.upcoming,"dimmingOpacity"))){return}if(hs.geckoMac&&hs.dimmingGeckoFix){hs.dimmer.style.display="none"}else{hs.animate(hs.dimmer,{opacity:0},hs.dimmingDuration,null,function(){hs.dimmer.style.display="none"})}},transit:function(a,d){var b=d||hs.getExpander();d=b;if(hs.upcoming){return false}else{hs.last=b}hs.removeEventListener(document,window.opera?"keypress":"keydown",hs.keyHandler);try{hs.upcoming=a;a.onclick()}catch(c){hs.last=hs.upcoming=null}try{if(!a||d.transitions[1]!="crossfade"){d.close()}}catch(c){}return false},previousOrNext:function(a,c){var b=hs.getExpander(a);if(b){return hs.transit(b.getAdjacentAnchor(c),b)}else{return false}},previous:function(a){return hs.previousOrNext(a,-1)},next:function(a){return hs.previousOrNext(a,1)},keyHandler:function(a){if(!a){a=window.event}if(!a.target){a.target=a.srcElement}if(typeof a.target.form!="undefined"){return true}if(!hs.fireEvent(hs,"onKeyDown",a)){return true}var b=hs.getExpander();var c=null;switch(a.keyCode){case 70:if(b){b.doFullExpand()}return true;case 32:c=2;break;case 34:case 39:case 40:c=1;break;case 8:case 33:case 37:case 38:c=-1;break;case 27:case 13:c=0}if(c!==null){if(c!=2){hs.removeEventListener(document,window.opera?"keypress":"keydown",hs.keyHandler)}if(!hs.enableKeyListener){return true}if(a.preventDefault){a.preventDefault()}else{a.returnValue=false}if(b){if(c==0){b.close()}else{if(c==2){if(b.slideshow){b.slideshow.hitSpace()}}else{if(b.slideshow){b.slideshow.pause()}hs.previousOrNext(b.key,c)}}return false}}return true},registerOverlay:function(a){hs.push(hs.overlays,hs.extend(a,{hsId:"hsId"+hs.idCounter++}))},addSlideshow:function(b){var d=b.slideshowGroup;if(typeof d=="object"){for(var c=0;c<d.length;c++){var e={};for(var a in b){e[a]=b[a]}e.slideshowGroup=d[c];hs.push(hs.slideshows,e)}}else{hs.push(hs.slideshows,b)}},getWrapperKey:function(c,b){var e,d=/^highslide-wrapper-([0-9]+)$/;e=c;while(e.parentNode){if(e.hsKey!==undefined){return e.hsKey}if(e.id&&d.test(e.id)){return e.id.replace(d,"$1")}e=e.parentNode}if(!b){e=c;while(e.parentNode){if(e.tagName&&hs.isHsAnchor(e)){for(var a=0;a<hs.expanders.length;a++){var f=hs.expanders[a];if(f&&f.a==e){return a}}}e=e.parentNode}}return null},getExpander:function(b,a){if(typeof b=="undefined"){return hs.expanders[hs.focusKey]||null}if(typeof b=="number"){return hs.expanders[b]||null}if(typeof b=="string"){b=hs.$(b)}return hs.expanders[hs.getWrapperKey(b,a)]||null},isHsAnchor:function(b){return(b.onclick&&b.onclick.toString().replace(/\s/g," ").match(/hs.(htmlE|e)xpand/))},reOrder:function(){for(var a=0;a<hs.expanders.length;a++){if(hs.expanders[a]&&hs.expanders[a].isExpanded){hs.focusTopmost()}}},fireEvent:function(c,a,b){return c&&c[a]?(c[a](c,b)!==false):true},mouseClickHandler:function(d){if(!d){d=window.event}if(d.button>1){return true}if(!d.target){d.target=d.srcElement}var b=d.target;while(b.parentNode&&!(/highslide-(image|move|html|resize)/.test(b.className))){b=b.parentNode}var f=hs.getExpander(b);if(f&&(f.isClosing||!f.isExpanded)){return true}if(f&&d.type=="mousedown"){if(d.target.form){return true}var a=b.className.match(/highslide-(image|move|resize)/);if(a){hs.dragArgs={exp:f,type:a[1],left:f.x.pos,width:f.x.size,top:f.y.pos,height:f.y.size,clickX:d.clientX,clickY:d.clientY};hs.addEventListener(document,"mousemove",hs.dragHandler);if(d.preventDefault){d.preventDefault()}if(/highslide-(image|html)-blur/.test(f.content.className)){f.focus();hs.hasFocused=true}return false}else{if(/highslide-html/.test(b.className)&&hs.focusKey!=f.key){f.focus();f.doShowHide("hidden")}}}else{if(d.type=="mouseup"){hs.removeEventListener(document,"mousemove",hs.dragHandler);if(hs.dragArgs){if(hs.styleRestoreCursor&&hs.dragArgs.type=="image"){hs.dragArgs.exp.content.style.cursor=hs.styleRestoreCursor}var c=hs.dragArgs.hasDragged;if(!c&&!hs.hasFocused&&!/(move|resize)/.test(hs.dragArgs.type)){if(hs.fireEvent(f,"onImageClick")){f.close()}}else{if(c||(!c&&hs.hasHtmlExpanders)){hs.dragArgs.exp.doShowHide("hidden")}}if(hs.dragArgs.exp.releaseMask){hs.dragArgs.exp.releaseMask.style.display="none"}if(c){hs.fireEvent(hs.dragArgs.exp,"onDrop",hs.dragArgs)}hs.hasFocused=false;hs.dragArgs=null}else{if(/highslide-image-blur/.test(b.className)){b.style.cursor=hs.styleRestoreCursor}}}}return false},dragHandler:function(c){if(!hs.dragArgs){return true}if(!c){c=window.event}var b=hs.dragArgs,d=b.exp;if(d.iframe){if(!d.releaseMask){d.releaseMask=hs.createElement("div",null,{position:"absolute",width:d.x.size+"px",height:d.y.size+"px",left:d.x.cb+"px",top:d.y.cb+"px",zIndex:4,background:(hs.ieLt9?"white":"none"),opacity:0.01},d.wrapper,true)}if(d.releaseMask.style.display=="none"){d.releaseMask.style.display=""}}b.dX=c.clientX-b.clickX;b.dY=c.clientY-b.clickY;var f=Math.sqrt(Math.pow(b.dX,2)+Math.pow(b.dY,2));if(!b.hasDragged){b.hasDragged=(b.type!="image"&&f>0)||(f>(hs.dragSensitivity||5))}if(b.hasDragged&&c.clientX>5&&c.clientY>5){if(!hs.fireEvent(d,"onDrag",b)){return false}if(b.type=="resize"){d.resize(b)}else{d.moveTo(b.left+b.dX,b.top+b.dY);if(b.type=="image"){d.content.style.cursor="move"}}}return false},wrapperMouseHandler:function(c){try{if(!c){c=window.event}var b=/mouseover/i.test(c.type);if(!c.target){c.target=c.srcElement}if(!c.relatedTarget){c.relatedTarget=b?c.fromElement:c.toElement}var d=hs.getExpander(c.target);if(!d.isExpanded){return}if(!d||!c.relatedTarget||hs.getExpander(c.relatedTarget,true)==d||hs.dragArgs){return}hs.fireEvent(d,b?"onMouseOver":"onMouseOut",c);for(var a=0;a<d.overlays.length;a++){(function(){var e=hs.$("hsId"+d.overlays[a]);if(e&&e.hideOnMouseOut){if(b){hs.setStyles(e,{visibility:"visible",display:""})}hs.animate(e,{opacity:b?e.opacity:0},e.dur)}})()}}catch(c){}},addEventListener:function(a,c,b){if(a==document&&c=="ready"){hs.push(hs.onReady,b)}try{a.addEventListener(c,b,false)}catch(d){try{a.detachEvent("on"+c,b);a.attachEvent("on"+c,b)}catch(d){a["on"+c]=b}}},removeEventListener:function(a,c,b){try{a.removeEventListener(c,b,false)}catch(d){try{a.detachEvent("on"+c,b)}catch(d){a["on"+c]=null}}},preloadFullImage:function(b){if(hs.continuePreloading&&hs.preloadTheseImages[b]&&hs.preloadTheseImages[b]!="undefined"){var a=document.createElement("img");a.onload=function(){a=null;hs.preloadFullImage(b+1)};a.src=hs.preloadTheseImages[b]}},preloadImages:function(c){if(c&&typeof c!="object"){hs.numberOfImagesToPreload=c}var a=hs.getAnchors();for(var b=0;b<a.images.length&&b<hs.numberOfImagesToPreload;b++){hs.push(hs.preloadTheseImages,hs.getSrc(a.images[b]))}if(hs.outlineType){new hs.Outline(hs.outlineType,function(){hs.preloadFullImage(0)})}else{hs.preloadFullImage(0)}if(hs.restoreCursor){var d=hs.createElement("img",{src:hs.graphicsDir+hs.restoreCursor})}},init:function(){if(!hs.container){hs.ieLt7=hs.ie&&hs.uaVersion<7;hs.ieLt9=hs.ie&&hs.uaVersion<9;hs.getPageSize();hs.ie6SSL=hs.ieLt7&&location.protocol=="https:";for(var a in hs.langDefaults){if(typeof hs[a]!="undefined"){hs.lang[a]=hs[a]}else{if(typeof hs.lang[a]=="undefined"&&typeof hs.langDefaults[a]!="undefined"){hs.lang[a]=hs.langDefaults[a]}}}hs.container=hs.createElement("div",{className:"highslide-container"},{position:"absolute",left:0,top:0,width:"100%",zIndex:hs.zIndexCounter,direction:"ltr"},document.body,true);hs.loading=hs.createElement("a",{className:"highslide-loading",title:hs.lang.loadingTitle,innerHTML:hs.lang.loadingText,href:"javascript:;"},{position:"absolute",top:"-9999px",opacity:hs.loadingOpacity,zIndex:1},hs.container);hs.garbageBin=hs.createElement("div",null,{display:"none"},hs.container);hs.viewport=hs.createElement("div",{className:"highslide-viewport highslide-viewport-size"},{visibility:(hs.safari&&hs.uaVersion<525)?"visible":"hidden"},hs.container,1);hs.clearing=hs.createElement("div",null,{clear:"both",paddingTop:"1px"},null,true);Math.linearTween=function(f,e,h,g){return h*f/g+e};Math.easeInQuad=function(f,e,h,g){return h*(f/=g)*f+e};Math.easeOutQuad=function(f,e,h,g){return -h*(f/=g)*(f-2)+e};hs.hideSelects=hs.ieLt7;hs.hideIframes=((window.opera&&hs.uaVersion<9)||navigator.vendor=="KDE"||(hs.ieLt7&&hs.uaVersion<5.5));hs.fireEvent(this,"onActivate")}},ready:function(){if(hs.isReady){return}hs.isReady=true;for(var a=0;a<hs.onReady.length;a++){hs.onReady[a]()}},updateAnchors:function(){var a,d,l=[],h=[],k=[],b={},m;for(var e=0;e<hs.openerTagNames.length;e++){d=document.getElementsByTagName(hs.openerTagNames[e]);for(var c=0;c<d.length;c++){a=d[c];m=hs.isHsAnchor(a);if(m){hs.push(l,a);if(m[0]=="hs.expand"){hs.push(h,a)}else{if(m[0]=="hs.htmlExpand"){hs.push(k,a)}}var f=hs.getParam(a,"slideshowGroup")||"none";if(!b[f]){b[f]=[]}hs.push(b[f],a)}}}hs.anchors={all:l,groups:b,images:h,htmls:k};return hs.anchors},getAnchors:function(){return hs.anchors||hs.updateAnchors()},close:function(a){var b=hs.getExpander(a);if(b){b.close()}return false}};hs.fx=function(b,a,c){this.options=a;this.elem=b;this.prop=c;if(!a.orig){a.orig={}}};hs.fx.prototype={update:function(){(hs.fx.step[this.prop]||hs.fx.step._default)(this);if(this.options.step){this.options.step.call(this.elem,this.now,this)}},custom:function(e,d,c){this.startTime=(new Date()).getTime();this.start=e;this.end=d;this.unit=c;this.now=this.start;this.pos=this.state=0;var a=this;function b(f){return a.step(f)}b.elem=this.elem;if(b()&&hs.timers.push(b)==1){hs.timerId=setInterval(function(){var g=hs.timers;for(var f=0;f<g.length;f++){if(!g[f]()){g.splice(f--,1)}}if(!g.length){clearInterval(hs.timerId)}},13)}},step:function(d){var c=(new Date()).getTime();if(d||c>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var a=true;for(var b in this.options.curAnim){if(this.options.curAnim[b]!==true){a=false}}if(a){if(this.options.complete){this.options.complete.call(this.elem)}}return false}else{var e=c-this.startTime;this.state=e/this.options.duration;this.pos=this.options.easing(e,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};hs.extend(hs.fx,{step:{opacity:function(a){hs.setStyles(a.elem,{opacity:a.now})},_default:function(a){try{if(a.elem.style&&a.elem.style[a.prop]!=null){a.elem.style[a.prop]=a.now+a.unit}else{a.elem[a.prop]=a.now}}catch(b){}}}});hs.Outline=function(g,e){this.onLoad=e;this.outlineType=g;var a=hs.uaVersion,f;this.hasAlphaImageLoader=hs.ie&&hs.uaVersion<7;if(!g){if(e){e()}return}hs.init();this.table=hs.createElement("table",{cellSpacing:0},{visibility:"hidden",position:"absolute",borderCollapse:"collapse",width:0},hs.container,true);var b=hs.createElement("tbody",null,null,this.table,1);this.td=[];for(var c=0;c<=8;c++){if(c%3==0){f=hs.createElement("tr",null,{height:"auto"},b,true)}this.td[c]=hs.createElement("td",null,null,f,true);var d=c!=4?{lineHeight:0,fontSize:0}:{position:"relative"};hs.setStyles(this.td[c],d)}this.td[4].className=g+" highslide-outline";this.preloadGraphic()};hs.Outline.prototype={preloadGraphic:function(){var b=hs.graphicsDir+(hs.outlinesDir||"outlines/")+this.outlineType+".png";var a=hs.safari&&hs.uaVersion<525?hs.container:null;this.graphic=hs.createElement("img",null,{position:"absolute",top:"-9999px"},a,true);var c=this;this.graphic.onload=function(){c.onGraphicLoad()};this.graphic.src=b},onGraphicLoad:function(){var d=this.offset=this.graphic.width/4,f=[[0,0],[0,-4],[-2,0],[0,-8],0,[-2,-8],[0,-2],[0,-6],[-2,-2]],c={height:(2*d)+"px",width:(2*d)+"px"};for(var b=0;b<=8;b++){if(f[b]){if(this.hasAlphaImageLoader){var a=(b==1||b==7)?"100%":this.graphic.width+"px";var e=hs.createElement("div",null,{width:"100%",height:"100%",position:"relative",overflow:"hidden"},this.td[b],true);hs.createElement("div",null,{filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale, src='"+this.graphic.src+"')",position:"absolute",width:a,height:this.graphic.height+"px",left:(f[b][0]*d)+"px",top:(f[b][1]*d)+"px"},e,true)}else{hs.setStyles(this.td[b],{background:"url("+this.graphic.src+") "+(f[b][0]*d)+"px "+(f[b][1]*d)+"px"})}if(window.opera&&(b==3||b==5)){hs.createElement("div",null,c,this.td[b],true)}hs.setStyles(this.td[b],c)}}this.graphic=null;if(hs.pendingOutlines[this.outlineType]){hs.pendingOutlines[this.outlineType].destroy()}hs.pendingOutlines[this.outlineType]=this;if(this.onLoad){this.onLoad()}},setPosition:function(g,e,c,b,f){var d=this.exp,a=d.wrapper.style,e=e||0,g=g||{x:d.x.pos+e,y:d.y.pos+e,w:d.x.get("wsize")-2*e,h:d.y.get("wsize")-2*e};if(c){this.table.style.visibility=(g.h>=4*this.offset)?"visible":"hidden"}hs.setStyles(this.table,{left:(g.x-this.offset)+"px",top:(g.y-this.offset)+"px",width:(g.w+2*this.offset)+"px"});g.w-=2*this.offset;g.h-=2*this.offset;hs.setStyles(this.td[4],{width:g.w>=0?g.w+"px":0,height:g.h>=0?g.h+"px":0});if(this.hasAlphaImageLoader){this.td[3].style.height=this.td[5].style.height=this.td[4].style.height}},destroy:function(a){if(a){this.table.style.visibility="hidden"}else{hs.discardElement(this.table)}}};hs.Dimension=function(b,a){this.exp=b;this.dim=a;this.ucwh=a=="x"?"Width":"Height";this.wh=this.ucwh.toLowerCase();this.uclt=a=="x"?"Left":"Top";this.lt=this.uclt.toLowerCase();this.ucrb=a=="x"?"Right":"Bottom";this.rb=this.ucrb.toLowerCase();this.p1=this.p2=0};hs.Dimension.prototype={get:function(a){switch(a){case"loadingPos":return this.tpos+this.tb+(this.t-hs.loading["offset"+this.ucwh])/2;case"loadingPosXfade":return this.pos+this.cb+this.p1+(this.size-hs.loading["offset"+this.ucwh])/2;case"wsize":return this.size+2*this.cb+this.p1+this.p2;case"fitsize":return this.clientSize-this.marginMin-this.marginMax;case"maxsize":return this.get("fitsize")-2*this.cb-this.p1-this.p2;case"opos":return this.pos-(this.exp.outline?this.exp.outline.offset:0);case"osize":return this.get("wsize")+(this.exp.outline?2*this.exp.outline.offset:0);case"imgPad":return this.imgSize?Math.round((this.size-this.imgSize)/2):0}},calcBorders:function(){this.cb=(this.exp.content["offset"+this.ucwh]-this.t)/2;this.marginMax=hs["margin"+this.ucrb]},calcThumb:function(){this.t=this.exp.el[this.wh]?parseInt(this.exp.el[this.wh]):this.exp.el["offset"+this.ucwh];this.tpos=this.exp.tpos[this.dim];this.tb=(this.exp.el["offset"+this.ucwh]-this.t)/2;if(this.tpos==0||this.tpos==-1){this.tpos=(hs.page[this.wh]/2)+hs.page["scroll"+this.uclt]}},calcExpanded:function(){var a=this.exp;this.justify="auto";if(a.align=="center"){this.justify="center"}else{if(new RegExp(this.lt).test(a.anchor)){this.justify=null}else{if(new RegExp(this.rb).test(a.anchor)){this.justify="max"}}}this.pos=this.tpos-this.cb+this.tb;if(this.maxHeight&&this.dim=="x"){a.maxWidth=Math.min(a.maxWidth||this.full,a.maxHeight*this.full/a.y.full)}this.size=Math.min(this.full,a["max"+this.ucwh]||this.full);this.minSize=a.allowSizeReduction?Math.min(a["min"+this.ucwh],this.full):this.full;if(a.isImage&&a.useBox){this.size=a[this.wh];this.imgSize=this.full}if(this.dim=="x"&&hs.padToMinWidth){this.minSize=a.minWidth}this.target=a["target"+this.dim.toUpperCase()];this.marginMin=hs["margin"+this.uclt];this.scroll=hs.page["scroll"+this.uclt];this.clientSize=hs.page[this.wh]},setSize:function(a){var f=this.exp;if(f.isImage&&(f.useBox||hs.padToMinWidth)){this.imgSize=a;this.size=Math.max(this.size,this.imgSize);f.content.style[this.lt]=this.get("imgPad")+"px"}else{this.size=a}f.content.style[this.wh]=a+"px";f.wrapper.style[this.wh]=this.get("wsize")+"px";if(f.outline){f.outline.setPosition()}if(f.releaseMask){f.releaseMask.style[this.wh]=a+"px"}if(this.dim=="y"&&f.iDoc&&f.body.style.height!="auto"){try{f.iDoc.body.style.overflow="auto"}catch(b){}}if(f.isHtml){var c=f.scrollerDiv;if(this.sizeDiff===undefined){this.sizeDiff=f.innerContent["offset"+this.ucwh]-c["offset"+this.ucwh]}c.style[this.wh]=(this.size-this.sizeDiff)+"px";if(this.dim=="x"){f.mediumContent.style.width="auto"}if(f.body){f.body.style[this.wh]="auto"}}if(this.dim=="x"&&f.overlayBox){f.sizeOverlayBox(true)}if(this.dim=="x"&&f.slideshow&&f.isImage){if(a==this.full){f.slideshow.disable("full-expand")}else{f.slideshow.enable("full-expand")}}},setPos:function(a){this.pos=a;this.exp.wrapper.style[this.lt]=a+"px";if(this.exp.outline){this.exp.outline.setPosition()}}};hs.Expander=function(k,f,b,l){if(document.readyState&&hs.ie&&!hs.isReady){hs.addEventListener(document,"ready",function(){new hs.Expander(k,f,b,l)});return}this.a=k;this.custom=b;this.contentType=l||"image";this.isHtml=(l=="html");this.isImage=!this.isHtml;hs.continuePreloading=false;this.overlays=[];this.last=hs.last;hs.last=null;hs.init();var m=this.key=hs.expanders.length;for(var g=0;g<hs.overrides.length;g++){var c=hs.overrides[g];this[c]=f&&typeof f[c]!="undefined"?f[c]:hs[c]}if(!this.src){this.src=k.href}var d=(f&&f.thumbnailId)?hs.$(f.thumbnailId):k;d=this.thumb=d.getElementsByTagName("img")[0]||d;this.thumbsUserSetId=d.id||k.id;if(!hs.fireEvent(this,"onInit")){return true}for(var g=0;g<hs.expanders.length;g++){if(hs.expanders[g]&&hs.expanders[g].a==k&&!(this.last&&this.transitions[1]=="crossfade")){hs.expanders[g].focus();return false}}if(!hs.allowSimultaneousLoading){for(var g=0;g<hs.expanders.length;g++){if(hs.expanders[g]&&hs.expanders[g].thumb!=d&&!hs.expanders[g].onLoadStarted){hs.expanders[g].cancelLoading()}}}hs.expanders[m]=this;if(!hs.allowMultipleInstances&&!hs.upcoming){if(hs.expanders[m-1]){hs.expanders[m-1].close()}if(typeof hs.focusKey!="undefined"&&hs.expanders[hs.focusKey]){hs.expanders[hs.focusKey].close()}}this.el=d;this.tpos=this.pageOrigin||hs.getPosition(d);hs.getPageSize();var j=this.x=new hs.Dimension(this,"x");j.calcThumb();var h=this.y=new hs.Dimension(this,"y");h.calcThumb();if(/area/i.test(d.tagName)){this.getImageMapAreaCorrection(d)}this.wrapper=hs.createElement("div",{id:"highslide-wrapper-"+this.key,className:"highslide-wrapper "+this.wrapperClassName},{visibility:"hidden",position:"absolute",zIndex:hs.zIndexCounter+=2},null,true);this.wrapper.onmouseover=this.wrapper.onmouseout=hs.wrapperMouseHandler;if(this.contentType=="image"&&this.outlineWhileAnimating==2){this.outlineWhileAnimating=0}if(!this.outlineType||(this.last&&this.isImage&&this.transitions[1]=="crossfade")){this[this.contentType+"Create"]()}else{if(hs.pendingOutlines[this.outlineType]){this.connectOutline();this[this.contentType+"Create"]()}else{this.showLoading();var e=this;new hs.Outline(this.outlineType,function(){e.connectOutline();e[e.contentType+"Create"]()})}}return true};hs.Expander.prototype={error:function(a){if(hs.debug){alert("Line "+a.lineNumber+": "+a.message)}else{window.location.href=this.src}},connectOutline:function(){var a=this.outline=hs.pendingOutlines[this.outlineType];a.exp=this;a.table.style.zIndex=this.wrapper.style.zIndex-1;hs.pendingOutlines[this.outlineType]=null},showLoading:function(){if(this.onLoadStarted||this.loading){return}this.loading=hs.loading;var c=this;this.loading.onclick=function(){c.cancelLoading()};if(!hs.fireEvent(this,"onShowLoading")){return}var c=this,a=this.x.get("loadingPos")+"px",b=this.y.get("loadingPos")+"px";if(!d&&this.last&&this.transitions[1]=="crossfade"){var d=this.last}if(d){a=d.x.get("loadingPosXfade")+"px";b=d.y.get("loadingPosXfade")+"px";this.loading.style.zIndex=hs.zIndexCounter++}setTimeout(function(){if(c.loading){hs.setStyles(c.loading,{left:a,top:b,zIndex:hs.zIndexCounter++})}},100)},imageCreate:function(){var b=this;var a=document.createElement("img");this.content=a;a.onload=function(){if(hs.expanders[b.key]){b.contentLoaded()}};if(hs.blockRightClick){a.oncontextmenu=function(){return false}}a.className="highslide-image";hs.setStyles(a,{visibility:"hidden",display:"block",position:"absolute",maxWidth:"9999px",zIndex:3});a.title=hs.lang.restoreTitle;if(hs.safari&&hs.uaVersion<525){hs.container.appendChild(a)}if(hs.ie&&hs.flushImgSize){a.src=null}a.src=this.src;this.showLoading()},htmlCreate:function(){if(!hs.fireEvent(this,"onBeforeGetContent")){return}this.content=hs.getCacheBinding(this.a);if(!this.content){this.content=hs.getNode(this.contentId)}if(!this.content){this.content=hs.getSelfRendered()}this.getInline(["maincontent"]);if(this.maincontent){var a=hs.getElementByClass(this.content,"div","highslide-body");if(a){a.appendChild(this.maincontent)}this.maincontent.style.display="block"}hs.fireEvent(this,"onAfterGetContent");var d=this.innerContent=this.content;if(/(swf|iframe)/.test(this.objectType)){this.setObjContainerSize(d)}hs.container.appendChild(this.wrapper);hs.setStyles(this.wrapper,{position:"static",padding:"0 "+hs.marginRight+"px 0 "+hs.marginLeft+"px"});this.content=hs.createElement("div",{className:"highslide-html"},{position:"relative",zIndex:3,height:0,overflow:"hidden"},this.wrapper);this.mediumContent=hs.createElement("div",null,null,this.content,1);this.mediumContent.appendChild(d);hs.setStyles(d,{position:"relative",display:"block",direction:hs.lang.cssDirection||""});if(this.width){d.style.width=this.width+"px"}if(this.height){hs.setStyles(d,{height:this.height+"px",overflow:"hidden"})}if(d.offsetWidth<this.minWidth){d.style.width=this.minWidth+"px"}if(this.objectType=="ajax"&&!hs.getCacheBinding(this.a)){this.showLoading();var c=this;var b=new hs.Ajax(this.a,d);b.src=this.src;b.onLoad=function(){if(hs.expanders[c.key]){c.contentLoaded()}};b.onError=function(){location.href=c.src};b.run()}else{if(this.objectType=="iframe"&&this.objectLoadTime=="before"){this.writeExtendedContent()}else{this.contentLoaded()}}},contentLoaded:function(){try{if(!this.content){return}this.content.onload=null;if(this.onLoadStarted){return}else{this.onLoadStarted=true}var j=this.x,g=this.y;if(this.loading){hs.setStyles(this.loading,{top:"-9999px"});this.loading=null;hs.fireEvent(this,"onHideLoading")}if(this.isImage){j.full=this.content.width;g.full=this.content.height;hs.setStyles(this.content,{width:j.t+"px",height:g.t+"px"});this.wrapper.appendChild(this.content);hs.container.appendChild(this.wrapper)}else{if(this.htmlGetSize){this.htmlGetSize()}}j.calcBorders();g.calcBorders();hs.setStyles(this.wrapper,{left:(j.tpos+j.tb-j.cb)+"px",top:(g.tpos+j.tb-g.cb)+"px"});this.initSlideshow();this.getOverlays();var f=j.full/g.full;j.calcExpanded();this.justify(j);g.calcExpanded();this.justify(g);if(this.isHtml){this.htmlSizeOperations()}if(this.overlayBox){this.sizeOverlayBox(0,1)}if(this.allowSizeReduction){if(this.isImage){this.correctRatio(f)}else{this.fitOverlayBox()}var k=this.slideshow;if(k&&this.last&&k.controls&&k.fixedControls){var h=k.overlayOptions.position||"",a;for(var c in hs.oPos){for(var b=0;b<5;b++){a=this[c];if(h.match(hs.oPos[c][b])){a.pos=this.last[c].pos+(this.last[c].p1-a.p1)+(this.last[c].size-a.size)*[0,0,0.5,1,1][b];if(k.fixedControls=="fit"){if(a.pos+a.size+a.p1+a.p2>a.scroll+a.clientSize-a.marginMax){a.pos=a.scroll+a.clientSize-a.size-a.marginMin-a.marginMax-a.p1-a.p2}if(a.pos<a.scroll+a.marginMin){a.pos=a.scroll+a.marginMin}}}}}}if(this.isImage&&this.x.full>(this.x.imgSize||this.x.size)){this.createFullExpand();if(this.overlays.length==1){this.sizeOverlayBox()}}}this.show()}catch(d){this.error(d)}},setObjContainerSize:function(a,d){var b=hs.getElementByClass(a,"DIV","highslide-body");if(/(iframe|swf)/.test(this.objectType)){if(this.objectWidth){b.style.width=this.objectWidth+"px"}if(this.objectHeight){b.style.height=this.objectHeight+"px"}}},writeExtendedContent:function(){if(this.hasExtendedContent){return}var f=this;this.body=hs.getElementByClass(this.innerContent,"DIV","highslide-body");if(this.objectType=="iframe"){this.showLoading();var g=hs.clearing.cloneNode(1);this.body.appendChild(g);this.newWidth=this.innerContent.offsetWidth;if(!this.objectWidth){this.objectWidth=g.offsetWidth}var c=this.innerContent.offsetHeight-this.body.offsetHeight,d=this.objectHeight||hs.page.height-c-hs.marginTop-hs.marginBottom,e=this.objectLoadTime=="before"?' onload="if (hs.expanders['+this.key+"]) hs.expanders["+this.key+'].contentLoaded()" ':"";this.body.innerHTML+='<iframe name="hs'+(new Date()).getTime()+'" frameborder="0" key="'+this.key+'" style="width:'+this.objectWidth+"px; height:"+d+'px" '+e+' src="'+this.src+'" ></iframe>';this.ruler=this.body.getElementsByTagName("div")[0];this.iframe=this.body.getElementsByTagName("iframe")[0];if(this.objectLoadTime=="after"){this.correctIframeSize()}}if(this.objectType=="swf"){this.body.id=this.body.id||"hs-flash-id-"+this.key;var b=this.swfOptions;if(!b.params){b.params={}}if(typeof b.params.wmode=="undefined"){b.params.wmode="transparent"}if(swfobject){swfobject.embedSWF(this.src,this.body.id,this.objectWidth,this.objectHeight,b.version||"7",b.expressInstallSwfurl,b.flashvars,b.params,b.attributes)}}this.hasExtendedContent=true},htmlGetSize:function(){if(this.iframe&&!this.objectHeight){this.iframe.style.height=this.body.style.height=this.getIframePageHeight()+"px"}this.innerContent.appendChild(hs.clearing);if(!this.x.full){this.x.full=this.innerContent.offsetWidth}this.y.full=this.innerContent.offsetHeight;this.innerContent.removeChild(hs.clearing);if(hs.ie&&this.newHeight>parseInt(this.innerContent.currentStyle.height)){this.newHeight=parseInt(this.innerContent.currentStyle.height)}hs.setStyles(this.wrapper,{position:"absolute",padding:"0"});hs.setStyles(this.content,{width:this.x.t+"px",height:this.y.t+"px"})},getIframePageHeight:function(){var a;try{var d=this.iDoc=this.iframe.contentDocument||this.iframe.contentWindow.document;var b=d.createElement("div");b.style.clear="both";d.body.appendChild(b);a=b.offsetTop;if(hs.ie){a+=parseInt(d.body.currentStyle.marginTop)+parseInt(d.body.currentStyle.marginBottom)-1}}catch(c){a=300}return a},correctIframeSize:function(){var b=this.innerContent.offsetWidth-this.ruler.offsetWidth;hs.discardElement(this.ruler);if(b<0){b=0}var a=this.innerContent.offsetHeight-this.iframe.offsetHeight;if(this.iDoc&&!this.objectHeight&&!this.height&&this.y.size==this.y.full){try{this.iDoc.body.style.overflow="hidden"}catch(c){}}hs.setStyles(this.iframe,{width:Math.abs(this.x.size-b)+"px",height:Math.abs(this.y.size-a)+"px"});hs.setStyles(this.body,{width:this.iframe.style.width,height:this.iframe.style.height});this.scrollingContent=this.iframe;this.scrollerDiv=this.scrollingContent},htmlSizeOperations:function(){this.setObjContainerSize(this.innerContent);if(this.objectType=="swf"&&this.objectLoadTime=="before"){this.writeExtendedContent()}if(this.x.size<this.x.full&&!this.allowWidthReduction){this.x.size=this.x.full}if(this.y.size<this.y.full&&!this.allowHeightReduction){this.y.size=this.y.full}this.scrollerDiv=this.innerContent;hs.setStyles(this.mediumContent,{position:"relative",width:this.x.size+"px"});hs.setStyles(this.innerContent,{border:"none",width:"auto",height:"auto"});var e=hs.getElementByClass(this.innerContent,"DIV","highslide-body");if(e&&!/(iframe|swf)/.test(this.objectType)){var b=e;e=hs.createElement(b.nodeName,null,{overflow:"hidden"},null,true);b.parentNode.insertBefore(e,b);e.appendChild(hs.clearing);e.appendChild(b);var c=this.innerContent.offsetWidth-e.offsetWidth;var a=this.innerContent.offsetHeight-e.offsetHeight;e.removeChild(hs.clearing);var d=hs.safari||navigator.vendor=="KDE"?1:0;hs.setStyles(e,{width:(this.x.size-c-d)+"px",height:(this.y.size-a)+"px",overflow:"auto",position:"relative"});if(d&&b.offsetHeight>e.offsetHeight){e.style.width=(parseInt(e.style.width)+d)+"px"}this.scrollingContent=e;this.scrollerDiv=this.scrollingContent}if(this.iframe&&this.objectLoadTime=="before"){this.correctIframeSize()}if(!this.scrollingContent&&this.y.size<this.mediumContent.offsetHeight){this.scrollerDiv=this.content}if(this.scrollerDiv==this.content&&!this.allowWidthReduction&&!/(iframe|swf)/.test(this.objectType)){this.x.size+=17}if(this.scrollerDiv&&this.scrollerDiv.offsetHeight>this.scrollerDiv.parentNode.offsetHeight){setTimeout("try { hs.expanders["+this.key+"].scrollerDiv.style.overflow = 'auto'; } catch(e) {}",hs.expandDuration)}},getImageMapAreaCorrection:function(d){var h=d.coords.split(",");for(var b=0;b<h.length;b++){h[b]=parseInt(h[b])}if(d.shape.toLowerCase()=="circle"){this.x.tpos+=h[0]-h[2];this.y.tpos+=h[1]-h[2];this.x.t=this.y.t=2*h[2]}else{var f,e,a=f=h[0],g=e=h[1];for(var b=0;b<h.length;b++){if(b%2==0){a=Math.min(a,h[b]);f=Math.max(f,h[b])}else{g=Math.min(g,h[b]);e=Math.max(e,h[b])}}this.x.tpos+=a;this.x.t=f-a;this.y.tpos+=g;this.y.t=e-g}},justify:function(f,b){var g,h=f.target,e=f==this.x?"x":"y";if(h&&h.match(/ /)){g=h.split(" ");h=g[0]}if(h&&hs.$(h)){f.pos=hs.getPosition(hs.$(h))[e];if(g&&g[1]&&g[1].match(/^[-]?[0-9]+px$/)){f.pos+=parseInt(g[1])}if(f.size<f.minSize){f.size=f.minSize}}else{if(f.justify=="auto"||f.justify=="center"){var d=false;var a=f.exp.allowSizeReduction;if(f.justify=="center"){f.pos=Math.round(f.scroll+(f.clientSize+f.marginMin-f.marginMax-f.get("wsize"))/2)}else{f.pos=Math.round(f.pos-((f.get("wsize")-f.t)/2))}if(f.pos<f.scroll+f.marginMin){f.pos=f.scroll+f.marginMin;d=true}if(!b&&f.size<f.minSize){f.size=f.minSize;a=false}if(f.pos+f.get("wsize")>f.scroll+f.clientSize-f.marginMax){if(!b&&d&&a){f.size=Math.min(f.size,f.get(e=="y"?"fitsize":"maxsize"))}else{if(f.get("wsize")<f.get("fitsize")){f.pos=f.scroll+f.clientSize-f.marginMax-f.get("wsize")}else{f.pos=f.scroll+f.marginMin;if(!b&&a){f.size=f.get(e=="y"?"fitsize":"maxsize")}}}}if(!b&&f.size<f.minSize){f.size=f.minSize;a=false}}else{if(f.justify=="max"){f.pos=Math.floor(f.pos-f.size+f.t)}}}if(f.pos<f.marginMin){var c=f.pos;f.pos=f.marginMin;if(a&&!b){f.size=f.size-(f.pos-c)}}},correctRatio:function(c){var a=this.x,g=this.y,e=false,d=Math.min(a.full,a.size),b=Math.min(g.full,g.size),f=(this.useBox||hs.padToMinWidth);if(d/b>c){d=b*c;if(d<a.minSize){d=a.minSize;b=d/c}e=true}else{if(d/b<c){b=d/c;e=true}}if(hs.padToMinWidth&&a.full<a.minSize){a.imgSize=a.full;g.size=g.imgSize=g.full}else{if(this.useBox){a.imgSize=d;g.imgSize=b}else{a.size=d;g.size=b}}e=this.fitOverlayBox(this.useBox?null:c,e);if(f&&g.size<g.imgSize){g.imgSize=g.size;a.imgSize=g.size*c}if(e||f){a.pos=a.tpos-a.cb+a.tb;a.minSize=a.size;this.justify(a,true);g.pos=g.tpos-g.cb+g.tb;g.minSize=g.size;this.justify(g,true);if(this.overlayBox){this.sizeOverlayBox()}}},fitOverlayBox:function(b,c){var a=this.x,d=this.y;if(this.overlayBox&&(this.isImage||this.allowHeightReduction)){while(d.size>this.minHeight&&a.size>this.minWidth&&d.get("wsize")>d.get("fitsize")){d.size-=10;if(b){a.size=d.size*b}this.sizeOverlayBox(0,1);c=true}}return c},reflow:function(){if(this.scrollerDiv){var a=/iframe/i.test(this.scrollerDiv.tagName)?(this.getIframePageHeight()+1)+"px":"auto";if(this.body){this.body.style.height=a}this.scrollerDiv.style.height=a;this.y.setSize(this.innerContent.offsetHeight)}},show:function(){var a=this.x,b=this.y;this.doShowHide("hidden");hs.fireEvent(this,"onBeforeExpand");if(this.slideshow&&this.slideshow.thumbstrip){this.slideshow.thumbstrip.selectThumb()}this.changeSize(1,{wrapper:{width:a.get("wsize"),height:b.get("wsize"),left:a.pos,top:b.pos},content:{left:a.p1+a.get("imgPad"),top:b.p1+b.get("imgPad"),width:a.imgSize||a.size,height:b.imgSize||b.size}},hs.expandDuration)},changeSize:function(d,i,b){var k=this.transitions,e=d?(this.last?this.last.a:null):hs.upcoming,j=(k[1]&&e&&hs.getParam(e,"transitions")[1]==k[1])?k[1]:k[0];if(this[j]&&j!="expand"){this[j](d,i);return}if(this.outline&&!this.outlineWhileAnimating){if(d){this.outline.setPosition()}else{this.outline.destroy((this.isHtml&&this.preserveContent))}}if(!d){this.destroyOverlays()}var c=this,h=c.x,g=c.y,f=this.easing;if(!d){f=this.easingClose||f}var a=d?function(){if(c.outline){c.outline.table.style.visibility="visible"}setTimeout(function(){c.afterExpand()},50)}:function(){c.afterClose()};if(d){hs.setStyles(this.wrapper,{width:h.t+"px",height:g.t+"px"})}if(d&&this.isHtml){hs.setStyles(this.wrapper,{left:(h.tpos-h.cb+h.tb)+"px",top:(g.tpos-g.cb+g.tb)+"px"})}if(this.fadeInOut){hs.setStyles(this.wrapper,{opacity:d?0:1});hs.extend(i.wrapper,{opacity:d})}hs.animate(this.wrapper,i.wrapper,{duration:b,easing:f,step:function(n,l){if(c.outline&&c.outlineWhileAnimating&&l.prop=="top"){var m=d?l.pos:1-l.pos;var o={w:h.t+(h.get("wsize")-h.t)*m,h:g.t+(g.get("wsize")-g.t)*m,x:h.tpos+(h.pos-h.tpos)*m,y:g.tpos+(g.pos-g.tpos)*m};c.outline.setPosition(o,0,1)}if(c.isHtml){if(l.prop=="left"){c.mediumContent.style.left=(h.pos-n)+"px"}if(l.prop=="top"){c.mediumContent.style.top=(g.pos-n)+"px"}}}});hs.animate(this.content,i.content,b,f,a);if(d){this.wrapper.style.visibility="visible";this.content.style.visibility="visible";if(this.isHtml){this.innerContent.style.visibility="visible"}this.a.className+=" highslide-active-anchor"}},fade:function(f,h){this.outlineWhileAnimating=false;var c=this,j=f?hs.expandDuration:0;if(f){hs.animate(this.wrapper,h.wrapper,0);hs.setStyles(this.wrapper,{opacity:0,visibility:"visible"});hs.animate(this.content,h.content,0);this.content.style.visibility="visible";hs.animate(this.wrapper,{opacity:1},j,null,function(){c.afterExpand()})}if(this.outline){this.outline.table.style.zIndex=this.wrapper.style.zIndex;var b=f||-1,d=this.outline.offset,a=f?3:d,g=f?d:3;for(var e=a;b*e<=b*g;e+=b,j+=25){(function(){var i=f?g-e:a-e;setTimeout(function(){c.outline.setPosition(0,i,1)},j)})()}}if(f){}else{setTimeout(function(){if(c.outline){c.outline.destroy(c.preserveContent)}c.destroyOverlays();hs.animate(c.wrapper,{opacity:0},hs.restoreDuration,null,function(){c.afterClose()})},j)}},crossfade:function(g,m,o){if(!g){return}var f=this,p=this.last,l=this.x,k=this.y,d=p.x,b=p.y,a=this.wrapper,i=this.content,c=this.overlayBox;hs.removeEventListener(document,"mousemove",hs.dragHandler);hs.setStyles(i,{width:(l.imgSize||l.size)+"px",height:(k.imgSize||k.size)+"px"});if(c){c.style.overflow="visible"}this.outline=p.outline;if(this.outline){this.outline.exp=f}p.outline=null;var h=hs.createElement("div",{className:"highslide-"+this.contentType},{position:"absolute",zIndex:4,overflow:"hidden",display:"none"});var j={oldImg:p,newImg:this};for(var e in j){this[e]=j[e].content.cloneNode(1);hs.setStyles(this[e],{position:"absolute",border:0,visibility:"visible"});h.appendChild(this[e])}a.appendChild(h);if(this.isHtml){hs.setStyles(this.mediumContent,{left:0,top:0})}if(c){c.className="";a.appendChild(c)}h.style.display="";p.content.style.display="none";if(hs.safari&&hs.uaVersion<525){this.wrapper.style.visibility="visible"}hs.animate(a,{width:l.size},{duration:hs.transitionDuration,step:function(u,r){var x=r.pos,q=1-x;var w,s={},t=["pos","size","p1","p2"];for(var v in t){w=t[v];s["x"+w]=Math.round(q*d[w]+x*l[w]);s["y"+w]=Math.round(q*b[w]+x*k[w]);s.ximgSize=Math.round(q*(d.imgSize||d.size)+x*(l.imgSize||l.size));s.ximgPad=Math.round(q*d.get("imgPad")+x*l.get("imgPad"));s.yimgSize=Math.round(q*(b.imgSize||b.size)+x*(k.imgSize||k.size));s.yimgPad=Math.round(q*b.get("imgPad")+x*k.get("imgPad"))}if(f.outline){f.outline.setPosition({x:s.xpos,y:s.ypos,w:s.xsize+s.xp1+s.xp2+2*l.cb,h:s.ysize+s.yp1+s.yp2+2*k.cb})}p.wrapper.style.clip="rect("+(s.ypos-b.pos)+"px, "+(s.xsize+s.xp1+s.xp2+s.xpos+2*d.cb-d.pos)+"px, "+(s.ysize+s.yp1+s.yp2+s.ypos+2*b.cb-b.pos)+"px, "+(s.xpos-d.pos)+"px)";hs.setStyles(i,{top:(s.yp1+k.get("imgPad"))+"px",left:(s.xp1+l.get("imgPad"))+"px",marginTop:(k.pos-s.ypos)+"px",marginLeft:(l.pos-s.xpos)+"px"});hs.setStyles(a,{top:s.ypos+"px",left:s.xpos+"px",width:(s.xp1+s.xp2+s.xsize+2*l.cb)+"px",height:(s.yp1+s.yp2+s.ysize+2*k.cb)+"px"});hs.setStyles(h,{width:(s.ximgSize||s.xsize)+"px",height:(s.yimgSize||s.ysize)+"px",left:(s.xp1+s.ximgPad)+"px",top:(s.yp1+s.yimgPad)+"px",visibility:"visible"});hs.setStyles(f.oldImg,{top:(b.pos-s.ypos+b.p1-s.yp1+b.get("imgPad")-s.yimgPad)+"px",left:(d.pos-s.xpos+d.p1-s.xp1+d.get("imgPad")-s.ximgPad)+"px"});hs.setStyles(f.newImg,{opacity:x,top:(k.pos-s.ypos+k.p1-s.yp1+k.get("imgPad")-s.yimgPad)+"px",left:(l.pos-s.xpos+l.p1-s.xp1+l.get("imgPad")-s.ximgPad)+"px"});if(c){hs.setStyles(c,{width:s.xsize+"px",height:s.ysize+"px",left:(s.xp1+l.cb)+"px",top:(s.yp1+k.cb)+"px"})}},complete:function(){a.style.visibility=i.style.visibility="visible";i.style.display="block";hs.discardElement(h);f.afterExpand();p.afterClose();f.last=null}})},reuseOverlay:function(d,c){if(!this.last){return false}for(var b=0;b<this.last.overlays.length;b++){var a=hs.$("hsId"+this.last.overlays[b]);if(a&&a.hsId==d.hsId){this.genOverlayBox();a.reuse=this.key;hs.push(this.overlays,this.last.overlays[b]);return true}}return false},afterExpand:function(){this.isExpanded=true;this.focus();if(this.isHtml&&this.objectLoadTime=="after"){this.writeExtendedContent()}if(this.iframe){try{var g=this,f=this.iframe.contentDocument||this.iframe.contentWindow.document;hs.addEventListener(f,"mousedown",function(){if(hs.focusKey!=g.key){g.focus()}})}catch(d){}if(hs.ie&&typeof this.isClosing!="boolean"){this.iframe.style.width=(this.objectWidth-1)+"px"}}if(this.dimmingOpacity){hs.dim(this)}if(hs.upcoming&&hs.upcoming==this.a){hs.upcoming=null}this.prepareNextOutline();var c=hs.page,b=hs.mouse.x+c.scrollLeft,a=hs.mouse.y+c.scrollTop;this.mouseIsOver=this.x.pos<b&&b<this.x.pos+this.x.get("wsize")&&this.y.pos<a&&a<this.y.pos+this.y.get("wsize");if(this.overlayBox){this.showOverlays()}hs.fireEvent(this,"onAfterExpand")},prepareNextOutline:function(){var a=this.key;var b=this.outlineType;new hs.Outline(b,function(){try{hs.expanders[a].preloadNext()}catch(c){}})},preloadNext:function(){var b=this.getAdjacentAnchor(1);if(b&&b.onclick.toString().match(/hs\.expand/)){var a=hs.createElement("img",{src:hs.getSrc(b)})}},getAdjacentAnchor:function(c){var b=this.getAnchorIndex(),a=hs.anchors.groups[this.slideshowGroup||"none"];if(a&&!a[b+c]&&this.slideshow&&this.slideshow.repeat){if(c==1){return a[0]}else{if(c==-1){return a[a.length-1]}}}return(a&&a[b+c])||null},getAnchorIndex:function(){var a=hs.getAnchors().groups[this.slideshowGroup||"none"];if(a){for(var b=0;b<a.length;b++){if(a[b]==this.a){return b}}}return null},getNumber:function(){if(this[this.numberPosition]){var a=hs.anchors.groups[this.slideshowGroup||"none"];if(a){var b=hs.lang.number.replace("%1",this.getAnchorIndex()+1).replace("%2",a.length);this[this.numberPosition].innerHTML='<div class="highslide-number">'+b+"</div>"+this[this.numberPosition].innerHTML}}},initSlideshow:function(){if(!this.last){for(var c=0;c<hs.slideshows.length;c++){var b=hs.slideshows[c],d=b.slideshowGroup;if(typeof d=="undefined"||d===null||d===this.slideshowGroup){this.slideshow=new hs.Slideshow(this.key,b)}}}else{this.slideshow=this.last.slideshow}var b=this.slideshow;if(!b){return}var a=b.expKey=this.key;b.checkFirstAndLast();b.disable("full-expand");if(b.controls){this.createOverlay(hs.extend(b.overlayOptions||{},{overlayId:b.controls,hsId:"controls",zIndex:5}))}if(b.thumbstrip){b.thumbstrip.add(this)}if(!this.last&&this.autoplay){b.play(true)}if(b.autoplay){b.autoplay=setTimeout(function(){hs.next(a)},(b.interval||500))}},cancelLoading:function(){hs.discardElement(this.wrapper);hs.expanders[this.key]=null;if(hs.upcoming==this.a){hs.upcoming=null}hs.undim(this.key);if(this.loading){hs.loading.style.left="-9999px"}hs.fireEvent(this,"onHideLoading")},writeCredits:function(){if(this.credits){return}this.credits=hs.createElement("a",{href:hs.creditsHref,target:hs.creditsTarget,className:"highslide-credits",innerHTML:hs.lang.creditsText,title:hs.lang.creditsTitle});this.createOverlay({overlayId:this.credits,position:this.creditsPosition||"top left",hsId:"credits"})},getInline:function(types,addOverlay){for(var i=0;i<types.length;i++){var type=types[i],s=null;if(type=="caption"&&!hs.fireEvent(this,"onBeforeGetCaption")){return}else{if(type=="heading"&&!hs.fireEvent(this,"onBeforeGetHeading")){return}}if(!this[type+"Id"]&&this.thumbsUserSetId){this[type+"Id"]=type+"-for-"+this.thumbsUserSetId}if(this[type+"Id"]){this[type]=hs.getNode(this[type+"Id"])}if(!this[type]&&!this[type+"Text"]&&this[type+"Eval"]){try{s=eval(this[type+"Eval"])}catch(e){}}if(!this[type]&&this[type+"Text"]){s=this[type+"Text"]}if(!this[type]&&!s){this[type]=hs.getNode(this.a["_"+type+"Id"]);if(!this[type]){var next=this.a.nextSibling;while(next&&!hs.isHsAnchor(next)){if((new RegExp("highslide-"+type)).test(next.className||null)){if(!next.id){this.a["_"+type+"Id"]=next.id="hsId"+hs.idCounter++}this[type]=hs.getNode(next.id);break}next=next.nextSibling}}}if(!this[type]&&!s&&this.numberPosition==type){s="\n"}if(!this[type]&&s){this[type]=hs.createElement("div",{className:"highslide-"+type,innerHTML:s})}if(addOverlay&&this[type]){var o={position:(type=="heading")?"above":"below"};for(var x in this[type+"Overlay"]){o[x]=this[type+"Overlay"][x]}o.overlayId=this[type];this.createOverlay(o)}}},doShowHide:function(a){if(hs.hideSelects){this.showHideElements("SELECT",a)}if(hs.hideIframes){this.showHideElements("IFRAME",a)}if(hs.geckoMac){this.showHideElements("*",a)}},showHideElements:function(c,b){var e=document.getElementsByTagName(c);var a=c=="*"?"overflow":"visibility";for(var f=0;f<e.length;f++){if(a=="visibility"||(document.defaultView.getComputedStyle(e[f],"").getPropertyValue("overflow")=="auto"||e[f].getAttribute("hidden-by")!=null)){var h=e[f].getAttribute("hidden-by");if(b=="visible"&&h){h=h.replace("["+this.key+"]","");e[f].setAttribute("hidden-by",h);if(!h){e[f].style[a]=e[f].origProp}}else{if(b=="hidden"){var k=hs.getPosition(e[f]);k.w=e[f].offsetWidth;k.h=e[f].offsetHeight;if(!this.dimmingOpacity){var j=(k.x+k.w<this.x.get("opos")||k.x>this.x.get("opos")+this.x.get("osize"));var g=(k.y+k.h<this.y.get("opos")||k.y>this.y.get("opos")+this.y.get("osize"))}var d=hs.getWrapperKey(e[f]);if(!j&&!g&&d!=this.key){if(!h){e[f].setAttribute("hidden-by","["+this.key+"]");e[f].origProp=e[f].style[a];e[f].style[a]="hidden"}else{if(h.indexOf("["+this.key+"]")==-1){e[f].setAttribute("hidden-by",h+"["+this.key+"]")}}}else{if((h=="["+this.key+"]"||hs.focusKey==d)&&d!=this.key){e[f].setAttribute("hidden-by","");e[f].style[a]=e[f].origProp||""}else{if(h&&h.indexOf("["+this.key+"]")>-1){e[f].setAttribute("hidden-by",h.replace("["+this.key+"]",""))}}}}}}}},focus:function(){this.wrapper.style.zIndex=hs.zIndexCounter+=2;for(var a=0;a<hs.expanders.length;a++){if(hs.expanders[a]&&a==hs.focusKey){var b=hs.expanders[a];b.content.className+=" highslide-"+b.contentType+"-blur";if(b.isImage){b.content.style.cursor=hs.ieLt7?"hand":"pointer";b.content.title=hs.lang.focusTitle}hs.fireEvent(b,"onBlur")}}if(this.outline){this.outline.table.style.zIndex=this.wrapper.style.zIndex-1}this.content.className="highslide-"+this.contentType;if(this.isImage){this.content.title=hs.lang.restoreTitle;if(hs.restoreCursor){hs.styleRestoreCursor=window.opera?"pointer":"url("+hs.graphicsDir+hs.restoreCursor+"), pointer";if(hs.ieLt7&&hs.uaVersion<6){hs.styleRestoreCursor="hand"}this.content.style.cursor=hs.styleRestoreCursor}}hs.focusKey=this.key;hs.addEventListener(document,window.opera?"keypress":"keydown",hs.keyHandler);hs.fireEvent(this,"onFocus")},moveTo:function(a,b){this.x.setPos(a);this.y.setPos(b)},resize:function(d){var a,b,c=d.width/d.height;a=Math.max(d.width+d.dX,Math.min(this.minWidth,this.x.full));if(this.isImage&&Math.abs(a-this.x.full)<12){a=this.x.full}b=this.isHtml?d.height+d.dY:a/c;if(b<Math.min(this.minHeight,this.y.full)){b=Math.min(this.minHeight,this.y.full);if(this.isImage){a=b*c}}this.resizeTo(a,b)},resizeTo:function(a,b){this.y.setSize(b);this.x.setSize(a);this.wrapper.style.height=this.y.get("wsize")+"px"},close:function(){if(this.isClosing||!this.isExpanded){return}if(this.transitions[1]=="crossfade"&&hs.upcoming){hs.getExpander(hs.upcoming).cancelLoading();hs.upcoming=null}if(!hs.fireEvent(this,"onBeforeClose")){return}this.isClosing=true;if(this.slideshow&&!hs.upcoming){this.slideshow.pause()}hs.removeEventListener(document,window.opera?"keypress":"keydown",hs.keyHandler);try{if(this.isHtml){this.htmlPrepareClose()}this.content.style.cursor="default";this.changeSize(0,{wrapper:{width:this.x.t,height:this.y.t,left:this.x.tpos-this.x.cb+this.x.tb,top:this.y.tpos-this.y.cb+this.y.tb},content:{left:0,top:0,width:this.x.t,height:this.y.t}},hs.restoreDuration)}catch(a){this.afterClose()}},htmlPrepareClose:function(){if(hs.geckoMac){if(!hs.mask){hs.mask=hs.createElement("div",null,{position:"absolute"},hs.container)}hs.setStyles(hs.mask,{width:this.x.size+"px",height:this.y.size+"px",left:this.x.pos+"px",top:this.y.pos+"px",display:"block"})}if(this.objectType=="swf"){try{hs.$(this.body.id).StopPlay()}catch(a){}}if(this.objectLoadTime=="after"&&!this.preserveContent){this.destroyObject()}if(this.scrollerDiv&&this.scrollerDiv!=this.scrollingContent){this.scrollerDiv.style.overflow="hidden"}},destroyObject:function(){if(hs.ie&&this.iframe){try{this.iframe.contentWindow.document.body.innerHTML=""}catch(a){}}if(this.objectType=="swf"){swfobject.removeSWF(this.body.id)}this.body.innerHTML=""},sleep:function(){if(this.outline){this.outline.table.style.display="none"}this.releaseMask=null;this.wrapper.style.display="none";this.isExpanded=false;hs.push(hs.sleeping,this)},awake:function(){try{hs.expanders[this.key]=this;if(!hs.allowMultipleInstances&&hs.focusKey!=this.key){try{hs.expanders[hs.focusKey].close()}catch(b){}}var d=hs.zIndexCounter++,a={display:"",zIndex:d};hs.setStyles(this.wrapper,a);this.isClosing=false;var c=this.outline||0;if(c){if(!this.outlineWhileAnimating){a.visibility="hidden"}hs.setStyles(c.table,a)}if(this.slideshow){this.initSlideshow()}this.show()}catch(b){}},createOverlay:function(e){var d=e.overlayId,a=(e.relativeTo=="viewport"&&!/panel$/.test(e.position));if(typeof d=="string"){d=hs.getNode(d)}if(e.html){d=hs.createElement("div",{innerHTML:e.html})}if(!d||typeof d=="string"){return}if(!hs.fireEvent(this,"onCreateOverlay",{overlay:d})){return}d.style.display="block";e.hsId=e.hsId||e.overlayId;if(this.transitions[1]=="crossfade"&&this.reuseOverlay(e,d)){return}this.genOverlayBox();var c=e.width&&/^[0-9]+(px|%)$/.test(e.width)?e.width:"auto";if(/^(left|right)panel$/.test(e.position)&&!/^[0-9]+px$/.test(e.width)){c="200px"}var b=hs.createElement("div",{id:"hsId"+hs.idCounter++,hsId:e.hsId},{position:"absolute",visibility:"hidden",width:c,direction:hs.lang.cssDirection||"",opacity:0},a?hs.viewport:this.overlayBox,true);if(a){b.hsKey=this.key}b.appendChild(d);hs.extend(b,{opacity:1,offsetX:0,offsetY:0,dur:(e.fade===0||e.fade===false||(e.fade==2&&hs.ie))?0:250});hs.extend(b,e);if(this.gotOverlays){this.positionOverlay(b);if(!b.hideOnMouseOut||this.mouseIsOver){hs.animate(b,{opacity:b.opacity},b.dur)}}hs.push(this.overlays,hs.idCounter-1)},positionOverlay:function(e){var f=e.position||"middle center",c=(e.relativeTo=="viewport"),b=e.offsetX,a=e.offsetY;if(c){hs.viewport.style.display="block";e.hsKey=this.key;if(e.offsetWidth>e.parentNode.offsetWidth){e.style.width="100%"}}else{if(e.parentNode!=this.overlayBox){this.overlayBox.appendChild(e)}}if(/left$/.test(f)){e.style.left=b+"px"}if(/center$/.test(f)){hs.setStyles(e,{left:"50%",marginLeft:(b-Math.round(e.offsetWidth/2))+"px"})}if(/right$/.test(f)){e.style.right=-b+"px"}if(/^leftpanel$/.test(f)){hs.setStyles(e,{right:"100%",marginRight:this.x.cb+"px",top:-this.y.cb+"px",bottom:-this.y.cb+"px",overflow:"auto"});this.x.p1=e.offsetWidth}else{if(/^rightpanel$/.test(f)){hs.setStyles(e,{left:"100%",marginLeft:this.x.cb+"px",top:-this.y.cb+"px",bottom:-this.y.cb+"px",overflow:"auto"});this.x.p2=e.offsetWidth}}var d=e.parentNode.offsetHeight;e.style.height="auto";if(c&&e.offsetHeight>d){e.style.height=hs.ieLt7?d+"px":"100%"}if(/^top/.test(f)){e.style.top=a+"px"}if(/^middle/.test(f)){hs.setStyles(e,{top:"50%",marginTop:(a-Math.round(e.offsetHeight/2))+"px"})}if(/^bottom/.test(f)){e.style.bottom=-a+"px"}if(/^above$/.test(f)){hs.setStyles(e,{left:(-this.x.p1-this.x.cb)+"px",right:(-this.x.p2-this.x.cb)+"px",bottom:"100%",marginBottom:this.y.cb+"px",width:"auto"});this.y.p1=e.offsetHeight}else{if(/^below$/.test(f)){hs.setStyles(e,{position:"relative",left:(-this.x.p1-this.x.cb)+"px",right:(-this.x.p2-this.x.cb)+"px",top:"100%",marginTop:this.y.cb+"px",width:"auto"});this.y.p2=e.offsetHeight;e.style.position="absolute"}}},getOverlays:function(){this.getInline(["heading","caption"],true);this.getNumber();if(this.caption){hs.fireEvent(this,"onAfterGetCaption")}if(this.heading){hs.fireEvent(this,"onAfterGetHeading")}if(this.heading&&this.dragByHeading){this.heading.className+=" highslide-move"}if(hs.showCredits){this.writeCredits()}for(var a=0;a<hs.overlays.length;a++){var d=hs.overlays[a],e=d.thumbnailId,b=d.slideshowGroup;if((!e&&!b)||(e&&e==this.thumbsUserSetId)||(b&&b===this.slideshowGroup)){if(this.isImage||(this.isHtml&&d.useOnHtml)){this.createOverlay(d)}}}var c=[];for(var a=0;a<this.overlays.length;a++){var d=hs.$("hsId"+this.overlays[a]);if(/panel$/.test(d.position)){this.positionOverlay(d)}else{hs.push(c,d)}}for(var a=0;a<c.length;a++){this.positionOverlay(c[a])}this.gotOverlays=true},genOverlayBox:function(){if(!this.overlayBox){this.overlayBox=hs.createElement("div",{className:this.wrapperClassName},{position:"absolute",width:(this.x.size||(this.useBox?this.width:null)||this.x.full)+"px",height:(this.y.size||this.y.full)+"px",visibility:"hidden",overflow:"hidden",zIndex:hs.ie?4:"auto"},hs.container,true)}},sizeOverlayBox:function(f,d){var c=this.overlayBox,a=this.x,h=this.y;hs.setStyles(c,{width:a.size+"px",height:h.size+"px"});if(f||d){for(var e=0;e<this.overlays.length;e++){var g=hs.$("hsId"+this.overlays[e]);var b=(hs.ieLt7||document.compatMode=="BackCompat");if(g&&/^(above|below)$/.test(g.position)){if(b){g.style.width=(c.offsetWidth+2*a.cb+a.p1+a.p2)+"px"}h[g.position=="above"?"p1":"p2"]=g.offsetHeight}if(g&&b&&/^(left|right)panel$/.test(g.position)){g.style.height=(c.offsetHeight+2*h.cb)+"px"}}}if(f){hs.setStyles(this.content,{top:h.p1+"px"});hs.setStyles(c,{top:(h.p1+h.cb)+"px"})}},showOverlays:function(){var a=this.overlayBox;a.className="";hs.setStyles(a,{top:(this.y.p1+this.y.cb)+"px",left:(this.x.p1+this.x.cb)+"px",overflow:"visible"});if(hs.safari){a.style.visibility="visible"}this.wrapper.appendChild(a);for(var c=0;c<this.overlays.length;c++){var d=hs.$("hsId"+this.overlays[c]);d.style.zIndex=d.zIndex||4;if(!d.hideOnMouseOut||this.mouseIsOver){d.style.visibility="visible";hs.setStyles(d,{visibility:"visible",display:""});hs.animate(d,{opacity:d.opacity},d.dur)}}},destroyOverlays:function(){if(!this.overlays.length){return}if(this.slideshow){var d=this.slideshow.controls;if(d&&hs.getExpander(d)==this){d.parentNode.removeChild(d)}}for(var a=0;a<this.overlays.length;a++){var b=hs.$("hsId"+this.overlays[a]);if(b&&b.parentNode==hs.viewport&&hs.getExpander(b)==this){hs.discardElement(b)}}if(this.isHtml&&this.preserveContent){this.overlayBox.style.top="-9999px";hs.container.appendChild(this.overlayBox)}else{hs.discardElement(this.overlayBox)}},createFullExpand:function(){if(this.slideshow&&this.slideshow.controls){this.slideshow.enable("full-expand");return}this.fullExpandLabel=hs.createElement("a",{href:"javascript:hs.expanders["+this.key+"].doFullExpand();",title:hs.lang.fullExpandTitle,className:"highslide-full-expand"});if(!hs.fireEvent(this,"onCreateFullExpand")){return}this.createOverlay({overlayId:this.fullExpandLabel,position:hs.fullExpandPosition,hideOnMouseOut:true,opacity:hs.fullExpandOpacity})},doFullExpand:function(){try{if(!hs.fireEvent(this,"onDoFullExpand")){return}if(this.fullExpandLabel){hs.discardElement(this.fullExpandLabel)}this.focus();var c=this.x.size,a=this.y.size;this.resizeTo(this.x.full,this.y.full);var b=this.x.pos-(this.x.size-c)/2;if(b<hs.marginLeft){b=hs.marginLeft}var f=this.y.pos-(this.y.size-a)/2;if(f<hs.marginTop){f=hs.marginTop}this.moveTo(b,f);this.doShowHide("hidden")}catch(d){this.error(d)}},afterClose:function(){this.a.className=this.a.className.replace("highslide-active-anchor","");this.doShowHide("visible");if(this.isHtml&&this.preserveContent&&this.transitions[1]!="crossfade"){this.sleep()}else{if(this.outline&&this.outlineWhileAnimating){this.outline.destroy()}hs.discardElement(this.wrapper)}if(hs.mask){hs.mask.style.display="none"}this.destroyOverlays();if(!hs.viewport.childNodes.length){hs.viewport.style.display="none"}if(this.dimmingOpacity){hs.undim(this.key)}hs.fireEvent(this,"onAfterClose");hs.expanders[this.key]=null;hs.reOrder()}};hs.Ajax=function(b,c,d){this.a=b;this.content=c;this.pre=d};hs.Ajax.prototype={run:function(){var d;if(!this.src){this.src=hs.getSrc(this.a)}if(this.src.match("#")){var a=this.src.split("#");this.src=a[0];this.id=a[1]}if(hs.cachedGets[this.src]){this.cachedGet=hs.cachedGets[this.src];if(this.id){this.getElementContent()}else{this.loadHTML()}return}try{d=new XMLHttpRequest()}catch(b){try{d=new ActiveXObject("Msxml2.XMLHTTP")}catch(b){try{d=new ActiveXObject("Microsoft.XMLHTTP")}catch(b){this.onError()}}}var f=this;d.onreadystatechange=function(){if(f.xhr.readyState==4){if(f.id){f.getElementContent()}else{f.loadHTML()}}};var c=this.src;this.xhr=d;if(hs.forceAjaxReload){c=c.replace(/$/,(/\?/.test(c)?"&":"?")+"dummy="+(new Date()).getTime())}d.open("GET",c,true);d.setRequestHeader("X-Requested-With","XMLHttpRequest");d.setRequestHeader("Content-Type","application/x-www-form-urlencoded");d.send(null)},getElementContent:function(){hs.init();var a=window.opera||hs.ie6SSL?{src:"about:blank"}:null;this.iframe=hs.createElement("iframe",a,{position:"absolute",top:"-9999px"},hs.container);this.loadHTML()},loadHTML:function(){var c=this.cachedGet||this.xhr.responseText,b;if(this.pre){hs.cachedGets[this.src]=c}if(!hs.ie||hs.uaVersion>=5.5){c=c.replace(new RegExp("<link[^>]*>","gi"),"").replace(new RegExp("<script[^>]*>.*?<\/script>","gi"),"");if(this.iframe){var f=this.iframe.contentDocument;if(!f&&this.iframe.contentWindow){f=this.iframe.contentWindow.document}if(!f){var g=this;setTimeout(function(){g.loadHTML()},25);return}f.open();f.write(c);f.close();try{c=f.getElementById(this.id).innerHTML}catch(d){try{c=this.iframe.document.getElementById(this.id).innerHTML}catch(d){}}hs.discardElement(this.iframe)}else{b=/(<body[^>]*>|<\/body>)/ig;if(b.test(c)){c=c.split(b)[hs.ieLt9?1:2]}}}hs.getElementByClass(this.content,"DIV","highslide-body").innerHTML=c;this.onLoad();for(var a in this){this[a]=null}}};hs.Slideshow=function(c,b){if(hs.dynamicallyUpdateAnchors!==false){hs.updateAnchors()}this.expKey=c;for(var a in b){this[a]=b[a]}if(this.useControls){this.getControls()}if(this.thumbstrip){this.thumbstrip=hs.Thumbstrip(this)}};hs.Slideshow.prototype={getControls:function(){this.controls=hs.createElement("div",{innerHTML:hs.replaceLang(hs.skin.controls)},null,hs.container);var b=["play","pause","previous","next","move","full-expand","close"];this.btn={};var c=this;for(var a=0;a<b.length;a++){this.btn[b[a]]=hs.getElementByClass(this.controls,"li","highslide-"+b[a]);this.enable(b[a])}this.btn.pause.style.display="none"},checkFirstAndLast:function(){if(this.repeat||!this.controls){return}var c=hs.expanders[this.expKey],b=c.getAnchorIndex(),a=/disabled$/;if(b==0){this.disable("previous")}else{if(a.test(this.btn.previous.getElementsByTagName("a")[0].className)){this.enable("previous")}}if(b+1==hs.anchors.groups[c.slideshowGroup||"none"].length){this.disable("next");this.disable("play")}else{if(a.test(this.btn.next.getElementsByTagName("a")[0].className)){this.enable("next");this.enable("play")}}},enable:function(d){if(!this.btn){return}var c=this,b=this.btn[d].getElementsByTagName("a")[0],e=/disabled$/;b.onclick=function(){c[d]();return false};if(e.test(b.className)){b.className=b.className.replace(e,"")}},disable:function(c){if(!this.btn){return}var b=this.btn[c].getElementsByTagName("a")[0];b.onclick=function(){return false};if(!/disabled$/.test(b.className)){b.className+=" disabled"}},hitSpace:function(){if(this.autoplay){this.pause()}else{this.play()}},play:function(a){if(this.btn){this.btn.play.style.display="none";this.btn.pause.style.display=""}this.autoplay=true;if(!a){hs.next(this.expKey)}},pause:function(){if(this.btn){this.btn.pause.style.display="none";this.btn.play.style.display=""}clearTimeout(this.autoplay);this.autoplay=null},previous:function(){this.pause();hs.previous(this.btn.previous)},next:function(){this.pause();hs.next(this.btn.next)},move:function(){},"full-expand":function(){hs.getExpander().doFullExpand()},close:function(){hs.close(this.btn.close)}};hs.Thumbstrip=function(k){function p(i){hs.extend(f||{},{overlayId:r,hsId:"thumbstrip",className:"highslide-thumbstrip-"+m+"-overlay "+(f.className||"")});if(hs.ieLt7){f.fade=0}i.createOverlay(f);hs.setStyles(r.parentNode,{overflow:"hidden"})}function c(i){d(undefined,Math.round(i*r[h?"offsetWidth":"offsetHeight"]*0.7))}function d(L,M){if(L===undefined){for(var K=0;K<j.length;K++){if(j[K]==hs.expanders[k.expKey].a){L=K;break}}}if(L===undefined){return}var G=r.getElementsByTagName("a"),z=G[L],w=z.parentNode,y=h?"Left":"Top",N=h?"Right":"Bottom",I=h?"Width":"Height",B="offset"+y,H="offset"+I,x=n.parentNode.parentNode[H],F=x-s[H],v=parseInt(s.style[h?"left":"top"])||0,C=v,D=20;if(M!==undefined){C=v-M;if(F>0){F=0}if(C>0){C=0}if(C<F){C=F}}else{for(var K=0;K<G.length;K++){G[K].className=""}z.className="highslide-active-anchor";var J=L>0?G[L-1].parentNode[B]:w[B],A=w[B]+w[H]+(G[L+1]?G[L+1].parentNode[H]:0);if(A>x-v){C=x-A}else{if(J<-v){C=-J}}}var E=w[B]+(w[H]-g[H])/2+C;hs.animate(s,h?{left:C}:{top:C},null,"easeOutQuad");hs.animate(g,h?{left:E}:{top:E},null,"easeOutQuad");l.style.display=C<0?"block":"none";t.style.display=(C>F)?"block":"none"}var j=hs.anchors.groups[hs.expanders[k.expKey].slideshowGroup||"none"],f=k.thumbstrip,m=f.mode||"horizontal",u=(m=="float"),o=u?["div","ul","li","span"]:["table","tbody","tr","td"],h=(m=="horizontal"),r=hs.createElement("div",{className:"highslide-thumbstrip highslide-thumbstrip-"+m,innerHTML:'<div class="highslide-thumbstrip-inner"><'+o[0]+"><"+o[1]+"></"+o[1]+"></"+o[0]+'></div><div class="highslide-scroll-up"><div></div></div><div class="highslide-scroll-down"><div></div></div><div class="highslide-marker"><div></div></div>'},{display:"none"},hs.container),e=r.childNodes,n=e[0],l=e[1],t=e[2],g=e[3],s=n.firstChild,a=r.getElementsByTagName(o[1])[0],b;for(var q=0;q<j.length;q++){if(q==0||!h){b=hs.createElement(o[2],null,null,a)}(function(){var v=j[q],i=hs.createElement(o[3],null,null,b),w=q;hs.createElement("a",{href:v.href,title:v.title,onclick:function(){if(/highslide-active-anchor/.test(this.className)){return false}hs.getExpander(this).focus();return hs.transit(v)},innerHTML:hs.stripItemFormatter?hs.stripItemFormatter(v):v.innerHTML},null,i)})()}if(!u){l.onclick=function(){c(-1)};t.onclick=function(){c(1)};hs.addEventListener(a,document.onmousewheel!==undefined?"mousewheel":"DOMMouseScroll",function(i){var v=0;i=i||window.event;if(i.wheelDelta){v=i.wheelDelta/120;if(hs.opera){v=-v}}else{if(i.detail){v=-i.detail/3}}if(v){c(-v*0.2)}if(i.preventDefault){i.preventDefault()}i.returnValue=false})}return{add:p,selectThumb:d}};hs.langDefaults=hs.lang;var HsExpander=hs.Expander;if(hs.ie&&window==window.top){(function(){try{document.documentElement.doScroll("left")}catch(a){setTimeout(arguments.callee,50);return}hs.ready()})()}hs.addEventListener(document,"DOMContentLoaded",hs.ready);hs.addEventListener(window,"load",hs.ready);hs.addEventListener(document,"ready",function(){if(hs.expandCursor||hs.dimmingOpacity){var d=hs.createElement("style",{type:"text/css"},null,document.getElementsByTagName("HEAD")[0]),c=document.compatMode=="BackCompat";function b(f,g){if(hs.ie&&(hs.uaVersion<9||c)){var e=document.styleSheets[document.styleSheets.length-1];if(typeof(e.addRule)=="object"){e.addRule(f,g)}}else{d.appendChild(document.createTextNode(f+" {"+g+"}"))}}function a(e){return"expression( ( ( ignoreMe = document.documentElement."+e+" ? document.documentElement."+e+" : document.body."+e+" ) ) + 'px' );"}if(hs.expandCursor){b(".highslide img","cursor: url("+hs.graphicsDir+hs.expandCursor+"), pointer !important;")}b(".highslide-viewport-size",hs.ie&&(hs.uaVersion<7||c)?"position: absolute; left:"+a("scrollLeft")+"top:"+a("scrollTop")+"width:"+a("clientWidth")+"height:"+a("clientHeight"):"position: fixed; width: 100%; height: 100%; left: 0; top: 0")}});hs.addEventListener(window,"resize",function(){hs.getPageSize();if(hs.viewport){for(var a=0;a<hs.viewport.childNodes.length;a++){var b=hs.viewport.childNodes[a],c=hs.getExpander(b);c.positionOverlay(b);if(b.hsId=="thumbstrip"){c.slideshow.thumbstrip.selectThumb()}}}});hs.addEventListener(document,"mousemove",function(a){hs.mouse={x:a.clientX,y:a.clientY}});hs.addEventListener(document,"mousedown",hs.mouseClickHandler);hs.addEventListener(document,"mouseup",hs.mouseClickHandler);hs.addEventListener(document,"ready",hs.setClickEvents);hs.addEventListener(window,"load",hs.preloadImages);hs.addEventListener(window,"load",hs.preloadAjax)};
products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-full.packed.js ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Name: Highslide JS
3
+ * Version: 4.1.13 (2011-10-06)
4
+ * Config: default +events +unobtrusive +imagemap +slideshow +positioning +transitions +viewport +thumbstrip +inline +ajax +iframe +flash +packed
5
+ * Author: Torstein Hønsi
6
+ * Support: www.highslide.com/support
7
+ * License: www.highslide.com/#license
8
+ */
9
+ eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('q(!m){A m={18:{97:\'aK\',aZ:\'fw...\',aY:\'8G 2i fP\',bD:\'8G 2i g0 2i eR\',9Z:\'eZ 2i fc D (f)\',cq:\'f8 by <i>an ao</i>\',cr:\'f4 2i f6 an ao fg\',8Y:\'aq\',8W:\'ay\',8Z:\'ag\',92:\'am\',90:\'am (eD)\',b0:\'eY\',ab:\'al\',au:\'al 1p (aj)\',ac:\'ah\',ad:\'ah 1p (aj)\',8s:\'aq (8w 1b)\',8X:\'ay (8w 3m)\',8V:\'ag\',ae:\'1:1\',3G:\'g7 %1 fz %2\',9W:\'8G 2i 26 2R, dC aA dE 2i 3u. dF 8w dB O 1D aA 3a.\'},5c:\'K/dw/\',7R:\'dv.5q\',6h:\'dx.5q\',6W:5Z,9A:5Z,4W:15,9B:15,4d:15,6L:15,4F:cY,be:0.75,9l:M,9f:5,3Y:2,ei:3,5S:1j,bz:\'4Q 3m\',bA:1,br:M,ct:\'em://K.eh/\',cs:\'ec\',aS:M,9w:[\'a\',\'5v\'],3q:[],cE:5Z,4b:0,87:50,6J:1j,6X:M,4D:M,3U:\'60\',7W:M,46:\'1M\',9n:\'1M\',b1:I,aC:I,a7:M,4s:aw,6k:aw,5Y:M,1Z:\'ev-dV\',8i:{2X:\'<P 1W="K-2X"><6t>\'+\'<1H 1W="K-3a">\'+\'<a 21="#" 24="{m.18.8s}">\'+\'<1C>{m.18.8Y}</1C></a>\'+\'</1H>\'+\'<1H 1W="K-3L">\'+\'<a 21="#" 24="{m.18.au}">\'+\'<1C>{m.18.ab}</1C></a>\'+\'</1H>\'+\'<1H 1W="K-3p">\'+\'<a 21="#" 24="{m.18.ad}">\'+\'<1C>{m.18.ac}</1C></a>\'+\'</1H>\'+\'<1H 1W="K-1D">\'+\'<a 21="#" 24="{m.18.8X}">\'+\'<1C>{m.18.8W}</1C></a>\'+\'</1H>\'+\'<1H 1W="K-3u">\'+\'<a 21="#" 24="{m.18.8V}">\'+\'<1C>{m.18.8Z}</1C></a>\'+\'</1H>\'+\'<1H 1W="K-1a-2F">\'+\'<a 21="#" 24="{m.18.9Z}">\'+\'<1C>{m.18.ae}</1C></a>\'+\'</1H>\'+\'<1H 1W="K-26">\'+\'<a 21="#" 24="{m.18.90}" >\'+\'<1C>{m.18.92}</1C></a>\'+\'</1H>\'+\'</6t></P>\',bd:\'<P 1W="K-e2"><6t>\'+\'<1H 1W="K-3a">\'+\'<a 21="#" 24="{m.18.8s}" 2p="E m.3a(k)">\'+\'<1C>{m.18.8Y}</1C></a>\'+\'</1H>\'+\'<1H 1W="K-1D">\'+\'<a 21="#" 24="{m.18.8X}" 2p="E m.1D(k)">\'+\'<1C>{m.18.8W}</1C></a>\'+\'</1H>\'+\'<1H 1W="K-3u">\'+\'<a 21="#" 24="{m.18.8V}" 2p="E 1j">\'+\'<1C>{m.18.8Z}</1C></a>\'+\'</1H>\'+\'<1H 1W="K-26">\'+\'<a 21="#" 24="{m.18.90}" 2p="E m.26(k)">\'+\'<1C>{m.18.92}</1C></a>\'+\'</1H>\'+\'</6t></P>\'+\'<P 1W="K-19"></P>\'+\'<P 1W="K-e7"><P>\'+\'<1C 1W="K-3O" 24="{m.18.b0}"><1C></1C></1C>\'+\'</P></P>\'},64:[],a1:M,16:[],a4:[\'5Y\',\'3t\',\'46\',\'9n\',\'b1\',\'aC\',\'1Z\',\'3Y\',\'dU\',\'dM\',\'dL\',\'b3\',\'dK\',\'dI\',\'dJ\',\'b2\',\'cv\',\'a7\',\'42\',\'6l\',\'3q\',\'4b\',\'L\',\'N\',\'88\',\'6J\',\'6X\',\'4D\',\'dN\',\'dO\',\'dT\',\'2I\',\'7W\',\'4j\',\'4x\',\'3U\',\'8e\',\'a9\',\'4s\',\'6k\',\'6M\',\'9i\',\'aX\',\'2N\',\'2Q\',\'cF\',\'cD\',\'1e\'],1T:[],61:0,8g:{x:[\'bM\',\'1b\',\'4X\',\'3m\',\'bC\'],y:[\'5N\',\'Y\',\'9a\',\'4Q\',\'7E\']},7B:{},b2:{},b3:{},8e:{aG:{},29:{},aF:{}},4m:[],6u:[],4n:{},4R:[],7q:[],5a:[],7k:{},8c:{},7l:[],2t:/dP\\/4\\.0/.11(4A.6d)?8:8J((4A.6d.5G().3b(/.+(?:b9|dQ|e9|2h)[\\/: ]([\\d.]+)/)||[0,\'0\'])[1]),2h:(W.6q&&!1S.3z),4M:/ea/.11(4A.6d),6y:/eu.+b9:1\\.[0-8].+es/.11(4A.6d),$:C(1v){q(1v)E W.9Q(1v)},2o:C(2a,3j){2a[2a.V]=3j},1d:C(ba,4l,49,6c,bh){A el=W.1d(ba);q(4l)m.3A(el,4l);q(bh)m.R(el,{94:0,8H:\'1E\',9D:0});q(49)m.R(el,49);q(6c)6c.1X(el);E el},3A:C(el,4l){O(A x 2Y 4l)el[x]=4l[x];E el},R:C(el,49){O(A x 2Y 49){q(m.3R&&x==\'1z\'){q(49[x]>0.99)el.G.ew(\'5Q\');J el.G.5Q=\'bg(1z=\'+(49[x]*2w)+\')\'}J el.G[x]=49[x]}},2z:C(el,1f,3C){A 4T,51,4w;q(1F 3C!=\'7j\'||3C===I){A 2H=c5;3C={4h:2H[2],2Q:2H[3],76:2H[4]}}q(1F 3C.4h!=\'3G\')3C.4h=5Z;3C.2Q=1h[3C.2Q]||1h.bj;3C.7g=m.3A({},1f);O(A 2Z 2Y 1f){A e=1J m.fx(el,3C,2Z);4T=8J(m.8I(el,2Z))||0;51=8J(1f[2Z]);4w=2Z!=\'1z\'?\'F\':\'\';e.3E(4T,51,4w)}},8I:C(el,1f){q(el.G[1f]){E el.G[1f]}J q(W.8L){E W.8L.cK(el,I).co(1f)}J{q(1f==\'1z\')1f=\'5Q\';A 3j=el.5y[1f.2k(/\\-(\\w)/g,C(a,b){E b.bi()})];q(1f==\'5Q\')3j=3j.2k(/bg\\(1z=([0-9]+)\\)/,C(a,b){E b/2w});E 3j===\'\'?1:3j}},7S:C(){A d=W,w=1S,63=d.7a&&d.7a!=\'8v\'?d.5h:d.19,3R=m.2h&&(m.2t<9||1F bf==\'1L\');A L=3R?63.8F:(d.5h.8F||7c.ep),N=3R?63.c4:7c.eo;m.4g={L:L,N:N,5O:3R?63.5O:bf,5R:3R?63.5R:ed};E m.4g},6K:C(el){q(/5v/i.11(el.3J)){A 7N=W.2C(\'1N\');O(A i=0;i<7N.V;i++){A u=7N[i].eb;q(u&&u.2k(/^.*?#/,\'\')==el.23.2Z){el=7N[i];5m}}}A p={x:el.4V,y:el.8O};5g(el.bb){el=el.bb;p.x+=el.4V;p.y+=el.8O;q(el!=W.19&&el!=W.5h){p.x-=el.5O;p.y-=el.5R}}E p},2F:C(a,29,3E,T){q(!a)a=m.1d(\'a\',I,{1o:\'1E\'},m.2b);q(1F a.6a==\'C\')E 29;q(T==\'3D\'){O(A i=0;i<m.4R.V;i++){q(m.4R[i]&&m.4R[i].a==a){m.4R[i].bP();m.4R[i]=I;E 1j}}m.aU=M}1t{1J m.5A(a,29,3E,T);E 1j}1y(e){E M}},9u:C(a,29,3E){E m.2F(a,29,3E,\'3D\')},89:C(){E m.1d(\'P\',{1c:\'K-3D-S\',2d:m.8b(m.8i.bd)})},4p:C(el,3J,1c){A 1m=el.2C(3J);O(A i=0;i<1m.V;i++){q((1J 4Y(1c)).11(1m[i].1c)){E 1m[i]}}E I},8b:C(s){s=s.2k(/\\s/g,\' \');A 2m=/{m\\.18\\.([^}]+)\\}/g,6v=s.3b(2m),18;q(6v)O(A i=0;i<6v.V;i++){18=6v[i].2k(2m,"$1");q(1F m.18[18]!=\'1L\')s=s.2k(6v[i],m.18[18])}E s},c1:C(){A 1m=W.2C(\'a\');O(A i=0;i<1m.V;i++){A T=m.aH(1m[i]);q(T&&!1m[i].aI){(C(){A t=T;q(m.1A(m,\'ek\',{7y:1m[i],T:t})){1m[i].2p=(T==\'2R\')?C(){E m.2F(k)}:C(){E m.9u(k,{2I:t})}}})();1m[i].aI=M}}m.6p()},aH:C(el){q(el.7b==\'K\')E\'2R\';J q(el.7b==\'K-2W\')E\'2W\';J q(el.7b==\'K-1k\')E\'1k\';J q(el.7b==\'K-3x\')E\'3x\'},86:C(a){O(A i=0;i<m.5a.V;i++){q(m.5a[i][0]==a){A c=m.5a[i][1];m.5a[i][1]=c.5J(1);E c}}E I},bI:C(e){A 2a=m.6p();O(A i=0;i<2a.56.V;i++){A a=2a.56[i];q(m.43(a,\'2I\')==\'2W\'&&m.43(a,\'7W\'))m.2o(m.7q,a)}m.8k(0)},8k:C(i){q(!m.7q[i])E;A a=m.7q[i];A 6z=m.4J(m.43(a,\'88\'));q(!6z)6z=m.89();A 2W=1J m.7x(a,6z,1);2W.9z=C(){};2W.3F=C(){m.2o(m.5a,[a,6z]);m.8k(i+1)};2W.9r()},aQ:C(){A 8d=0,7n=-1,16=m.16,B,1B;O(A i=0;i<16.V;i++){B=16[i];q(B){1B=B.U.G.1B;q(1B&&1B>8d){8d=1B;7n=i}}}q(7n==-1)m.3d=-1;J 16[7n].3M()},43:C(a,6b){a.6a=a.2p;A p=a.6a?a.6a():I;a.6a=I;E(p&&1F p[6b]!=\'1L\')?p[6b]:(1F m[6b]!=\'1L\'?m[6b]:I)},7s:C(a){A 1e=m.43(a,\'1e\');q(1e)E 1e;E a.21},4J:C(1v){A 1P=m.$(1v),4q=m.8c[1v],a={};q(!1P&&!4q)E I;q(!4q){4q=1P.5J(M);4q.1v=\'\';m.8c[1v]=4q;E 1P}J{E 4q.5J(M)}},3B:C(d){q(d)m.9y.1X(d);m.9y.2d=\'\'},1u:C(B){q(!m.2v){84=M;m.2v=m.1d(\'P\',{1c:\'K-dc K-2x-D\',5r:\'\',2p:C(){q(m.1A(m,\'d3\'))m.26()}},{1n:\'1Y\',1z:0},m.2b,M);q(/(df|d2|cU|cT)/.11(4A.6d)){A 19=W.19;C 81(){m.R(m.2v,{L:19.cR+\'F\',N:19.cV+\'F\'})}81();m.2j(1S,\'3O\',81)}}m.2v.G.1o=\'\';A 84=m.2v.5r==\'\';m.2v.5r+=\'|\'+B.Q;q(84){q(m.6y&&m.aR)m.R(m.2v,{9t:\'7T(\'+m.5c+\'d0.ak)\',1z:1});J m.2z(m.2v,{1z:B.4b},m.87)}},9x:C(Q){q(!m.2v)E;q(1F Q!=\'1L\')m.2v.5r=m.2v.5r.2k(\'|\'+Q,\'\');q((1F Q!=\'1L\'&&m.2v.5r!=\'\')||(m.2q&&m.43(m.2q,\'4b\')))E;q(m.6y&&m.aR)m.2v.G.1o=\'1E\';J m.2z(m.2v,{1z:0},m.87,I,C(){m.2v.G.1o=\'1E\'})},8N:C(7z,B){A 1i=B||m.2G();B=1i;q(m.2q)E 1j;J m.1i=1i;m.4z(W,1S.3z?\'6U\':\'71\',m.68);1t{m.2q=7z;7z.2p()}1y(e){m.1i=m.2q=I}1t{q(!7z||B.3q[1]!=\'4e\')B.26()}1y(e){}E 1j},7O:C(el,2n){A B=m.2G(el);q(B)E m.8N(B.7V(2n),B);J E 1j},3a:C(el){E m.7O(el,-1)},1D:C(el){E m.7O(el,1)},68:C(e){q(!e)e=1S.2u;q(!e.2L)e.2L=e.9k;q(1F e.2L.9j!=\'1L\')E M;q(!m.1A(m,\'dz\',e))E M;A B=m.2G();A 2n=I;b6(e.dy){2c 70:q(B)B.7r();E M;2c 32:2n=2;5m;2c 34:2c 39:2c 40:2n=1;5m;2c 8:2c 33:2c 37:2c 38:2n=-1;5m;2c 27:2c 13:2n=0}q(2n!==I){q(2n!=2)m.4z(W,1S.3z?\'6U\':\'71\',m.68);q(!m.aS)E M;q(e.5n)e.5n();J e.c0=1j;q(B){q(2n==0){B.26()}J q(2n==2){q(B.1p)B.1p.cl()}J{q(B.1p)B.1p.3p();m.7O(B.Q,2n)}E 1j}}E M},du:C(14){m.2o(m.1T,m.3A(14,{22:\'22\'+m.61++}))},dt:C(1r){A 3c=1r.2N;q(1F 3c==\'7j\'){O(A i=0;i<3c.V;i++){A o={};O(A x 2Y 1r)o[x]=1r[x];o.2N=3c[i];m.2o(m.6u,o)}}J{m.2o(m.6u,1r)}},9U:C(7y,7h){A el,2m=/^K-U-([0-9]+)$/;el=7y;5g(el.23){q(el.6R!==1L)E el.6R;q(el.1v&&2m.11(el.1v))E el.1v.2k(2m,"$1");el=el.23}q(!7h){el=7y;5g(el.23){q(el.3J&&m.77(el)){O(A Q=0;Q<m.16.V;Q++){A B=m.16[Q];q(B&&B.a==el)E Q}}el=el.23}}E I},2G:C(el,7h){q(1F el==\'1L\')E m.16[m.3d]||I;q(1F el==\'3G\')E m.16[el]||I;q(1F el==\'a8\')el=m.$(el);E m.16[m.9U(el,7h)]||I},77:C(a){E(a.2p&&a.2p.cC().2k(/\\s/g,\' \').3b(/m.(dj|e)dh/))},bw:C(){O(A i=0;i<m.16.V;i++)q(m.16[i]&&m.16[i].55)m.aQ()},1A:C(6i,9K,2H){E 6i&&6i[9K]?(6i[9K](6i,2H)!==1j):M},8z:C(e){q(!e)e=1S.2u;q(e.ds>1)E M;q(!e.2L)e.2L=e.9k;A el=e.2L;5g(el.23&&!(/K-(2R|3u|3D|3O)/.11(el.1c))){el=el.23}A B=m.2G(el);q(B&&(B.62||!B.55))E M;q(B&&e.T==\'8y\'){q(e.2L.9j)E M;A 3b=el.1c.3b(/K-(2R|3u|3O)/);q(3b){m.2y={B:B,T:3b[1],1b:B.x.H,L:B.x.D,Y:B.y.H,N:B.y.D,aV:e.7A,aO:e.7F};m.2j(W,\'7D\',m.6H);q(e.5n)e.5n();q(/K-(2R|3D)-9J/.11(B.S.1c)){B.3M();m.a6=M}E 1j}J q(/K-3D/.11(el.1c)&&m.3d!=B.Q){B.3M();B.59(\'1q\')}}J q(e.T==\'c3\'){m.4z(W,\'7D\',m.6H);q(m.2y){q(m.54&&m.2y.T==\'2R\')m.2y.B.S.G.4L=m.54;A 3I=m.2y.3I;q(!3I&&!m.a6&&!/(3u|3O)/.11(m.2y.T)){q(m.1A(B,\'dr\'))B.26()}J q(3I||(!3I&&m.aU)){m.2y.B.59(\'1q\')}q(m.2y.B.3W)m.2y.B.3W.G.1o=\'1E\';q(3I)m.1A(m.2y.B,\'do\',m.2y);m.a6=1j;m.2y=I}J q(/K-2R-9J/.11(el.1c)){el.G.4L=m.54}}E 1j},6H:C(e){q(!m.2y)E M;q(!e)e=1S.2u;A a=m.2y,B=a.B;q(B.1k){q(!B.3W)B.3W=m.1d(\'P\',I,{1l:\'2l\',L:B.x.D+\'F\',N:B.y.D+\'F\',1b:B.x.cb+\'F\',Y:B.y.cb+\'F\',1B:4,9t:(m.3R?\'eB\':\'1E\'),1z:0.eU},B.U,M);q(B.3W.G.1o==\'1E\')B.3W.G.1o=\'\'}a.dX=e.7A-a.aV;a.dY=e.7F-a.aO;A 9g=1h.fG(1h.aE(a.dX,2)+1h.aE(a.dY,2));q(!a.3I)a.3I=(a.T!=\'2R\'&&9g>0)||(9g>(m.fK||5));q(a.3I&&e.7A>5&&e.7F>5){q(!m.1A(B,\'fN\',a))E 1j;q(a.T==\'3O\')B.3O(a);J{B.9m(a.1b+a.dX,a.Y+a.dY);q(a.T==\'2R\')B.S.G.4L=\'3u\'}}E 1j},aP:C(e){1t{q(!e)e=1S.2u;A 66=/fM/i.11(e.T);q(!e.2L)e.2L=e.9k;q(!e.7P)e.7P=66?e.fE:e.fD;A B=m.2G(e.2L);q(!B.55)E;q(!B||!e.7P||m.2G(e.7P,M)==B||m.2y)E;m.1A(B,66?\'ft\':\'fr\',e);O(A i=0;i<B.1T.V;i++)(C(){A o=m.$(\'22\'+B.1T[i]);q(o&&o.7d){q(66)m.R(o,{1n:\'1Y\',1o:\'\'});m.2z(o,{1z:66?o.1z:0},o.4i)}})()}1y(e){}},2j:C(el,2u,3Q){q(el==W&&2u==\'41\'){m.2o(m.7l,3Q)}1t{el.2j(2u,3Q,1j)}1y(e){1t{el.aM(\'65\'+2u,3Q);el.fy(\'65\'+2u,3Q)}1y(e){el[\'65\'+2u]=3Q}}},4z:C(el,2u,3Q){1t{el.4z(2u,3Q,1j)}1y(e){1t{el.aM(\'65\'+2u,3Q)}1y(e){el[\'65\'+2u]=I}}},7C:C(i){q(m.a1&&m.64[i]&&m.64[i]!=\'1L\'){A 1N=W.1d(\'1N\');1N.4N=C(){1N=I;m.7C(i+1)};1N.1e=m.64[i]}},c2:C(3G){q(3G&&1F 3G!=\'7j\')m.9f=3G;A 2a=m.6p();O(A i=0;i<2a.4Z.V&&i<m.9f;i++){m.2o(m.64,m.7s(2a.4Z[i]))}q(m.1Z)1J m.6r(m.1Z,C(){m.7C(0)});J m.7C(0);q(m.6h)A 5q=m.1d(\'1N\',{1e:m.5c+m.6h})},7m:C(){q(!m.2b){m.3Z=m.2h&&m.2t<7;m.3R=m.2h&&m.2t<9;m.7S();m.cf=m.3Z&&85.g5==\'g4:\';O(A x 2Y m.7o){q(1F m[x]!=\'1L\')m.18[x]=m[x];J q(1F m.18[x]==\'1L\'&&1F m.7o[x]!=\'1L\')m.18[x]=m.7o[x]}m.2b=m.1d(\'P\',{1c:\'K-2b\'},{1l:\'2l\',1b:0,Y:0,L:\'2w%\',1B:m.4F,9S:\'aK\'},W.19,M);m.2r=m.1d(\'a\',{1c:\'K-2r\',24:m.18.aY,2d:m.18.aZ,21:\'bt:;\'},{1l:\'2l\',Y:\'-4v\',1z:m.be,1B:1},m.2b);m.9y=m.1d(\'P\',I,{1o:\'1E\'},m.2b);m.2x=m.1d(\'P\',{1c:\'K-2x K-2x-D\'},{1n:(m.4M&&m.2t<73)?\'1Y\':\'1q\'},m.2b,1);m.3w=m.1d(\'P\',I,{aJ:\'bc\',g9:\'ga\'},I,M);1h.g2=C(t,b,c,d){E c*t/d+b};1h.bj=C(t,b,c,d){E c*(t/=d)*t+b};1h.8S=C(t,b,c,d){E-c*(t/=d)*(t-2)+b};m.cO=m.3Z;m.cQ=((1S.3z&&m.2t<9)||4A.av==\'at\'||(m.3Z&&m.2t<5.5));m.1A(k,\'fU\')}},41:C(){q(m.9F)E;m.9F=M;O(A i=0;i<m.7l.V;i++)m.7l[i]()},95:C(){A el,1m,6q=[],4Z=[],56=[],3i={},2m;O(A i=0;i<m.9w.V;i++){1m=W.2C(m.9w[i]);O(A j=0;j<1m.V;j++){el=1m[j];2m=m.77(el);q(2m){m.2o(6q,el);q(2m[0]==\'m.2F\')m.2o(4Z,el);J q(2m[0]==\'m.9u\')m.2o(56,el);A g=m.43(el,\'2N\')||\'1E\';q(!3i[g])3i[g]=[];m.2o(3i[g],el)}}}m.4U={6q:6q,3i:3i,4Z:4Z,56:56};E m.4U},6p:C(){E m.4U||m.95()},26:C(el){A B=m.2G(el);q(B)B.26();E 1j}};m.fx=C(30,1r,1f){k.1r=1r;k.30=30;k.1f=1f;q(!1r.b7)1r.b7={}};m.fx.5w={82:C(){(m.fx.3P[k.1f]||m.fx.3P.ap)(k);q(k.1r.3P)k.1r.3P.ax(k.30,k.4o,k)},3E:C(8u,2i,4w){k.9c=(1J 7K()).79();k.4T=8u;k.51=2i;k.4w=4w;k.4o=k.4T;k.H=k.96=0;A 7c=k;C t(7i){E 7c.3P(7i)}t.30=k.30;q(t()&&m.4m.2o(t)==1){m.af=fX(C(){A 4m=m.4m;O(A i=0;i<4m.V;i++)q(!4m[i]())4m.gd(i--,1);q(!4m.V){eT(m.af)}},13)}},3P:C(7i){A t=(1J 7K()).79();q(7i||t>=k.1r.4h+k.9c){k.4o=k.51;k.H=k.96=1;k.82();k.1r.7g[k.1f]=M;A 9s=M;O(A i 2Y k.1r.7g)q(k.1r.7g[i]!==M)9s=1j;q(9s){q(k.1r.76)k.1r.76.ax(k.30)}E 1j}J{A n=t-k.9c;k.96=n/k.1r.4h;k.H=k.1r.2Q(n,0,1,k.1r.4h);k.4o=k.4T+((k.51-k.4T)*k.H);k.82()}E M}};m.3A(m.fx,{3P:{1z:C(fx){m.R(fx.30,{1z:fx.4o})},ap:C(fx){1t{q(fx.30.G&&fx.30.G[fx.1f]!=I)fx.30.G[fx.1f]=fx.4o+fx.4w;J fx.30[fx.1f]=fx.4o}1y(e){}}}});m.6r=C(1Z,3F){k.3F=3F;k.1Z=1Z;A v=m.2t,47;k.9G=m.2h&&m.2t<7;q(!1Z){q(3F)3F();E}m.7m();k.2g=m.1d(\'2g\',{eJ:0},{1n:\'1q\',1l:\'2l\',eN:\'eM\',L:0},m.2b,M);A 4G=m.1d(\'4G\',I,I,k.2g,1);k.2J=[];O(A i=0;i<=8;i++){q(i%3==0)47=m.1d(\'47\',I,{N:\'1M\'},4G,M);k.2J[i]=m.1d(\'2J\',I,I,47,M);A G=i!=4?{eL:0,eK:0}:{1l:\'4y\'};m.R(k.2J[i],G)}k.2J[4].1c=1Z+\' K-1g\';k.ai()};m.6r.5w={ai:C(){A 1e=m.5c+(m.f1||"fi/")+k.1Z+".ak";A ar=m.4M&&m.2t<73?m.2b:I;k.3V=m.1d(\'1N\',I,{1l:\'2l\',Y:\'-4v\'},ar,M);A 3v=k;k.3V.4N=C(){3v.az()};k.3V.1e=1e},az:C(){A o=k.1w=k.3V.L/4,H=[[0,0],[0,-4],[-2,0],[0,-8],0,[-2,-8],[0,-2],[0,-6],[-2,-2]],1u={N:(2*o)+\'F\',L:(2*o)+\'F\'};O(A i=0;i<=8;i++){q(H[i]){q(k.9G){A w=(i==1||i==7)?\'2w%\':k.3V.L+\'F\';A P=m.1d(\'P\',I,{L:\'2w%\',N:\'2w%\',1l:\'4y\',2e:\'1q\'},k.2J[i],M);m.1d(\'P\',I,{5Q:"fo:fn.bv.fm(fl=fe, 1e=\'"+k.3V.1e+"\')",1l:\'2l\',L:w,N:k.3V.N+\'F\',1b:(H[i][0]*o)+\'F\',Y:(H[i][1]*o)+\'F\'},P,M)}J{m.R(k.2J[i],{9t:\'7T(\'+k.3V.1e+\') \'+(H[i][0]*o)+\'F \'+(H[i][1]*o)+\'F\'})}q(1S.3z&&(i==3||i==5))m.1d(\'P\',I,1u,k.2J[i],M);m.R(k.2J[i],1u)}}k.3V=I;q(m.4n[k.1Z])m.4n[k.1Z].5U();m.4n[k.1Z]=k;q(k.3F)k.3F()},4C:C(H,1w,aB,4i,2Q){A B=k.B,5X=B.U.G,1w=1w||0,H=H||{x:B.x.H+1w,y:B.y.H+1w,w:B.x.Z(\'2f\')-2*1w,h:B.y.Z(\'2f\')-2*1w};q(aB)k.2g.G.1n=(H.h>=4*k.1w)?\'1Y\':\'1q\';m.R(k.2g,{1b:(H.x-k.1w)+\'F\',Y:(H.y-k.1w)+\'F\',L:(H.w+2*k.1w)+\'F\'});H.w-=2*k.1w;H.h-=2*k.1w;m.R(k.2J[4],{L:H.w>=0?H.w+\'F\':0,N:H.h>=0?H.h+\'F\':0});q(k.9G)k.2J[3].G.N=k.2J[5].G.N=k.2J[4].G.N},5U:C(bk){q(bk)k.2g.G.1n=\'1q\';J m.3B(k.2g)}};m.6A=C(B,1u){k.B=B;k.1u=1u;k.3l=1u==\'x\'?\'bY\':\'bW\';k.3k=k.3l.5G();k.6m=1u==\'x\'?\'cj\':\'c8\';k.6Y=k.6m.5G();k.9L=1u==\'x\'?\'c7\':\'bX\';k.b5=k.9L.5G();k.1G=k.36=0};m.6A.5w={Z:C(Q){b6(Q){2c\'9T\':E k.1K+k.3s+(k.t-m.2r[\'1w\'+k.3l])/2;2c\'9v\':E k.H+k.cb+k.1G+(k.D-m.2r[\'1w\'+k.3l])/2;2c\'2f\':E k.D+2*k.cb+k.1G+k.36;2c\'5e\':E k.4K-k.3o-k.4S;2c\'8D\':E k.Z(\'5e\')-2*k.cb-k.1G-k.36;2c\'6e\':E k.H-(k.B.1g?k.B.1g.1w:0);2c\'9R\':E k.Z(\'2f\')+(k.B.1g?2*k.B.1g.1w:0);2c\'2K\':E k.1V?1h.3e((k.D-k.1V)/2):0}},8a:C(){k.cb=(k.B.S[\'1w\'+k.3l]-k.t)/2;k.4S=m[\'9D\'+k.9L]},9M:C(){k.t=k.B.el[k.3k]?3H(k.B.el[k.3k]):k.B.el[\'1w\'+k.3l];k.1K=k.B.1K[k.1u];k.3s=(k.B.el[\'1w\'+k.3l]-k.t)/2;q(k.1K==0||k.1K==-1){k.1K=(m.4g[k.3k]/2)+m.4g[\'28\'+k.6m]}},8h:C(){A B=k.B;k.2T=\'1M\';q(B.9n==\'4X\')k.2T=\'4X\';J q(1J 4Y(k.6Y).11(B.46))k.2T=I;J q(1J 4Y(k.b5).11(B.46))k.2T=\'4t\';k.H=k.1K-k.cb+k.3s;q(k.9i&&k.1u==\'x\')B.6M=1h.31(B.6M||k.1a,B.9i*k.1a/B.y.1a);k.D=1h.31(k.1a,B[\'4t\'+k.3l]||k.1a);k.2U=B.5Y?1h.31(B[\'31\'+k.3l],k.1a):k.1a;q(B.2E&&B.3t){k.D=B[k.3k];k.1V=k.1a}q(k.1u==\'x\'&&m.5S)k.2U=B.4s;k.2L=B[\'2L\'+k.1u.bi()];k.3o=m[\'9D\'+k.6m];k.28=m.4g[\'28\'+k.6m];k.4K=m.4g[k.3k]},72:C(i){A B=k.B;q(B.2E&&(B.3t||m.5S)){k.1V=i;k.D=1h.4t(k.D,k.1V);B.S.G[k.6Y]=k.Z(\'2K\')+\'F\'}J k.D=i;B.S.G[k.3k]=i+\'F\';B.U.G[k.3k]=k.Z(\'2f\')+\'F\';q(B.1g)B.1g.4C();q(B.3W)B.3W.G[k.3k]=i+\'F\';q(k.1u==\'y\'&&B.5C&&B.19.G.N!=\'1M\')1t{B.5C.19.G.2e=\'1M\'}1y(e){}q(B.2A){A d=B.2s;q(k.9e===1L)k.9e=B.1s[\'1w\'+k.3l]-d[\'1w\'+k.3l];d.G[k.3k]=(k.D-k.9e)+\'F\';q(k.1u==\'x\')B.4c.G.L=\'1M\';q(B.19)B.19.G[k.3k]=\'1M\'}q(k.1u==\'x\'&&B.1x)B.57(M);q(k.1u==\'x\'&&B.1p&&B.2E){q(i==k.1a)B.1p.5d(\'1a-2F\');J B.1p.4u(\'1a-2F\')}},aa:C(i){k.H=i;k.B.U.G[k.6Y]=i+\'F\';q(k.B.1g)k.B.1g.4C()}};m.5A=C(a,29,3E,35){q(W.bS&&m.2h&&!m.9F){m.2j(W,\'41\',C(){1J m.5A(a,29,3E,35)});E}k.a=a;k.3E=3E;k.35=35||\'2R\';k.2A=(35==\'3D\');k.2E=!k.2A;m.a1=1j;k.1T=[];k.1i=m.1i;m.1i=I;m.7m();A Q=k.Q=m.16.V;O(A i=0;i<m.a4.V;i++){A 2Z=m.a4[i];k[2Z]=29&&1F 29[2Z]!=\'1L\'?29[2Z]:m[2Z]}q(!k.1e)k.1e=a.21;A el=(29&&29.9P)?m.$(29.9P):a;el=k.aW=el.2C(\'1N\')[0]||el;k.6Q=el.1v||a.1v;q(!m.1A(k,\'f3\'))E M;O(A i=0;i<m.16.V;i++){q(m.16[i]&&m.16[i].a==a&&!(k.1i&&k.3q[1]==\'4e\')){m.16[i].3M();E 1j}}q(!m.f5)O(A i=0;i<m.16.V;i++){q(m.16[i]&&m.16[i].aW!=el&&!m.16[i].6D){m.16[i].6P()}}m.16[Q]=k;q(!m.9l&&!m.2q){q(m.16[Q-1])m.16[Q-1].26();q(1F m.3d!=\'1L\'&&m.16[m.3d])m.16[m.3d].26()}k.el=el;k.1K=k.aX||m.6K(el);m.7S();A x=k.x=1J m.6A(k,\'x\');x.9M();A y=k.y=1J m.6A(k,\'y\');y.9M();q(/5v/i.11(el.3J))k.b8(el);k.U=m.1d(\'P\',{1v:\'K-U-\'+k.Q,1c:\'K-U \'+k.a9},{1n:\'1q\',1l:\'2l\',1B:m.4F+=2},I,M);k.U.eX=k.U.eS=m.aP;q(k.35==\'2R\'&&k.3Y==2)k.3Y=0;q(!k.1Z||(k.1i&&k.2E&&k.3q[1]==\'4e\')){k[k.35+\'9H\']()}J q(m.4n[k.1Z]){k.9I();k[k.35+\'9H\']()}J{k.6n();A B=k;1J m.6r(k.1Z,C(){B.9I();B[B.35+\'9H\']()})}E M};m.5A.5w={9o:C(e){q(m.g8)dq(\'dk \'+e.dl+\': \'+e.dD);J 1S.85.21=k.1e},9I:C(){A 1g=k.1g=m.4n[k.1Z];1g.B=k;1g.2g.G.1B=k.U.G.1B-1;m.4n[k.1Z]=I},6n:C(){q(k.6D||k.2r)E;k.2r=m.2r;A B=k;k.2r.2p=C(){B.6P()};q(!m.1A(k,\'d5\'))E;A B=k,l=k.x.Z(\'9T\')+\'F\',t=k.y.Z(\'9T\')+\'F\';q(!2P&&k.1i&&k.3q[1]==\'4e\')A 2P=k.1i;q(2P){l=2P.x.Z(\'9v\')+\'F\';t=2P.y.Z(\'9v\')+\'F\';k.2r.G.1B=m.4F++}4a(C(){q(B.2r)m.R(B.2r,{1b:l,Y:t,1B:m.4F++})},2w)},ey:C(){A B=k;A 1N=W.1d(\'1N\');k.S=1N;1N.4N=C(){q(m.16[B.Q])B.69()};q(m.e3)1N.dp=C(){E 1j};1N.1c=\'K-2R\';m.R(1N,{1n:\'1q\',1o:\'3X\',1l:\'2l\',6M:\'4v\',1B:3});1N.24=m.18.9W;q(m.4M&&m.2t<73)m.2b.1X(1N);q(m.2h&&m.dH)1N.1e=I;1N.1e=k.1e;k.6n()},d4:C(){q(!m.1A(k,\'da\'))E;k.S=m.86(k.a);q(!k.S)k.S=m.4J(k.88);q(!k.S)k.S=m.89();k.a2([\'6C\']);q(k.6C){A 19=m.4p(k.S,\'P\',\'K-19\');q(19)19.1X(k.6C);k.6C.G.1o=\'3X\'}m.1A(k,\'fp\');A 1s=k.1s=k.S;q(/(3x|1k)/.11(k.2I))k.91(1s);m.2b.1X(k.U);m.R(k.U,{1l:\'fa\',94:\'0 \'+m.9B+\'F 0 \'+m.4W+\'F\'});k.S=m.1d(\'P\',{1c:\'K-3D\'},{1l:\'4y\',1B:3,N:0,2e:\'1q\'},k.U);k.4c=m.1d(\'P\',I,I,k.S,1);k.4c.1X(1s);m.R(1s,{1l:\'4y\',1o:\'3X\',9S:m.18.97||\'\'});q(k.L)1s.G.L=k.L+\'F\';q(k.N)m.R(1s,{N:k.N+\'F\',2e:\'1q\'});q(1s.1O<k.4s)1s.G.L=k.4s+\'F\';q(k.2I==\'2W\'&&!m.86(k.a)){k.6n();A B=k;A 2W=1J m.7x(k.a,1s);2W.1e=k.1e;2W.3F=C(){q(m.16[B.Q])B.69()};2W.9z=C(){85.21=B.1e};2W.9r()}J q(k.2I==\'1k\'&&k.3U==\'60\'){k.6T()}J k.69()},69:C(){1t{q(!k.S)E;k.S.4N=I;q(k.6D)E;J k.6D=M;A x=k.x,y=k.y;q(k.2r){m.R(k.2r,{Y:\'-4v\'});k.2r=I;m.1A(k,\'cu\')}q(k.2E){x.1a=k.S.L;y.1a=k.S.N;m.R(k.S,{L:x.t+\'F\',N:y.t+\'F\'});k.U.1X(k.S);m.2b.1X(k.U)}J q(k.7Z)k.7Z();x.8a();y.8a();m.R(k.U,{1b:(x.1K+x.3s-x.cb)+\'F\',Y:(y.1K+x.3s-y.cb)+\'F\'});k.a0();k.bB();A 2M=x.1a/y.1a;x.8h();k.2T(x);y.8h();k.2T(y);q(k.2A)k.b4();q(k.1x)k.57(0,1);q(k.5Y){q(k.2E)k.cG(2M);J k.8x();A 1R=k.1p;q(1R&&k.1i&&1R.2X&&1R.aT){A H=1R.cB.1l||\'\',p;O(A 1u 2Y m.8g)O(A i=0;i<5;i++){p=k[1u];q(H.3b(m.8g[1u][i])){p.H=k.1i[1u].H+(k.1i[1u].1G-p.1G)+(k.1i[1u].D-p.D)*[0,0,.5,1,1][i];q(1R.aT==\'f0\'){q(p.H+p.D+p.1G+p.36>p.28+p.4K-p.4S)p.H=p.28+p.4K-p.D-p.3o-p.4S-p.1G-p.36;q(p.H<p.28+p.3o)p.H=p.28+p.3o}}}}q(k.2E&&k.x.1a>(k.x.1V||k.x.D)){k.bs();q(k.1T.V==1)k.57()}}k.a5()}1y(e){k.9o(e)}},91:C(6c,1M){A c=m.4p(6c,\'7J\',\'K-19\');q(/(1k|3x)/.11(k.2I)){q(k.4j)c.G.L=k.4j+\'F\';q(k.4x)c.G.N=k.4x+\'F\'}},6T:C(){q(k.aD)E;A B=k;k.19=m.4p(k.1s,\'7J\',\'K-19\');q(k.2I==\'1k\'){k.6n();A 5o=m.3w.5J(1);k.19.1X(5o);k.eP=k.1s.1O;q(!k.4j)k.4j=5o.1O;A 5b=k.1s.1U-k.19.1U,h=k.4x||m.4g.N-5b-m.4d-m.6L,4N=k.3U==\'60\'?\' 4N="q (m.16[\'+k.Q+\']) m.16[\'+k.Q+\'].69()" \':\'\';k.19.2d+=\'<1k 2Z="m\'+(1J 7K()).79()+\'" eQ="0" Q="\'+k.Q+\'" \'+\' G="L:\'+k.4j+\'F; N:\'+h+\'F" \'+4N+\' 1e="\'+k.1e+\'" ></1k>\';k.5o=k.19.2C(\'P\')[0];k.1k=k.19.2C(\'1k\')[0];q(k.3U==\'6x\')k.8A()}q(k.2I==\'3x\'){k.19.1v=k.19.1v||\'m-fY-1v-\'+k.Q;A a=k.8e;q(!a.29)a.29={};q(1F a.29.aN==\'1L\')a.29.aN=\'fR\';q(9p)9p.fT(k.1e,k.19.1v,k.4j,k.4x,a.g1||\'7\',a.gb,a.aG,a.29,a.aF)}k.aD=M},7Z:C(){q(k.1k&&!k.4x){k.1k.G.N=k.19.G.N=k.8p()+\'F\'}k.1s.1X(m.3w);q(!k.x.1a)k.x.1a=k.1s.1O;k.y.1a=k.1s.1U;k.1s.9q(m.3w);q(m.2h&&k.aL>3H(k.1s.5y.N)){k.aL=3H(k.1s.5y.N)}m.R(k.U,{1l:\'2l\',94:\'0\'});m.R(k.S,{L:k.x.t+\'F\',N:k.y.t+\'F\'})},8p:C(){A h;1t{A 2B=k.5C=k.1k.9O||k.1k.6g.W;A 3w=2B.1d(\'P\');3w.G.aJ=\'bc\';2B.19.1X(3w);h=3w.8O;q(m.2h)h+=3H(2B.19.5y.4d)+3H(2B.19.5y.6L)-1}1y(e){h=de}E h},8A:C(){A 5i=k.1s.1O-k.5o.1O;m.3B(k.5o);q(5i<0)5i=0;A 5b=k.1s.1U-k.1k.1U;q(k.5C&&!k.4x&&!k.N&&k.y.D==k.y.1a)1t{k.5C.19.G.2e=\'1q\'}1y(e){}m.R(k.1k,{L:1h.9Y(k.x.D-5i)+\'F\',N:1h.9Y(k.y.D-5b)+\'F\'});m.R(k.19,{L:k.1k.G.L,N:k.1k.G.N});k.52=k.1k;k.2s=k.52},b4:C(){k.91(k.1s);q(k.2I==\'3x\'&&k.3U==\'60\')k.6T();q(k.x.D<k.x.1a&&!k.6J)k.x.D=k.x.1a;q(k.y.D<k.y.1a&&!k.6X)k.y.D=k.y.1a;k.2s=k.1s;m.R(k.4c,{1l:\'4y\',L:k.x.D+\'F\'});m.R(k.1s,{8H:\'1E\',L:\'1M\',N:\'1M\'});A 1P=m.4p(k.1s,\'7J\',\'K-19\');q(1P&&!/(1k|3x)/.11(k.2I)){A 5f=1P;1P=m.1d(5f.d8,I,{2e:\'1q\'},I,M);5f.23.dG(1P,5f);1P.1X(m.3w);1P.1X(5f);A 5i=k.1s.1O-1P.1O;A 5b=k.1s.1U-1P.1U;1P.9q(m.3w);A 6E=m.4M||4A.av==\'at\'?1:0;m.R(1P,{L:(k.x.D-5i-6E)+\'F\',N:(k.y.D-5b)+\'F\',2e:\'1M\',1l:\'4y\'});q(6E&&5f.1U>1P.1U){1P.G.L=(3H(1P.G.L)+6E)+\'F\'}k.52=1P;k.2s=k.52}q(k.1k&&k.3U==\'60\')k.8A();q(!k.52&&k.y.D<k.4c.1U)k.2s=k.S;q(k.2s==k.S&&!k.6J&&!/(1k|3x)/.11(k.2I)){k.x.D+=17}q(k.2s&&k.2s.1U>k.2s.23.1U){4a("1t { m.16["+k.Q+"].2s.G.2e = \'1M\'; } 1y(e) {}",m.6W)}},b8:C(5v){A c=5v.fC.7G(\',\');O(A i=0;i<c.V;i++)c[i]=3H(c[i]);q(5v.ff.5G()==\'eI\'){k.x.1K+=c[0]-c[2];k.y.1K+=c[1]-c[2];k.x.t=k.y.t=2*c[2]}J{A 5H,5z,5x=5H=c[0],5B=5z=c[1];O(A i=0;i<c.V;i++){q(i%2==0){5x=1h.31(5x,c[i]);5H=1h.4t(5H,c[i])}J{5B=1h.31(5B,c[i]);5z=1h.4t(5z,c[i])}}k.x.1K+=5x;k.x.t=5H-5x;k.y.1K+=5B;k.y.t=5z-5B}},2T:C(p,5u){A 4H,2P=p.2L,1u=p==k.x?\'x\':\'y\';q(2P&&2P.3b(/ /)){4H=2P.7G(\' \');2P=4H[0]}q(2P&&m.$(2P)){p.H=m.6K(m.$(2P))[1u];q(4H&&4H[1]&&4H[1].3b(/^[-]?[0-9]+F$/))p.H+=3H(4H[1]);q(p.D<p.2U)p.D=p.2U}J q(p.2T==\'1M\'||p.2T==\'4X\'){A 8C=1j;A 5s=p.B.5Y;q(p.2T==\'4X\')p.H=1h.3e(p.28+(p.4K+p.3o-p.4S-p.Z(\'2f\'))/2);J p.H=1h.3e(p.H-((p.Z(\'2f\')-p.t)/2));q(p.H<p.28+p.3o){p.H=p.28+p.3o;8C=M}q(!5u&&p.D<p.2U){p.D=p.2U;5s=1j}q(p.H+p.Z(\'2f\')>p.28+p.4K-p.4S){q(!5u&&8C&&5s){p.D=1h.31(p.D,p.Z(1u==\'y\'?\'5e\':\'8D\'))}J q(p.Z(\'2f\')<p.Z(\'5e\')){p.H=p.28+p.4K-p.4S-p.Z(\'2f\')}J{p.H=p.28+p.3o;q(!5u&&5s)p.D=p.Z(1u==\'y\'?\'5e\':\'8D\')}}q(!5u&&p.D<p.2U){p.D=p.2U;5s=1j}}J q(p.2T==\'4t\'){p.H=1h.dm(p.H-p.D+p.t)}q(p.H<p.3o){A cH=p.H;p.H=p.3o;q(5s&&!5u)p.D=p.D-(p.H-cH)}},cG:C(2M){A x=k.x,y=k.y,3T=1j,3f=1h.31(x.1a,x.D),3y=1h.31(y.1a,y.D),3t=(k.3t||m.5S);q(3f/3y>2M){ 3f=3y*2M;q(3f<x.2U){3f=x.2U;3y=3f/2M}3T=M}J q(3f/3y<2M){ 3y=3f/2M;3T=M}q(m.5S&&x.1a<x.2U){x.1V=x.1a;y.D=y.1V=y.1a}J q(k.3t){x.1V=3f;y.1V=3y}J{x.D=3f;y.D=3y}3T=k.8x(k.3t?I:2M,3T);q(3t&&y.D<y.1V){y.1V=y.D;x.1V=y.D*2M}q(3T||3t){x.H=x.1K-x.cb+x.3s;x.2U=x.D;k.2T(x,M);y.H=y.1K-y.cb+y.3s;y.2U=y.D;k.2T(y,M);q(k.1x)k.57()}},8x:C(2M,3T){A x=k.x,y=k.y;q(k.1x&&(k.2E||k.6X)){5g(y.D>k.6k&&x.D>k.4s&&y.Z(\'2f\')>y.Z(\'5e\')){y.D-=10;q(2M)x.D=y.D*2M;k.57(0,1);3T=M}}E 3T},dS:C(){q(k.2s){A h=/1k/i.11(k.2s.3J)?(k.8p()+1)+\'F\':\'1M\';q(k.19)k.19.G.N=h;k.2s.G.N=h;k.y.72(k.1s.1U)}},a5:C(){A x=k.x,y=k.y;k.59(\'1q\');m.1A(k,\'et\');q(k.1p&&k.1p.2D)k.1p.2D.5t();k.9b(1,{U:{L:x.Z(\'2f\'),N:y.Z(\'2f\'),1b:x.H,Y:y.H},S:{1b:x.1G+x.Z(\'2K\'),Y:y.1G+y.Z(\'2K\'),L:x.1V||x.D,N:y.1V||y.D}},m.6W)},9b:C(1I,2i,4i){A 5M=k.3q,8o=1I?(k.1i?k.1i.a:I):m.2q,t=(5M[1]&&8o&&m.43(8o,\'3q\')[1]==5M[1])?5M[1]:5M[0];q(k[t]&&t!=\'2F\'){k[t](1I,2i);E}q(k.1g&&!k.3Y){q(1I)k.1g.4C();J k.1g.5U((k.2A&&k.4D))}q(!1I)k.78();A B=k,x=B.x,y=B.y,2Q=k.2Q;q(!1I)2Q=k.cF||2Q;A 6x=1I?C(){q(B.1g)B.1g.2g.G.1n="1Y";4a(C(){B.6I()},50)}:C(){B.5D()};q(1I)m.R(k.U,{L:x.t+\'F\',N:y.t+\'F\'});q(1I&&k.2A){m.R(k.U,{1b:(x.1K-x.cb+x.3s)+\'F\',Y:(y.1K-y.cb+y.3s)+\'F\'})}q(k.cD){m.R(k.U,{1z:1I?0:1});m.3A(2i.U,{1z:1I})}m.2z(k.U,2i.U,{4h:4i,2Q:2Q,3P:C(3j,2H){q(B.1g&&B.3Y&&2H.1f==\'Y\'){A 5W=1I?2H.H:1-2H.H;A H={w:x.t+(x.Z(\'2f\')-x.t)*5W,h:y.t+(y.Z(\'2f\')-y.t)*5W,x:x.1K+(x.H-x.1K)*5W,y:y.1K+(y.H-y.1K)*5W};B.1g.4C(H,0,1)}q(B.2A){q(2H.1f==\'1b\')B.4c.G.1b=(x.H-3j)+\'F\';q(2H.1f==\'Y\')B.4c.G.Y=(y.H-3j)+\'F\'}}});m.2z(k.S,2i.S,4i,2Q,6x);q(1I){k.U.G.1n=\'1Y\';k.S.G.1n=\'1Y\';q(k.2A)k.1s.G.1n=\'1Y\';k.a.1c+=\' K-4I-46\'}},6w:C(1I,2i){k.3Y=1j;A B=k,t=1I?m.6W:0;q(1I){m.2z(k.U,2i.U,0);m.R(k.U,{1z:0,1n:\'1Y\'});m.2z(k.S,2i.S,0);k.S.G.1n=\'1Y\';m.2z(k.U,{1z:1},t,I,C(){B.6I()})}q(k.1g){k.1g.2g.G.1B=k.U.G.1B;A 6Z=1I||-1,1w=k.1g.1w,8r=1I?3:1w,8q=1I?1w:3;O(A i=8r;6Z*i<=6Z*8q;i+=6Z,t+=25){(C(){A o=1I?8q-i:8r-i;4a(C(){B.1g.4C(0,o,1)},t)})()}}q(1I){}J{4a(C(){q(B.1g)B.1g.5U(B.4D);B.78();m.2z(B.U,{1z:0},m.9A,I,C(){B.5D()})},t)}},4e:C(1I,2i,8u){q(!1I)E;A B=k,1i=k.1i,x=k.x,y=k.y,3n=1i.x,3g=1i.y,U=k.U,S=k.S,1x=k.1x;m.4z(W,\'7D\',m.6H);m.R(S,{L:(x.1V||x.D)+\'F\',N:(y.1V||y.D)+\'F\'});q(1x)1x.G.2e=\'1Y\';k.1g=1i.1g;q(k.1g)k.1g.B=B;1i.1g=I;A 5l=m.1d(\'P\',{1c:\'K-\'+k.35},{1l:\'2l\',1B:4,2e:\'1q\',1o:\'1E\'});A 8t={cN:1i,cM:k};O(A n 2Y 8t){k[n]=8t[n].S.5J(1);m.R(k[n],{1l:\'2l\',8H:0,1n:\'1Y\'});5l.1X(k[n])}U.1X(5l);q(k.2A)m.R(k.4c,{1b:0,Y:0});q(1x){1x.1c=\'\';U.1X(1x)}5l.G.1o=\'\';1i.S.G.1o=\'1E\';q(m.4M&&m.2t<73){k.U.G.1n=\'1Y\'}m.2z(U,{L:x.D},{4h:m.cE,3P:C(3j,2H){A H=2H.H,4B=1-H;A 1f,D={},93=[\'H\',\'D\',\'1G\',\'36\'];O(A n 2Y 93){1f=93[n];D[\'x\'+1f]=1h.3e(4B*3n[1f]+H*x[1f]);D[\'y\'+1f]=1h.3e(4B*3g[1f]+H*y[1f]);D.cI=1h.3e(4B*(3n.1V||3n.D)+H*(x.1V||x.D));D.6S=1h.3e(4B*3n.Z(\'2K\')+H*x.Z(\'2K\'));D.cJ=1h.3e(4B*(3g.1V||3g.D)+H*(y.1V||y.D));D.6V=1h.3e(4B*3g.Z(\'2K\')+H*y.Z(\'2K\'))}q(B.1g)B.1g.4C({x:D.3h,y:D.3r,w:D.5L+D.44+D.8U+2*x.cb,h:D.5K+D.45+D.8T+2*y.cb});1i.U.G.d7=\'d6(\'+(D.3r-3g.H)+\'F, \'+(D.5L+D.44+D.8U+D.3h+2*3n.cb-3n.H)+\'F, \'+(D.5K+D.45+D.8T+D.3r+2*3g.cb-3g.H)+\'F, \'+(D.3h-3n.H)+\'F)\';m.R(S,{Y:(D.45+y.Z(\'2K\'))+\'F\',1b:(D.44+x.Z(\'2K\'))+\'F\',4d:(y.H-D.3r)+\'F\',4W:(x.H-D.3h)+\'F\'});m.R(U,{Y:D.3r+\'F\',1b:D.3h+\'F\',L:(D.44+D.8U+D.5L+2*x.cb)+\'F\',N:(D.45+D.8T+D.5K+2*y.cb)+\'F\'});m.R(5l,{L:(D.cI||D.5L)+\'F\',N:(D.cJ||D.5K)+\'F\',1b:(D.44+D.6S)+\'F\',Y:(D.45+D.6V)+\'F\',1n:\'1Y\'});m.R(B.cN,{Y:(3g.H-D.3r+3g.1G-D.45+3g.Z(\'2K\')-D.6V)+\'F\',1b:(3n.H-D.3h+3n.1G-D.44+3n.Z(\'2K\')-D.6S)+\'F\'});m.R(B.cM,{1z:H,Y:(y.H-D.3r+y.1G-D.45+y.Z(\'2K\')-D.6V)+\'F\',1b:(x.H-D.3h+x.1G-D.44+x.Z(\'2K\')-D.6S)+\'F\'});q(1x)m.R(1x,{L:D.5L+\'F\',N:D.5K+\'F\',1b:(D.44+x.cb)+\'F\',Y:(D.45+y.cb)+\'F\'})},76:C(){U.G.1n=S.G.1n=\'1Y\';S.G.1o=\'3X\';m.3B(5l);B.6I();1i.5D();B.1i=I}})},bQ:C(o,el){q(!k.1i)E 1j;O(A i=0;i<k.1i.1T.V;i++){A 6G=m.$(\'22\'+k.1i.1T[i]);q(6G&&6G.22==o.22){k.9V();6G.cS=k.Q;m.2o(k.1T,k.1i.1T[i]);E M}}E 1j},6I:C(){k.55=M;k.3M();q(k.2A&&k.3U==\'6x\')k.6T();q(k.1k){1t{A B=k,2B=k.1k.9O||k.1k.6g.W;m.2j(2B,\'8y\',C(){q(m.3d!=B.Q)B.3M()})}1y(e){}q(m.2h&&1F k.62!=\'cW\')k.1k.G.L=(k.4j-1)+\'F\'}q(k.4b)m.1u(k);q(m.2q&&m.2q==k.a)m.2q=I;k.cL();A p=m.4g,8Q=m.7B.x+p.5O,8P=m.7B.y+p.5R;k.9C=k.x.H<8Q&&8Q<k.x.H+k.x.Z(\'2f\')&&k.y.H<8P&&8P<k.y.H+k.y.Z(\'2f\');q(k.1x)k.bn();m.1A(k,\'d1\')},cL:C(){A Q=k.Q;A 1Z=k.1Z;1J m.6r(1Z,C(){1t{m.16[Q].cP()}1y(e){}})},cP:C(){A 1D=k.7V(1);q(1D&&1D.2p.cC().3b(/m\\.2F/))A 1N=m.1d(\'1N\',{1e:m.7s(1D)})},7V:C(2n){A 7U=k.7v(),as=m.4U.3i[k.2N||\'1E\'];q(as&&!as[7U+2n]&&k.1p&&k.1p.cm){q(2n==1)E as[0];J q(2n==-1)E as[as.V-1]}E(as&&as[7U+2n])||I},7v:C(){A 2a=m.6p().3i[k.2N||\'1E\'];q(2a)O(A i=0;i<2a.V;i++){q(2a[i]==k.a)E i}E I},bq:C(){q(k[k.6l]){A 2a=m.4U.3i[k.2N||\'1E\'];q(2a){A s=m.18.3G.2k(\'%1\',k.7v()+1).2k(\'%2\',2a.V);k[k.6l].2d=\'<P 1W="K-3G">\'+s+\'</P>\'+k[k.6l].2d}}},a0:C(){q(!k.1i){O(A i=0;i<m.6u.V;i++){A 1R=m.6u[i],3c=1R.2N;q(1F 3c==\'1L\'||3c===I||3c===k.2N)k.1p=1J m.83(k.Q,1R)}}J{k.1p=k.1i.1p}A 1R=k.1p;q(!1R)E;A Q=1R.4k=k.Q;1R.ch();1R.5d(\'1a-2F\');q(1R.2X){k.4O(m.3A(1R.cB||{},{4P:1R.2X,22:\'2X\',1B:5}))}q(1R.2D)1R.2D.7p(k);q(!k.1i&&k.42)1R.3L(M);q(1R.42){1R.42=4a(C(){m.1D(Q)},(1R.fH||fs))}},6P:C(){m.3B(k.U);m.16[k.Q]=I;q(m.2q==k.a)m.2q=I;m.9x(k.Q);q(k.2r)m.2r.G.1b=\'-4v\';m.1A(k,\'cu\')},bp:C(){q(k.67)E;k.67=m.1d(\'a\',{21:m.ct,2L:m.cs,1c:\'K-67\',2d:m.18.cq,24:m.18.cr});k.4O({4P:k.67,1l:k.cv||\'Y 1b\',22:\'67\'})},a2:C(8f,cy){O(A i=0;i<8f.V;i++){A T=8f[i],s=I;q(T==\'9X\'&&!m.1A(k,\'eH\'))E;J q(T==\'58\'&&!m.1A(k,\'eG\'))E;q(!k[T+\'5p\']&&k.6Q)k[T+\'5p\']=T+\'-O-\'+k.6Q;q(k[T+\'5p\'])k[T]=m.4J(k[T+\'5p\']);q(!k[T]&&!k[T+\'8j\']&&k[T+\'cw\'])1t{s=fh(k[T+\'cw\'])}1y(e){}q(!k[T]&&k[T+\'8j\']){s=k[T+\'8j\']}q(!k[T]&&!s){k[T]=m.4J(k.a[\'cA\'+T+\'5p\']);q(!k[T]){A 1D=k.a.cz;5g(1D&&!m.77(1D)){q((1J 4Y(\'K-\'+T)).11(1D.1c||I)){q(!1D.1v)k.a[\'cA\'+T+\'5p\']=1D.1v=\'22\'+m.61++;k[T]=m.4J(1D.1v);5m}1D=1D.cz}}}q(!k[T]&&!s&&k.6l==T)s=\'\\n\';q(!k[T]&&s)k[T]=m.1d(\'P\',{1c:\'K-\'+T,2d:s});q(cy&&k[T]){A o={1l:(T==\'58\')?\'5N\':\'7E\'};O(A x 2Y k[T+\'cx\'])o[x]=k[T+\'cx\'][x];o.4P=k[T];k.4O(o)}}},59:C(1n){q(m.cO)k.6B(\'fk\',1n);q(m.cQ)k.6B(\'dd\',1n);q(m.6y)k.6B(\'*\',1n)},6B:C(3J,1n){A 1m=W.2C(3J);A 1f=3J==\'*\'?\'2e\':\'1n\';O(A i=0;i<1m.V;i++){q(1f==\'1n\'||(W.8L.cK(1m[i],"").co(\'2e\')==\'1M\'||1m[i].bH(\'1q-by\')!=I)){A 2S=1m[i].bH(\'1q-by\');q(1n==\'1Y\'&&2S){2S=2S.2k(\'[\'+k.Q+\']\',\'\');1m[i].5F(\'1q-by\',2S);q(!2S)1m[i].G[1f]=1m[i].9N}J q(1n==\'1q\'){A 3N=m.6K(1m[i]);3N.w=1m[i].1O;3N.h=1m[i].1U;q(!k.4b){A bl=(3N.x+3N.w<k.x.Z(\'6e\')||3N.x>k.x.Z(\'6e\')+k.x.Z(\'9R\'));A bG=(3N.y+3N.h<k.y.Z(\'6e\')||3N.y>k.y.Z(\'6e\')+k.y.Z(\'9R\'))}A 6F=m.9U(1m[i]);q(!bl&&!bG&&6F!=k.Q){q(!2S){1m[i].5F(\'1q-by\',\'[\'+k.Q+\']\');1m[i].9N=1m[i].G[1f];1m[i].G[1f]=\'1q\'}J q(2S.bF(\'[\'+k.Q+\']\')==-1){1m[i].5F(\'1q-by\',2S+\'[\'+k.Q+\']\')}}J q((2S==\'[\'+k.Q+\']\'||m.3d==6F)&&6F!=k.Q){1m[i].5F(\'1q-by\',\'\');1m[i].G[1f]=1m[i].9N||\'\'}J q(2S&&2S.bF(\'[\'+k.Q+\']\')>-1){1m[i].5F(\'1q-by\',2S.2k(\'[\'+k.Q+\']\',\'\'))}}}}},3M:C(){k.U.G.1B=m.4F+=2;O(A i=0;i<m.16.V;i++){q(m.16[i]&&i==m.3d){A 4r=m.16[i];4r.S.1c+=\' K-\'+4r.35+\'-9J\';q(4r.2E){4r.S.G.4L=m.3Z?\'bE\':\'7Q\';4r.S.24=m.18.bD}m.1A(4r,\'eW\')}}q(k.1g)k.1g.2g.G.1B=k.U.G.1B-1;k.S.1c=\'K-\'+k.35;q(k.2E){k.S.24=m.18.9W;q(m.6h){m.54=1S.3z?\'7Q\':\'7T(\'+m.5c+m.6h+\'), 7Q\';q(m.3Z&&m.2t<6)m.54=\'bE\';k.S.G.4L=m.54}}m.3d=k.Q;m.2j(W,1S.3z?\'6U\':\'71\',m.68);m.1A(k,\'fd\')},9m:C(x,y){k.x.aa(x);k.y.aa(y)},3O:C(e){A w,h,r=e.L/e.N;w=1h.4t(e.L+e.dX,1h.31(k.4s,k.x.1a));q(k.2E&&1h.9Y(w-k.x.1a)<12)w=k.x.1a;h=k.2A?e.N+e.dY:w/r;q(h<1h.31(k.6k,k.y.1a)){h=1h.31(k.6k,k.y.1a);q(k.2E)w=h*r}k.9h(w,h)},9h:C(w,h){k.y.72(h);k.x.72(w);k.U.G.N=k.y.Z(\'2f\')+\'F\'},26:C(){q(k.62||!k.55)E;q(k.3q[1]==\'4e\'&&m.2q){m.2G(m.2q).6P();m.2q=I}q(!m.1A(k,\'eV\'))E;k.62=M;q(k.1p&&!m.2q)k.1p.3p();m.4z(W,1S.3z?\'6U\':\'71\',m.68);1t{q(k.2A)k.bJ();k.S.G.4L=\'fj\';k.9b(0,{U:{L:k.x.t,N:k.y.t,1b:k.x.1K-k.x.cb+k.x.3s,Y:k.y.1K-k.y.cb+k.y.3s},S:{1b:0,Y:0,L:k.x.t,N:k.y.t}},m.9A)}1y(e){k.5D()}},bJ:C(){q(m.6y){q(!m.6s)m.6s=m.1d(\'P\',I,{1l:\'2l\'},m.2b);m.R(m.6s,{L:k.x.D+\'F\',N:k.y.D+\'F\',1b:k.x.H+\'F\',Y:k.y.H+\'F\',1o:\'3X\'})}q(k.2I==\'3x\')1t{m.$(k.19.1v).f9()}1y(e){}q(k.3U==\'6x\'&&!k.4D)k.bK();q(k.2s&&k.2s!=k.52)k.2s.G.2e=\'1q\'},bK:C(){q(m.2h&&k.1k)1t{k.1k.6g.W.19.2d=\'\'}1y(e){}q(k.2I==\'3x\')9p.fb(k.19.1v);k.19.2d=\'\'},bx:C(){q(k.1g)k.1g.2g.G.1o=\'1E\';k.3W=I;k.U.G.1o=\'1E\';k.55=1j;m.2o(m.4R,k)},bP:C(){1t{m.16[k.Q]=k;q(!m.9l&&m.3d!=k.Q){1t{m.16[m.3d].26()}1y(e){}}A z=m.4F++,5X={1o:\'\',1B:z};m.R(k.U,5X);k.62=1j;A o=k.1g||0;q(o){q(!k.3Y)5X.1n=\'1q\';m.R(o.2g,5X)}q(k.1p){k.a0()}k.a5()}1y(e){}},4O:C(o){A el=o.4P,53=(o.bO==\'2x\'&&!/7M$/.11(o.1l));q(1F el==\'a8\')el=m.4J(el);q(o.3D)el=m.1d(\'P\',{2d:o.3D});q(!el||1F el==\'a8\')E;q(!m.1A(k,\'f7\',{14:el}))E;el.G.1o=\'3X\';o.22=o.22||o.4P;q(k.3q[1]==\'4e\'&&k.bQ(o,el))E;k.9V();A L=o.L&&/^[0-9]+(F|%)$/.11(o.L)?o.L:\'1M\';q(/^(1b|3m)7M$/.11(o.1l)&&!/^[0-9]+F$/.11(o.L))L=\'f2\';A 14=m.1d(\'P\',{1v:\'22\'+m.61++,22:o.22},{1l:\'2l\',1n:\'1q\',L:L,9S:m.18.97||\'\',1z:0},53?m.2x:k.1x,M);q(53)14.6R=k.Q;14.1X(el);m.3A(14,{1z:1,bN:0,bL:0,4i:(o.6w===0||o.6w===1j||(o.6w==2&&m.2h))?0:5Z});m.3A(14,o);q(k.bo){k.5V(14);q(!14.7d||k.9C)m.2z(14,{1z:14.1z},14.4i)}m.2o(k.1T,m.61-1)},5V:C(14){A p=14.1l||\'9a 4X\',53=(14.bO==\'2x\'),74=14.bN,6O=14.bL;q(53){m.2x.G.1o=\'3X\';14.6R=k.Q;q(14.1O>14.23.1O)14.G.L=\'2w%\'}J q(14.23!=k.1x)k.1x.1X(14);q(/1b$/.11(p))14.G.1b=74+\'F\';q(/4X$/.11(p))m.R(14,{1b:\'50%\',4W:(74-1h.3e(14.1O/2))+\'F\'});q(/3m$/.11(p))14.G.3m=-74+\'F\';q(/^bM$/.11(p)){m.R(14,{3m:\'2w%\',9B:k.x.cb+\'F\',Y:-k.y.cb+\'F\',4Q:-k.y.cb+\'F\',2e:\'1M\'});k.x.1G=14.1O}J q(/^bC$/.11(p)){m.R(14,{1b:\'2w%\',4W:k.x.cb+\'F\',Y:-k.y.cb+\'F\',4Q:-k.y.cb+\'F\',2e:\'1M\'});k.x.36=14.1O}A 9d=14.23.1U;14.G.N=\'1M\';q(53&&14.1U>9d)14.G.N=m.3Z?9d+\'F\':\'2w%\';q(/^Y/.11(p))14.G.Y=6O+\'F\';q(/^9a/.11(p))m.R(14,{Y:\'50%\',4d:(6O-1h.3e(14.1U/2))+\'F\'});q(/^4Q/.11(p))14.G.4Q=-6O+\'F\';q(/^5N$/.11(p)){m.R(14,{1b:(-k.x.1G-k.x.cb)+\'F\',3m:(-k.x.36-k.x.cb)+\'F\',4Q:\'2w%\',6L:k.y.cb+\'F\',L:\'1M\'});k.y.1G=14.1U}J q(/^7E$/.11(p)){m.R(14,{1l:\'4y\',1b:(-k.x.1G-k.x.cb)+\'F\',3m:(-k.x.36-k.x.cb)+\'F\',Y:\'2w%\',4d:k.y.cb+\'F\',L:\'1M\'});k.y.36=14.1U;14.G.1l=\'2l\'}},bB:C(){k.a2([\'58\',\'9X\'],M);k.bq();q(k.9X)m.1A(k,\'eE\');q(k.58)m.1A(k,\'eF\');q(k.58&&k.a7)k.58.1c+=\' K-3u\';q(m.br)k.bp();O(A i=0;i<m.1T.V;i++){A o=m.1T[i],6N=o.9P,3c=o.2N;q((!6N&&!3c)||(6N&&6N==k.6Q)||(3c&&3c===k.2N)){q(k.2E||(k.2A&&o.eO))k.4O(o)}}A 7I=[];O(A i=0;i<k.1T.V;i++){A o=m.$(\'22\'+k.1T[i]);q(/7M$/.11(o.1l))k.5V(o);J m.2o(7I,o)}O(A i=0;i<7I.V;i++)k.5V(7I[i]);k.bo=M},9V:C(){q(!k.1x)k.1x=m.1d(\'P\',{1c:k.a9},{1l:\'2l\',L:(k.x.D||(k.3t?k.L:I)||k.x.1a)+\'F\',N:(k.y.D||k.y.1a)+\'F\',1n:\'1q\',2e:\'1q\',1B:m.2h?4:\'1M\'},m.2b,M)},57:C(98,bm){A 1x=k.1x,x=k.x,y=k.y;m.R(1x,{L:x.D+\'F\',N:y.D+\'F\'});q(98||bm){O(A i=0;i<k.1T.V;i++){A o=m.$(\'22\'+k.1T[i]);A 9E=(m.3Z||W.7a==\'8v\');q(o&&/^(5N|7E)$/.11(o.1l)){q(9E){o.G.L=(1x.1O+2*x.cb+x.1G+x.36)+\'F\'}y[o.1l==\'5N\'?\'1G\':\'36\']=o.1U}q(o&&9E&&/^(1b|3m)7M$/.11(o.1l)){o.G.N=(1x.1U+2*y.cb)+\'F\'}}}q(98){m.R(k.S,{Y:y.1G+\'F\'});m.R(1x,{Y:(y.1G+y.cb)+\'F\'})}},bn:C(){A b=k.1x;b.1c=\'\';m.R(b,{Y:(k.y.1G+k.y.cb)+\'F\',1b:(k.x.1G+k.x.cb)+\'F\',2e:\'1Y\'});q(m.4M)b.G.1n=\'1Y\';k.U.1X(b);O(A i=0;i<k.1T.V;i++){A o=m.$(\'22\'+k.1T[i]);o.G.1B=o.1B||4;q(!o.7d||k.9C){o.G.1n=\'1Y\';m.R(o,{1n:\'1Y\',1o:\'\'});m.2z(o,{1z:o.1z},o.4i)}}},78:C(){q(!k.1T.V)E;q(k.1p){A c=k.1p.2X;q(c&&m.2G(c)==k)c.23.9q(c)}O(A i=0;i<k.1T.V;i++){A o=m.$(\'22\'+k.1T[i]);q(o&&o.23==m.2x&&m.2G(o)==k)m.3B(o)}q(k.2A&&k.4D){k.1x.G.Y=\'-4v\';m.2b.1X(k.1x)}J m.3B(k.1x)},bs:C(){q(k.1p&&k.1p.2X){k.1p.4u(\'1a-2F\');E}k.7u=m.1d(\'a\',{21:\'bt:m.16[\'+k.Q+\'].7r();\',24:m.18.9Z,1c:\'K-1a-2F\'});q(!m.1A(k,\'fq\'))E;k.4O({4P:k.7u,1l:m.bz,7d:M,1z:m.bA})},7r:C(){1t{q(!m.1A(k,\'fZ\'))E;q(k.7u)m.3B(k.7u);k.3M();A 3f=k.x.D,3y=k.y.D;k.9h(k.x.1a,k.y.1a);A 3h=k.x.H-(k.x.D-3f)/2;q(3h<m.4W)3h=m.4W;A 3r=k.y.H-(k.y.D-3y)/2;q(3r<m.4d)3r=m.4d;k.9m(3h,3r);k.59(\'1q\')}1y(e){k.9o(e)}},5D:C(){k.a.1c=k.a.1c.2k(\'K-4I-46\',\'\');k.59(\'1Y\');q(k.2A&&k.4D&&k.3q[1]!=\'4e\'){k.bx()}J{q(k.1g&&k.3Y)k.1g.5U();m.3B(k.U)}q(m.6s)m.6s.G.1o=\'1E\';k.78();q(!m.2x.7L.V)m.2x.G.1o=\'1E\';q(k.4b)m.9x(k.Q);m.1A(k,\'fW\');m.16[k.Q]=I;m.bw()}};m.7x=C(a,S,7t){k.a=a;k.S=S;k.7t=7t};m.7x.5w={9r:C(){A 2V;q(!k.1e)k.1e=m.7s(k.a);q(k.1e.3b(\'#\')){A 2a=k.1e.7G(\'#\');k.1e=2a[0];k.1v=2a[1]}q(m.7k[k.1e]){k.cd=m.7k[k.1e];q(k.1v)k.a3();J k.6f();E}1t{2V=1J cp()}1y(e){1t{2V=1J bu("fS.bR")}1y(e){1t{2V=1J bu("bv.bR")}1y(e){k.9z()}}}A 3v=k;2V.gc=C(){q(3v.2V.bS==4){q(3v.1v)3v.a3();J 3v.6f()}};A 1e=k.1e;k.2V=2V;q(m.g3)1e=1e.2k(/$/,(/\\?/.11(1e)?\'&\':\'?\')+\'g6=\'+(1J 7K()).79());2V.ca(\'fQ\',1e,M);2V.ce(\'X-fA-fB\',\'cp\');2V.ce(\'fu-fv\',\'fL/x-fO-9j-fJ\');2V.fF(I)},a3:C(){m.7m();A 4l=1S.3z||m.cf?{1e:\'fI:eC\'}:I;k.1k=m.1d(\'1k\',4l,{1l:\'2l\',Y:\'-4v\'},m.2b);k.6f()},6f:C(){A s=k.cd||k.2V.dn,7H;q(k.7t)m.7k[k.1e]=s;q(!m.2h||m.2t>=5.5){s=s.2k(1J 4Y(\'<di[^>]*>\',\'c9\'),\'\').2k(1J 4Y(\'<cc[^>]*>.*?</cc>\',\'c9\'),\'\');q(k.1k){A 2B=k.1k.9O;q(!2B&&k.1k.6g)2B=k.1k.6g.W;q(!2B){A 3v=k;4a(C(){3v.6f()},25);E}2B.ca();2B.dg(s);2B.26();1t{s=2B.9Q(k.1v).2d}1y(e){1t{s=k.1k.W.9Q(k.1v).2d}1y(e){}}m.3B(k.1k)}J{7H=/(<19[^>]*>|<\\/19>)/db;q(7H.11(s))s=s.7G(7H)[m.3R?1:2]}}m.4p(k.S,\'7J\',\'K-19\').2d=s;k.3F();O(A x 2Y k)k[x]=I}};m.83=C(4k,1r){q(m.cX!==1j)m.95();k.4k=4k;O(A x 2Y 1r)k[x]=1r[x];q(k.cZ)k.cg();q(k.2D)k.2D=m.ci(k)};m.83.5w={cg:C(){k.2X=m.1d(\'P\',{2d:m.8b(m.8i.2X)},I,m.2b);A 6j=[\'3L\',\'3p\',\'3a\',\'1D\',\'3u\',\'1a-2F\',\'26\'];k.1Q={};A 3v=k;O(A i=0;i<6j.V;i++){k.1Q[6j[i]]=m.4p(k.2X,\'1H\',\'K-\'+6j[i]);k.4u(6j[i])}k.1Q.3p.G.1o=\'1E\'},ch:C(){q(k.cm||!k.2X)E;A B=m.16[k.4k],5q=B.7v(),2m=/7w$/;q(5q==0)k.5d(\'3a\');J q(2m.11(k.1Q.3a.2C(\'a\')[0].1c))k.4u(\'3a\');q(5q+1==m.4U.3i[B.2N||\'1E\'].V){k.5d(\'1D\');k.5d(\'3L\')}J q(2m.11(k.1Q.1D.2C(\'a\')[0].1c)){k.4u(\'1D\');k.4u(\'3L\')}},4u:C(1Q){q(!k.1Q)E;A cn=k,a=k.1Q[1Q].2C(\'a\')[0],2m=/7w$/;a.2p=C(){cn[1Q]();E 1j};q(2m.11(a.1c))a.1c=a.1c.2k(2m,\'\')},5d:C(1Q){q(!k.1Q)E;A a=k.1Q[1Q].2C(\'a\')[0];a.2p=C(){E 1j};q(!/7w$/.11(a.1c))a.1c+=\' 7w\'},cl:C(){q(k.42)k.3p();J k.3L()},3L:C(ck){q(k.1Q){k.1Q.3L.G.1o=\'1E\';k.1Q.3p.G.1o=\'\'}k.42=M;q(!ck)m.1D(k.4k)},3p:C(){q(k.1Q){k.1Q.3p.G.1o=\'1E\';k.1Q.3L.G.1o=\'\'}d9(k.42);k.42=I},3a:C(){k.3p();m.3a(k.1Q.3a)},1D:C(){k.3p();m.1D(k.1Q.1D)},3u:C(){},\'1a-2F\':C(){m.2G().7r()},26:C(){m.26(k.1Q.26)}};m.ci=C(1p){C 7p(B){m.3A(1r||{},{4P:4E,22:\'2D\',1c:\'K-2D-\'+5k+\'-14 \'+(1r.1c||\'\')});q(m.3Z)1r.6w=0;B.4O(1r);m.R(4E.23,{2e:\'1q\'})};C 28(3K){5t(1L,1h.3e(3K*4E[3S?\'1O\':\'1U\']*0.7))};C 5t(i,80){q(i===1L)O(A j=0;j<5I.V;j++){q(5I[j]==m.16[1p.4k].a){i=j;5m}}q(i===1L)E;A as=4E.2C(\'a\'),4I=as[i],48=4I.23,1b=3S?\'cj\':\'c8\',3m=3S?\'c7\':\'bX\',L=3S?\'bY\':\'bW\',4V=\'1w\'+1b,1O=\'1w\'+L,7e=P.23.23[1O],5j=7e-2g[1O],6o=3H(2g.G[3S?\'1b\':\'Y\'])||0,2O=6o,ej=20;q(80!==1L){2O=6o-80;q(5j>0)5j=0;q(2O>0)2O=0;q(2O<5j)2O=5j}J{O(A j=0;j<as.V;j++)as[j].1c=\'\';4I.1c=\'K-4I-46\';A 7X=i>0?as[i-1].23[4V]:48[4V],7Y=48[4V]+48[1O]+(as[i+1]?as[i+1].23[1O]:0);q(7Y>7e-6o)2O=7e-7Y;J q(7X<-6o)2O=-7X}A 8R=48[4V]+(48[1O]-7f[1O])/2+2O;m.2z(2g,3S?{1b:2O}:{Y:2O},I,\'8S\');m.2z(7f,3S?{1b:8R}:{Y:8R},I,\'8S\');8l.G.1o=2O<0?\'3X\':\'1E\';8M.G.1o=(2O>5j)?\'3X\':\'1E\'};A 5I=m.4U.3i[m.16[1p.4k].2N||\'1E\'],1r=1p.2D,5k=1r.5k||\'bV\',8K=(5k==\'en\'),4f=8K?[\'P\',\'6t\',\'1H\',\'1C\']:[\'2g\',\'4G\',\'47\',\'2J\'],3S=(5k==\'bV\'),4E=m.1d(\'P\',{1c:\'K-2D K-2D-\'+5k,2d:\'<P 1W="K-2D-eg">\'+\'<\'+4f[0]+\'><\'+4f[1]+\'></\'+4f[1]+\'></\'+4f[0]+\'></P>\'+\'<P 1W="K-28-1I"><P></P></P>\'+\'<P 1W="K-28-ee"><P></P></P>\'+\'<P 1W="K-7f"><P></P></P>\'},{1o:\'1E\'},m.2b),5E=4E.7L,P=5E[0],8l=5E[1],8M=5E[2],7f=5E[3],2g=P.ef,4G=4E.2C(4f[1])[0],47;O(A i=0;i<5I.V;i++){q(i==0||!3S)47=m.1d(4f[2],I,I,4G);(C(){A a=5I[i],48=m.1d(4f[3],I,I,47),ex=i;m.1d(\'a\',{21:a.21,24:a.24,2p:C(){q(/K-4I-46/.11(k.1c))E 1j;m.2G(k).3M();E m.8N(a)},2d:m.bT?m.bT(a):a.2d},I,48)})()}q(!8K){8l.2p=C(){28(-1)};8M.2p=C(){28(1)};m.2j(4G,W.eA!==1L?\'er\':\'eq\',C(e){A 3K=0;e=e||1S.2u;q(e.bU){3K=e.bU/dR;q(m.3z)3K=-3K}J q(e.bZ){3K=-e.bZ/3}q(3K)28(-3K*0.2);q(e.5n)e.5n();e.c0=1j})}E{7p:7p,5t:5t}};m.7o=m.18;A e8=m.5A;q(m.2h&&1S==1S.Y){(C(){1t{W.5h.e4(\'1b\')}1y(e){4a(c5.dZ,50);E}m.41()})()}m.2j(W,\'dW\',m.41);m.2j(1S,\'8B\',m.41);m.2j(W,\'41\',C(){q(m.7R||m.4b){A G=m.1d(\'G\',{T:\'e0/8I\'},I,W.2C(\'e1\')[0]),8E=W.7a==\'8v\';C 5P(8m,8n){q(m.2h&&(m.2t<9||8E)){A 1i=W.c6[W.c6.V-1];q(1F(1i.5P)=="7j")1i.5P(8m,8n)}J{G.1X(W.e6(8m+" {"+8n+"}"))}}C 5T(1f){E\'e5( ( ( ez = W.5h.\'+1f+\' ? W.5h.\'+1f+\' : W.19.\'+1f+\' ) ) + \\\'F\\\' );\'}q(m.7R)5P(\'.K 1N\',\'4L: 7T(\'+m.5c+m.7R+\'), 7Q !dA;\');5P(\'.K-2x-D\',m.2h&&(m.2t<7||8E)?\'1l: 2l; \'+\'1b:\'+5T(\'5O\')+\'Y:\'+5T(\'5R\')+\'L:\'+5T(\'8F\')+\'N:\'+5T(\'c4\'):\'1l: fV; L: 2w%; N: 2w%; 1b: 0; Y: 0\')}});m.2j(1S,\'3O\',C(){m.7S();q(m.2x)O(A i=0;i<m.2x.7L.V;i++){A 1P=m.2x.7L[i],B=m.2G(1P);B.5V(1P);q(1P.22==\'2D\')B.1p.2D.5t()}});m.2j(W,\'7D\',C(e){m.7B={x:e.7A,y:e.7F}});m.2j(W,\'8y\',m.8z);m.2j(W,\'c3\',m.8z);m.2j(W,\'41\',m.c1);m.2j(1S,\'8B\',m.c2);m.2j(1S,\'8B\',m.bI)}',62,1006,'||||||||||||||||||||this||hs||||if||||||||||var|exp|function|size|return|px|style|pos|null|else|highslide|width|true|height|for|div|key|setStyles|content|type|wrapper|length|document||top|get||test|||overlay||expanders||lang|body|full|left|className|createElement|src|prop|outline|Math|last|false|iframe|position|els|visibility|display|slideshow|hidden|options|innerContent|try|dim|id|offset|overlayBox|catch|opacity|fireEvent|zIndex|span|next|none|typeof|p1|li|up|new|tpos|undefined|auto|img|offsetWidth|node|btn|ss|window|overlays|offsetHeight|imgSize|class|appendChild|visible|outlineType||href|hsId|parentNode|title||close||scroll|params|arr|container|case|innerHTML|overflow|wsize|table|ie|to|addEventListener|replace|absolute|re|op|push|onclick|upcoming|loading|scrollerDiv|uaVersion|event|dimmer|100|viewport|dragArgs|animate|isHtml|doc|getElementsByTagName|thumbstrip|isImage|expand|getExpander|args|objectType|td|imgPad|target|ratio|slideshowGroup|tblPos|tgt|easing|image|hiddenBy|justify|minSize|xhr|ajax|controls|in|name|elem|min||||contentType|p2||||previous|match|sg|focusKey|round|xSize|lastY|xpos|groups|val|wh|ucwh|right|lastX|marginMin|pause|transitions|ypos|tb|useBox|move|pThis|clearing|swf|ySize|opera|extend|discardElement|opt|html|custom|onLoad|number|parseInt|hasDragged|tagName|delta|play|focus|elPos|resize|step|func|ieLt9|isX|changed|objectLoadTime|graphic|releaseMask|block|outlineWhileAnimating|ieLt7||ready|autoplay|getParam|xp1|yp1|anchor|tr|cell|styles|setTimeout|dimmingOpacity|mediumContent|marginTop|crossfade|tree|page|duration|dur|objectWidth|expKey|attribs|timers|pendingOutlines|now|getElementByClass|clone|blurExp|minWidth|max|enable|9999px|unit|objectHeight|relative|removeEventListener|navigator|invPos|setPosition|preserveContent|dom|zIndexCounter|tbody|tgtArr|active|getNode|clientSize|cursor|safari|onload|createOverlay|overlayId|bottom|sleeping|marginMax|start|anchors|offsetLeft|marginLeft|center|RegExp|images||end|scrollingContent|relToVP|styleRestoreCursor|isExpanded|htmls|sizeOverlayBox|heading|doShowHide|cacheBindings|hDiff|graphicsDir|disable|fitsize|cNode|while|documentElement|wDiff|minTblPos|mode|fadeBox|break|preventDefault|ruler|Id|cur|owner|allowReduce|selectThumb|moveOnly|area|prototype|minX|currentStyle|maxY|Expander|minY|iDoc|afterClose|domCh|setAttribute|toLowerCase|maxX|group|cloneNode|ysize|xsize|trans|above|scrollLeft|addRule|filter|scrollTop|padToMinWidth|fix|destroy|positionOverlay|fac|stl|allowSizeReduction|250|before|idCounter|isClosing|iebody|preloadTheseImages|on|over|credits|keyHandler|contentLoaded|getParams|param|parent|userAgent|opos|loadHTML|contentWindow|restoreCursor|obj|buttons|minHeight|numberPosition|uclt|showLoading|curTblPos|getAnchors|all|Outline|mask|ul|slideshows|matches|fade|after|geckoMac|cache|Dimension|showHideElements|maincontent|onLoadStarted|kdeBugCorr|wrapperKey|oDiv|dragHandler|afterExpand|allowWidthReduction|getPosition|marginBottom|maxWidth|tId|offY|cancelLoading|thumbsUserSetId|hsKey|ximgPad|writeExtendedContent|keypress|yimgPad|expandDuration|allowHeightReduction|lt|dir||keydown|setSize|525|offX||complete|isHsAnchor|destroyOverlays|getTime|compatMode|rel|self|hideOnMouseOut|overlayWidth|marker|curAnim|expOnly|gotoEnd|object|cachedGets|onReady|init|topmostKey|langDefaults|add|preloadTheseAjax|doFullExpand|getSrc|pre|fullExpandLabel|getAnchorIndex|disabled|Ajax|element|adj|clientX|mouse|preloadFullImage|mousemove|below|clientY|split|regBody|os|DIV|Date|childNodes|panel|imgs|previousOrNext|relatedTarget|pointer|expandCursor|getPageSize|url|current|getAdjacentAnchor|cacheAjax|activeLeft|activeRight|htmlGetSize|scrollBy|pixDimmerSize|update|Slideshow|isNew|location|getCacheBinding|dimmingDuration|contentId|getSelfRendered|calcBorders|replaceLang|clones|topZ|swfOptions|types|oPos|calcExpanded|skin|Text|preloadAjaxElement|scrollUp|sel|dec|other|getIframePageHeight|endOff|startOff|previousTitle|names|from|BackCompat|arrow|fitOverlayBox|mousedown|mouseClickHandler|correctIframeSize|load|hasMovedMin|maxsize|backCompat|clientWidth|Click|border|css|parseFloat|floatMode|defaultView|scrollDown|transit|offsetTop|mY|mX|markerPos|easeOutQuad|yp2|xp2|moveTitle|nextText|nextTitle|previousText|moveText|closeTitle|setObjContainerSize|closeText|props|padding|updateAnchors|state|cssDirection|doWrapper||middle|changeSize|startTime|parOff|sizeDiff|numberOfImagesToPreload|distance|resizeTo|maxHeight|form|srcElement|allowMultipleInstances|moveTo|align|error|swfobject|removeChild|run|done|background|htmlExpand|loadingPosXfade|openerTagNames|undim|garbageBin|onError|restoreDuration|marginRight|mouseIsOver|margin|ie6|isReady|hasAlphaImageLoader|Create|connectOutline|blur|evt|ucrb|calcThumb|origProp|contentDocument|thumbnailId|getElementById|osize|direction|loadingPos|getWrapperKey|genOverlayBox|restoreTitle|caption|abs|fullExpandTitle|initSlideshow|continuePreloading|getInline|getElementContent|overrides|show|hasFocused|dragByHeading|string|wrapperClassName|setPos|playText|pauseText|pauseTitle|fullExpandText|timerId|Move|Pause|preloadGraphic|spacebar|png|Play|Close|Highslide|JS|_default|Previous|appendTo||KDE|playTitle|vendor|200|call|Next|onGraphicLoad|and|vis|targetY|hasExtendedContent|pow|attributes|flashvars|isUnobtrusiveAnchor|hsHasSetClick|clear|ltr|newHeight|detachEvent|wmode|clickY|wrapperMouseHandler|focusTopmost|dimmingGeckoFix|enableKeyListener|fixedControls|hasHtmlExpanders|clickX|thumb|pageOrigin|loadingTitle|loadingText|resizeTitle|targetX|headingOverlay|captionOverlay|htmlSizeOperations|rb|switch|orig|getImageMapAreaCorrection|rv|tag|offsetParent|both|contentWrapper|loadingOpacity|pageXOffset|alpha|nopad|toUpperCase|easeInQuad|hide|clearsX|doPanels|showOverlays|gotOverlays|writeCredits|getNumber|showCredits|createFullExpand|javascript|ActiveXObject|Microsoft|reOrder|sleep||fullExpandPosition|fullExpandOpacity|getOverlays|rightpanel|focusTitle|hand|indexOf|clearsY|getAttribute|preloadAjax|htmlPrepareClose|destroyObject|offsetY|leftpanel|offsetX|relativeTo|awake|reuseOverlay|XMLHTTP|readyState|stripItemFormatter|wheelDelta|horizontal|Height|Bottom|Width|detail|returnValue|setClickEvents|preloadImages|mouseup|clientHeight|arguments|styleSheets|Right|Top|gi|open||script|cachedGet|setRequestHeader|ie6SSL|getControls|checkFirstAndLast|Thumbstrip|Left|wait|hitSpace|repeat|sls|getPropertyValue|XMLHttpRequest|creditsText|creditsTitle|creditsTarget|creditsHref|onHideLoading|creditsPosition|Eval|Overlay|addOverlay|nextSibling|_|overlayOptions|toString|fadeInOut|transitionDuration|easingClose|correctRatio|tmpMin|ximgSize|yimgSize|getComputedStyle|prepareNextOutline|newImg|oldImg|hideSelects|preloadNext|hideIframes|scrollWidth|reuse|iPod|iPhone|scrollHeight|boolean|dynamicallyUpdateAnchors|10001|useControls|geckodimmer|onAfterExpand|iPad|onDimmerClick|htmlCreate|onShowLoading|rect|clip|nodeName|clearTimeout|onBeforeGetContent|ig|dimming|IFRAME|300|Android|write|xpand|link|htmlE|Line|lineNumber|floor|responseText|onDrop|oncontextmenu|alert|onImageClick|button|addSlideshow|registerOverlay|zoomin|graphics|zoomout|keyCode|onKeyDown|important|keys|click|message|drag|Use|insertBefore|flushImgSize|headingText|headingEval|headingId|captionEval|captionText|maincontentId|maincontentText|Trident|it|120|reflow|maincontentEval|captionId|shadow|DOMContentLoaded|||callee|text|HEAD|header|blockRightClick|doScroll|expression|createTextNode|footer|HsExpander|ra|Safari|useMap|_self|pageYOffset|down|firstChild|inner|com|outlineStartOffset|mgnRight|onSetClickEvent||http|float|innerHeight|innerWidth|DOMMouseScroll|mousewheel|Gecko|onBeforeExpand|Macintosh|drop|removeAttribute|pI|imageCreate|ignoreMe|onmousewheel|white|blank|esc|onAfterGetCaption|onAfterGetHeading|onBeforeGetHeading|onBeforeGetCaption|circle|cellSpacing|fontSize|lineHeight|collapse|borderCollapse|useOnHtml|newWidth|frameborder|front|onmouseout|clearInterval|01|onBeforeClose|onBlur|onmouseover|Resize|Expand|fit|outlinesDir|200px|onInit|Go|allowSimultaneousLoading|the|onCreateOverlay|Powered|StopPlay|static|removeSWF|actual|onFocus|scale|shape|homepage|eval|outlines|default|SELECT|sizingMethod|AlphaImageLoader|DXImageTransform|progid|onAfterGetContent|onCreateFullExpand|onMouseOut|500|onMouseOver|Content|Type|Loading||attachEvent|of|Requested|With|coords|toElement|fromElement|send|sqrt|interval|about|urlencoded|dragSensitivity|application|mouseover|onDrag|www|cancel|GET|transparent|Msxml2|embedSWF|onActivate|fixed|onAfterClose|setInterval|flash|onDoFullExpand|bring|version|linearTween|forceAjaxReload|https|protocol|dummy|Image|debug|paddingTop|1px|expressInstallSwfurl|onreadystatechange|splice'.split('|'),0,{}))
products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-ie6.css ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .closebutton {
2
+ /* NOTE! This URL is relative to the HTML page, not the CSS */
3
+ filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
4
+ src='../highslide/graphics/close.png', sizingMethod='scale');
5
+
6
+ background: none;
7
+ cursor: hand;
8
+ }
9
+
10
+ /* Viewport fixed hack */
11
+ .highslide-viewport {
12
+ position: absolute;
13
+ left: expression( ( ( ignoreMe1 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
14
+ top: expression( ( ignoreMe2 = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) + 'px' );
15
+ width: expression( ( ( ignoreMe3 = document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) ) + 'px' );
16
+ height: expression( ( ( ignoreMe4 = document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) ) + 'px' );
17
+ }
18
+
19
+ /* Thumbstrip PNG fix */
20
+ .highslide-scroll-down, .highslide-scroll-up {
21
+ position: relative;
22
+ overflow: hidden;
23
+ }
24
+ .highslide-scroll-down div, .highslide-scroll-up div {
25
+ /* NOTE! This URL is relative to the HTML page, not the CSS */
26
+ filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
27
+ src='../highslide/graphics/scrollarrows.png', sizingMethod='scale');
28
+ background: none !important;
29
+ position: absolute;
30
+ cursor: hand;
31
+ width: 75px;
32
+ height: 75px !important;
33
+ }
34
+ .highslide-thumbstrip-horizontal .highslide-scroll-down div {
35
+ left: -50px;
36
+ top: -15px;
37
+ }
38
+ .highslide-thumbstrip-horizontal .highslide-scroll-up div {
39
+ top: -15px;
40
+ }
41
+ .highslide-thumbstrip-vertical .highslide-scroll-down div {
42
+ top: -50px;
43
+ }
44
+
45
+ /* Thumbstrip marker arrow trasparent background fix */
46
+ .highslide-thumbstrip .highslide-marker {
47
+ border-color: white; /* match the background */
48
+ }
49
+ .dark .highslide-thumbstrip-horizontal .highslide-marker {
50
+ border-color: #111;
51
+ }
52
+ .highslide-viewport .highslide-marker {
53
+ border-color: #333;
54
+ }
55
+ .highslide-thumbstrip {
56
+ float: left;
57
+ }
58
+
59
+ /* Positioning fixes for the control bar */
60
+ .text-controls .highslide-controls {
61
+ width: 480px;
62
+ }
63
+ .text-controls a span {
64
+ width: 4em;
65
+ }
66
+ .text-controls .highslide-full-expand a span {
67
+ width: 0;
68
+ }
69
+ .text-controls .highslide-close a span {
70
+ width: 0;
71
+ }
72
+
73
+ /* Special */
74
+ .in-page .highslide-thumbstrip-horizontal .highslide-marker {
75
+ border-bottom: gray;
76
+ }
products/photocrati_nextgen/modules/lightbox/static/highslide/highslide-with-gallery.js ADDED
@@ -0,0 +1,2657 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Name: Highslide JS
3
+ * Version: 4.1.13 (2011-10-06)
4
+ * Config: default +slideshow +positioning +transitions +viewport +thumbstrip
5
+ * Author: Torstein Hønsi
6
+ * Support: www.highslide.com/support
7
+ * License: www.highslide.com/#license
8
+ */
9
+ if (!hs) { var hs = {
10
+ // Language strings
11
+ lang : {
12
+ cssDirection: 'ltr',
13
+ loadingText : 'Loading...',
14
+ loadingTitle : 'Click to cancel',
15
+ focusTitle : 'Click to bring to front',
16
+ fullExpandTitle : 'Expand to actual size (f)',
17
+ creditsText : 'Powered by <i>Highslide JS</i>',
18
+ creditsTitle : 'Go to the Highslide JS homepage',
19
+ previousText : 'Previous',
20
+ nextText : 'Next',
21
+ moveText : 'Move',
22
+ closeText : 'Close',
23
+ closeTitle : 'Close (esc)',
24
+ resizeTitle : 'Resize',
25
+ playText : 'Play',
26
+ playTitle : 'Play slideshow (spacebar)',
27
+ pauseText : 'Pause',
28
+ pauseTitle : 'Pause slideshow (spacebar)',
29
+ previousTitle : 'Previous (arrow left)',
30
+ nextTitle : 'Next (arrow right)',
31
+ moveTitle : 'Move',
32
+ fullExpandText : '1:1',
33
+ number: 'Image %1 of %2',
34
+ restoreTitle : 'Click to close image, click and drag to move. Use arrow keys for next and previous.'
35
+ },
36
+ // See http://highslide.com/ref for examples of settings
37
+ graphicsDir : 'highslide/graphics/',
38
+ expandCursor : 'zoomin.cur', // null disables
39
+ restoreCursor : 'zoomout.cur', // null disables
40
+ expandDuration : 250, // milliseconds
41
+ restoreDuration : 250,
42
+ marginLeft : 15,
43
+ marginRight : 15,
44
+ marginTop : 15,
45
+ marginBottom : 15,
46
+ zIndexCounter : 1001, // adjust to other absolutely positioned elements
47
+ loadingOpacity : 0.75,
48
+ allowMultipleInstances: true,
49
+ numberOfImagesToPreload : 5,
50
+ outlineWhileAnimating : 2, // 0 = never, 1 = always, 2 = HTML only
51
+ outlineStartOffset : 3, // ends at 10
52
+ padToMinWidth : false, // pad the popup width to make room for wide caption
53
+ fullExpandPosition : 'bottom right',
54
+ fullExpandOpacity : 1,
55
+ showCredits : true, // you can set this to false if you want
56
+ creditsHref : 'http://highslide.com/',
57
+ creditsTarget : '_self',
58
+ enableKeyListener : true,
59
+ openerTagNames : ['a'], // Add more to allow slideshow indexing
60
+ transitions : [],
61
+ transitionDuration: 250,
62
+ dimmingOpacity: 0, // Lightbox style dimming background
63
+ dimmingDuration: 50, // 0 for instant dimming
64
+
65
+ anchor : 'auto', // where the image expands from
66
+ align : 'auto', // position in the client (overrides anchor)
67
+ targetX: null, // the id of a target element
68
+ targetY: null,
69
+ dragByHeading: true,
70
+ minWidth: 200,
71
+ minHeight: 200,
72
+ allowSizeReduction: true, // allow the image to reduce to fit client size. If false, this overrides minWidth and minHeight
73
+ outlineType : 'drop-shadow', // set null to disable outlines
74
+ skin : {
75
+ controls:
76
+ '<div class="highslide-controls"><ul>'+
77
+ '<li class="highslide-previous">'+
78
+ '<a href="#" title="{hs.lang.previousTitle}">'+
79
+ '<span>{hs.lang.previousText}</span></a>'+
80
+ '</li>'+
81
+ '<li class="highslide-play">'+
82
+ '<a href="#" title="{hs.lang.playTitle}">'+
83
+ '<span>{hs.lang.playText}</span></a>'+
84
+ '</li>'+
85
+ '<li class="highslide-pause">'+
86
+ '<a href="#" title="{hs.lang.pauseTitle}">'+
87
+ '<span>{hs.lang.pauseText}</span></a>'+
88
+ '</li>'+
89
+ '<li class="highslide-next">'+
90
+ '<a href="#" title="{hs.lang.nextTitle}">'+
91
+ '<span>{hs.lang.nextText}</span></a>'+
92
+ '</li>'+
93
+ '<li class="highslide-move">'+
94
+ '<a href="#" title="{hs.lang.moveTitle}">'+
95
+ '<span>{hs.lang.moveText}</span></a>'+
96
+ '</li>'+
97
+ '<li class="highslide-full-expand">'+
98
+ '<a href="#" title="{hs.lang.fullExpandTitle}">'+
99
+ '<span>{hs.lang.fullExpandText}</span></a>'+
100
+ '</li>'+
101
+ '<li class="highslide-close">'+
102
+ '<a href="#" title="{hs.lang.closeTitle}" >'+
103
+ '<span>{hs.lang.closeText}</span></a>'+
104
+ '</li>'+
105
+ '</ul></div>'
106
+ },
107
+ // END OF YOUR SETTINGS
108
+
109
+
110
+ // declare internal properties
111
+ preloadTheseImages : [],
112
+ continuePreloading: true,
113
+ expanders : [],
114
+ overrides : [
115
+ 'allowSizeReduction',
116
+ 'useBox',
117
+ 'anchor',
118
+ 'align',
119
+ 'targetX',
120
+ 'targetY',
121
+ 'outlineType',
122
+ 'outlineWhileAnimating',
123
+ 'captionId',
124
+ 'captionText',
125
+ 'captionEval',
126
+ 'captionOverlay',
127
+ 'headingId',
128
+ 'headingText',
129
+ 'headingEval',
130
+ 'headingOverlay',
131
+ 'creditsPosition',
132
+ 'dragByHeading',
133
+ 'autoplay',
134
+ 'numberPosition',
135
+ 'transitions',
136
+ 'dimmingOpacity',
137
+
138
+ 'width',
139
+ 'height',
140
+
141
+ 'wrapperClassName',
142
+ 'minWidth',
143
+ 'minHeight',
144
+ 'maxWidth',
145
+ 'maxHeight',
146
+ 'pageOrigin',
147
+ 'slideshowGroup',
148
+ 'easing',
149
+ 'easingClose',
150
+ 'fadeInOut',
151
+ 'src'
152
+ ],
153
+ overlays : [],
154
+ idCounter : 0,
155
+ oPos : {
156
+ x: ['leftpanel', 'left', 'center', 'right', 'rightpanel'],
157
+ y: ['above', 'top', 'middle', 'bottom', 'below']
158
+ },
159
+ mouse: {},
160
+ headingOverlay: {},
161
+ captionOverlay: {},
162
+ timers : [],
163
+
164
+ slideshows : [],
165
+
166
+ pendingOutlines : {},
167
+ clones : {},
168
+ onReady: [],
169
+ uaVersion: /Trident\/4\.0/.test(navigator.userAgent) ? 8 :
170
+ parseFloat((navigator.userAgent.toLowerCase().match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1]),
171
+ ie : (document.all && !window.opera),
172
+ //ie : navigator && /MSIE [678]/.test(navigator.userAgent), // ie9 compliant?
173
+ safari : /Safari/.test(navigator.userAgent),
174
+ geckoMac : /Macintosh.+rv:1\.[0-8].+Gecko/.test(navigator.userAgent),
175
+
176
+ $ : function (id) {
177
+ if (id) return document.getElementById(id);
178
+ },
179
+
180
+ push : function (arr, val) {
181
+ arr[arr.length] = val;
182
+ },
183
+
184
+ createElement : function (tag, attribs, styles, parent, nopad) {
185
+ var el = document.createElement(tag);
186
+ if (attribs) hs.extend(el, attribs);
187
+ if (nopad) hs.setStyles(el, {padding: 0, border: 'none', margin: 0});
188
+ if (styles) hs.setStyles(el, styles);
189
+ if (parent) parent.appendChild(el);
190
+ return el;
191
+ },
192
+
193
+ extend : function (el, attribs) {
194
+ for (var x in attribs) el[x] = attribs[x];
195
+ return el;
196
+ },
197
+
198
+ setStyles : function (el, styles) {
199
+ for (var x in styles) {
200
+ if (hs.ieLt9 && x == 'opacity') {
201
+ if (styles[x] > 0.99) el.style.removeAttribute('filter');
202
+ else el.style.filter = 'alpha(opacity='+ (styles[x] * 100) +')';
203
+ }
204
+ else el.style[x] = styles[x];
205
+ }
206
+ },
207
+ animate: function(el, prop, opt) {
208
+ var start,
209
+ end,
210
+ unit;
211
+ if (typeof opt != 'object' || opt === null) {
212
+ var args = arguments;
213
+ opt = {
214
+ duration: args[2],
215
+ easing: args[3],
216
+ complete: args[4]
217
+ };
218
+ }
219
+ if (typeof opt.duration != 'number') opt.duration = 250;
220
+ opt.easing = Math[opt.easing] || Math.easeInQuad;
221
+ opt.curAnim = hs.extend({}, prop);
222
+ for (var name in prop) {
223
+ var e = new hs.fx(el, opt , name );
224
+
225
+ start = parseFloat(hs.css(el, name)) || 0;
226
+ end = parseFloat(prop[name]);
227
+ unit = name != 'opacity' ? 'px' : '';
228
+
229
+ e.custom( start, end, unit );
230
+ }
231
+ },
232
+ css: function(el, prop) {
233
+ if (el.style[prop]) {
234
+ return el.style[prop];
235
+ } else if (document.defaultView) {
236
+ return document.defaultView.getComputedStyle(el, null).getPropertyValue(prop);
237
+
238
+ } else {
239
+ if (prop == 'opacity') prop = 'filter';
240
+ var val = el.currentStyle[prop.replace(/\-(\w)/g, function (a, b){ return b.toUpperCase(); })];
241
+ if (prop == 'filter')
242
+ val = val.replace(/alpha\(opacity=([0-9]+)\)/,
243
+ function (a, b) { return b / 100 });
244
+ return val === '' ? 1 : val;
245
+ }
246
+ },
247
+
248
+ getPageSize : function () {
249
+ var d = document, w = window, iebody = d.compatMode && d.compatMode != 'BackCompat'
250
+ ? d.documentElement : d.body,
251
+ ieLt9 = hs.ie && (hs.uaVersion < 9 || typeof pageXOffset == 'undefined');
252
+
253
+ var width = ieLt9 ? iebody.clientWidth :
254
+ (d.documentElement.clientWidth || self.innerWidth),
255
+ height = ieLt9 ? iebody.clientHeight : self.innerHeight;
256
+ hs.page = {
257
+ width: width,
258
+ height: height,
259
+ scrollLeft: ieLt9 ? iebody.scrollLeft : pageXOffset,
260
+ scrollTop: ieLt9 ? iebody.scrollTop : pageYOffset
261
+ };
262
+ return hs.page;
263
+ },
264
+
265
+ getPosition : function(el) {
266
+ var p = { x: el.offsetLeft, y: el.offsetTop };
267
+ while (el.offsetParent) {
268
+ el = el.offsetParent;
269
+ p.x += el.offsetLeft;
270
+ p.y += el.offsetTop;
271
+ if (el != document.body && el != document.documentElement) {
272
+ p.x -= el.scrollLeft;
273
+ p.y -= el.scrollTop;
274
+ }
275
+ }
276
+ return p;
277
+ },
278
+
279
+ expand : function(a, params, custom, type) {
280
+ if (!a) a = hs.createElement('a', null, { display: 'none' }, hs.container);
281
+ if (typeof a.getParams == 'function') return params;
282
+ try {
283
+ new hs.Expander(a, params, custom);
284
+ return false;
285
+ } catch (e) { return true; }
286
+ },
287
+ getElementByClass : function (el, tagName, className) {
288
+ var els = el.getElementsByTagName(tagName);
289
+ for (var i = 0; i < els.length; i++) {
290
+ if ((new RegExp(className)).test(els[i].className)) {
291
+ return els[i];
292
+ }
293
+ }
294
+ return null;
295
+ },
296
+ replaceLang : function(s) {
297
+ s = s.replace(/\s/g, ' ');
298
+ var re = /{hs\.lang\.([^}]+)\}/g,
299
+ matches = s.match(re),
300
+ lang;
301
+ if (matches) for (var i = 0; i < matches.length; i++) {
302
+ lang = matches[i].replace(re, "$1");
303
+ if (typeof hs.lang[lang] != 'undefined') s = s.replace(matches[i], hs.lang[lang]);
304
+ }
305
+ return s;
306
+ },
307
+
308
+
309
+ focusTopmost : function() {
310
+ var topZ = 0,
311
+ topmostKey = -1,
312
+ expanders = hs.expanders,
313
+ exp,
314
+ zIndex;
315
+ for (var i = 0; i < expanders.length; i++) {
316
+ exp = expanders[i];
317
+ if (exp) {
318
+ zIndex = exp.wrapper.style.zIndex;
319
+ if (zIndex && zIndex > topZ) {
320
+ topZ = zIndex;
321
+ topmostKey = i;
322
+ }
323
+ }
324
+ }
325
+ if (topmostKey == -1) hs.focusKey = -1;
326
+ else expanders[topmostKey].focus();
327
+ },
328
+
329
+ getParam : function (a, param) {
330
+ a.getParams = a.onclick;
331
+ var p = a.getParams ? a.getParams() : null;
332
+ a.getParams = null;
333
+
334
+ return (p && typeof p[param] != 'undefined') ? p[param] :
335
+ (typeof hs[param] != 'undefined' ? hs[param] : null);
336
+ },
337
+
338
+ getSrc : function (a) {
339
+ var src = hs.getParam(a, 'src');
340
+ if (src) return src;
341
+ return a.href;
342
+ },
343
+
344
+ getNode : function (id) {
345
+ var node = hs.$(id), clone = hs.clones[id], a = {};
346
+ if (!node && !clone) return null;
347
+ if (!clone) {
348
+ clone = node.cloneNode(true);
349
+ clone.id = '';
350
+ hs.clones[id] = clone;
351
+ return node;
352
+ } else {
353
+ return clone.cloneNode(true);
354
+ }
355
+ },
356
+
357
+ discardElement : function(d) {
358
+ if (d) hs.garbageBin.appendChild(d);
359
+ hs.garbageBin.innerHTML = '';
360
+ },
361
+ dim : function(exp) {
362
+ if (!hs.dimmer) {
363
+ isNew = true;
364
+ hs.dimmer = hs.createElement ('div', {
365
+ className: 'highslide-dimming highslide-viewport-size',
366
+ owner: '',
367
+ onclick: function() {
368
+
369
+ hs.close();
370
+ }
371
+ }, {
372
+ visibility: 'visible',
373
+ opacity: 0
374
+ }, hs.container, true);
375
+
376
+ if (/(Android|iPad|iPhone|iPod)/.test(navigator.userAgent)) {
377
+ var body = document.body;
378
+ function pixDimmerSize() {
379
+ hs.setStyles(hs.dimmer, {
380
+ width: body.scrollWidth +'px',
381
+ height: body.scrollHeight +'px'
382
+ });
383
+ }
384
+ pixDimmerSize();
385
+ hs.addEventListener(window, 'resize', pixDimmerSize);
386
+ }
387
+ }
388
+ hs.dimmer.style.display = '';
389
+
390
+ var isNew = hs.dimmer.owner == '';
391
+ hs.dimmer.owner += '|'+ exp.key;
392
+
393
+ if (isNew) {
394
+ if (hs.geckoMac && hs.dimmingGeckoFix)
395
+ hs.setStyles(hs.dimmer, {
396
+ background: 'url('+ hs.graphicsDir + 'geckodimmer.png)',
397
+ opacity: 1
398
+ });
399
+ else
400
+ hs.animate(hs.dimmer, { opacity: exp.dimmingOpacity }, hs.dimmingDuration);
401
+ }
402
+ },
403
+ undim : function(key) {
404
+ if (!hs.dimmer) return;
405
+ if (typeof key != 'undefined') hs.dimmer.owner = hs.dimmer.owner.replace('|'+ key, '');
406
+
407
+ if (
408
+ (typeof key != 'undefined' && hs.dimmer.owner != '')
409
+ || (hs.upcoming && hs.getParam(hs.upcoming, 'dimmingOpacity'))
410
+ ) return;
411
+
412
+ if (hs.geckoMac && hs.dimmingGeckoFix) hs.dimmer.style.display = 'none';
413
+ else hs.animate(hs.dimmer, { opacity: 0 }, hs.dimmingDuration, null, function() {
414
+ hs.dimmer.style.display = 'none';
415
+ });
416
+ },
417
+ transit : function (adj, exp) {
418
+ var last = exp || hs.getExpander();
419
+ exp = last;
420
+ if (hs.upcoming) return false;
421
+ else hs.last = last;
422
+ hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);
423
+ try {
424
+ hs.upcoming = adj;
425
+ adj.onclick();
426
+ } catch (e){
427
+ hs.last = hs.upcoming = null;
428
+ }
429
+ try {
430
+ if (!adj || exp.transitions[1] != 'crossfade')
431
+ exp.close();
432
+ } catch (e) {}
433
+ return false;
434
+ },
435
+
436
+ previousOrNext : function (el, op) {
437
+ var exp = hs.getExpander(el);
438
+ if (exp) return hs.transit(exp.getAdjacentAnchor(op), exp);
439
+ else return false;
440
+ },
441
+
442
+ previous : function (el) {
443
+ return hs.previousOrNext(el, -1);
444
+ },
445
+
446
+ next : function (el) {
447
+ return hs.previousOrNext(el, 1);
448
+ },
449
+
450
+ keyHandler : function(e) {
451
+ if (!e) e = window.event;
452
+ if (!e.target) e.target = e.srcElement; // ie
453
+ if (typeof e.target.form != 'undefined') return true; // form element has focus
454
+ var exp = hs.getExpander();
455
+
456
+ var op = null;
457
+ switch (e.keyCode) {
458
+ case 70: // f
459
+ if (exp) exp.doFullExpand();
460
+ return true;
461
+ case 32: // Space
462
+ op = 2;
463
+ break;
464
+ case 34: // Page Down
465
+ case 39: // Arrow right
466
+ case 40: // Arrow down
467
+ op = 1;
468
+ break;
469
+ case 8: // Backspace
470
+ case 33: // Page Up
471
+ case 37: // Arrow left
472
+ case 38: // Arrow up
473
+ op = -1;
474
+ break;
475
+ case 27: // Escape
476
+ case 13: // Enter
477
+ op = 0;
478
+ }
479
+ if (op !== null) {if (op != 2)hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);
480
+ if (!hs.enableKeyListener) return true;
481
+
482
+ if (e.preventDefault) e.preventDefault();
483
+ else e.returnValue = false;
484
+ if (exp) {
485
+ if (op == 0) {
486
+ exp.close();
487
+ } else if (op == 2) {
488
+ if (exp.slideshow) exp.slideshow.hitSpace();
489
+ } else {
490
+ if (exp.slideshow) exp.slideshow.pause();
491
+ hs.previousOrNext(exp.key, op);
492
+ }
493
+ return false;
494
+ }
495
+ }
496
+ return true;
497
+ },
498
+
499
+
500
+ registerOverlay : function (overlay) {
501
+ hs.push(hs.overlays, hs.extend(overlay, { hsId: 'hsId'+ hs.idCounter++ } ));
502
+ },
503
+
504
+
505
+ addSlideshow : function (options) {
506
+ var sg = options.slideshowGroup;
507
+ if (typeof sg == 'object') {
508
+ for (var i = 0; i < sg.length; i++) {
509
+ var o = {};
510
+ for (var x in options) o[x] = options[x];
511
+ o.slideshowGroup = sg[i];
512
+ hs.push(hs.slideshows, o);
513
+ }
514
+ } else {
515
+ hs.push(hs.slideshows, options);
516
+ }
517
+ },
518
+
519
+ getWrapperKey : function (element, expOnly) {
520
+ var el, re = /^highslide-wrapper-([0-9]+)$/;
521
+ // 1. look in open expanders
522
+ el = element;
523
+ while (el.parentNode) {
524
+ if (el.hsKey !== undefined) return el.hsKey;
525
+ if (el.id && re.test(el.id)) return el.id.replace(re, "$1");
526
+ el = el.parentNode;
527
+ }
528
+ // 2. look in thumbnail
529
+ if (!expOnly) {
530
+ el = element;
531
+ while (el.parentNode) {
532
+ if (el.tagName && hs.isHsAnchor(el)) {
533
+ for (var key = 0; key < hs.expanders.length; key++) {
534
+ var exp = hs.expanders[key];
535
+ if (exp && exp.a == el) return key;
536
+ }
537
+ }
538
+ el = el.parentNode;
539
+ }
540
+ }
541
+ return null;
542
+ },
543
+
544
+ getExpander : function (el, expOnly) {
545
+ if (typeof el == 'undefined') return hs.expanders[hs.focusKey] || null;
546
+ if (typeof el == 'number') return hs.expanders[el] || null;
547
+ if (typeof el == 'string') el = hs.$(el);
548
+ return hs.expanders[hs.getWrapperKey(el, expOnly)] || null;
549
+ },
550
+
551
+ isHsAnchor : function (a) {
552
+ return (a.onclick && a.onclick.toString().replace(/\s/g, ' ').match(/hs.(htmlE|e)xpand/));
553
+ },
554
+
555
+ reOrder : function () {
556
+ for (var i = 0; i < hs.expanders.length; i++)
557
+ if (hs.expanders[i] && hs.expanders[i].isExpanded) hs.focusTopmost();
558
+ },
559
+
560
+ mouseClickHandler : function(e)
561
+ {
562
+ if (!e) e = window.event;
563
+ if (e.button > 1) return true;
564
+ if (!e.target) e.target = e.srcElement;
565
+
566
+ var el = e.target;
567
+ while (el.parentNode
568
+ && !(/highslide-(image|move|html|resize)/.test(el.className)))
569
+ {
570
+ el = el.parentNode;
571
+ }
572
+ var exp = hs.getExpander(el);
573
+ if (exp && (exp.isClosing || !exp.isExpanded)) return true;
574
+
575
+ if (exp && e.type == 'mousedown') {
576
+ if (e.target.form) return true;
577
+ var match = el.className.match(/highslide-(image|move|resize)/);
578
+ if (match) {
579
+ hs.dragArgs = {
580
+ exp: exp ,
581
+ type: match[1],
582
+ left: exp.x.pos,
583
+ width: exp.x.size,
584
+ top: exp.y.pos,
585
+ height: exp.y.size,
586
+ clickX: e.clientX,
587
+ clickY: e.clientY
588
+ };
589
+
590
+
591
+ hs.addEventListener(document, 'mousemove', hs.dragHandler);
592
+ if (e.preventDefault) e.preventDefault(); // FF
593
+
594
+ if (/highslide-(image|html)-blur/.test(exp.content.className)) {
595
+ exp.focus();
596
+ hs.hasFocused = true;
597
+ }
598
+ return false;
599
+ }
600
+ } else if (e.type == 'mouseup') {
601
+
602
+ hs.removeEventListener(document, 'mousemove', hs.dragHandler);
603
+
604
+ if (hs.dragArgs) {
605
+ if (hs.styleRestoreCursor && hs.dragArgs.type == 'image')
606
+ hs.dragArgs.exp.content.style.cursor = hs.styleRestoreCursor;
607
+ var hasDragged = hs.dragArgs.hasDragged;
608
+
609
+ if (!hasDragged &&!hs.hasFocused && !/(move|resize)/.test(hs.dragArgs.type)) {
610
+ exp.close();
611
+ }
612
+ else if (hasDragged || (!hasDragged && hs.hasHtmlExpanders)) {
613
+ hs.dragArgs.exp.doShowHide('hidden');
614
+ }
615
+ hs.hasFocused = false;
616
+ hs.dragArgs = null;
617
+
618
+ } else if (/highslide-image-blur/.test(el.className)) {
619
+ el.style.cursor = hs.styleRestoreCursor;
620
+ }
621
+ }
622
+ return false;
623
+ },
624
+
625
+ dragHandler : function(e)
626
+ {
627
+ if (!hs.dragArgs) return true;
628
+ if (!e) e = window.event;
629
+ var a = hs.dragArgs, exp = a.exp;
630
+
631
+ a.dX = e.clientX - a.clickX;
632
+ a.dY = e.clientY - a.clickY;
633
+
634
+ var distance = Math.sqrt(Math.pow(a.dX, 2) + Math.pow(a.dY, 2));
635
+ if (!a.hasDragged) a.hasDragged = (a.type != 'image' && distance > 0)
636
+ || (distance > (hs.dragSensitivity || 5));
637
+
638
+ if (a.hasDragged && e.clientX > 5 && e.clientY > 5) {
639
+
640
+ if (a.type == 'resize') exp.resize(a);
641
+ else {
642
+ exp.moveTo(a.left + a.dX, a.top + a.dY);
643
+ if (a.type == 'image') exp.content.style.cursor = 'move';
644
+ }
645
+ }
646
+ return false;
647
+ },
648
+
649
+ wrapperMouseHandler : function (e) {
650
+ try {
651
+ if (!e) e = window.event;
652
+ var over = /mouseover/i.test(e.type);
653
+ if (!e.target) e.target = e.srcElement; // ie
654
+ if (!e.relatedTarget) e.relatedTarget =
655
+ over ? e.fromElement : e.toElement; // ie
656
+ var exp = hs.getExpander(e.target);
657
+ if (!exp.isExpanded) return;
658
+ if (!exp || !e.relatedTarget || hs.getExpander(e.relatedTarget, true) == exp
659
+ || hs.dragArgs) return;
660
+ for (var i = 0; i < exp.overlays.length; i++) (function() {
661
+ var o = hs.$('hsId'+ exp.overlays[i]);
662
+ if (o && o.hideOnMouseOut) {
663
+ if (over) hs.setStyles(o, { visibility: 'visible', display: '' });
664
+ hs.animate(o, { opacity: over ? o.opacity : 0 }, o.dur);
665
+ }
666
+ })();
667
+ } catch (e) {}
668
+ },
669
+ addEventListener : function (el, event, func) {
670
+ if (el == document && event == 'ready') {
671
+ hs.push(hs.onReady, func);
672
+ }
673
+ try {
674
+ el.addEventListener(event, func, false);
675
+ } catch (e) {
676
+ try {
677
+ el.detachEvent('on'+ event, func);
678
+ el.attachEvent('on'+ event, func);
679
+ } catch (e) {
680
+ el['on'+ event] = func;
681
+ }
682
+ }
683
+ },
684
+
685
+ removeEventListener : function (el, event, func) {
686
+ try {
687
+ el.removeEventListener(event, func, false);
688
+ } catch (e) {
689
+ try {
690
+ el.detachEvent('on'+ event, func);
691
+ } catch (e) {
692
+ el['on'+ event] = null;
693
+ }
694
+ }
695
+ },
696
+
697
+ preloadFullImage : function (i) {
698
+ if (hs.continuePreloading && hs.preloadTheseImages[i] && hs.preloadTheseImages[i] != 'undefined') {
699
+ var img = document.createElement('img');
700
+ img.onload = function() {
701
+ img = null;
702
+ hs.preloadFullImage(i + 1);
703
+ };
704
+ img.src = hs.preloadTheseImages[i];
705
+ }
706
+ },
707
+ preloadImages : function (number) {
708
+ if (number && typeof number != 'object') hs.numberOfImagesToPreload = number;
709
+
710
+ var arr = hs.getAnchors();
711
+ for (var i = 0; i < arr.images.length && i < hs.numberOfImagesToPreload; i++) {
712
+ hs.push(hs.preloadTheseImages, hs.getSrc(arr.images[i]));
713
+ }
714
+
715
+ // preload outlines
716
+ if (hs.outlineType) new hs.Outline(hs.outlineType, function () { hs.preloadFullImage(0)} );
717
+ else
718
+
719
+ hs.preloadFullImage(0);
720
+
721
+ // preload cursor
722
+ if (hs.restoreCursor) var cur = hs.createElement('img', { src: hs.graphicsDir + hs.restoreCursor });
723
+ },
724
+
725
+
726
+ init : function () {
727
+ if (!hs.container) {
728
+
729
+ hs.ieLt7 = hs.ie && hs.uaVersion < 7;
730
+ hs.ieLt9 = hs.ie && hs.uaVersion < 9;
731
+
732
+ hs.getPageSize();
733
+ for (var x in hs.langDefaults) {
734
+ if (typeof hs[x] != 'undefined') hs.lang[x] = hs[x];
735
+ else if (typeof hs.lang[x] == 'undefined' && typeof hs.langDefaults[x] != 'undefined')
736
+ hs.lang[x] = hs.langDefaults[x];
737
+ }
738
+
739
+ hs.container = hs.createElement('div', {
740
+ className: 'highslide-container'
741
+ }, {
742
+ position: 'absolute',
743
+ left: 0,
744
+ top: 0,
745
+ width: '100%',
746
+ zIndex: hs.zIndexCounter,
747
+ direction: 'ltr'
748
+ },
749
+ document.body,
750
+ true
751
+ );
752
+ hs.loading = hs.createElement('a', {
753
+ className: 'highslide-loading',
754
+ title: hs.lang.loadingTitle,
755
+ innerHTML: hs.lang.loadingText,
756
+ href: 'javascript:;'
757
+ }, {
758
+ position: 'absolute',
759
+ top: '-9999px',
760
+ opacity: hs.loadingOpacity,
761
+ zIndex: 1
762
+ }, hs.container
763
+ );
764
+ hs.garbageBin = hs.createElement('div', null, { display: 'none' }, hs.container);
765
+ hs.viewport = hs.createElement('div', {
766
+ className: 'highslide-viewport highslide-viewport-size'
767
+ }, {
768
+ visibility: (hs.safari && hs.uaVersion < 525) ? 'visible' : 'hidden'
769
+ }, hs.container, 1
770
+ );
771
+
772
+ // http://www.robertpenner.com/easing/
773
+ Math.linearTween = function (t, b, c, d) {
774
+ return c*t/d + b;
775
+ };
776
+ Math.easeInQuad = function (t, b, c, d) {
777
+ return c*(t/=d)*t + b;
778
+ };
779
+ Math.easeOutQuad = function (t, b, c, d) {
780
+ return -c *(t/=d)*(t-2) + b;
781
+ };
782
+
783
+ hs.hideSelects = hs.ieLt7;
784
+ hs.hideIframes = ((window.opera && hs.uaVersion < 9) || navigator.vendor == 'KDE'
785
+ || (hs.ieLt7 && hs.uaVersion < 5.5));
786
+ }
787
+ },
788
+ ready : function() {
789
+ if (hs.isReady) return;
790
+ hs.isReady = true;
791
+ for (var i = 0; i < hs.onReady.length; i++) hs.onReady[i]();
792
+ },
793
+
794
+ updateAnchors : function() {
795
+ var el, els, all = [], images = [],groups = {}, re;
796
+
797
+ for (var i = 0; i < hs.openerTagNames.length; i++) {
798
+ els = document.getElementsByTagName(hs.openerTagNames[i]);
799
+ for (var j = 0; j < els.length; j++) {
800
+ el = els[j];
801
+ re = hs.isHsAnchor(el);
802
+ if (re) {
803
+ hs.push(all, el);
804
+ if (re[0] == 'hs.expand') hs.push(images, el);
805
+ var g = hs.getParam(el, 'slideshowGroup') || 'none';
806
+ if (!groups[g]) groups[g] = [];
807
+ hs.push(groups[g], el);
808
+ }
809
+ }
810
+ }
811
+ hs.anchors = { all: all, groups: groups, images: images };
812
+ return hs.anchors;
813
+
814
+ },
815
+
816
+ getAnchors : function() {
817
+ return hs.anchors || hs.updateAnchors();
818
+ },
819
+
820
+
821
+ close : function(el) {
822
+ var exp = hs.getExpander(el);
823
+ if (exp) exp.close();
824
+ return false;
825
+ }
826
+ }; // end hs object
827
+ hs.fx = function( elem, options, prop ){
828
+ this.options = options;
829
+ this.elem = elem;
830
+ this.prop = prop;
831
+
832
+ if (!options.orig) options.orig = {};
833
+ };
834
+ hs.fx.prototype = {
835
+ update: function(){
836
+ (hs.fx.step[this.prop] || hs.fx.step._default)(this);
837
+
838
+ if (this.options.step)
839
+ this.options.step.call(this.elem, this.now, this);
840
+
841
+ },
842
+ custom: function(from, to, unit){
843
+ this.startTime = (new Date()).getTime();
844
+ this.start = from;
845
+ this.end = to;
846
+ this.unit = unit;// || this.unit || "px";
847
+ this.now = this.start;
848
+ this.pos = this.state = 0;
849
+
850
+ var self = this;
851
+ function t(gotoEnd){
852
+ return self.step(gotoEnd);
853
+ }
854
+
855
+ t.elem = this.elem;
856
+
857
+ if ( t() && hs.timers.push(t) == 1 ) {
858
+ hs.timerId = setInterval(function(){
859
+ var timers = hs.timers;
860
+
861
+ for ( var i = 0; i < timers.length; i++ )
862
+ if ( !timers[i]() )
863
+ timers.splice(i--, 1);
864
+
865
+ if ( !timers.length ) {
866
+ clearInterval(hs.timerId);
867
+ }
868
+ }, 13);
869
+ }
870
+ },
871
+ step: function(gotoEnd){
872
+ var t = (new Date()).getTime();
873
+ if ( gotoEnd || t >= this.options.duration + this.startTime ) {
874
+ this.now = this.end;
875
+ this.pos = this.state = 1;
876
+ this.update();
877
+
878
+ this.options.curAnim[ this.prop ] = true;
879
+
880
+ var done = true;
881
+ for ( var i in this.options.curAnim )
882
+ if ( this.options.curAnim[i] !== true )
883
+ done = false;
884
+
885
+ if ( done ) {
886
+ if (this.options.complete) this.options.complete.call(this.elem);
887
+ }
888
+ return false;
889
+ } else {
890
+ var n = t - this.startTime;
891
+ this.state = n / this.options.duration;
892
+ this.pos = this.options.easing(n, 0, 1, this.options.duration);
893
+ this.now = this.start + ((this.end - this.start) * this.pos);
894
+ this.update();
895
+ }
896
+ return true;
897
+ }
898
+
899
+ };
900
+
901
+ hs.extend( hs.fx, {
902
+ step: {
903
+
904
+ opacity: function(fx){
905
+ hs.setStyles(fx.elem, { opacity: fx.now });
906
+ },
907
+
908
+ _default: function(fx){
909
+ try {
910
+ if ( fx.elem.style && fx.elem.style[ fx.prop ] != null )
911
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
912
+ else
913
+ fx.elem[ fx.prop ] = fx.now;
914
+ } catch (e) {}
915
+ }
916
+ }
917
+ });
918
+
919
+ hs.Outline = function (outlineType, onLoad) {
920
+ this.onLoad = onLoad;
921
+ this.outlineType = outlineType;
922
+ var v = hs.uaVersion, tr;
923
+
924
+ this.hasAlphaImageLoader = hs.ie && hs.uaVersion < 7;
925
+ if (!outlineType) {
926
+ if (onLoad) onLoad();
927
+ return;
928
+ }
929
+
930
+ hs.init();
931
+ this.table = hs.createElement(
932
+ 'table', {
933
+ cellSpacing: 0
934
+ }, {
935
+ visibility: 'hidden',
936
+ position: 'absolute',
937
+ borderCollapse: 'collapse',
938
+ width: 0
939
+ },
940
+ hs.container,
941
+ true
942
+ );
943
+ var tbody = hs.createElement('tbody', null, null, this.table, 1);
944
+
945
+ this.td = [];
946
+ for (var i = 0; i <= 8; i++) {
947
+ if (i % 3 == 0) tr = hs.createElement('tr', null, { height: 'auto' }, tbody, true);
948
+ this.td[i] = hs.createElement('td', null, null, tr, true);
949
+ var style = i != 4 ? { lineHeight: 0, fontSize: 0} : { position : 'relative' };
950
+ hs.setStyles(this.td[i], style);
951
+ }
952
+ this.td[4].className = outlineType +' highslide-outline';
953
+
954
+ this.preloadGraphic();
955
+ };
956
+
957
+ hs.Outline.prototype = {
958
+ preloadGraphic : function () {
959
+ var src = hs.graphicsDir + (hs.outlinesDir || "outlines/")+ this.outlineType +".png";
960
+
961
+ var appendTo = hs.safari && hs.uaVersion < 525 ? hs.container : null;
962
+ this.graphic = hs.createElement('img', null, { position: 'absolute',
963
+ top: '-9999px' }, appendTo, true); // for onload trigger
964
+
965
+ var pThis = this;
966
+ this.graphic.onload = function() { pThis.onGraphicLoad(); };
967
+
968
+ this.graphic.src = src;
969
+ },
970
+
971
+ onGraphicLoad : function () {
972
+ var o = this.offset = this.graphic.width / 4,
973
+ pos = [[0,0],[0,-4],[-2,0],[0,-8],0,[-2,-8],[0,-2],[0,-6],[-2,-2]],
974
+ dim = { height: (2*o) +'px', width: (2*o) +'px' };
975
+ for (var i = 0; i <= 8; i++) {
976
+ if (pos[i]) {
977
+ if (this.hasAlphaImageLoader) {
978
+ var w = (i == 1 || i == 7) ? '100%' : this.graphic.width +'px';
979
+ var div = hs.createElement('div', null, { width: '100%', height: '100%', position: 'relative', overflow: 'hidden'}, this.td[i], true);
980
+ hs.createElement ('div', null, {
981
+ filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale, src='"+ this.graphic.src + "')",
982
+ position: 'absolute',
983
+ width: w,
984
+ height: this.graphic.height +'px',
985
+ left: (pos[i][0]*o)+'px',
986
+ top: (pos[i][1]*o)+'px'
987
+ },
988
+ div,
989
+ true);
990
+ } else {
991
+ hs.setStyles(this.td[i], { background: 'url('+ this.graphic.src +') '+ (pos[i][0]*o)+'px '+(pos[i][1]*o)+'px'});
992
+ }
993
+
994
+ if (window.opera && (i == 3 || i ==5))
995
+ hs.createElement('div', null, dim, this.td[i], true);
996
+
997
+ hs.setStyles (this.td[i], dim);
998
+ }
999
+ }
1000
+ this.graphic = null;
1001
+ if (hs.pendingOutlines[this.outlineType]) hs.pendingOutlines[this.outlineType].destroy();
1002
+ hs.pendingOutlines[this.outlineType] = this;
1003
+ if (this.onLoad) this.onLoad();
1004
+ },
1005
+
1006
+ setPosition : function (pos, offset, vis, dur, easing) {
1007
+ var exp = this.exp,
1008
+ stl = exp.wrapper.style,
1009
+ offset = offset || 0,
1010
+ pos = pos || {
1011
+ x: exp.x.pos + offset,
1012
+ y: exp.y.pos + offset,
1013
+ w: exp.x.get('wsize') - 2 * offset,
1014
+ h: exp.y.get('wsize') - 2 * offset
1015
+ };
1016
+ if (vis) this.table.style.visibility = (pos.h >= 4 * this.offset)
1017
+ ? 'visible' : 'hidden';
1018
+ hs.setStyles(this.table, {
1019
+ left: (pos.x - this.offset) +'px',
1020
+ top: (pos.y - this.offset) +'px',
1021
+ width: (pos.w + 2 * this.offset) +'px'
1022
+ });
1023
+
1024
+ pos.w -= 2 * this.offset;
1025
+ pos.h -= 2 * this.offset;
1026
+ hs.setStyles (this.td[4], {
1027
+ width: pos.w >= 0 ? pos.w +'px' : 0,
1028
+ height: pos.h >= 0 ? pos.h +'px' : 0
1029
+ });
1030
+ if (this.hasAlphaImageLoader) this.td[3].style.height
1031
+ = this.td[5].style.height = this.td[4].style.height;
1032
+
1033
+ },
1034
+
1035
+ destroy : function(hide) {
1036
+ if (hide) this.table.style.visibility = 'hidden';
1037
+ else hs.discardElement(this.table);
1038
+ }
1039
+ };
1040
+
1041
+ hs.Dimension = function(exp, dim) {
1042
+ this.exp = exp;
1043
+ this.dim = dim;
1044
+ this.ucwh = dim == 'x' ? 'Width' : 'Height';
1045
+ this.wh = this.ucwh.toLowerCase();
1046
+ this.uclt = dim == 'x' ? 'Left' : 'Top';
1047
+ this.lt = this.uclt.toLowerCase();
1048
+ this.ucrb = dim == 'x' ? 'Right' : 'Bottom';
1049
+ this.rb = this.ucrb.toLowerCase();
1050
+ this.p1 = this.p2 = 0;
1051
+ };
1052
+ hs.Dimension.prototype = {
1053
+ get : function(key) {
1054
+ switch (key) {
1055
+ case 'loadingPos':
1056
+ return this.tpos + this.tb + (this.t - hs.loading['offset'+ this.ucwh]) / 2;
1057
+ case 'loadingPosXfade':
1058
+ return this.pos + this.cb+ this.p1 + (this.size - hs.loading['offset'+ this.ucwh]) / 2;
1059
+ case 'wsize':
1060
+ return this.size + 2 * this.cb + this.p1 + this.p2;
1061
+ case 'fitsize':
1062
+ return this.clientSize - this.marginMin - this.marginMax;
1063
+ case 'maxsize':
1064
+ return this.get('fitsize') - 2 * this.cb - this.p1 - this.p2 ;
1065
+ case 'opos':
1066
+ return this.pos - (this.exp.outline ? this.exp.outline.offset : 0);
1067
+ case 'osize':
1068
+ return this.get('wsize') + (this.exp.outline ? 2*this.exp.outline.offset : 0);
1069
+ case 'imgPad':
1070
+ return this.imgSize ? Math.round((this.size - this.imgSize) / 2) : 0;
1071
+
1072
+ }
1073
+ },
1074
+ calcBorders: function() {
1075
+ // correct for borders
1076
+ this.cb = (this.exp.content['offset'+ this.ucwh] - this.t) / 2;
1077
+
1078
+ this.marginMax = hs['margin'+ this.ucrb];
1079
+ },
1080
+ calcThumb: function() {
1081
+ this.t = this.exp.el[this.wh] ? parseInt(this.exp.el[this.wh]) :
1082
+ this.exp.el['offset'+ this.ucwh];
1083
+ this.tpos = this.exp.tpos[this.dim];
1084
+ this.tb = (this.exp.el['offset'+ this.ucwh] - this.t) / 2;
1085
+ if (this.tpos == 0 || this.tpos == -1) {
1086
+ this.tpos = (hs.page[this.wh] / 2) + hs.page['scroll'+ this.uclt];
1087
+ };
1088
+ },
1089
+ calcExpanded: function() {
1090
+ var exp = this.exp;
1091
+ this.justify = 'auto';
1092
+
1093
+ // get alignment
1094
+ if (exp.align == 'center') this.justify = 'center';
1095
+ else if (new RegExp(this.lt).test(exp.anchor)) this.justify = null;
1096
+ else if (new RegExp(this.rb).test(exp.anchor)) this.justify = 'max';
1097
+
1098
+
1099
+ // size and position
1100
+ this.pos = this.tpos - this.cb + this.tb;
1101
+
1102
+ if (this.maxHeight && this.dim == 'x')
1103
+ exp.maxWidth = Math.min(exp.maxWidth || this.full, exp.maxHeight * this.full / exp.y.full);
1104
+
1105
+ this.size = Math.min(this.full, exp['max'+ this.ucwh] || this.full);
1106
+ this.minSize = exp.allowSizeReduction ?
1107
+ Math.min(exp['min'+ this.ucwh], this.full) :this.full;
1108
+ if (exp.isImage && exp.useBox) {
1109
+ this.size = exp[this.wh];
1110
+ this.imgSize = this.full;
1111
+ }
1112
+ if (this.dim == 'x' && hs.padToMinWidth) this.minSize = exp.minWidth;
1113
+ this.target = exp['target'+ this.dim.toUpperCase()];
1114
+ this.marginMin = hs['margin'+ this.uclt];
1115
+ this.scroll = hs.page['scroll'+ this.uclt];
1116
+ this.clientSize = hs.page[this.wh];
1117
+ },
1118
+ setSize: function(i) {
1119
+ var exp = this.exp;
1120
+ if (exp.isImage && (exp.useBox || hs.padToMinWidth)) {
1121
+ this.imgSize = i;
1122
+ this.size = Math.max(this.size, this.imgSize);
1123
+ exp.content.style[this.lt] = this.get('imgPad')+'px';
1124
+ } else
1125
+ this.size = i;
1126
+
1127
+ exp.content.style[this.wh] = i +'px';
1128
+ exp.wrapper.style[this.wh] = this.get('wsize') +'px';
1129
+ if (exp.outline) exp.outline.setPosition();
1130
+ if (this.dim == 'x' && exp.overlayBox) exp.sizeOverlayBox(true);
1131
+ if (this.dim == 'x' && exp.slideshow && exp.isImage) {
1132
+ if (i == this.full) exp.slideshow.disable('full-expand');
1133
+ else exp.slideshow.enable('full-expand');
1134
+ }
1135
+ },
1136
+ setPos: function(i) {
1137
+ this.pos = i;
1138
+ this.exp.wrapper.style[this.lt] = i +'px';
1139
+
1140
+ if (this.exp.outline) this.exp.outline.setPosition();
1141
+
1142
+ }
1143
+ };
1144
+
1145
+ hs.Expander = function(a, params, custom, contentType) {
1146
+ if (document.readyState && hs.ie && !hs.isReady) {
1147
+ hs.addEventListener(document, 'ready', function() {
1148
+ new hs.Expander(a, params, custom, contentType);
1149
+ });
1150
+ return;
1151
+ }
1152
+ this.a = a;
1153
+ this.custom = custom;
1154
+ this.contentType = contentType || 'image';
1155
+ this.isImage = !this.isHtml;
1156
+
1157
+ hs.continuePreloading = false;
1158
+ this.overlays = [];
1159
+ this.last = hs.last;
1160
+ hs.last = null;
1161
+ hs.init();
1162
+ var key = this.key = hs.expanders.length;
1163
+ // override inline parameters
1164
+ for (var i = 0; i < hs.overrides.length; i++) {
1165
+ var name = hs.overrides[i];
1166
+ this[name] = params && typeof params[name] != 'undefined' ?
1167
+ params[name] : hs[name];
1168
+ }
1169
+ if (!this.src) this.src = a.href;
1170
+
1171
+ // get thumb
1172
+ var el = (params && params.thumbnailId) ? hs.$(params.thumbnailId) : a;
1173
+ el = this.thumb = el.getElementsByTagName('img')[0] || el;
1174
+ this.thumbsUserSetId = el.id || a.id;
1175
+
1176
+ // check if already open
1177
+ for (var i = 0; i < hs.expanders.length; i++) {
1178
+ if (hs.expanders[i] && hs.expanders[i].a == a
1179
+ && !(this.last && this.transitions[1] == 'crossfade')) {
1180
+ hs.expanders[i].focus();
1181
+ return false;
1182
+ }
1183
+ }
1184
+
1185
+ // cancel other
1186
+ if (!hs.allowSimultaneousLoading) for (var i = 0; i < hs.expanders.length; i++) {
1187
+ if (hs.expanders[i] && hs.expanders[i].thumb != el && !hs.expanders[i].onLoadStarted) {
1188
+ hs.expanders[i].cancelLoading();
1189
+ }
1190
+ }
1191
+ hs.expanders[key] = this;
1192
+ if (!hs.allowMultipleInstances && !hs.upcoming) {
1193
+ if (hs.expanders[key-1]) hs.expanders[key-1].close();
1194
+ if (typeof hs.focusKey != 'undefined' && hs.expanders[hs.focusKey])
1195
+ hs.expanders[hs.focusKey].close();
1196
+ }
1197
+
1198
+ // initiate metrics
1199
+ this.el = el;
1200
+ this.tpos = this.pageOrigin || hs.getPosition(el);
1201
+ hs.getPageSize();
1202
+ var x = this.x = new hs.Dimension(this, 'x');
1203
+ x.calcThumb();
1204
+ var y = this.y = new hs.Dimension(this, 'y');
1205
+ y.calcThumb();
1206
+ this.wrapper = hs.createElement(
1207
+ 'div', {
1208
+ id: 'highslide-wrapper-'+ this.key,
1209
+ className: 'highslide-wrapper '+ this.wrapperClassName
1210
+ }, {
1211
+ visibility: 'hidden',
1212
+ position: 'absolute',
1213
+ zIndex: hs.zIndexCounter += 2
1214
+ }, null, true );
1215
+
1216
+ this.wrapper.onmouseover = this.wrapper.onmouseout = hs.wrapperMouseHandler;
1217
+ if (this.contentType == 'image' && this.outlineWhileAnimating == 2)
1218
+ this.outlineWhileAnimating = 0;
1219
+
1220
+ // get the outline
1221
+ if (!this.outlineType
1222
+ || (this.last && this.isImage && this.transitions[1] == 'crossfade')) {
1223
+ this[this.contentType +'Create']();
1224
+
1225
+ } else if (hs.pendingOutlines[this.outlineType]) {
1226
+ this.connectOutline();
1227
+ this[this.contentType +'Create']();
1228
+
1229
+ } else {
1230
+ this.showLoading();
1231
+ var exp = this;
1232
+ new hs.Outline(this.outlineType,
1233
+ function () {
1234
+ exp.connectOutline();
1235
+ exp[exp.contentType +'Create']();
1236
+ }
1237
+ );
1238
+ }
1239
+ return true;
1240
+ };
1241
+
1242
+ hs.Expander.prototype = {
1243
+ error : function(e) {
1244
+ if (hs.debug) alert ('Line '+ e.lineNumber +': '+ e.message);
1245
+ else window.location.href = this.src;
1246
+ },
1247
+
1248
+ connectOutline : function() {
1249
+ var outline = this.outline = hs.pendingOutlines[this.outlineType];
1250
+ outline.exp = this;
1251
+ outline.table.style.zIndex = this.wrapper.style.zIndex - 1;
1252
+ hs.pendingOutlines[this.outlineType] = null;
1253
+ },
1254
+
1255
+ showLoading : function() {
1256
+ if (this.onLoadStarted || this.loading) return;
1257
+
1258
+ this.loading = hs.loading;
1259
+ var exp = this;
1260
+ this.loading.onclick = function() {
1261
+ exp.cancelLoading();
1262
+ };
1263
+ var exp = this,
1264
+ l = this.x.get('loadingPos') +'px',
1265
+ t = this.y.get('loadingPos') +'px';
1266
+ if (!tgt && this.last && this.transitions[1] == 'crossfade')
1267
+ var tgt = this.last;
1268
+ if (tgt) {
1269
+ l = tgt.x.get('loadingPosXfade') +'px';
1270
+ t = tgt.y.get('loadingPosXfade') +'px';
1271
+ this.loading.style.zIndex = hs.zIndexCounter++;
1272
+ }
1273
+ setTimeout(function () {
1274
+ if (exp.loading) hs.setStyles(exp.loading, { left: l, top: t, zIndex: hs.zIndexCounter++ })}
1275
+ , 100);
1276
+ },
1277
+
1278
+ imageCreate : function() {
1279
+ var exp = this;
1280
+
1281
+ var img = document.createElement('img');
1282
+ this.content = img;
1283
+ img.onload = function () {
1284
+ if (hs.expanders[exp.key]) exp.contentLoaded();
1285
+ };
1286
+ if (hs.blockRightClick) img.oncontextmenu = function() { return false; };
1287
+ img.className = 'highslide-image';
1288
+ hs.setStyles(img, {
1289
+ visibility: 'hidden',
1290
+ display: 'block',
1291
+ position: 'absolute',
1292
+ maxWidth: '9999px',
1293
+ zIndex: 3
1294
+ });
1295
+ img.title = hs.lang.restoreTitle;
1296
+ if (hs.safari && hs.uaVersion < 525) hs.container.appendChild(img);
1297
+ if (hs.ie && hs.flushImgSize) img.src = null;
1298
+ img.src = this.src;
1299
+
1300
+ this.showLoading();
1301
+ },
1302
+
1303
+ contentLoaded : function() {
1304
+ try {
1305
+ if (!this.content) return;
1306
+ this.content.onload = null;
1307
+ if (this.onLoadStarted) return;
1308
+ else this.onLoadStarted = true;
1309
+
1310
+ var x = this.x, y = this.y;
1311
+
1312
+ if (this.loading) {
1313
+ hs.setStyles(this.loading, { top: '-9999px' });
1314
+ this.loading = null;
1315
+ }
1316
+ x.full = this.content.width;
1317
+ y.full = this.content.height;
1318
+
1319
+ hs.setStyles(this.content, {
1320
+ width: x.t +'px',
1321
+ height: y.t +'px'
1322
+ });
1323
+ this.wrapper.appendChild(this.content);
1324
+ hs.container.appendChild(this.wrapper);
1325
+
1326
+ x.calcBorders();
1327
+ y.calcBorders();
1328
+
1329
+ hs.setStyles (this.wrapper, {
1330
+ left: (x.tpos + x.tb - x.cb) +'px',
1331
+ top: (y.tpos + x.tb - y.cb) +'px'
1332
+ });
1333
+
1334
+
1335
+ this.initSlideshow();
1336
+ this.getOverlays();
1337
+
1338
+ var ratio = x.full / y.full;
1339
+ x.calcExpanded();
1340
+ this.justify(x);
1341
+
1342
+ y.calcExpanded();
1343
+ this.justify(y);
1344
+ if (this.overlayBox) this.sizeOverlayBox(0, 1);
1345
+
1346
+
1347
+ if (this.allowSizeReduction) {
1348
+ this.correctRatio(ratio);
1349
+ var ss = this.slideshow;
1350
+ if (ss && this.last && ss.controls && ss.fixedControls) {
1351
+ var pos = ss.overlayOptions.position || '', p;
1352
+ for (var dim in hs.oPos) for (var i = 0; i < 5; i++) {
1353
+ p = this[dim];
1354
+ if (pos.match(hs.oPos[dim][i])) {
1355
+ p.pos = this.last[dim].pos
1356
+ + (this.last[dim].p1 - p.p1)
1357
+ + (this.last[dim].size - p.size) * [0, 0, .5, 1, 1][i];
1358
+ if (ss.fixedControls == 'fit') {
1359
+ if (p.pos + p.size + p.p1 + p.p2 > p.scroll + p.clientSize - p.marginMax)
1360
+ p.pos = p.scroll + p.clientSize - p.size - p.marginMin - p.marginMax - p.p1 - p.p2;
1361
+ if (p.pos < p.scroll + p.marginMin) p.pos = p.scroll + p.marginMin;
1362
+ }
1363
+ }
1364
+ }
1365
+ }
1366
+ if (this.isImage && this.x.full > (this.x.imgSize || this.x.size)) {
1367
+ this.createFullExpand();
1368
+ if (this.overlays.length == 1) this.sizeOverlayBox();
1369
+ }
1370
+ }
1371
+ this.show();
1372
+
1373
+ } catch (e) {
1374
+ this.error(e);
1375
+ }
1376
+ },
1377
+
1378
+ justify : function (p, moveOnly) {
1379
+ var tgtArr, tgt = p.target, dim = p == this.x ? 'x' : 'y';
1380
+
1381
+ if (tgt && tgt.match(/ /)) {
1382
+ tgtArr = tgt.split(' ');
1383
+ tgt = tgtArr[0];
1384
+ }
1385
+ if (tgt && hs.$(tgt)) {
1386
+ p.pos = hs.getPosition(hs.$(tgt))[dim];
1387
+ if (tgtArr && tgtArr[1] && tgtArr[1].match(/^[-]?[0-9]+px$/))
1388
+ p.pos += parseInt(tgtArr[1]);
1389
+ if (p.size < p.minSize) p.size = p.minSize;
1390
+
1391
+ } else if (p.justify == 'auto' || p.justify == 'center') {
1392
+
1393
+ var hasMovedMin = false;
1394
+
1395
+ var allowReduce = p.exp.allowSizeReduction;
1396
+ if (p.justify == 'center')
1397
+ p.pos = Math.round(p.scroll + (p.clientSize + p.marginMin - p.marginMax - p.get('wsize')) / 2);
1398
+ else
1399
+ p.pos = Math.round(p.pos - ((p.get('wsize') - p.t) / 2));
1400
+ if (p.pos < p.scroll + p.marginMin) {
1401
+ p.pos = p.scroll + p.marginMin;
1402
+ hasMovedMin = true;
1403
+ }
1404
+ if (!moveOnly && p.size < p.minSize) {
1405
+ p.size = p.minSize;
1406
+ allowReduce = false;
1407
+ }
1408
+ if (p.pos + p.get('wsize') > p.scroll + p.clientSize - p.marginMax) {
1409
+ if (!moveOnly && hasMovedMin && allowReduce) {
1410
+ p.size = Math.min(p.size, p.get(dim == 'y' ? 'fitsize' : 'maxsize'));
1411
+ } else if (p.get('wsize') < p.get('fitsize')) {
1412
+ p.pos = p.scroll + p.clientSize - p.marginMax - p.get('wsize');
1413
+ } else { // image larger than viewport
1414
+ p.pos = p.scroll + p.marginMin;
1415
+ if (!moveOnly && allowReduce) p.size = p.get(dim == 'y' ? 'fitsize' : 'maxsize');
1416
+ }
1417
+ }
1418
+
1419
+ if (!moveOnly && p.size < p.minSize) {
1420
+ p.size = p.minSize;
1421
+ allowReduce = false;
1422
+ }
1423
+
1424
+
1425
+ } else if (p.justify == 'max') {
1426
+ p.pos = Math.floor(p.pos - p.size + p.t);
1427
+ }
1428
+
1429
+
1430
+ if (p.pos < p.marginMin) {
1431
+ var tmpMin = p.pos;
1432
+ p.pos = p.marginMin;
1433
+
1434
+ if (allowReduce && !moveOnly) p.size = p.size - (p.pos - tmpMin);
1435
+
1436
+ }
1437
+ },
1438
+
1439
+ correctRatio : function(ratio) {
1440
+ var x = this.x,
1441
+ y = this.y,
1442
+ changed = false,
1443
+ xSize = Math.min(x.full, x.size),
1444
+ ySize = Math.min(y.full, y.size),
1445
+ useBox = (this.useBox || hs.padToMinWidth);
1446
+
1447
+ if (xSize / ySize > ratio) { // width greater
1448
+ xSize = ySize * ratio;
1449
+ if (xSize < x.minSize) { // below minWidth
1450
+ xSize = x.minSize;
1451
+ ySize = xSize / ratio;
1452
+ }
1453
+ changed = true;
1454
+
1455
+ } else if (xSize / ySize < ratio) { // height greater
1456
+ ySize = xSize / ratio;
1457
+ changed = true;
1458
+ }
1459
+
1460
+ if (hs.padToMinWidth && x.full < x.minSize) {
1461
+ x.imgSize = x.full;
1462
+ y.size = y.imgSize = y.full;
1463
+ } else if (this.useBox) {
1464
+ x.imgSize = xSize;
1465
+ y.imgSize = ySize;
1466
+ } else {
1467
+ x.size = xSize;
1468
+ y.size = ySize;
1469
+ }
1470
+ changed = this.fitOverlayBox(this.useBox ? null : ratio, changed);
1471
+ if (useBox && y.size < y.imgSize) {
1472
+ y.imgSize = y.size;
1473
+ x.imgSize = y.size * ratio;
1474
+ }
1475
+ if (changed || useBox) {
1476
+ x.pos = x.tpos - x.cb + x.tb;
1477
+ x.minSize = x.size;
1478
+ this.justify(x, true);
1479
+
1480
+ y.pos = y.tpos - y.cb + y.tb;
1481
+ y.minSize = y.size;
1482
+ this.justify(y, true);
1483
+ if (this.overlayBox) this.sizeOverlayBox();
1484
+ }
1485
+
1486
+
1487
+ },
1488
+ fitOverlayBox : function(ratio, changed) {
1489
+ var x = this.x, y = this.y;
1490
+ if (this.overlayBox) {
1491
+ while (y.size > this.minHeight && x.size > this.minWidth
1492
+ && y.get('wsize') > y.get('fitsize')) {
1493
+ y.size -= 10;
1494
+ if (ratio) x.size = y.size * ratio;
1495
+ this.sizeOverlayBox(0, 1);
1496
+ changed = true;
1497
+ }
1498
+ }
1499
+ return changed;
1500
+ },
1501
+
1502
+ show : function () {
1503
+ var x = this.x, y = this.y;
1504
+ this.doShowHide('hidden');
1505
+ if (this.slideshow && this.slideshow.thumbstrip) this.slideshow.thumbstrip.selectThumb();
1506
+
1507
+ // Apply size change
1508
+ this.changeSize(
1509
+ 1, {
1510
+ wrapper: {
1511
+ width : x.get('wsize'),
1512
+ height : y.get('wsize'),
1513
+ left: x.pos,
1514
+ top: y.pos
1515
+ },
1516
+ content: {
1517
+ left: x.p1 + x.get('imgPad'),
1518
+ top: y.p1 + y.get('imgPad'),
1519
+ width:x.imgSize ||x.size,
1520
+ height:y.imgSize ||y.size
1521
+ }
1522
+ },
1523
+ hs.expandDuration
1524
+ );
1525
+ },
1526
+
1527
+ changeSize : function(up, to, dur) {
1528
+ // transition
1529
+ var trans = this.transitions,
1530
+ other = up ? (this.last ? this.last.a : null) : hs.upcoming,
1531
+ t = (trans[1] && other
1532
+ && hs.getParam(other, 'transitions')[1] == trans[1]) ?
1533
+ trans[1] : trans[0];
1534
+
1535
+ if (this[t] && t != 'expand') {
1536
+ this[t](up, to);
1537
+ return;
1538
+ }
1539
+
1540
+ if (this.outline && !this.outlineWhileAnimating) {
1541
+ if (up) this.outline.setPosition();
1542
+ else this.outline.destroy();
1543
+ }
1544
+
1545
+
1546
+ if (!up) this.destroyOverlays();
1547
+
1548
+ var exp = this,
1549
+ x = exp.x,
1550
+ y = exp.y,
1551
+ easing = this.easing;
1552
+ if (!up) easing = this.easingClose || easing;
1553
+ var after = up ?
1554
+ function() {
1555
+
1556
+ if (exp.outline) exp.outline.table.style.visibility = "visible";
1557
+ setTimeout(function() {
1558
+ exp.afterExpand();
1559
+ }, 50);
1560
+ } :
1561
+ function() {
1562
+ exp.afterClose();
1563
+ };
1564
+ if (up) hs.setStyles( this.wrapper, {
1565
+ width: x.t +'px',
1566
+ height: y.t +'px'
1567
+ });
1568
+ if (this.fadeInOut) {
1569
+ hs.setStyles(this.wrapper, { opacity: up ? 0 : 1 });
1570
+ hs.extend(to.wrapper, { opacity: up });
1571
+ }
1572
+ hs.animate( this.wrapper, to.wrapper, {
1573
+ duration: dur,
1574
+ easing: easing,
1575
+ step: function(val, args) {
1576
+ if (exp.outline && exp.outlineWhileAnimating && args.prop == 'top') {
1577
+ var fac = up ? args.pos : 1 - args.pos;
1578
+ var pos = {
1579
+ w: x.t + (x.get('wsize') - x.t) * fac,
1580
+ h: y.t + (y.get('wsize') - y.t) * fac,
1581
+ x: x.tpos + (x.pos - x.tpos) * fac,
1582
+ y: y.tpos + (y.pos - y.tpos) * fac
1583
+ };
1584
+ exp.outline.setPosition(pos, 0, 1);
1585
+ }
1586
+ }
1587
+ });
1588
+ hs.animate( this.content, to.content, dur, easing, after);
1589
+ if (up) {
1590
+ this.wrapper.style.visibility = 'visible';
1591
+ this.content.style.visibility = 'visible';
1592
+ this.a.className += ' highslide-active-anchor';
1593
+ }
1594
+ },
1595
+
1596
+
1597
+
1598
+ fade : function(up, to) {
1599
+ this.outlineWhileAnimating = false;
1600
+ var exp = this, t = up ? hs.expandDuration : 0;
1601
+
1602
+ if (up) {
1603
+ hs.animate(this.wrapper, to.wrapper, 0);
1604
+ hs.setStyles(this.wrapper, { opacity: 0, visibility: 'visible' });
1605
+ hs.animate(this.content, to.content, 0);
1606
+ this.content.style.visibility = 'visible';
1607
+
1608
+ hs.animate(this.wrapper, { opacity: 1 }, t, null,
1609
+ function() { exp.afterExpand(); });
1610
+ }
1611
+
1612
+ if (this.outline) {
1613
+ this.outline.table.style.zIndex = this.wrapper.style.zIndex;
1614
+ var dir = up || -1,
1615
+ offset = this.outline.offset,
1616
+ startOff = up ? 3 : offset,
1617
+ endOff = up? offset : 3;
1618
+ for (var i = startOff; dir * i <= dir * endOff; i += dir, t += 25) {
1619
+ (function() {
1620
+ var o = up ? endOff - i : startOff - i;
1621
+ setTimeout(function() {
1622
+ exp.outline.setPosition(0, o, 1);
1623
+ }, t);
1624
+ })();
1625
+ }
1626
+ }
1627
+
1628
+
1629
+ if (up) {}//setTimeout(function() { exp.afterExpand(); }, t+50);
1630
+ else {
1631
+ setTimeout( function() {
1632
+ if (exp.outline) exp.outline.destroy(exp.preserveContent);
1633
+
1634
+ exp.destroyOverlays();
1635
+
1636
+ hs.animate( exp.wrapper, { opacity: 0 }, hs.restoreDuration, null, function(){
1637
+ exp.afterClose();
1638
+ });
1639
+ }, t);
1640
+ }
1641
+ },
1642
+ crossfade : function (up, to, from) {
1643
+ if (!up) return;
1644
+ var exp = this,
1645
+ last = this.last,
1646
+ x = this.x,
1647
+ y = this.y,
1648
+ lastX = last.x,
1649
+ lastY = last.y,
1650
+ wrapper = this.wrapper,
1651
+ content = this.content,
1652
+ overlayBox = this.overlayBox;
1653
+ hs.removeEventListener(document, 'mousemove', hs.dragHandler);
1654
+
1655
+ hs.setStyles(content, {
1656
+ width: (x.imgSize || x.size) +'px',
1657
+ height: (y.imgSize || y.size) +'px'
1658
+ });
1659
+ if (overlayBox) overlayBox.style.overflow = 'visible';
1660
+ this.outline = last.outline;
1661
+ if (this.outline) this.outline.exp = exp;
1662
+ last.outline = null;
1663
+ var fadeBox = hs.createElement('div', {
1664
+ className: 'highslide-'+ this.contentType
1665
+ }, {
1666
+ position: 'absolute',
1667
+ zIndex: 4,
1668
+ overflow: 'hidden',
1669
+ display: 'none'
1670
+ }
1671
+ );
1672
+ var names = { oldImg: last, newImg: this };
1673
+ for (var n in names) {
1674
+ this[n] = names[n].content.cloneNode(1);
1675
+ hs.setStyles(this[n], {
1676
+ position: 'absolute',
1677
+ border: 0,
1678
+ visibility: 'visible'
1679
+ });
1680
+ fadeBox.appendChild(this[n]);
1681
+ }
1682
+ wrapper.appendChild(fadeBox);
1683
+ if (overlayBox) {
1684
+ overlayBox.className = '';
1685
+ wrapper.appendChild(overlayBox);
1686
+ }
1687
+ fadeBox.style.display = '';
1688
+ last.content.style.display = 'none';
1689
+
1690
+
1691
+ if (hs.safari && hs.uaVersion < 525) {
1692
+ this.wrapper.style.visibility = 'visible';
1693
+ }
1694
+ hs.animate(wrapper, {
1695
+ width: x.size
1696
+ }, {
1697
+ duration: hs.transitionDuration,
1698
+ step: function(val, args) {
1699
+ var pos = args.pos,
1700
+ invPos = 1 - pos;
1701
+ var prop,
1702
+ size = {},
1703
+ props = ['pos', 'size', 'p1', 'p2'];
1704
+ for (var n in props) {
1705
+ prop = props[n];
1706
+ size['x'+ prop] = Math.round(invPos * lastX[prop] + pos * x[prop]);
1707
+ size['y'+ prop] = Math.round(invPos * lastY[prop] + pos * y[prop]);
1708
+ size.ximgSize = Math.round(
1709
+ invPos * (lastX.imgSize || lastX.size) + pos * (x.imgSize || x.size));
1710
+ size.ximgPad = Math.round(invPos * lastX.get('imgPad') + pos * x.get('imgPad'));
1711
+ size.yimgSize = Math.round(
1712
+ invPos * (lastY.imgSize || lastY.size) + pos * (y.imgSize || y.size));
1713
+ size.yimgPad = Math.round(invPos * lastY.get('imgPad') + pos * y.get('imgPad'));
1714
+ }
1715
+ if (exp.outline) exp.outline.setPosition({
1716
+ x: size.xpos,
1717
+ y: size.ypos,
1718
+ w: size.xsize + size.xp1 + size.xp2 + 2 * x.cb,
1719
+ h: size.ysize + size.yp1 + size.yp2 + 2 * y.cb
1720
+ });
1721
+ last.wrapper.style.clip = 'rect('
1722
+ + (size.ypos - lastY.pos)+'px, '
1723
+ + (size.xsize + size.xp1 + size.xp2 + size.xpos + 2 * lastX.cb - lastX.pos) +'px, '
1724
+ + (size.ysize + size.yp1 + size.yp2 + size.ypos + 2 * lastY.cb - lastY.pos) +'px, '
1725
+ + (size.xpos - lastX.pos)+'px)';
1726
+
1727
+ hs.setStyles(content, {
1728
+ top: (size.yp1 + y.get('imgPad')) +'px',
1729
+ left: (size.xp1 + x.get('imgPad')) +'px',
1730
+ marginTop: (y.pos - size.ypos) +'px',
1731
+ marginLeft: (x.pos - size.xpos) +'px'
1732
+ });
1733
+ hs.setStyles(wrapper, {
1734
+ top: size.ypos +'px',
1735
+ left: size.xpos +'px',
1736
+ width: (size.xp1 + size.xp2 + size.xsize + 2 * x.cb)+ 'px',
1737
+ height: (size.yp1 + size.yp2 + size.ysize + 2 * y.cb) + 'px'
1738
+ });
1739
+ hs.setStyles(fadeBox, {
1740
+ width: (size.ximgSize || size.xsize) + 'px',
1741
+ height: (size.yimgSize || size.ysize) +'px',
1742
+ left: (size.xp1 + size.ximgPad) +'px',
1743
+ top: (size.yp1 + size.yimgPad) +'px',
1744
+ visibility: 'visible'
1745
+ });
1746
+
1747
+ hs.setStyles(exp.oldImg, {
1748
+ top: (lastY.pos - size.ypos + lastY.p1 - size.yp1 + lastY.get('imgPad') - size.yimgPad)+'px',
1749
+ left: (lastX.pos - size.xpos + lastX.p1 - size.xp1 + lastX.get('imgPad') - size.ximgPad)+'px'
1750
+ });
1751
+
1752
+ hs.setStyles(exp.newImg, {
1753
+ opacity: pos,
1754
+ top: (y.pos - size.ypos + y.p1 - size.yp1 + y.get('imgPad') - size.yimgPad) +'px',
1755
+ left: (x.pos - size.xpos + x.p1 - size.xp1 + x.get('imgPad') - size.ximgPad) +'px'
1756
+ });
1757
+ if (overlayBox) hs.setStyles(overlayBox, {
1758
+ width: size.xsize + 'px',
1759
+ height: size.ysize +'px',
1760
+ left: (size.xp1 + x.cb) +'px',
1761
+ top: (size.yp1 + y.cb) +'px'
1762
+ });
1763
+ },
1764
+ complete: function () {
1765
+ wrapper.style.visibility = content.style.visibility = 'visible';
1766
+ content.style.display = 'block';
1767
+ hs.discardElement(fadeBox);
1768
+ exp.afterExpand();
1769
+ last.afterClose();
1770
+ exp.last = null;
1771
+ }
1772
+
1773
+ });
1774
+ },
1775
+ reuseOverlay : function(o, el) {
1776
+ if (!this.last) return false;
1777
+ for (var i = 0; i < this.last.overlays.length; i++) {
1778
+ var oDiv = hs.$('hsId'+ this.last.overlays[i]);
1779
+ if (oDiv && oDiv.hsId == o.hsId) {
1780
+ this.genOverlayBox();
1781
+ oDiv.reuse = this.key;
1782
+ hs.push(this.overlays, this.last.overlays[i]);
1783
+ return true;
1784
+ }
1785
+ }
1786
+ return false;
1787
+ },
1788
+
1789
+
1790
+ afterExpand : function() {
1791
+ this.isExpanded = true;
1792
+ this.focus();
1793
+ if (this.dimmingOpacity) hs.dim(this);
1794
+ if (hs.upcoming && hs.upcoming == this.a) hs.upcoming = null;
1795
+ this.prepareNextOutline();
1796
+ var p = hs.page, mX = hs.mouse.x + p.scrollLeft, mY = hs.mouse.y + p.scrollTop;
1797
+ this.mouseIsOver = this.x.pos < mX && mX < this.x.pos + this.x.get('wsize')
1798
+ && this.y.pos < mY && mY < this.y.pos + this.y.get('wsize');
1799
+ if (this.overlayBox) this.showOverlays();
1800
+
1801
+ },
1802
+
1803
+
1804
+ prepareNextOutline : function() {
1805
+ var key = this.key;
1806
+ var outlineType = this.outlineType;
1807
+ new hs.Outline(outlineType,
1808
+ function () { try { hs.expanders[key].preloadNext(); } catch (e) {} });
1809
+ },
1810
+
1811
+
1812
+ preloadNext : function() {
1813
+ var next = this.getAdjacentAnchor(1);
1814
+ if (next && next.onclick.toString().match(/hs\.expand/))
1815
+ var img = hs.createElement('img', { src: hs.getSrc(next) });
1816
+ },
1817
+
1818
+
1819
+ getAdjacentAnchor : function(op) {
1820
+ var current = this.getAnchorIndex(), as = hs.anchors.groups[this.slideshowGroup || 'none'];
1821
+ if (as && !as[current + op] && this.slideshow && this.slideshow.repeat) {
1822
+ if (op == 1) return as[0];
1823
+ else if (op == -1) return as[as.length-1];
1824
+ }
1825
+ return (as && as[current + op]) || null;
1826
+ },
1827
+
1828
+ getAnchorIndex : function() {
1829
+ var arr = hs.getAnchors().groups[this.slideshowGroup || 'none'];
1830
+ if (arr) for (var i = 0; i < arr.length; i++) {
1831
+ if (arr[i] == this.a) return i;
1832
+ }
1833
+ return null;
1834
+ },
1835
+
1836
+
1837
+ getNumber : function() {
1838
+ if (this[this.numberPosition]) {
1839
+ var arr = hs.anchors.groups[this.slideshowGroup || 'none'];
1840
+ if (arr) {
1841
+ var s = hs.lang.number.replace('%1', this.getAnchorIndex() + 1).replace('%2', arr.length);
1842
+ this[this.numberPosition].innerHTML =
1843
+ '<div class="highslide-number">'+ s +'</div>'+ this[this.numberPosition].innerHTML;
1844
+ }
1845
+ }
1846
+ },
1847
+ initSlideshow : function() {
1848
+ if (!this.last) {
1849
+ for (var i = 0; i < hs.slideshows.length; i++) {
1850
+ var ss = hs.slideshows[i], sg = ss.slideshowGroup;
1851
+ if (typeof sg == 'undefined' || sg === null || sg === this.slideshowGroup)
1852
+ this.slideshow = new hs.Slideshow(this.key, ss);
1853
+ }
1854
+ } else {
1855
+ this.slideshow = this.last.slideshow;
1856
+ }
1857
+ var ss = this.slideshow;
1858
+ if (!ss) return;
1859
+ var key = ss.expKey = this.key;
1860
+
1861
+ ss.checkFirstAndLast();
1862
+ ss.disable('full-expand');
1863
+ if (ss.controls) {
1864
+ this.createOverlay(hs.extend(ss.overlayOptions || {}, {
1865
+ overlayId: ss.controls,
1866
+ hsId: 'controls',
1867
+ zIndex: 5
1868
+ }));
1869
+ }
1870
+ if (ss.thumbstrip) ss.thumbstrip.add(this);
1871
+ if (!this.last && this.autoplay) ss.play(true);
1872
+ if (ss.autoplay) {
1873
+ ss.autoplay = setTimeout(function() {
1874
+ hs.next(key);
1875
+ }, (ss.interval || 500));
1876
+ }
1877
+ },
1878
+
1879
+ cancelLoading : function() {
1880
+ hs.discardElement (this.wrapper);
1881
+ hs.expanders[this.key] = null;
1882
+ if (hs.upcoming == this.a) hs.upcoming = null;
1883
+ hs.undim(this.key);
1884
+ if (this.loading) hs.loading.style.left = '-9999px';
1885
+ },
1886
+
1887
+ writeCredits : function () {
1888
+ if (this.credits) return;
1889
+ this.credits = hs.createElement('a', {
1890
+ href: hs.creditsHref,
1891
+ target: hs.creditsTarget,
1892
+ className: 'highslide-credits',
1893
+ innerHTML: hs.lang.creditsText,
1894
+ title: hs.lang.creditsTitle
1895
+ });
1896
+ this.createOverlay({
1897
+ overlayId: this.credits,
1898
+ position: this.creditsPosition || 'top left',
1899
+ hsId: 'credits'
1900
+ });
1901
+ },
1902
+
1903
+ getInline : function(types, addOverlay) {
1904
+ for (var i = 0; i < types.length; i++) {
1905
+ var type = types[i], s = null;
1906
+ if (!this[type +'Id'] && this.thumbsUserSetId)
1907
+ this[type +'Id'] = type +'-for-'+ this.thumbsUserSetId;
1908
+ if (this[type +'Id']) this[type] = hs.getNode(this[type +'Id']);
1909
+ if (!this[type] && !this[type +'Text'] && this[type +'Eval']) try {
1910
+ s = eval(this[type +'Eval']);
1911
+ } catch (e)