benmanns-atreides 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (449) hide show
  1. data/LICENSE +7 -0
  2. data/README.rdoc +1 -0
  3. data/app/assets/javascripts/atreides/admin.facebook.js +137 -0
  4. data/app/assets/javascripts/atreides/admin.js +23 -0
  5. data/app/assets/javascripts/atreides/admin_base.js.erb +273 -0
  6. data/app/assets/javascripts/atreides/admin_edit.js +9 -0
  7. data/app/assets/javascripts/atreides/application.js +15 -0
  8. data/app/assets/javascripts/atreides/public.js +24 -0
  9. data/app/assets/javascripts/atreides/public_base.js.erb +119 -0
  10. data/app/assets/javascripts/atreides/terryblr.js +57 -0
  11. data/app/assets/stylesheets/atreides/admin.css +21 -0
  12. data/app/assets/stylesheets/atreides/admin_base.css.erb +1693 -0
  13. data/app/assets/stylesheets/atreides/application.css +13 -0
  14. data/app/assets/stylesheets/atreides/formtastic_changes.css +10 -0
  15. data/app/assets/stylesheets/atreides/iphone-checkboxes.css.erb +97 -0
  16. data/app/assets/stylesheets/atreides/jBreadCrumb.css +109 -0
  17. data/app/assets/stylesheets/atreides/public.css +15 -0
  18. data/app/assets/stylesheets/atreides/public_base.css +101 -0
  19. data/app/assets/stylesheets/atreides/swfupload.css.erb +63 -0
  20. data/app/controllers/admin/atreides/content_parts_controller.rb +43 -0
  21. data/app/controllers/admin/atreides/dropbox_controller.rb +40 -0
  22. data/app/controllers/admin/atreides/facebook_controller.rb +38 -0
  23. data/app/controllers/admin/atreides/features_controller.rb +63 -0
  24. data/app/controllers/admin/atreides/github_controller.rb +35 -0
  25. data/app/controllers/admin/atreides/links_controller.rb +3 -0
  26. data/app/controllers/admin/atreides/messages_controller.rb +3 -0
  27. data/app/controllers/admin/atreides/orders_controller.rb +35 -0
  28. data/app/controllers/admin/atreides/pages_controller.rb +59 -0
  29. data/app/controllers/admin/atreides/photos_controller.rb +79 -0
  30. data/app/controllers/admin/atreides/posts_controller.rb +109 -0
  31. data/app/controllers/admin/atreides/products_controller.rb +39 -0
  32. data/app/controllers/admin/atreides/sessions_controller.rb +7 -0
  33. data/app/controllers/admin/atreides/sizes_controller.rb +4 -0
  34. data/app/controllers/admin/atreides/tags_controller.rb +20 -0
  35. data/app/controllers/admin/atreides/users_controller.rb +50 -0
  36. data/app/controllers/admin/atreides/videos_controller.rb +53 -0
  37. data/app/controllers/atreides/admin_controller.rb +96 -0
  38. data/app/controllers/atreides/admin_home_controller.rb +215 -0
  39. data/app/controllers/atreides/application_controller.rb +93 -0
  40. data/app/controllers/atreides/home_controller.rb +71 -0
  41. data/app/controllers/atreides/likes_controller.rb +44 -0
  42. data/app/controllers/atreides/pages_controller.rb +34 -0
  43. data/app/controllers/atreides/posts_controller.rb +119 -0
  44. data/app/controllers/atreides/public_controller.rb +43 -0
  45. data/app/helpers/admin/atreides/dropbox_helper.rb +42 -0
  46. data/app/helpers/admin/atreides/features_helper.rb +4 -0
  47. data/app/helpers/admin/atreides/github_helper.rb +43 -0
  48. data/app/helpers/admin/atreides/links_helper.rb +4 -0
  49. data/app/helpers/admin/atreides/messages_helper.rb +4 -0
  50. data/app/helpers/admin/atreides/orders_helper.rb +30 -0
  51. data/app/helpers/admin/atreides/pages_helper.rb +17 -0
  52. data/app/helpers/admin/atreides/photos_helper.rb +14 -0
  53. data/app/helpers/admin/atreides/posts_helper.rb +41 -0
  54. data/app/helpers/admin/atreides/products_helper.rb +37 -0
  55. data/app/helpers/admin/atreides/sizes_helper.rb +4 -0
  56. data/app/helpers/admin/atreides/user_sessions_helper.rb +4 -0
  57. data/app/helpers/admin/atreides/users_helper.rb +8 -0
  58. data/app/helpers/admin/atreides/videos_helper.rb +4 -0
  59. data/app/helpers/atreides/admin_helper.rb +243 -0
  60. data/app/helpers/atreides/admin_home_helper.rb +4 -0
  61. data/app/helpers/atreides/application_helper.rb +210 -0
  62. data/app/helpers/atreides/home_helper.rb +4 -0
  63. data/app/helpers/atreides/posts_helper.rb +119 -0
  64. data/app/inputs/files_input.rb +13 -0
  65. data/app/inputs/price_input.rb +18 -0
  66. data/app/inputs/underline_input.rb +16 -0
  67. data/app/models/atreides/ability.rb +24 -0
  68. data/app/models/atreides/content_part.rb +106 -0
  69. data/app/models/atreides/facebook_user.rb +103 -0
  70. data/app/models/atreides/feature.rb +90 -0
  71. data/app/models/atreides/github.rb +74 -0
  72. data/app/models/atreides/like.rb +35 -0
  73. data/app/models/atreides/line_item.rb +4 -0
  74. data/app/models/atreides/link.rb +32 -0
  75. data/app/models/atreides/message.rb +34 -0
  76. data/app/models/atreides/order.rb +209 -0
  77. data/app/models/atreides/page.rb +114 -0
  78. data/app/models/atreides/photo.rb +130 -0
  79. data/app/models/atreides/post.rb +271 -0
  80. data/app/models/atreides/preferences.rb +31 -0
  81. data/app/models/atreides/product.rb +75 -0
  82. data/app/models/atreides/site.rb +59 -0
  83. data/app/models/atreides/size.rb +44 -0
  84. data/app/models/atreides/tag.rb +31 -0
  85. data/app/models/atreides/tweet.rb +123 -0
  86. data/app/models/atreides/user.rb +129 -0
  87. data/app/models/atreides/video.rb +206 -0
  88. data/app/models/atreides/vote.rb +43 -0
  89. data/app/models/fb_post_publisher_job.rb +72 -0
  90. data/app/models/settings.rb +19 -0
  91. data/app/models/tumblr_post_publisher_job.rb +75 -0
  92. data/app/models/tw_post_publisher_job.rb +54 -0
  93. data/app/views/admin/_edit_head_content.html.haml +2 -0
  94. data/app/views/admin/atreides/content_parts/_form.html.haml +21 -0
  95. data/app/views/admin/atreides/content_parts/_photos.html.haml +18 -0
  96. data/app/views/admin/atreides/content_parts/_text.html.haml +1 -0
  97. data/app/views/admin/atreides/content_parts/_videos.html.haml +12 -0
  98. data/app/views/admin/atreides/content_parts/destroy.js.haml +3 -0
  99. data/app/views/admin/atreides/content_parts/edit.html.haml +0 -0
  100. data/app/views/admin/atreides/content_parts/new.html.haml +0 -0
  101. data/app/views/admin/atreides/content_parts/new.js.haml +11 -0
  102. data/app/views/admin/atreides/dropbox/_uploader.html.haml +134 -0
  103. data/app/views/admin/atreides/dropbox/list.html.haml +27 -0
  104. data/app/views/admin/atreides/dropbox/setup.html.haml +8 -0
  105. data/app/views/admin/atreides/facebook/index.html.haml +29 -0
  106. data/app/views/admin/atreides/features/_form.html.haml +60 -0
  107. data/app/views/admin/atreides/features/edit.html.haml +1 -0
  108. data/app/views/admin/atreides/features/index.html.haml +24 -0
  109. data/app/views/admin/atreides/features/new.html.haml +1 -0
  110. data/app/views/admin/atreides/github/index.html.haml +26 -0
  111. data/app/views/admin/atreides/github/show.html.haml +19 -0
  112. data/app/views/admin/atreides/likes/create.js.haml +2 -0
  113. data/app/views/admin/atreides/orders/_sidebar.html.haml +20 -0
  114. data/app/views/admin/atreides/orders/edit.html.haml +52 -0
  115. data/app/views/admin/atreides/orders/index.html.haml +8 -0
  116. data/app/views/admin/atreides/pages/_form.html.haml +31 -0
  117. data/app/views/admin/atreides/pages/edit.html.haml +3 -0
  118. data/app/views/admin/atreides/pages/index.html.haml +15 -0
  119. data/app/views/admin/atreides/pages/index.js.haml +4 -0
  120. data/app/views/admin/atreides/pages/new.html.haml +2 -0
  121. data/app/views/admin/atreides/photos/create.js.haml +18 -0
  122. data/app/views/admin/atreides/photos/destroy.js.haml +3 -0
  123. data/app/views/admin/atreides/posts/_archives.html.haml +19 -0
  124. data/app/views/admin/atreides/posts/_form.html.haml +66 -0
  125. data/app/views/admin/atreides/posts/_form_buttons.html.haml +9 -0
  126. data/app/views/admin/atreides/posts/_form_sidebar.html.haml +85 -0
  127. data/app/views/admin/atreides/posts/edit.html.haml +2 -0
  128. data/app/views/admin/atreides/posts/index.html.haml +24 -0
  129. data/app/views/admin/atreides/posts/index.js.haml +1 -0
  130. data/app/views/admin/atreides/posts/new.html.haml +2 -0
  131. data/app/views/admin/atreides/products/edit.html.haml +69 -0
  132. data/app/views/admin/atreides/products/index.html.haml +31 -0
  133. data/app/views/admin/atreides/sessions/new.html.haml +13 -0
  134. data/app/views/admin/atreides/user_sessions/new.html.haml +10 -0
  135. data/app/views/admin/atreides/users/_form.html.haml +19 -0
  136. data/app/views/admin/atreides/users/edit.html.haml +6 -0
  137. data/app/views/admin/atreides/users/index.html.haml +11 -0
  138. data/app/views/admin/atreides/users/new.html.haml +6 -0
  139. data/app/views/admin/atreides/users/show.html.haml +4 -0
  140. data/app/views/admin/atreides/videos/create.js.haml +9 -0
  141. data/app/views/admin/atreides/videos/destroy.js.haml +3 -0
  142. data/app/views/admin/common/_archive_sidebar.html.haml +28 -0
  143. data/app/views/admin/common/_list_table.html.erb +37 -0
  144. data/app/views/admin/common/_list_table_row.html.erb +18 -0
  145. data/app/views/admin/common/_pagination.html.erb +1 -0
  146. data/app/views/admin/common/_search_form.html.erb +6 -0
  147. data/app/views/admin/common/access_denied.html.haml +1 -0
  148. data/app/views/atreides/admin/_content_nav.html.haml +7 -0
  149. data/app/views/atreides/admin_home/_analytics.html.haml +93 -0
  150. data/app/views/atreides/admin_home/_fb_page_likes_analytics_tbody.haml +10 -0
  151. data/app/views/atreides/admin_home/_fb_page_views_analytics_tbody.haml +10 -0
  152. data/app/views/atreides/admin_home/_top_landing_pages_analytics_tbody.haml +14 -0
  153. data/app/views/atreides/admin_home/_top_referrers_analytics_tbody.haml +12 -0
  154. data/app/views/atreides/admin_home/_tweets_analytics_tbody.html.haml +8 -0
  155. data/app/views/atreides/admin_home/_visitors_analytics_tbody.html.haml +12 -0
  156. data/app/views/atreides/admin_home/index.html.haml +57 -0
  157. data/app/views/atreides/admin_home/search.html.haml +11 -0
  158. data/app/views/atreides/admin_home/setup.html.haml +15 -0
  159. data/app/views/atreides/common/_gallery_params.xml.erb +174 -0
  160. data/app/views/atreides/common/slideshow.xml.haml +6 -0
  161. data/app/views/atreides/errors/404.html.haml +10 -0
  162. data/app/views/atreides/errors/500.html.haml +4 -0
  163. data/app/views/atreides/home/index.html.haml +30 -0
  164. data/app/views/atreides/home/index.js.haml +1 -0
  165. data/app/views/atreides/home/robots.txt.erb +5 -0
  166. data/app/views/atreides/home/sitemap.xml.builder +35 -0
  167. data/app/views/atreides/pages/show.html.haml +3 -0
  168. data/app/views/atreides/posts/_archives.html.haml +19 -0
  169. data/app/views/atreides/posts/_featured_posts.html.haml +10 -0
  170. data/app/views/atreides/posts/_list.html.haml +9 -0
  171. data/app/views/atreides/posts/archives.html.haml +3 -0
  172. data/app/views/atreides/posts/archives.js.haml +1 -0
  173. data/app/views/atreides/posts/gallery_params.xml.haml +1 -0
  174. data/app/views/atreides/posts/index.atom.builder +22 -0
  175. data/app/views/atreides/posts/index.html.haml +13 -0
  176. data/app/views/atreides/posts/index.rss.builder +21 -0
  177. data/app/views/atreides/posts/show.html.haml +8 -0
  178. data/app/views/atreides/posts/tagged.html.haml +4 -0
  179. data/app/views/atreides/posts/tagged.js.haml +1 -0
  180. data/app/views/layouts/admin.html.haml +65 -0
  181. data/app/views/layouts/application.html.haml +37 -0
  182. data/app/views/layouts/atreides/application.html.erb +14 -0
  183. data/app/views/layouts/public.html.haml +39 -0
  184. data/config/cucumber.yml +11 -0
  185. data/config/locales/en.yml +207 -0
  186. data/config/locales/fr.yml +199 -0
  187. data/config/routes.rb +119 -0
  188. data/lib/assets/images/atreides/admin/add.png +0 -0
  189. data/lib/assets/images/atreides/admin/add_btn.png +0 -0
  190. data/lib/assets/images/atreides/admin/add_dashboard.png +0 -0
  191. data/lib/assets/images/atreides/admin/add_photo_button_sprite.png +0 -0
  192. data/lib/assets/images/atreides/admin/add_photos_btn.png +0 -0
  193. data/lib/assets/images/atreides/admin/background.png +0 -0
  194. data/lib/assets/images/atreides/admin/calendar.png +0 -0
  195. data/lib/assets/images/atreides/admin/chevron.gif +0 -0
  196. data/lib/assets/images/atreides/admin/chevron_overlay.png +0 -0
  197. data/lib/assets/images/atreides/admin/choose_photos_button_sprite.png +0 -0
  198. data/lib/assets/images/atreides/admin/content_bg.png +0 -0
  199. data/lib/assets/images/atreides/admin/content_bg_edit_form.png +0 -0
  200. data/lib/assets/images/atreides/admin/content_part_break.png +0 -0
  201. data/lib/assets/images/atreides/admin/content_part_drop_target.png +0 -0
  202. data/lib/assets/images/atreides/admin/content_part_icons.png +0 -0
  203. data/lib/assets/images/atreides/admin/content_part_photos.png +0 -0
  204. data/lib/assets/images/atreides/admin/content_part_text.png +0 -0
  205. data/lib/assets/images/atreides/admin/content_part_videos.png +0 -0
  206. data/lib/assets/images/atreides/admin/content_top_edit_form.png +0 -0
  207. data/lib/assets/images/atreides/admin/dashboard-indicator.gif +0 -0
  208. data/lib/assets/images/atreides/admin/dashboard_controls_activity.png +0 -0
  209. data/lib/assets/images/atreides/admin/dashboard_controls_customize.png +0 -0
  210. data/lib/assets/images/atreides/admin/dashboard_controls_drafts.png +0 -0
  211. data/lib/assets/images/atreides/admin/dashboard_controls_open.png +0 -0
  212. data/lib/assets/images/atreides/admin/dashboard_controls_posts.png +0 -0
  213. data/lib/assets/images/atreides/admin/dashboard_controls_queue.png +0 -0
  214. data/lib/assets/images/atreides/admin/dashboard_nav_border.png +0 -0
  215. data/lib/assets/images/atreides/admin/delete_bg.png +0 -0
  216. data/lib/assets/images/atreides/admin/down_arrow.png +0 -0
  217. data/lib/assets/images/atreides/admin/dropbox_big.jpg +0 -0
  218. data/lib/assets/images/atreides/admin/dropbox_btn.png +0 -0
  219. data/lib/assets/images/atreides/admin/dropbox_folder.png +0 -0
  220. data/lib/assets/images/atreides/admin/dropbox_icon.gif +0 -0
  221. data/lib/assets/images/atreides/admin/dropbox_icon.png +0 -0
  222. data/lib/assets/images/atreides/admin/expand_collapse.png +0 -0
  223. data/lib/assets/images/atreides/admin/form_sidebar_divider.png +0 -0
  224. data/lib/assets/images/atreides/admin/grey_hatch_bg.png +0 -0
  225. data/lib/assets/images/atreides/admin/header.png +0 -0
  226. data/lib/assets/images/atreides/admin/icon_dropbox.gif +0 -0
  227. data/lib/assets/images/atreides/admin/icon_home.gif +0 -0
  228. data/lib/assets/images/atreides/admin/input_bg.gif +0 -0
  229. data/lib/assets/images/atreides/admin/large_loading.gif +0 -0
  230. data/lib/assets/images/atreides/admin/new_content_icons.png +0 -0
  231. data/lib/assets/images/atreides/admin/off.png +0 -0
  232. data/lib/assets/images/atreides/admin/on.png +0 -0
  233. data/lib/assets/images/atreides/admin/page_icon.png +0 -0
  234. data/lib/assets/images/atreides/admin/permalink.png +0 -0
  235. data/lib/assets/images/atreides/admin/photos-display-type-gallery.png +0 -0
  236. data/lib/assets/images/atreides/admin/photos-display-type-photos.png +0 -0
  237. data/lib/assets/images/atreides/admin/product.png +0 -0
  238. data/lib/assets/images/atreides/admin/remove.png +0 -0
  239. data/lib/assets/images/atreides/admin/resize.png +0 -0
  240. data/lib/assets/images/atreides/admin/save_btn.png +0 -0
  241. data/lib/assets/images/atreides/admin/search_icon.png +0 -0
  242. data/lib/assets/images/atreides/admin/select_arrows.png +0 -0
  243. data/lib/assets/images/atreides/admin/slider.png +0 -0
  244. data/lib/assets/images/atreides/admin/slider_center.png +0 -0
  245. data/lib/assets/images/atreides/admin/slider_left.png +0 -0
  246. data/lib/assets/images/atreides/admin/slider_right.png +0 -0
  247. data/lib/assets/images/atreides/admin/sprite.png +0 -0
  248. data/lib/assets/images/atreides/admin/upload_btn.png +0 -0
  249. data/lib/assets/images/atreides/admin/video_bg.png +0 -0
  250. data/lib/assets/images/atreides/blank.gif +0 -0
  251. data/lib/assets/images/atreides/closelabel.png +0 -0
  252. data/lib/assets/images/atreides/loading.gif +0 -0
  253. data/lib/assets/images/atreides/sprite.png +0 -0
  254. data/lib/assets/images/atreides/tipsy.gif +0 -0
  255. data/lib/atreides.rb +81 -0
  256. data/lib/atreides/base/aasmstates.rb +117 -0
  257. data/lib/atreides/base/base.rb +40 -0
  258. data/lib/atreides/base/taggable.rb +43 -0
  259. data/lib/atreides/base/validation.rb +23 -0
  260. data/lib/atreides/configuration.rb +61 -0
  261. data/lib/atreides/engine.rb +41 -0
  262. data/lib/atreides/extendable.rb +12 -0
  263. data/lib/atreides/i18n_helpers.rb +65 -0
  264. data/lib/atreides/railties/tasks.rake +68 -0
  265. data/lib/atreides/time_formats.rb +19 -0
  266. data/lib/atreides/validators.rb +15 -0
  267. data/lib/atreides/version.rb +4 -0
  268. data/lib/generators/atreides/USAGE +0 -0
  269. data/lib/generators/atreides/atreides_generator.rb +57 -0
  270. data/lib/generators/templates/Procfile +2 -0
  271. data/lib/generators/templates/add_role_to_users.rb +16 -0
  272. data/lib/generators/templates/add_userid_to_resources.rb +15 -0
  273. data/lib/generators/templates/create_content_parts.rb +66 -0
  274. data/lib/generators/templates/create_features.rb +21 -0
  275. data/lib/generators/templates/create_likes.rb +16 -0
  276. data/lib/generators/templates/create_line_items.rb +21 -0
  277. data/lib/generators/templates/create_links.rb +16 -0
  278. data/lib/generators/templates/create_messages.rb +24 -0
  279. data/lib/generators/templates/create_orders.rb +31 -0
  280. data/lib/generators/templates/create_pages.rb +29 -0
  281. data/lib/generators/templates/create_photos.rb +22 -0
  282. data/lib/generators/templates/create_posts.rb +36 -0
  283. data/lib/generators/templates/create_preferences.rb +14 -0
  284. data/lib/generators/templates/create_products.rb +22 -0
  285. data/lib/generators/templates/create_sessions.rb +16 -0
  286. data/lib/generators/templates/create_sites.rb +35 -0
  287. data/lib/generators/templates/create_sizes.rb +16 -0
  288. data/lib/generators/templates/create_tweets.rb +25 -0
  289. data/lib/generators/templates/create_videos.rb +24 -0
  290. data/lib/generators/templates/create_votes.rb +20 -0
  291. data/lib/generators/templates/delayed_job.rb +5 -0
  292. data/lib/generators/templates/devise_create_users.rb +42 -0
  293. data/lib/generators/templates/em-net-http_override.rb +74 -0
  294. data/lib/generators/templates/initializer.rb +21 -0
  295. data/lib/generators/templates/new_relic.rb +6 -0
  296. data/lib/generators/templates/oembed.yml +63 -0
  297. data/lib/generators/templates/settings.yml +78 -0
  298. data/lib/generators/templates/string_extensions.rb +20 -0
  299. data/lib/generators/templates/unicorn.rb +2 -0
  300. data/lib/tasks/atreides_tasks.rake +4 -0
  301. data/lib/tasks/cucumber.rake +58 -0
  302. data/lib/tasks/tasks.rake +403 -0
  303. data/lib/tasks/yard.rake +18 -0
  304. data/vendor/assets/flash/atreides/player.swf +0 -0
  305. data/vendor/assets/flash/atreides/slideshowpro.swf +0 -0
  306. data/vendor/assets/flash/atreides/swfupload.swf +0 -0
  307. data/vendor/assets/images/atreides/share/aim_16.png +0 -0
  308. data/vendor/assets/images/atreides/share/apple_16.png +0 -0
  309. data/vendor/assets/images/atreides/share/bebo_16.png +0 -0
  310. data/vendor/assets/images/atreides/share/blogger_16.png +0 -0
  311. data/vendor/assets/images/atreides/share/brightkite_16.png +0 -0
  312. data/vendor/assets/images/atreides/share/cargo_16.png +0 -0
  313. data/vendor/assets/images/atreides/share/delicious_16.png +0 -0
  314. data/vendor/assets/images/atreides/share/designfloat_16.png +0 -0
  315. data/vendor/assets/images/atreides/share/designmoo_16.png +0 -0
  316. data/vendor/assets/images/atreides/share/deviantart_16.png +0 -0
  317. data/vendor/assets/images/atreides/share/digg_16.png +0 -0
  318. data/vendor/assets/images/atreides/share/digg_alt_16.png +0 -0
  319. data/vendor/assets/images/atreides/share/dopplr_16.png +0 -0
  320. data/vendor/assets/images/atreides/share/dribbble_16.png +0 -0
  321. data/vendor/assets/images/atreides/share/email_16.png +0 -0
  322. data/vendor/assets/images/atreides/share/ember_16.png +0 -0
  323. data/vendor/assets/images/atreides/share/evernote_16.png +0 -0
  324. data/vendor/assets/images/atreides/share/facebook_16.png +0 -0
  325. data/vendor/assets/images/atreides/share/flickr_16.png +0 -0
  326. data/vendor/assets/images/atreides/share/friendfeed_16.png +0 -0
  327. data/vendor/assets/images/atreides/share/gamespot_16.png +0 -0
  328. data/vendor/assets/images/atreides/share/google_16.png +0 -0
  329. data/vendor/assets/images/atreides/share/google_voice_16.png +0 -0
  330. data/vendor/assets/images/atreides/share/google_wave_16.png +0 -0
  331. data/vendor/assets/images/atreides/share/googletalk_16.png +0 -0
  332. data/vendor/assets/images/atreides/share/gowalla_16.png +0 -0
  333. data/vendor/assets/images/atreides/share/grooveshark_16.png +0 -0
  334. data/vendor/assets/images/atreides/share/ilike_16.png +0 -0
  335. data/vendor/assets/images/atreides/share/komodomedia_azure_16.png +0 -0
  336. data/vendor/assets/images/atreides/share/komodomedia_wood_16.png +0 -0
  337. data/vendor/assets/images/atreides/share/lastfm_16.png +0 -0
  338. data/vendor/assets/images/atreides/share/license.txt +9 -0
  339. data/vendor/assets/images/atreides/share/linkedin_16.png +0 -0
  340. data/vendor/assets/images/atreides/share/mixx_16.png +0 -0
  341. data/vendor/assets/images/atreides/share/mobileme_16.png +0 -0
  342. data/vendor/assets/images/atreides/share/mynameise_16.png +0 -0
  343. data/vendor/assets/images/atreides/share/myspace_16.png +0 -0
  344. data/vendor/assets/images/atreides/share/netvibes_16.png +0 -0
  345. data/vendor/assets/images/atreides/share/newsvine_16.png +0 -0
  346. data/vendor/assets/images/atreides/share/openid_16.png +0 -0
  347. data/vendor/assets/images/atreides/share/orkut_16.png +0 -0
  348. data/vendor/assets/images/atreides/share/pandora_16.png +0 -0
  349. data/vendor/assets/images/atreides/share/paypal_16.png +0 -0
  350. data/vendor/assets/images/atreides/share/picasa_16.png +0 -0
  351. data/vendor/assets/images/atreides/share/plurk_16.png +0 -0
  352. data/vendor/assets/images/atreides/share/posterous_16.png +0 -0
  353. data/vendor/assets/images/atreides/share/qik_16.png +0 -0
  354. data/vendor/assets/images/atreides/share/readernaut_16.png +0 -0
  355. data/vendor/assets/images/atreides/share/reddit_16.png +0 -0
  356. data/vendor/assets/images/atreides/share/roboto_16.png +0 -0
  357. data/vendor/assets/images/atreides/share/rss_16.png +0 -0
  358. data/vendor/assets/images/atreides/share/sharethis_16.png +0 -0
  359. data/vendor/assets/images/atreides/share/skype_16.png +0 -0
  360. data/vendor/assets/images/atreides/share/stumbleupon_16.png +0 -0
  361. data/vendor/assets/images/atreides/share/technorati_16.png +0 -0
  362. data/vendor/assets/images/atreides/share/tumblr_16.png +0 -0
  363. data/vendor/assets/images/atreides/share/twitter_16.png +0 -0
  364. data/vendor/assets/images/atreides/share/viddler_16.png +0 -0
  365. data/vendor/assets/images/atreides/share/vimeo_16.png +0 -0
  366. data/vendor/assets/images/atreides/share/virb_16.png +0 -0
  367. data/vendor/assets/images/atreides/share/windows_16.png +0 -0
  368. data/vendor/assets/images/atreides/share/wordpress_16.png +0 -0
  369. data/vendor/assets/images/atreides/share/xing_16.png +0 -0
  370. data/vendor/assets/images/atreides/share/yahoo_16.png +0 -0
  371. data/vendor/assets/images/atreides/share/yahoobuzz_16.png +0 -0
  372. data/vendor/assets/images/atreides/share/yelp_16.png +0 -0
  373. data/vendor/assets/images/atreides/share/youtube_16.png +0 -0
  374. data/vendor/assets/javascripts/atreides/backbone-0.3.3.js +1100 -0
  375. data/vendor/assets/javascripts/atreides/cufon-yui.js +7 -0
  376. data/vendor/assets/javascripts/atreides/facebox.js +309 -0
  377. data/vendor/assets/javascripts/atreides/fileuploader.js +1250 -0
  378. data/vendor/assets/javascripts/atreides/g.raphael-min.js +7 -0
  379. data/vendor/assets/javascripts/atreides/galleria.js +2 -0
  380. data/vendor/assets/javascripts/atreides/galleria/src/galleria.js +3816 -0
  381. data/vendor/assets/javascripts/atreides/galleria/src/plugins/galleria.flickr.js +221 -0
  382. data/vendor/assets/javascripts/atreides/galleria/src/plugins/galleria.history.js +602 -0
  383. data/vendor/assets/javascripts/atreides/galleria/src/themes/classic/classic-loader.gif +0 -0
  384. data/vendor/assets/javascripts/atreides/galleria/src/themes/classic/classic-map.png +0 -0
  385. data/vendor/assets/javascripts/atreides/galleria/src/themes/classic/galleria.classic.css +202 -0
  386. data/vendor/assets/javascripts/atreides/galleria/src/themes/classic/galleria.classic.js +92 -0
  387. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/b.png +0 -0
  388. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/down.gif +0 -0
  389. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/fix.gif +0 -0
  390. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/fullscreen-demo.html +34 -0
  391. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/galleria.fullscreen.css +46 -0
  392. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/galleria.fullscreen.js +193 -0
  393. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/i.png +0 -0
  394. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/l.gif +0 -0
  395. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/l2.png +0 -0
  396. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/loader.gif +0 -0
  397. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/n.gif +0 -0
  398. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/p.gif +0 -0
  399. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/r.gif +0 -0
  400. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/r2.png +0 -0
  401. data/vendor/assets/javascripts/atreides/galleria/src/themes/fullscreen/up.gif +0 -0
  402. data/vendor/assets/javascripts/atreides/jquery-1.7.js +4 -0
  403. data/vendor/assets/javascripts/atreides/jquery-ui.js +11603 -0
  404. data/vendor/assets/javascripts/atreides/jquery.autogrow.js +132 -0
  405. data/vendor/assets/javascripts/atreides/jquery.cookie.js +96 -0
  406. data/vendor/assets/javascripts/atreides/jquery.countdown.js +759 -0
  407. data/vendor/assets/javascripts/atreides/jquery.cycle.js +918 -0
  408. data/vendor/assets/javascripts/atreides/jquery.easing.1.3.js +205 -0
  409. data/vendor/assets/javascripts/atreides/jquery.flash.js +288 -0
  410. data/vendor/assets/javascripts/atreides/jquery.iphone-checkboxes.js +214 -0
  411. data/vendor/assets/javascripts/atreides/jquery.jBreadCrumb.1.1.js +240 -0
  412. data/vendor/assets/javascripts/atreides/jquery.multipleselectbox-min.js +15 -0
  413. data/vendor/assets/javascripts/atreides/jquery.multipleselectbox.js +446 -0
  414. data/vendor/assets/javascripts/atreides/jquery.swfupload.js +64 -0
  415. data/vendor/assets/javascripts/atreides/jquery.tipsy.js +104 -0
  416. data/vendor/assets/javascripts/atreides/jquery.uniform.js +461 -0
  417. data/vendor/assets/javascripts/atreides/jquery_ujs.js +316 -0
  418. data/vendor/assets/javascripts/atreides/jtags.js +125 -0
  419. data/vendor/assets/javascripts/atreides/raphael-min.js +7 -0
  420. data/vendor/assets/javascripts/atreides/raphael.analytics.js +205 -0
  421. data/vendor/assets/javascripts/atreides/raphael.path.methods.js +53 -0
  422. data/vendor/assets/javascripts/atreides/raphael.pie.js +44 -0
  423. data/vendor/assets/javascripts/atreides/sifr.js +18 -0
  424. data/vendor/assets/javascripts/atreides/swfobject.js +4 -0
  425. data/vendor/assets/javascripts/atreides/swfupload/handlers.js +290 -0
  426. data/vendor/assets/javascripts/atreides/swfupload/swfupload.cookies.js +53 -0
  427. data/vendor/assets/javascripts/atreides/swfupload/swfupload.js +980 -0
  428. data/vendor/assets/javascripts/atreides/swfupload/swfupload.queue.js +98 -0
  429. data/vendor/assets/javascripts/atreides/swfupload/swfupload.speed.js +342 -0
  430. data/vendor/assets/javascripts/atreides/swfupload/swfupload.swfobject.js +111 -0
  431. data/vendor/assets/javascripts/atreides/underscore-1.1.6.js +807 -0
  432. data/vendor/assets/stylesheets/atreides/admin_grid.css +258 -0
  433. data/vendor/assets/stylesheets/atreides/facebox.css +80 -0
  434. data/vendor/assets/stylesheets/atreides/formtastic.css +144 -0
  435. data/vendor/assets/stylesheets/atreides/galleria.css +24 -0
  436. data/vendor/assets/stylesheets/atreides/ie.css +35 -0
  437. data/vendor/assets/stylesheets/atreides/images/bg_fallback.png +0 -0
  438. data/vendor/assets/stylesheets/atreides/images/icon_sprite.png +0 -0
  439. data/vendor/assets/stylesheets/atreides/images/progress_bar.gif +0 -0
  440. data/vendor/assets/stylesheets/atreides/images/slider_handles.png +0 -0
  441. data/vendor/assets/stylesheets/atreides/images/ui-icons_222222_256x240.png +0 -0
  442. data/vendor/assets/stylesheets/atreides/images/ui-icons_454545_256x240.png +0 -0
  443. data/vendor/assets/stylesheets/atreides/jquery-ui.css +738 -0
  444. data/vendor/assets/stylesheets/atreides/multipleselectbox.css +33 -0
  445. data/vendor/assets/stylesheets/atreides/print.css +29 -0
  446. data/vendor/assets/stylesheets/atreides/public_grid.css +258 -0
  447. data/vendor/assets/stylesheets/atreides/tipsy.css +7 -0
  448. data/vendor/assets/stylesheets/atreides/uniform.default.css +476 -0
  449. metadata +1566 -0
@@ -0,0 +1,7 @@
1
+ /*
2
+ * g.Raphael 0.4 - Charting library, based on Raphaël
3
+ *
4
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
5
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
6
+ */
7
+ (function(){Raphael.fn.g=Raphael.fn.g||{};Raphael.fn.g.markers={disc:"disc",o:"disc",flower:"flower",f:"flower",diamond:"diamond",d:"diamond",square:"square",s:"square",triangle:"triangle",t:"triangle",star:"star","*":"star",cross:"cross",x:"cross",plus:"plus","+":"plus",arrow:"arrow","->":"arrow"};Raphael.fn.g.shim={stroke:"none",fill:"#000","fill-opacity":0};Raphael.fn.g.txtattr={font:"12px Arial, sans-serif"};Raphael.fn.g.colors=[];var b=[0.6,0.2,0.05,0.1333,0.75,0];for(var a=0;a<10;a++){if(a<b.length){Raphael.fn.g.colors.push("hsb("+b[a]+", .75, .75)");}else{Raphael.fn.g.colors.push("hsb("+b[a-b.length]+", 1, .5)");}}Raphael.fn.g.text=function(c,f,e){return this.text(c,f,e).attr(this.g.txtattr);};Raphael.fn.g.labelise=function(c,f,e){if(c){return(c+"").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g,function(g,i,h){if(i){return(+f).toFixed(i.replace(/^#+\.?/g,"").length);}if(h){return(f*100/e).toFixed(h.replace(/^%+\.?/g,"").length)+"%";}});}else{return(+f).toFixed(0);}};Raphael.fn.g.finger=function(j,i,e,k,f,g,h){if((f&&!k)||(!f&&!e)){return h?"":this.path();}g={square:"square",sharp:"sharp",soft:"soft"}[g]||"round";var m;k=Math.round(k);e=Math.round(e);j=Math.round(j);i=Math.round(i);switch(g){case"round":if(!f){var c=Math.floor(k/2);if(e<c){c=e;m=["M",j+0.5,i+0.5-Math.floor(k/2),"l",0,0,"a",c,Math.floor(k/2),0,0,1,0,k,"l",0,0,"z"];}else{m=["M",j+0.5,i+0.5-c,"l",e-c,0,"a",c,c,0,1,1,0,k,"l",c-e,0,"z"];}}else{var c=Math.floor(e/2);if(k<c){c=k;m=["M",j-Math.floor(e/2),i,"l",0,0,"a",Math.floor(e/2),c,0,0,1,e,0,"l",0,0,"z"];}else{m=["M",j-c,i,"l",0,c-k,"a",c,c,0,1,1,e,0,"l",0,k-c,"z"];}}break;case"sharp":if(!f){var l=Math.floor(k/2);m=["M",j,i+l,"l",0,-k,Math.max(e-l,0),0,Math.min(l,e),l,-Math.min(l,e),l+(l*2<k),"z"];}else{var l=Math.floor(e/2);m=["M",j+l,i,"l",-e,0,0,-Math.max(k-l,0),l,-Math.min(l,k),l,Math.min(l,k),l,"z"];}break;case"square":if(!f){m=["M",j,i+Math.floor(k/2),"l",0,-k,e,0,0,k,"z"];}else{m=["M",j+Math.floor(e/2),i,"l",1-e,0,0,-k,e-1,0,"z"];}break;case"soft":var c;if(!f){c=Math.min(e,Math.round(k/5));m=["M",j+0.5,i+0.5-Math.floor(k/2),"l",e-c,0,"a",c,c,0,0,1,c,c,"l",0,k-c*2,"a",c,c,0,0,1,-c,c,"l",c-e,0,"z"];}else{c=Math.min(Math.round(e/5),k);m=["M",j-Math.floor(e/2),i,"l",0,c-k,"a",c,c,0,0,1,c,-c,"l",e-2*c,0,"a",c,c,0,0,1,c,c,"l",0,k-c,"z"];}}if(h){return m.join(",");}else{return this.path(m);}};Raphael.fn.g.disc=function(c,f,e){return this.circle(c,f,e);};Raphael.fn.g.line=function(c,f,e){return this.rect(c-e,f-e/5,2*e,2*e/5);};Raphael.fn.g.square=function(c,f,e){e=e*0.7;return this.rect(c-e,f-e,2*e,2*e);};Raphael.fn.g.triangle=function(c,f,e){e*=1.75;return this.path("M".concat(c,",",f,"m0-",e*0.58,"l",e*0.5,",",e*0.87,"-",e,",0z"));};Raphael.fn.g.diamond=function(c,f,e){return this.path(["M",c,f-e,"l",e,e,-e,e,-e,-e,e,-e,"z"]);};Raphael.fn.g.flower=function(g,f,c,e){c=c*1.25;var l=c,k=l*0.5;e=+e<3||!e?5:e;var m=["M",g,f+k,"Q"],j;for(var h=1;h<e*2+1;h++){j=h%2?l:k;m=m.concat([+(g+j*Math.sin(h*Math.PI/e)).toFixed(3),+(f+j*Math.cos(h*Math.PI/e)).toFixed(3)]);}m.push("z");return this.path(m.join(","));};Raphael.fn.g.star=function(c,k,j,e){e=e||j*0.5;var h=["M",c,k+e,"L"],g;for(var f=1;f<10;f++){g=f%2?j:e;h=h.concat([(c+g*Math.sin(f*Math.PI*0.2)).toFixed(3),(k+g*Math.cos(f*Math.PI*0.2)).toFixed(3)]);}h.push("z");return this.path(h.join(","));};Raphael.fn.g.cross=function(c,f,e){e=e/2.5;return this.path("M".concat(c-e,",",f,"l",[-e,-e,e,-e,e,e,e,-e,e,e,-e,e,e,e,-e,e,-e,-e,-e,e,-e,-e,"z"]));};Raphael.fn.g.plus=function(c,f,e){e=e/2;return this.path("M".concat(c-e/2,",",f-e/2,"l",[0,-e,e,0,0,e,e,0,0,e,-e,0,0,e,-e,0,0,-e,-e,0,0,-e,"z"]));};Raphael.fn.g.arrow=function(c,f,e){return this.path("M".concat(c-e*0.7,",",f-e*0.4,"l",[e*0.6,0,0,-e*0.4,e,e*0.8,-e,e*0.8,0,-e*0.4,-e*0.6,0],"z"));};Raphael.fn.g.tag=function(c,k,j,i,g){i=i||0;g=g==null?5:g;j=j==null?"$9.99":j;var f=0.5522*g,e=this.set(),h=3;e.push(this.path().attr({fill:"#000",stroke:"none"}));e.push(this.text(c,k,j).attr(this.g.txtattr).attr({fill:"#fff"}));e.update=function(){this.rotate(0,c,k);var m=this[1].getBBox();if(m.height>=g*2){this[0].attr({path:["M",c,k+g,"a",g,g,0,1,1,0,-g*2,g,g,0,1,1,0,g*2,"m",0,-g*2-h,"a",g+h,g+h,0,1,0,0,(g+h)*2,"L",c+g+h,k+m.height/2+h,"l",m.width+2*h,0,0,-m.height-2*h,-m.width-2*h,0,"L",c,k-g-h].join(",")});}else{var l=Math.sqrt(Math.pow(g+h,2)-Math.pow(m.height/2+h,2));this[0].attr({path:["M",c,k+g,"c",-f,0,-g,f-g,-g,-g,0,-f,g-f,-g,g,-g,f,0,g,g-f,g,g,0,f,f-g,g,-g,g,"M",c+l,k-m.height/2-h,"a",g+h,g+h,0,1,0,0,m.height+2*h,"l",g+h-l+m.width+2*h,0,0,-m.height-2*h,"L",c+l,k-m.height/2-h].join(",")});}this[1].attr({x:c+g+h+m.width/2,y:k});i=(360-i)%360;this.rotate(i,c,k);i>90&&i<270&&this[1].attr({x:c-g-h-m.width/2,y:k,rotation:[180+i,c,k]});return this;};e.update();return e;};Raphael.fn.g.popupit=function(j,i,k,e,q){e=e==null?2:e;q=q||5;j=Math.round(j)+0.5;i=Math.round(i)+0.5;var g=k.getBBox(),l=Math.round(g.width/2),f=Math.round(g.height/2),o=[0,l+q*2,0,-l-q*2],m=[-f*2-q*3,-f-q,0,-f-q],c=["M",j-o[e],i-m[e],"l",-q,(e==2)*-q,-Math.max(l-q,0),0,"a",q,q,0,0,1,-q,-q,"l",0,-Math.max(f-q,0),(e==3)*-q,-q,(e==3)*q,-q,0,-Math.max(f-q,0),"a",q,q,0,0,1,q,-q,"l",Math.max(l-q,0),0,q,!e*-q,q,!e*q,Math.max(l-q,0),0,"a",q,q,0,0,1,q,q,"l",0,Math.max(f-q,0),(e==1)*q,q,(e==1)*-q,q,0,Math.max(f-q,0),"a",q,q,0,0,1,-q,q,"l",-Math.max(l-q,0),0,"z"].join(","),n=[{x:j,y:i+q*2+f},{x:j-q*2-l,y:i},{x:j,y:i-q*2-f},{x:j+q*2+l,y:i}][e];k.translate(n.x-l-g.x,n.y-f-g.y);return this.path(c).attr({fill:"#000",stroke:"none"}).insertBefore(k.node?k:k[0]);};Raphael.fn.g.popup=function(c,j,i,e,g){e=e==null?2:e;g=g||5;i=i||"$9.99";var f=this.set(),h=3;f.push(this.path().attr({fill:"#000",stroke:"none"}));f.push(this.text(c,j,i).attr(this.g.txtattr).attr({fill:"#fff"}));f.update=function(m,l,n){m=m||c;l=l||j;var q=this[1].getBBox(),s=q.width/2,o=q.height/2,v=[0,s+g*2,0,-s-g*2],t=[-o*2-g*3,-o-g,0,-o-g],k=["M",m-v[e],l-t[e],"l",-g,(e==2)*-g,-Math.max(s-g,0),0,"a",g,g,0,0,1,-g,-g,"l",0,-Math.max(o-g,0),(e==3)*-g,-g,(e==3)*g,-g,0,-Math.max(o-g,0),"a",g,g,0,0,1,g,-g,"l",Math.max(s-g,0),0,g,!e*-g,g,!e*g,Math.max(s-g,0),0,"a",g,g,0,0,1,g,g,"l",0,Math.max(o-g,0),(e==1)*g,g,(e==1)*-g,g,0,Math.max(o-g,0),"a",g,g,0,0,1,-g,g,"l",-Math.max(s-g,0),0,"z"].join(","),u=[{x:m,y:l+g*2+o},{x:m-g*2-s,y:l},{x:m,y:l-g*2-o},{x:m+g*2+s,y:l}][e];if(n){this[0].animate({path:k},500,">");this[1].animate(u,500,">");}else{this[0].attr({path:k});this[1].attr(u);}return this;};return f.update(c,j);};Raphael.fn.g.flag=function(c,i,h,g){g=g||0;h=h||"$9.99";var e=this.set(),f=3;e.push(this.path().attr({fill:"#000",stroke:"none"}));e.push(this.text(c,i,h).attr(this.g.txtattr).attr({fill:"#fff"}));e.update=function(j,m){this.rotate(0,j,m);var l=this[1].getBBox(),k=l.height/2;this[0].attr({path:["M",j,m,"l",k+f,-k-f,l.width+2*f,0,0,l.height+2*f,-l.width-2*f,0,"z"].join(",")});this[1].attr({x:j+k+f+l.width/2,y:m});g=360-g;this.rotate(g,j,m);g>90&&g<270&&this[1].attr({x:j-r-f-l.width/2,y:m,rotation:[180+g,j,m]});return this;};return e.update(c,i);};Raphael.fn.g.label=function(c,g,f){var e=this.set();e.push(this.rect(c,g,10,10).attr({stroke:"none",fill:"#000"}));e.push(this.text(c,g,f).attr(this.g.txtattr).attr({fill:"#fff"}));e.update=function(){var i=this[1].getBBox(),h=Math.min(i.width+10,i.height+10)/2;this[0].attr({x:i.x-h/2,y:i.y-h/2,width:i.width+h,height:i.height+h,r:h});};e.update();return e;};Raphael.fn.g.labelit=function(f){var e=f.getBBox(),c=Math.min(20,e.width+10,e.height+10)/2;return this.rect(e.x-c/2,e.y-c/2,e.width+c,e.height+c,c).attr({stroke:"none",fill:"#000"}).insertBefore(f[0]);};Raphael.fn.g.drop=function(c,i,h,f,g){f=f||30;g=g||0;var e=this.set();e.push(this.path(["M",c,i,"l",f,0,"A",f*0.4,f*0.4,0,1,0,c+f*0.7,i-f*0.7,"z"]).attr({fill:"#000",stroke:"none",rotation:[22.5-g,c,i]}));g=(g+90)*Math.PI/180;e.push(this.text(c+f*Math.sin(g),i+f*Math.cos(g),h).attr(this.g.txtattr).attr({"font-size":f*12/30,fill:"#fff"}));e.drop=e[0];e.text=e[1];return e;};Raphael.fn.g.blob=function(e,k,j,i,g){i=(+i+1?i:45)+90;g=g||12;var c=Math.PI/180,h=g*12/12;var f=this.set();f.push(this.path().attr({fill:"#000",stroke:"none"}));f.push(this.text(e+g*Math.sin((i)*c),k+g*Math.cos((i)*c)-h/2,j).attr(this.g.txtattr).attr({"font-size":h,fill:"#fff"}));f.update=function(q,p,v){q=q||e;p=p||k;var y=this[1].getBBox(),B=Math.max(y.width+h,g*25/12),x=Math.max(y.height+h,g*25/12),m=q+g*Math.sin((i-22.5)*c),z=p+g*Math.cos((i-22.5)*c),o=q+g*Math.sin((i+22.5)*c),A=p+g*Math.cos((i+22.5)*c),D=(o-m)/2,C=(A-z)/2,n=B/2,l=x/2,u=-Math.sqrt(Math.abs(n*n*l*l-n*n*C*C-l*l*D*D)/(n*n*C*C+l*l*D*D)),t=u*n*C/l+(o+m)/2,s=u*-l*D/n+(A+z)/2;if(v){this.animate({x:t,y:s,path:["M",e,k,"L",o,A,"A",n,l,0,1,1,m,z,"z"].join(",")},500,">");}else{this.attr({x:t,y:s,path:["M",e,k,"L",o,A,"A",n,l,0,1,1,m,z,"z"].join(",")});}return this;};f.update(e,k);return f;};Raphael.fn.g.colorValue=function(g,f,e,c){return"hsb("+[Math.min((1-g/f)*0.4,1),e||0.75,c||0.75]+")";};Raphael.fn.g.snapEnds=function(l,m,k){var h=l,n=m;if(h==n){return{from:h,to:n,power:0};}function o(f){return Math.abs(f-0.5)<0.25?Math.floor(f)+0.5:Math.round(f);}var j=(n-h)/k,c=Math.floor(j),g=c,e=0;if(c){while(g){e--;g=Math.floor(j*Math.pow(10,e))/Math.pow(10,e);}e++;}else{while(!c){e=e||1;c=Math.floor(j*Math.pow(10,e))/Math.pow(10,e);e++;}e&&e--;}var n=o(m*Math.pow(10,e))/Math.pow(10,e);if(n<m){n=o((m+0.5)*Math.pow(10,e))/Math.pow(10,e);}var h=o((l-(e>0?0:0.5))*Math.pow(10,e))/Math.pow(10,e);return{from:h,to:n,power:e};};Raphael.fn.g.axis=function(s,q,m,E,h,H,k,J,l,c){c=c==null?2:c;l=l||"t";H=H||10;var D=l=="|"||l==" "?["M",s+0.5,q,"l",0,0.001]:k==1||k==3?["M",s+0.5,q,"l",0,-m]:["M",s,q+0.5,"l",m,0],v=this.g.snapEnds(E,h,H),I=v.from,z=v.to,G=v.power,F=0,A=this.set();d=(z-I)/H;var p=I,o=G>0?G:0;u=m/H;if(+k==1||+k==3){var e=q,w=(k-1?1:-1)*(c+3+!!(k-1));while(e>=q-m){l!="-"&&l!=" "&&(D=D.concat(["M",s-(l=="+"||l=="|"?c:!(k-1)*c*2),e+0.5,"l",c*2+1,0]));A.push(this.text(s+w,e,(J&&J[F++])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr).attr({"text-anchor":k-1?"start":"end"}));p+=d;e-=u;}if(Math.round(e+u-(q-m))){l!="-"&&l!=" "&&(D=D.concat(["M",s-(l=="+"||l=="|"?c:!(k-1)*c*2),q-m+0.5,"l",c*2+1,0]));A.push(this.text(s+w,q-m,(J&&J[F])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr).attr({"text-anchor":k-1?"start":"end"}));}}else{var g=s,p=I,o=G>0?G:0,w=(k?-1:1)*(c+9+!k),u=m/H,B=0,C=0;while(g<=s+m){l!="-"&&l!=" "&&(D=D.concat(["M",g+0.5,q-(l=="+"?c:!!k*c*2),"l",0,c*2+1]));A.push(B=this.text(g,q+w,(J&&J[F++])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr));var n=B.getBBox();if(C>=n.x-5){A.pop(A.length-1).remove();}else{C=n.x+n.width;}p+=d;g+=u;}if(Math.round(g-u-s-m)){l!="-"&&l!=" "&&(D=D.concat(["M",s+m+0.5,q-(l=="+"?c:!!k*c*2),"l",0,c*2+1]));A.push(this.text(s+m,q+w,(J&&J[F])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr));}}var K=this.path(D);K.text=A;K.all=this.set([K,A]);K.remove=function(){this.text.remove();this.constructor.prototype.remove.call(this);};return K;};Raphael.el.lighter=function(e){e=e||2;var c=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[c[0],c[1]];c[0]=Raphael.rgb2hsb(Raphael.getRGB(c[0]).hex);c[1]=Raphael.rgb2hsb(Raphael.getRGB(c[1]).hex);c[0].b=Math.min(c[0].b*e,1);c[0].s=c[0].s/e;c[1].b=Math.min(c[1].b*e,1);c[1].s=c[1].s/e;this.attr({fill:"hsb("+[c[0].h,c[0].s,c[0].b]+")",stroke:"hsb("+[c[1].h,c[1].s,c[1].b]+")"});};Raphael.el.darker=function(e){e=e||2;var c=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[c[0],c[1]];c[0]=Raphael.rgb2hsb(Raphael.getRGB(c[0]).hex);c[1]=Raphael.rgb2hsb(Raphael.getRGB(c[1]).hex);c[0].s=Math.min(c[0].s*e,1);c[0].b=c[0].b/e;c[1].s=Math.min(c[1].s*e,1);c[1].b=c[1].b/e;this.attr({fill:"hsb("+[c[0].h,c[0].s,c[0].b]+")",stroke:"hsb("+[c[1].h,c[1].s,c[1].b]+")"});};Raphael.el.original=function(){if(this.fs){this.attr({fill:this.fs[0],stroke:this.fs[1]});delete this.fs;}};})();
@@ -0,0 +1,2 @@
1
+ //= require atreides/galleria/src/galleria.js
2
+ //= require atreides/galleria/src/plugins/galleria.history.js
@@ -0,0 +1,3816 @@
1
+ /*
2
+ * Galleria v 1.2 prerelease 1.1 2010-11-23
3
+ * http://galleria.aino.se
4
+ *
5
+ * Copyright (c) 2010, Aino
6
+ * Licensed under the MIT license.
7
+ */
8
+
9
+ (function($) {
10
+
11
+ // some references
12
+ var undef,
13
+ window = this,
14
+ doc = document,
15
+ $doc = $( doc );
16
+
17
+ // internal constants
18
+ var DEBUG = false,
19
+ NAV = navigator.userAgent.toLowerCase(),
20
+ HASH = window.location.hash.replace(/#\//, ''),
21
+ CLICK = function() {
22
+ // use this to make touch devices snappier
23
+ return Galleria.TOUCH ? 'touchstart' : 'click';
24
+ },
25
+ IE = (function() {
26
+ var v = 3,
27
+ div = doc.createElement( 'div' );
28
+ while (
29
+ div.innerHTML = '<!--[if gt IE '+(++v)+']><i></i><![endif]-->',
30
+ div.getElementsByTagName('i')[0]
31
+ );
32
+ return v > 4 ? v : undef;
33
+ }() ),
34
+ DOM = function() {
35
+ return {
36
+ html: doc.documentElement,
37
+ body: doc.body,
38
+ head: doc.getElementsByTagName('head')[0],
39
+ title: doc.title
40
+ };
41
+ },
42
+
43
+ // the internal timeouts object
44
+ // provides helper methods for controlling timeouts
45
+ _timeouts = {
46
+
47
+ trunk: {},
48
+
49
+ add: function( id, fn, delay, loop ) {
50
+ loop = loop || false;
51
+ this.clear( id );
52
+ if ( loop ) {
53
+ var old = fn;
54
+ fn = function() {
55
+ old();
56
+ _timeouts.add( id, fn, delay );
57
+ };
58
+ }
59
+ this.trunk[ id ] = window.setTimeout( fn, delay );
60
+ },
61
+
62
+ clear: function( id ) {
63
+
64
+ var del = function( i ) {
65
+ window.clearTimeout( this.trunk[ i ] );
66
+ delete this.trunk[ i ];
67
+ };
68
+
69
+ if ( !!id && id in this.trunk ) {
70
+ del.call( _timeouts, id );
71
+
72
+ } else if ( typeof id == 'undefined' ) {
73
+ for ( var i in this.trunk ) {
74
+ del.call( _timeouts, i );
75
+ }
76
+ }
77
+ }
78
+ },
79
+
80
+ // the internal gallery holder
81
+ _galleries = [],
82
+
83
+ // the transitions holder
84
+ _transitions = {
85
+
86
+ fade: function(params, complete) {
87
+ $(params.next).css('opacity', 0).show().animate({
88
+ opacity: 1
89
+ }, params.speed, complete);
90
+
91
+ if (params.prev) {
92
+ $(params.prev).css('opacity', 1).show().animate({
93
+ opacity: 0
94
+ }, params.speed);
95
+ }
96
+ },
97
+
98
+ flash: function(params, complete) {
99
+ $(params.next).css('opacity', 0);
100
+ if (params.prev) {
101
+ $(params.prev).animate({
102
+ opacity: 0
103
+ }, (params.speed / 2), function() {
104
+ $(params.next).animate({
105
+ opacity: 1
106
+ }, params.speed, complete);
107
+ });
108
+ } else {
109
+ $(params.next).animate({
110
+ opacity: 1
111
+ }, params.speed, complete);
112
+ }
113
+ },
114
+
115
+ pulse: function(params, complete) {
116
+ if (params.prev) {
117
+ $(params.prev).hide();
118
+ }
119
+ $(params.next).css('opacity', 0).animate({
120
+ opacity:1
121
+ }, params.speed, complete);
122
+ },
123
+
124
+ slide: function(params, complete) {
125
+ var image = $(params.next).parent(),
126
+ images = this.$('images'), // ??
127
+ width = this._stageWidth,
128
+ easing = this.getOptions( 'easing' );
129
+
130
+ image.css({
131
+ left: width * ( params.rewind ? -1 : 1 )
132
+ });
133
+ images.animate({
134
+ left: width * ( params.rewind ? 1 : -1 )
135
+ }, {
136
+ duration: params.speed,
137
+ queue: false,
138
+ easing: easing,
139
+ complete: function() {
140
+ images.css('left', 0);
141
+ image.css('left', 0);
142
+ complete();
143
+ }
144
+ });
145
+ },
146
+
147
+ fadeslide: function(params, complete) {
148
+
149
+ var x = 0,
150
+ easing = this.getOptions('easing'),
151
+ distance = this.getStageWidth();
152
+
153
+ if (params.prev) {
154
+ x = Utils.parseValue( $(params.prev).css('left') );
155
+ $(params.prev).css({
156
+ opacity: 1,
157
+ left: x
158
+ }).animate({
159
+ opacity: 0,
160
+ left: x + ( distance * ( params.rewind ? 1 : -1 ) )
161
+ },{
162
+ duration: params.speed,
163
+ queue: false,
164
+ easing: easing
165
+ });
166
+ }
167
+
168
+ x = Utils.parseValue( $(params.next).css('left') );
169
+
170
+ $(params.next).css({
171
+ left: x + ( distance * ( params.rewind ? -1 : 1 ) ),
172
+ opacity: 0
173
+ }).animate({
174
+ opacity: 1,
175
+ left: x
176
+ }, {
177
+ duration: params.speed,
178
+ complete: complete,
179
+ queue: false,
180
+ easing: easing
181
+ });
182
+ }
183
+ },
184
+
185
+ // the Utils singleton
186
+ Utils = (function() {
187
+
188
+ return {
189
+
190
+ array : function( obj ) {
191
+ return Array.prototype.slice.call(obj);
192
+ },
193
+
194
+ create : function( className, nodeName ) {
195
+ nodeName = nodeName || 'div';
196
+ var elem = doc.createElement( nodeName );
197
+ elem.className = className;
198
+ return elem;
199
+ },
200
+
201
+ forceStyles : function( elem, styles ) {
202
+ elem = $(elem);
203
+ if ( elem.attr( 'style' ) ) {
204
+ elem.data( 'styles', elem.attr( 'style' ) ).removeAttr( 'style' );
205
+ }
206
+ elem.css( styles );
207
+ },
208
+
209
+ revertStyles : function() {
210
+ $.each( Utils.array( arguments ), function( i, elem ) {
211
+
212
+ elem = $( elem ).removeAttr( 'style' );
213
+
214
+ if ( elem.data( 'styles' ) ) {
215
+ elem.attr( 'style', elem.data('styles') ).data( 'styles', null );
216
+ }
217
+ });
218
+ },
219
+
220
+ moveOut : function( elem ) {
221
+ Utils.forceStyles( elem, {
222
+ position: 'absolute',
223
+ left: -10000
224
+ });
225
+ },
226
+
227
+ moveIn : function() {
228
+ Utils.revertStyles.apply( Utils, Utils.array( arguments ) );
229
+ },
230
+
231
+ hide : function( elem, speed, callback ) {
232
+ elem = $(elem);
233
+
234
+ // save the value if not exist
235
+ if (! elem.data('opacity') ) {
236
+ elem.data('opacity', elem.css('opacity') );
237
+ }
238
+
239
+ // always hide
240
+ var style = { opacity: 0 };
241
+
242
+ if (speed) {
243
+ elem.stop().animate( style, speed, callback );
244
+ } else {
245
+ elem.css( style );
246
+ };
247
+ },
248
+
249
+ show : function( elem, speed, callback ) {
250
+ elem = $(elem);
251
+
252
+ // bring back saved opacity
253
+ var saved = parseFloat( elem.data('opacity') ) || 1,
254
+ style = { opacity: saved };
255
+
256
+ // reset save if opacity == 1
257
+ if (saved == 1) {
258
+ elem.data('opacity', null);
259
+ }
260
+
261
+ // animate or toggle
262
+ if (speed) {
263
+ elem.stop().animate( style, speed, callback );
264
+ } else {
265
+ elem.css( style );
266
+ };
267
+ },
268
+
269
+ addTimer : function() {
270
+ _timeouts.add.apply( _timeouts, Utils.array( arguments ) );
271
+ return this;
272
+ },
273
+
274
+ clearTimer : function() {
275
+ _timeouts.clear.apply( _timeouts, Utils.array( arguments ) );
276
+ return this;
277
+ },
278
+
279
+ wait : function(options) {
280
+ options = $.extend({
281
+ until : function() { return false; },
282
+ success : function() {},
283
+ error : function() { Galleria.raise('Could not complete wait function.'); },
284
+ timeout: 3000
285
+ }, options);
286
+
287
+ var start = Utils.timestamp(),
288
+ elapsed,
289
+ now;
290
+
291
+ window.setTimeout(function() {
292
+ now = Utils.timestamp();
293
+ elapsed = now - start;
294
+ if ( options.until( elapsed ) ) {
295
+ options.success();
296
+ return false;
297
+ }
298
+
299
+ if (now >= start + options.timeout) {
300
+ options.error();
301
+ return false;
302
+ }
303
+ window.setTimeout(arguments.callee, 2);
304
+ }, 2);
305
+ },
306
+
307
+ toggleQuality : function( img, force ) {
308
+
309
+ if ( !( IE == 7 || IE == 8 ) || !!img === false ) {
310
+ return;
311
+ }
312
+
313
+ if ( typeof force === 'undefined' ) {
314
+ force = img.style.msInterpolationMode == 'nearest-neighbor';
315
+ }
316
+
317
+ img.style.msInterpolationMode = force ? 'bicubic' : 'nearest-neighbor';
318
+ },
319
+
320
+ insertStyleTag : function( styles ) {
321
+ var style = doc.createElement( 'style' );
322
+ DOM().head.appendChild( style );
323
+
324
+ if ( style.styleSheet ) { // IE
325
+ style.styleSheet.cssText = styles;
326
+ } else {
327
+ var cssText = doc.createTextNode( styles );
328
+ style.appendChild( cssText );
329
+ }
330
+ },
331
+
332
+ // a loadscript method that works for local scripts
333
+ loadScript: function( url, callback ) {
334
+ var done = false,
335
+ script = $('<scr'+'ipt>').attr({
336
+ src: url,
337
+ async: true
338
+ }).get(0);
339
+
340
+ // Attach handlers for all browsers
341
+ script.onload = script.onreadystatechange = function() {
342
+ if ( !done && (!this.readyState ||
343
+ this.readyState == 'loaded' || this.readyState == 'complete') ) {
344
+ done = true;
345
+
346
+ if (typeof callback == 'function') {
347
+ callback.call( this, this );
348
+ }
349
+
350
+ // Handle memory leak in IE
351
+ script.onload = script.onreadystatechange = null;
352
+ }
353
+ };
354
+
355
+ var s = doc.getElementsByTagName( 'script' )[0];
356
+ s.parentNode.insertBefore( script, s );
357
+ },
358
+
359
+ // parse anything into a number
360
+ parseValue: function( val ) {
361
+ if (typeof val == 'number') {
362
+ return val;
363
+ } else if (typeof val == 'string') {
364
+ var arr = val.match(/\-?\d/g);
365
+ return arr && arr.constructor == Array ? arr.join('') * 1 : 0;
366
+ } else {
367
+ return 0;
368
+ }
369
+ },
370
+
371
+ // timestamp abstraction
372
+ timestamp: function() {
373
+ return new Date().getTime();
374
+ },
375
+
376
+ // this is pretty crap, but works for now
377
+ // it will add a callback, but it can't guarantee that the styles can be fetched
378
+ // using getComputedStyle further checking needed, possibly a dummy element
379
+ loadCSS : function( href, id, callback ) {
380
+
381
+ var link,
382
+ ready = false,
383
+ length;
384
+
385
+ // look for manual css
386
+ $('link[rel=stylesheet]').each(function() {
387
+ if ( new RegExp( href ).test( this.href ) ) {
388
+ link = this;
389
+ return false;
390
+ }
391
+ });
392
+
393
+ if ( typeof id == 'function' ) {
394
+ callback = id;
395
+ id = undef;
396
+ }
397
+
398
+ callback = callback || function() {}; // dirty
399
+
400
+ // if already present, return
401
+ if ( link ) {
402
+ callback.call( link, link );
403
+ return link;
404
+ }
405
+
406
+ // save the length of stylesheets to check against
407
+ length = doc.styleSheets.length;
408
+
409
+ // add timestamp if DEBUG is true
410
+ if ( DEBUG ) {
411
+ href += '?' + Utils.timestamp();
412
+ }
413
+
414
+ // check for existing id
415
+ if( $('#'+id).length ) {
416
+ $('#'+id).attr('href', href);
417
+ length--;
418
+ ready = true;
419
+ } else {
420
+ link = $( '<link>' ).attr({
421
+ rel: 'stylesheet',
422
+ href: href,
423
+ id: id
424
+ }).get(0);
425
+
426
+ window.setTimeout(function() {
427
+ var styles = $('link[rel="stylesheet"], style');
428
+ if ( styles.length ) {
429
+ styles.get(0).parentNode.insertBefore( link, styles[0] );
430
+ } else {
431
+ DOM().head.appendChild( link );
432
+ }
433
+
434
+ if ( IE ) {
435
+ link.attachEvent( 'onreadystatechange', function(e) {
436
+ if( link.readyState == 'complete' ) {
437
+ ready = true;
438
+ }
439
+ });
440
+ } else {
441
+ // what to do here? returning for now.
442
+ ready = true;
443
+ }
444
+ }, 10);
445
+ }
446
+
447
+ if (typeof callback == 'function') {
448
+
449
+ Utils.wait({
450
+ until: function() {
451
+ return ready && doc.styleSheets.length > length;
452
+ },
453
+ success: function() {
454
+ Utils.addTimer( 'css', function() {
455
+ callback.call( link, link );
456
+ }, 100);
457
+ },
458
+ error: function() {
459
+ Galleria.raise( 'Theme CSS could not load' );
460
+ },
461
+ timeout: 1000
462
+ });
463
+ }
464
+ return link;
465
+ }
466
+ };
467
+ })();
468
+
469
+ /**
470
+ The main Galleria class
471
+
472
+ @class
473
+
474
+ @example var gallery = new Galleria();
475
+
476
+ @author http://aino.se
477
+
478
+ @requires jQuery
479
+
480
+ @returns {Galleria}
481
+ */
482
+
483
+ Galleria = function() {
484
+
485
+ var self = this;
486
+
487
+ // the theme used
488
+ this._theme = undef;
489
+
490
+ // internal options
491
+ this._options = {};
492
+
493
+ // flag for controlling play/pause
494
+ this._playing = false;
495
+
496
+ // internal interval for slideshow
497
+ this._playtime = 5000;
498
+
499
+ // internal variable for the currently active image
500
+ this._active = null;
501
+
502
+ // the internal queue, arrayified
503
+ this._queue = { length: 0 };
504
+
505
+ // the internal data array
506
+ this._data = [];
507
+
508
+ // the internal dom collection
509
+ this._dom = {};
510
+
511
+ // the internal thumbnails array
512
+ this._thumbnails = [];
513
+
514
+ // internal init flag
515
+ this._initialized = false;
516
+
517
+ // global stagewidth/height
518
+ this._stageWidth = 0;
519
+ this._stageHeight = 0;
520
+
521
+ // target holder
522
+ this._target = undef;
523
+
524
+ // instance id
525
+ this._id = Utils.timestamp();
526
+
527
+ // add some elements
528
+ var divs = 'container stage images image-nav image-nav-left image-nav-right ' +
529
+ 'info info-text info-title info-description info-author ' +
530
+ 'thumbnails thumbnails-list thumbnails-container thumb-nav-left thumb-nav-right ' +
531
+ 'loader counter tooltip',
532
+ spans = 'current total';
533
+
534
+ $.each( divs.split(' '), function( i, elemId ) {
535
+ self._dom[ elemId ] = Utils.create( 'galleria-' + elemId );
536
+ });
537
+
538
+ $.each( spans.split(' '), function( i, elemId ) {
539
+ self._dom[ elemId ] = Utils.create( 'galleria-' + elemId, 'span' );
540
+ });
541
+
542
+ // the internal keyboard object
543
+ // keeps reference of the keybinds and provides helper methods for binding keys
544
+ var keyboard = this._keyboard = {
545
+
546
+ keys : {
547
+ 'UP': 38,
548
+ 'DOWN': 40,
549
+ 'LEFT': 37,
550
+ 'RIGHT': 39,
551
+ 'RETURN': 13,
552
+ 'ESCAPE': 27,
553
+ 'BACKSPACE': 8,
554
+ 'SPACE': 32
555
+ },
556
+
557
+ map : {},
558
+
559
+ bound: false,
560
+
561
+ press: function(e) {
562
+ var key = e.keyCode || e.which;
563
+ if ( key in keyboard.map && typeof keyboard.map[key] == 'function' ) {
564
+ keyboard.map[key].call(self, e);
565
+ }
566
+ },
567
+
568
+ attach: function(map) {
569
+ for( var key in map ) {
570
+ var up = key.toUpperCase();
571
+ if ( up in keyboard.keys ) {
572
+ keyboard.map[ keyboard.keys[up] ] = map[key];
573
+ }
574
+ }
575
+ if ( !keyboard.bound ) {
576
+ keyboard.bound = true;
577
+ $doc.bind('keydown', keyboard.press);
578
+ }
579
+ },
580
+
581
+ detach: function() {
582
+ keyboard.bound = false;
583
+ $doc.unbind('keydown', keyboard.press);
584
+ }
585
+ };
586
+
587
+ // internal controls for keeping track of active / inactive images
588
+ var controls = this._controls = {
589
+
590
+ 0: undef,
591
+
592
+ 1: undef,
593
+
594
+ active : 0,
595
+
596
+ swap : function() {
597
+ controls.active = controls.active ? 0 : 1;
598
+ },
599
+
600
+ getActive : function() {
601
+ return controls[ controls.active ];
602
+ },
603
+
604
+ getNext : function() {
605
+ return controls[ 1 - controls.active ];
606
+ }
607
+ };
608
+
609
+ // internal carousel object
610
+ var carousel = this._carousel = {
611
+
612
+ // shortcuts
613
+ next: self.$('thumb-nav-right'),
614
+ prev: self.$('thumb-nav-left'),
615
+
616
+ // cache the width
617
+ width: 0,
618
+
619
+ // track the current position
620
+ current: 0,
621
+
622
+ // cache max value
623
+ max: 0,
624
+
625
+ // save all hooks for each width in an array
626
+ hooks: [],
627
+
628
+ // update the carousel
629
+ // you can run this method anytime, f.ex on window.resize
630
+ update: function() {
631
+ var w = 0,
632
+ h = 0,
633
+ hooks = [0];
634
+
635
+ $.each( self._thumbnails, function( i, thumb ) {
636
+ if ( thumb.ready ) {
637
+ w += thumb.outerWidth || $( thumb.container ).outerWidth( true );
638
+ hooks[ i+1 ] = w;
639
+ h = Math.max( h, thumb.outerHeight || $( thumb.container).outerHeight( true ) );
640
+ }
641
+ });
642
+
643
+ self.$( 'thumbnails' ).css({
644
+ width: w,
645
+ height: h
646
+ });
647
+
648
+ carousel.max = w;
649
+ carousel.hooks = hooks;
650
+ carousel.width = self.$( 'thumbnails-list' ).width();
651
+ carousel.setClasses();
652
+
653
+ self.$( 'thumbnails-container' ).toggleClass( 'galleria-carousel', w > carousel.width );
654
+
655
+ // todo: fix so the carousel moves to the left
656
+ },
657
+
658
+ bindControls: function() {
659
+
660
+ carousel.next.bind( CLICK(), function(e) {
661
+ e.preventDefault();
662
+
663
+ if ( self._options.carousel_steps == 'auto' ) {
664
+
665
+ for ( var i = carousel.current; i < carousel.hooks.length; i++ ) {
666
+ if ( carousel.hooks[i] - carousel.hooks[ carousel.current ] > carousel.width ) {
667
+ carousel.set(i - 2);
668
+ break;
669
+ }
670
+ }
671
+
672
+ } else {
673
+ carousel.set( carousel.current + self._options.carousel_steps);
674
+ }
675
+ });
676
+
677
+ carousel.prev.bind( CLICK(), function(e) {
678
+ e.preventDefault();
679
+
680
+ if ( self._options.carousel_steps == 'auto' ) {
681
+
682
+ for ( var i = carousel.current; i >= 0; i-- ) {
683
+ if ( carousel.hooks[ carousel.current ] - carousel.hooks[i] > carousel.width ) {
684
+ carousel.set( i + 2 );
685
+ break;
686
+ } else if ( i == 0 ) {
687
+ carousel.set( 0 );
688
+ break;
689
+ }
690
+ }
691
+ } else {
692
+ carousel.set( carousel.current - self._options.carousel_steps );
693
+ }
694
+ });
695
+ },
696
+
697
+ // calculate and set positions
698
+ set: function( i ) {
699
+ i = Math.max( i, 0 );
700
+ while ( carousel.hooks[i - 1] + carousel.width > carousel.max && i >= 0 ) {
701
+ i--;
702
+ }
703
+ carousel.current = i;
704
+ carousel.animate();
705
+ },
706
+
707
+ // get the last position
708
+ getLast: function(i) {
709
+ return ( i || carousel.current ) - 1;
710
+ },
711
+
712
+ // follow the active image
713
+ follow: function(i) {
714
+
715
+ //don't follow if position fits
716
+ if ( i == 0 || i == carousel.hooks.length - 2 ) {
717
+ carousel.set( i );
718
+ return;
719
+ }
720
+
721
+ // calculate last position
722
+ var last = carousel.current;
723
+ while( carousel.hooks[last] - carousel.hooks[ carousel.current ] <
724
+ carousel.width && last <= carousel.hooks.length ) {
725
+ last ++;
726
+ }
727
+
728
+ // set position
729
+ if ( i - 1 < carousel.current ) {
730
+ carousel.set( i - 1 );
731
+ } else if ( i + 2 > last) {
732
+ carousel.set( i - last + carousel.current + 2 );
733
+ }
734
+ },
735
+
736
+ // helper for setting disabled classes
737
+ setClasses: function() {
738
+ carousel.prev.toggleClass( 'disabled', !carousel.current );
739
+ carousel.next.toggleClass( 'disabled', carousel.hooks[ carousel.current ] + carousel.width > carousel.max );
740
+ },
741
+
742
+ // the animation method
743
+ animate: function(to) {
744
+ carousel.setClasses();
745
+ var num = carousel.hooks[ carousel.current ] * -1;
746
+
747
+ if ( isNaN( num ) ) {
748
+ return;
749
+ }
750
+
751
+ self.$( 'thumbnails' ).animate({
752
+ left: num
753
+ },{
754
+ duration: self._options.carousel_speed,
755
+ easing: self._options.easing,
756
+ queue: false
757
+ });
758
+ }
759
+ };
760
+
761
+ // tooltip control
762
+ // added in 1.2
763
+ var tooltip = this._tooltip = {
764
+
765
+ initialized : false,
766
+
767
+ open: false,
768
+
769
+ init: function() {
770
+
771
+ tooltip.initialized = true;
772
+
773
+ var css = '.galleria-tooltip{padding:3px 8px;max-width:50%;background:#ffe;color:#000;z-index:3;position:absolute;font-size:11px;line-height:1.3' +
774
+ 'opacity:0;box-shadow:0 0 2px rgba(0,0,0,.4);-moz-box-shadow:0 0 2px rgba(0,0,0,.4);-webkit-box-shadow:0 0 2px rgba(0,0,0,.4);}';
775
+
776
+ Utils.insertStyleTag(css);
777
+
778
+ self.$( 'tooltip' ).css('opacity', .8);
779
+ Utils.hide( self.get('tooltip') );
780
+
781
+ },
782
+
783
+ // move handler
784
+ move: function( e ) {
785
+ var mouseX = self.getMousePosition(e).x,
786
+ mouseY = self.getMousePosition(e).y,
787
+ $elem = self.$( 'tooltip' ),
788
+ x = mouseX,
789
+ y = mouseY,
790
+ height = $elem.outerHeight( true ) + 1,
791
+ width = $elem.outerWidth( true ),
792
+ limitY = height + 15;
793
+
794
+ var maxX = self.$( 'container').width() - width - 2,
795
+ maxY = self.$( 'container').height() - height - 2;
796
+
797
+ if ( !isNaN(x) && !isNaN(y) ) {
798
+
799
+ x += 10;
800
+ y -= 30;
801
+
802
+ x = Math.max( 0, Math.min( maxX, x ) );
803
+ y = Math.max( 0, Math.min( maxY, y ) );
804
+
805
+ if( mouseY < limitY ) {
806
+ y = limitY;
807
+ }
808
+
809
+ $elem.css({ left: x, top: y });
810
+ }
811
+ },
812
+
813
+ // bind elements to the tooltip
814
+ // you can bind multiple elementIDs using { elemID : function } or { elemID : string }
815
+ // you can also bind single DOM elements using bind(elem, string)
816
+ bind: function( elem, value ) {
817
+
818
+ if (! tooltip.initialized ) {
819
+ tooltip.init();
820
+ }
821
+
822
+ var hover = function( elem, value) {
823
+
824
+ tooltip.define( elem, value );
825
+
826
+ $( elem ).hover(function() {
827
+
828
+ Utils.clearTimer('switch_tooltip');
829
+ self.$('container').unbind( 'mousemove', tooltip.move ).bind( 'mousemove', tooltip.move ).trigger( 'mousemove' );
830
+ tooltip.show( elem );
831
+
832
+ Galleria.utils.addTimer( 'tooltip', function() {
833
+ self.$( 'tooltip' ).stop();
834
+ Utils.show( self.get( 'tooltip' ), 400 );
835
+ tooltip.open = true;
836
+
837
+ }, tooltip.open ? 0 : 1000);
838
+
839
+ }, function() {
840
+
841
+ self.$( 'container' ).unbind( 'mousemove', tooltip.move );
842
+ Utils.clearTimer( 'tooltip' );
843
+
844
+ self.$( 'tooltip' ).stop();
845
+
846
+ Utils.hide( self.get( 'tooltip' ), 200, function() {
847
+ Utils.addTimer('switch_tooltip', function() {
848
+ tooltip.open = false;
849
+ }, 1000);
850
+ });
851
+ });
852
+ };
853
+
854
+ if (typeof value == 'string') {
855
+ hover( ( elem in self._dom ? self.get(elem) : elem ), value );
856
+ } else {
857
+ // asume elemID here
858
+ $.each( elem, function( elemID, val ) {
859
+ hover( self.get(elemID), val );
860
+ });
861
+ }
862
+ },
863
+
864
+ show: function( elem ) {
865
+
866
+ elem = $( elem in self._dom ? self.get(elem) : elem );
867
+
868
+ var text = elem.data( 'tt' );
869
+
870
+ if ( ! text ) {
871
+ return;
872
+ }
873
+
874
+ text = typeof text == 'function' ? text() : text;
875
+
876
+ self.$( 'tooltip' ).html( text.replace(/\s/, '&nbsp;') );
877
+
878
+ // trigger mousemove on mouseup in case of click
879
+ elem.bind( 'mouseup', function( e ) {
880
+
881
+ // attach a tiny settimeout to make sure the new tooltip is filled
882
+ window.setTimeout( (function( ev ) {
883
+ return function() {
884
+ tooltip.move( ev );
885
+ }
886
+ })( e ), 10);
887
+
888
+ elem.unbind( 'mouseup', arguments.callee );
889
+ });
890
+ },
891
+
892
+ define: function( elem, value ) {
893
+
894
+ // we store functions, not strings
895
+ if (typeof value !== 'function') {
896
+ var s = value;
897
+ value = function() {
898
+ return s;
899
+ };
900
+ }
901
+
902
+ elem = $( elem in self._dom ? self.get(elem) : elem ).data('tt', value);
903
+
904
+ tooltip.show( elem );
905
+
906
+ }
907
+ };
908
+
909
+ // internal fullscreen control
910
+ // added in 1.195
911
+ // still kind of experimental
912
+ var fullscreen = this._fullscreen = {
913
+ scrolled: 0,
914
+ enter: function(callback) {
915
+
916
+ // hide the image until rescale is complete
917
+ Utils.hide( self.getActiveImage() );
918
+
919
+ self.$( 'container' ).addClass( 'fullscreen' );
920
+
921
+ fullscreen.scrolled = $(window).scrollTop();
922
+
923
+ // begin styleforce
924
+ Utils.forceStyles(self.get('container'), {
925
+ position: 'fixed',
926
+ top: 140,
927
+ left: 0,
928
+ width: '100%',
929
+ //height: '90%',
930
+ bottom: 0,
931
+ zIndex: 10000
932
+ });
933
+
934
+ var htmlbody = {
935
+ height: '100%',
936
+ overflow: 'hidden',
937
+ margin:0,
938
+ padding:0
939
+ };
940
+
941
+ Utils.forceStyles( DOM().html, htmlbody );
942
+ Utils.forceStyles( DOM().body, htmlbody );
943
+
944
+ // attach some keys
945
+ self.attachKeyboard({
946
+ escape: self.exitFullscreen,
947
+ right: self.next,
948
+ left: self.prev
949
+ });
950
+
951
+ // init the first rescale and attach callbacks
952
+ self.rescale(function() {
953
+
954
+ Utils.addTimer('fullscreen_enter', function() {
955
+ // show the image after 50 ms
956
+ Utils.show( self.getActiveImage() );
957
+
958
+ if (typeof callback == 'function') {
959
+ callback.call( self );
960
+ }
961
+
962
+ }, 100);
963
+
964
+ self.trigger( Galleria.FULLSCREEN_ENTER );
965
+ });
966
+
967
+ // bind the scaling to the resize event
968
+ $(window).resize( function() {
969
+ fullscreen.scale();
970
+ } );
971
+ },
972
+
973
+ scale : function() {
974
+ self.rescale();
975
+ },
976
+
977
+ exit: function(callback) {
978
+
979
+ Utils.hide( self.getActiveImage() );
980
+
981
+ self.$('container').removeClass( 'fullscreen' );
982
+
983
+ // revert all styles
984
+ Utils.revertStyles( self.get('container'), DOM().html, DOM().body );
985
+
986
+ // scroll back
987
+ window.scrollTo(0, fullscreen.scrolled);
988
+
989
+ // detach all keyboard events (is this good?)
990
+ self.detachKeyboard();
991
+
992
+ self.rescale(function() {
993
+ Utils.addTimer('fullscreen_exit', function() {
994
+
995
+ // show the image after 50 ms
996
+ Utils.show( self.getActiveImage() );
997
+
998
+ if ( typeof callback == 'function' ) {
999
+ callback.call( self );
1000
+ }
1001
+
1002
+ }, 50);
1003
+
1004
+ self.trigger( Galleria.FULLSCREEN_EXIT );
1005
+ });
1006
+
1007
+ $(window).unbind('resize', fullscreen.scale);
1008
+ }
1009
+ };
1010
+
1011
+ // the internal idle object for controlling idle states
1012
+ // TODO occational event conflicts
1013
+ var idle = this._idle = {
1014
+
1015
+ trunk: [],
1016
+
1017
+ bound: false,
1018
+
1019
+ add: function(elem, to) {
1020
+ if (!elem) {
1021
+ return;
1022
+ }
1023
+ if (!idle.bound) {
1024
+ idle.addEvent();
1025
+ }
1026
+ elem = $(elem);
1027
+
1028
+ var from = {};
1029
+
1030
+ for (var style in to) {
1031
+ from[style] = elem.css(style);
1032
+ }
1033
+ elem.data('idle', {
1034
+ from: from,
1035
+ to: to,
1036
+ complete: true,
1037
+ busy: false
1038
+ });
1039
+ idle.addTimer();
1040
+ idle.trunk.push(elem);
1041
+ },
1042
+
1043
+ remove: function(elem) {
1044
+
1045
+ elem = jQuery(elem);
1046
+
1047
+ $.each(idle.trunk, function(i, el) {
1048
+ if ( el.length && !el.not(elem).length ) {
1049
+ self._idle.show(elem);
1050
+ self._idle.trunk.splice(i, 1);
1051
+ }
1052
+ });
1053
+
1054
+ if (!idle.trunk.length) {
1055
+ idle.removeEvent();
1056
+ Utils.clearTimer('idle');
1057
+ }
1058
+ },
1059
+
1060
+ addEvent : function() {
1061
+ idle.bound = true;
1062
+ self.$('container').bind('mousemove click', idle.showAll );
1063
+ },
1064
+
1065
+ removeEvent : function() {
1066
+ idle.bound = false;
1067
+ self.$('container').unbind('mousemove click', idle.showAll );
1068
+ },
1069
+
1070
+ addTimer : function() {
1071
+ Utils.addTimer('idle', function() {
1072
+ self._idle.hide();
1073
+ }, self._options.idle_time );
1074
+ },
1075
+
1076
+ hide : function() {
1077
+
1078
+ self.trigger( Galleria.IDLE_ENTER );
1079
+
1080
+ $.each( idle.trunk, function(i, elem) {
1081
+
1082
+ var data = elem.data('idle');
1083
+
1084
+ if (! data) {
1085
+ return;
1086
+ }
1087
+
1088
+ elem.data('idle').complete = false;
1089
+
1090
+ elem.stop().animate(data.to, {
1091
+ duration: 600,
1092
+ queue: false,
1093
+ easing: 'swing'
1094
+ });
1095
+ });
1096
+ },
1097
+
1098
+ showAll : function() {
1099
+
1100
+ Utils.clearTimer('idle');
1101
+
1102
+ $.each(self._idle.trunk, function( i, elem ) {
1103
+ self._idle.show( elem );
1104
+ });
1105
+ },
1106
+
1107
+ show: function(elem) {
1108
+
1109
+ var data = elem.data('idle');
1110
+
1111
+ if (!data.busy && !data.complete) {
1112
+
1113
+ data.busy = true;
1114
+
1115
+ self.trigger( Galleria.IDLE_EXIT );
1116
+
1117
+ Utils.clearTimer( 'idle' );
1118
+
1119
+ elem.stop().animate(data.from, {
1120
+ duration: 300,
1121
+ queue: false,
1122
+ easing: 'swing',
1123
+ complete: function() {
1124
+ $(this).data('idle').busy = false;
1125
+ $(this).data('idle').complete = true;
1126
+ }
1127
+ });
1128
+ }
1129
+ idle.addTimer();
1130
+ }
1131
+ };
1132
+
1133
+ // internal lightbox object
1134
+ // creates a predesigned lightbox for simple popups of images in galleria
1135
+ var lightbox = this._lightbox = {
1136
+
1137
+ width : 0,
1138
+
1139
+ height : 0,
1140
+
1141
+ initialized : false,
1142
+
1143
+ active : null,
1144
+
1145
+ image : null,
1146
+
1147
+ elems : {},
1148
+
1149
+ init : function() {
1150
+
1151
+ // trigger the event
1152
+ self.trigger( Galleria.LIGHTBOX_OPEN );
1153
+
1154
+ if ( lightbox.initialized ) {
1155
+ return;
1156
+ }
1157
+ lightbox.initialized = true;
1158
+
1159
+ // create some elements to work with
1160
+ var elems = 'overlay box content shadow title info close prevholder prev nextholder next counter image',
1161
+ el = {},
1162
+ op = self._options,
1163
+ css = '',
1164
+ cssMap = {
1165
+ overlay: 'position:fixed;display:none;opacity:'+op.overlay_opacity+';top:0;left:0;width:100%;height:100%;background:'+op.overlay_background+';z-index:99990',
1166
+ box: 'position:fixed;display:none;width:400px;height:400px;top:50%;left:50%;margin-top:-200px;margin-left:-200px;z-index:99991',
1167
+ shadow: 'position:absolute;background:#000;width:100%;height:100%;',
1168
+ content: 'position:absolute;background-color:#fff;top:10px;left:10px;right:10px;bottom:10px;overflow:hidden',
1169
+ info: 'position:absolute;bottom:10px;left:10px;right:10px;color:#444;font:11px/13px arial,sans-serif;height:13px',
1170
+ close: 'position:absolute;top:10px;right:10px;height:20px;width:20px;background:#fff;text-align:center;cursor:pointer;color:#444;font:16px/22px arial,sans-serif;z-index:99999',
1171
+ image: 'position:absolute;top:10px;left:10px;right:10px;bottom:30px;overflow:hidden',
1172
+ prevholder: 'position:absolute;width:50%;height:100%;cursor:pointer',
1173
+ nextholder: 'position:absolute;width:50%;height:100%;right:0;cursor:pointer',
1174
+ prev: 'position:absolute;top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;left:20px;display:none;line-height:40px;text-align:center;color:#000',
1175
+ next: 'position:absolute;top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;right:20px;left:auto;display:none;line-height:40px;text-align:center;color:#000',
1176
+ title: 'float:left',
1177
+ counter: 'float:right;margin-left:8px'
1178
+ },
1179
+ hover = function(elem) {
1180
+ return elem.hover(
1181
+ function() { $(this).css( 'color', '#bbb' ); },
1182
+ function() { $(this).css( 'color', '#444' ); }
1183
+ );
1184
+ };
1185
+
1186
+ // create and insert CSS
1187
+ $.each(cssMap, function( key, value ) {
1188
+ css += '.galleria-lightbox-'+key+'{'+value+'}';
1189
+ });
1190
+
1191
+ Utils.insertStyleTag( css );
1192
+
1193
+ // create the elements
1194
+ $.each(elems.split(' '), function( i, elemId ) {
1195
+ self.addElement( 'lightbox-' + elemId );
1196
+ el[ elemId ] = lightbox.elems[ elemId ] = self.get( 'lightbox-' + elemId );
1197
+ });
1198
+
1199
+ // initiate the image
1200
+ lightbox.image = new Galleria.Picture();
1201
+
1202
+ // append the elements
1203
+ self.append({
1204
+ 'lightbox-box': ['lightbox-shadow','lightbox-content', 'lightbox-close','lightbox-prevholder','lightbox-nextholder'],
1205
+ 'lightbox-info': ['lightbox-title','lightbox-counter'],
1206
+ 'lightbox-content': ['lightbox-info', 'lightbox-image'],
1207
+ 'lightbox-prevholder': 'lightbox-prev',
1208
+ 'lightbox-nextholder': 'lightbox-next'
1209
+ });
1210
+
1211
+ $( el.image ).append( lightbox.image.container );
1212
+
1213
+ $( DOM().body ).append( el.overlay, el.box );
1214
+
1215
+ // add the prev/next nav and bind some controls
1216
+
1217
+ hover( $( el.close ).bind( CLICK(), lightbox.hide ).html('&#215;') );
1218
+
1219
+ $.each( ['Prev','Next'], function(i, dir) {
1220
+
1221
+ var $d = $( el[ dir.toLowerCase() ] ).html( /v/.test( dir ) ? '‹&nbsp;' : '&nbsp;›' );
1222
+
1223
+ $( el[ dir.toLowerCase()+'holder'] ).hover(function() {
1224
+ $d.show();
1225
+ }, function() {
1226
+ $d.fadeOut( 200 );
1227
+ }).bind( CLICK(), function() {
1228
+ lightbox[ 'show' + dir ]();
1229
+ });
1230
+
1231
+ });
1232
+ $( el.overlay ).bind( CLICK(), lightbox.hide );
1233
+
1234
+ },
1235
+
1236
+ rescale: function(event) {
1237
+
1238
+ // calculate
1239
+ var width = Math.min( $(window).width()-40, lightbox.width ),
1240
+ height = Math.min( $(window).height()-60, lightbox.height ),
1241
+ ratio = Math.min( width / lightbox.width, height / lightbox.height ),
1242
+ destWidth = ( lightbox.width * ratio ) + 40,
1243
+ destHeight = ( lightbox.height * ratio ) + 60,
1244
+ to = {
1245
+ width: destWidth,
1246
+ height: destHeight,
1247
+ marginTop: Math.ceil( destHeight / 2 ) *- 1,
1248
+ marginLeft: Math.ceil( destWidth / 2 ) *- 1
1249
+ };
1250
+
1251
+ // if rescale event, don't animate
1252
+ if ( event ) {
1253
+ $( lightbox.elems.box ).css( to );
1254
+ } else {
1255
+ $( lightbox.elems.box ).animate(
1256
+ to,
1257
+ self._options.lightbox_transition_speed,
1258
+ self._options.easing,
1259
+ function() {
1260
+ var image = lightbox.image,
1261
+ speed = self._options.lightbox_fade_speed;
1262
+
1263
+ self.trigger({
1264
+ type: Galleria.LIGHTBOX_IMAGE,
1265
+ imageTarget: image.image
1266
+ });
1267
+
1268
+ image.show();
1269
+ Utils.show( image.image, speed );
1270
+ Utils.show( lightbox.elems.info, speed );
1271
+ }
1272
+ );
1273
+ }
1274
+ },
1275
+
1276
+ hide: function() {
1277
+
1278
+ // remove the image
1279
+ lightbox.image.image = null;
1280
+
1281
+ $(window).unbind('resize', lightbox.rescale);
1282
+
1283
+ $( lightbox.elems.box ).hide();
1284
+
1285
+ Utils.hide( lightbox.elems.info );
1286
+
1287
+ Utils.hide( lightbox.elems.overlay, 200, function() {
1288
+ $( this ).hide().css( 'opacity', self._options.overlay_opacity );
1289
+ self.trigger( Galleria.LIGHTBOX_CLOSE );
1290
+ });
1291
+ },
1292
+
1293
+ showNext: function() {
1294
+ lightbox.show( self.getNext( lightbox.active ) );
1295
+ },
1296
+
1297
+ showPrev: function() {
1298
+ lightbox.show( self.getPrev( lightbox.active ) );
1299
+ },
1300
+
1301
+ show: function(index) {
1302
+
1303
+ lightbox.active = index = typeof index == 'number' ? index : self.getIndex();
1304
+
1305
+ if ( !lightbox.initialized ) {
1306
+ lightbox.init();
1307
+ }
1308
+
1309
+ $(window).unbind('resize', lightbox.rescale );
1310
+
1311
+ var data = self.getData(index),
1312
+ total = self.getDataLength();
1313
+
1314
+ Utils.hide( lightbox.elems.info );
1315
+
1316
+ lightbox.image.load( data.image, function( image ) {
1317
+
1318
+ lightbox.width = image.original.width;
1319
+ lightbox.height = image.original.height;
1320
+
1321
+ $( image.image ).css({
1322
+ width: '100.5%',
1323
+ height: '100.5%',
1324
+ top: 0,
1325
+ zIndex: 99998,
1326
+ opacity: 0
1327
+ });
1328
+
1329
+ lightbox.elems.title.innerHTML = data.title;
1330
+ lightbox.elems.counter.innerHTML = (index + 1) + ' / ' + total;
1331
+ $(window).resize( lightbox.rescale );
1332
+ lightbox.rescale();
1333
+ });
1334
+
1335
+ $( lightbox.elems.overlay ).show();
1336
+ $( lightbox.elems.box ).show();
1337
+ }
1338
+ };
1339
+
1340
+ return this;
1341
+ };
1342
+
1343
+ // end Galleria constructor
1344
+
1345
+ Galleria.prototype = {
1346
+
1347
+ // bring back the constructor reference
1348
+
1349
+ constructor: Galleria,
1350
+
1351
+ /**
1352
+ Use this function to initialize the gallery and start loading.
1353
+ Should only be called once per instance.
1354
+
1355
+ @param {HTML Element} target The target element
1356
+ @param {Object} options The gallery options
1357
+
1358
+ @returns {Galleria}
1359
+ */
1360
+
1361
+ init: function( target, options ) {
1362
+
1363
+ var self = this;
1364
+
1365
+ // save the instance
1366
+ _galleries.push( this );
1367
+
1368
+ // save the original ingredients
1369
+ this._original = {
1370
+ target: target,
1371
+ options: options,
1372
+ data: null
1373
+ };
1374
+
1375
+ // save the target here
1376
+ this._target = this._dom.target = target.nodeName ? target : $( target ).get(0);
1377
+
1378
+ // raise error if no target is detected
1379
+ if ( !this._target ) {
1380
+ Galleria.raise('Target not found.');
1381
+ return;
1382
+ }
1383
+
1384
+ // apply options
1385
+ this._options = {
1386
+ autoplay: false,
1387
+ carousel: true,
1388
+ carousel_follow: true,
1389
+ carousel_speed: 400,
1390
+ carousel_steps: 'auto',
1391
+ clicknext: false,
1392
+ data_config : function( elem ) { return {}; },
1393
+ data_selector: 'img',
1394
+ data_source: this._target,
1395
+ debug: undef,
1396
+ easing: 'galleria',
1397
+ extend: function(options) {},
1398
+ height: 'auto',
1399
+ idle_time: 3000,
1400
+ image_crop: false,
1401
+ image_margin: 0,
1402
+ image_pan: false,
1403
+ image_pan_smoothness: 12,
1404
+ image_position: '50%',
1405
+ keep_source: false,
1406
+ lightbox_fade_speed: 200,
1407
+ lightbox_transition_speed: 500,
1408
+ link_source_images: true,
1409
+ max_scale_ratio: undef,
1410
+ min_scale_ratio: undef,
1411
+ on_image: function(img,thumb) {},
1412
+ overlay_opacity: .85,
1413
+ overlay_background: '#0b0b0b',
1414
+ pause_on_interaction: true, // 1.9.96
1415
+ popup_links: false,
1416
+ preload: 2,
1417
+ queue: true,
1418
+ show: 0,
1419
+ show_info: true,
1420
+ show_counter: true,
1421
+ show_imagenav: true,
1422
+ thumb_crop: true,
1423
+ thumb_event_type: CLICK(),
1424
+ thumb_fit: true,
1425
+ thumb_margin: 0,
1426
+ thumb_quality: 'auto',
1427
+ thumbnails: true,
1428
+ transition: 'fade',
1429
+ transition_initial: undef,
1430
+ transition_speed: 400,
1431
+ width: 'auto'
1432
+ };
1433
+
1434
+ // apply debug
1435
+ if ( options && options.debug === true ) {
1436
+ DEBUG = true;
1437
+ }
1438
+
1439
+ // hide all content
1440
+ $( this._target ).children().hide();
1441
+
1442
+ // now we just have to wait for the theme...
1443
+ if ( Galleria.theme ) {
1444
+ this._init();
1445
+ } else {
1446
+ Utils.addTimer('themeload', function() {
1447
+ Galleria.raise( 'No theme found.', true);
1448
+ }, 2000);
1449
+
1450
+ $doc.one( Galleria.THEMELOAD, function() {
1451
+ Utils.clearTimer( 'themeload' );
1452
+ self._init.call( self );
1453
+ });
1454
+ }
1455
+ },
1456
+
1457
+ // the internal _init is called when the THEMELOAD event is triggered
1458
+ // this method should only be called once per instance
1459
+ // for manipulation of data, use the .load method
1460
+
1461
+ _init: function() {
1462
+ var self = this;
1463
+
1464
+ if ( this._initialized ) {
1465
+ Galleria.raise( 'Init failed: Gallery instance already initialized.' );
1466
+ return this;
1467
+ }
1468
+
1469
+ this._initialized = true;
1470
+
1471
+ if ( !Galleria.theme ) {
1472
+ Galleria.raise( 'Init failed: No theme found.' );
1473
+ return this;
1474
+ }
1475
+
1476
+ // merge the theme & caller options
1477
+ $.extend( true, this._options, Galleria.theme.defaults, this._original.options );
1478
+
1479
+ // bind the gallery to run when data is ready
1480
+ this.bind( Galleria.DATA, function() {
1481
+
1482
+ // save the new data
1483
+ this._original.data = this._data;
1484
+
1485
+ // lets show the counter here
1486
+ this.get('total').innerHTML = this.getDataLength();
1487
+
1488
+ // cache the container
1489
+ var $container = this.$( 'container' );
1490
+
1491
+ // the gallery is ready, let's just wait for the css
1492
+ var num = { width: 0, height: 0 };
1493
+ var testElem = Utils.create('galleria-image');
1494
+
1495
+ // check container and thumbnail height
1496
+ Utils.wait({
1497
+ until: function() {
1498
+
1499
+ // keep trying to get the value
1500
+ $.each(['width', 'height'], function( i, m ) {
1501
+
1502
+ // first check if options is set
1503
+
1504
+ if (self._options[ m ] && typeof self._options[ m ] == 'number') {
1505
+ num[ m ] = self._options[ m ];
1506
+ } else {
1507
+
1508
+ // else extract the meassures in the following order:
1509
+
1510
+ num[m] = Utils.parseValue( $container.css( m ) ) || // 1. the container css
1511
+ Utils.parseValue( self.$( 'target' ).css( m ) ) || // 2. the target css
1512
+ $container[ m ]() || // 3. the container jQuery method
1513
+ self.$( 'target' )[ m ](); // 4. the container jQuery method
1514
+ }
1515
+
1516
+ });
1517
+
1518
+ var thumbHeight = function() {
1519
+ return true;
1520
+ };
1521
+
1522
+ // make sure thumbnails have a height as well
1523
+ if ( self._options.thumbnails ) {
1524
+ self.$('thumbnails').append( testElem );
1525
+ thumbHeight = function() {
1526
+ return !!$( testElem ).height();
1527
+ };
1528
+ }
1529
+
1530
+ return thumbHeight() && num.width && num.height > 50;
1531
+
1532
+ },
1533
+ success: function() {
1534
+
1535
+ // remove the testElem
1536
+ $( testElem ).remove();
1537
+
1538
+ // apply the new meassures
1539
+ $container.width( num.width );
1540
+ $container.height( num.height );
1541
+
1542
+ // for some strange reason, webkit needs a single setTimeout to play ball
1543
+ if ( Galleria.WEBKIT ) {
1544
+ window.setTimeout( function() {
1545
+ self._run();
1546
+ }, 1);
1547
+ } else {
1548
+ self._run();
1549
+ }
1550
+ },
1551
+ error: function() {
1552
+ // Height was probably not set, raise a hard error
1553
+ Galleria.raise('Width & Height not found.', true);
1554
+ },
1555
+ timeout: 2000
1556
+ });
1557
+ });
1558
+
1559
+ // postrun some stuff after the gallery is ready
1560
+ // make sure it only runs once
1561
+ var one = false;
1562
+
1563
+ this.bind( Galleria.READY, function() {
1564
+
1565
+ // show counter
1566
+ Utils.show( this.get('counter') );
1567
+
1568
+ // bind clicknext
1569
+ if ( this._options.clicknext ) {
1570
+ $.each( this._data, function( i, data ) {
1571
+ delete data.link;
1572
+ });
1573
+ this.$( 'stage' ).css({ cursor : 'pointer' }).bind( CLICK(), function(e) {
1574
+ self.next();
1575
+ });
1576
+ }
1577
+
1578
+ // bind carousel nav
1579
+ if ( this._options.carousel ) {
1580
+ this._carousel.bindControls();
1581
+ }
1582
+
1583
+ // start autoplay
1584
+ if ( this._options.autoplay ) {
1585
+
1586
+ this.pause();
1587
+
1588
+ if ( typeof this._options.autoplay == 'number' ) {
1589
+ this._playtime = this._options.autoplay;
1590
+ }
1591
+
1592
+ this.trigger( Galleria.PLAY );
1593
+ this._playing = true;
1594
+ }
1595
+
1596
+ // if second load, just do the show and return
1597
+ if ( one ) {
1598
+ if ( typeof this._options.show == 'number' ) {
1599
+ this.show( this._options.show );
1600
+ }
1601
+ return;
1602
+ }
1603
+
1604
+ one = true;
1605
+
1606
+ // initialize the History plugin
1607
+ if ( Galleria.History ) {
1608
+
1609
+ // bind the show method
1610
+ Galleria.History.change(function(e) {
1611
+
1612
+ // grab history ID
1613
+ var val = parseInt( e.value.replace( /\//, '' ) );
1614
+
1615
+ // if ID is NaN, the user pressed back from the first image
1616
+ // return to previous address
1617
+ if (isNaN(val)) {
1618
+ window.history.go(-1);
1619
+
1620
+ // else show the image
1621
+ } else {
1622
+ self.show( val, undef, true );
1623
+ }
1624
+ });
1625
+ }
1626
+
1627
+ // call the theme init method
1628
+ Galleria.theme.init.call( this, this._options );
1629
+
1630
+ // call the extend option
1631
+ this._options.extend.call( this, this._options );
1632
+
1633
+ // show the initial image
1634
+ // first test for permalinks in history
1635
+ if ( /^[0-9]{1,4}$/.test( HASH ) && Galleria.History ) {
1636
+ this.show( HASH, undef, true );
1637
+
1638
+ } else {
1639
+ this.show( this._options.show );
1640
+ }
1641
+
1642
+ });
1643
+
1644
+ // build the gallery frame
1645
+ this.append({
1646
+ 'info-text' :
1647
+ ['info-title', 'info-description', 'info-author'],
1648
+ 'info' :
1649
+ ['info-text'],
1650
+ 'image-nav' :
1651
+ ['image-nav-right', 'image-nav-left'],
1652
+ 'stage' :
1653
+ ['images', 'loader', 'counter', 'image-nav'],
1654
+ 'thumbnails-list' :
1655
+ ['thumbnails'],
1656
+ 'thumbnails-container' :
1657
+ ['thumb-nav-left', 'thumbnails-list', 'thumb-nav-right'],
1658
+ 'container' :
1659
+ ['stage', 'thumbnails-container', 'info', 'tooltip']
1660
+ });
1661
+
1662
+ Utils.hide( this.$( 'counter' ).append(
1663
+ this.get( 'current' ),
1664
+ ' / ',
1665
+ this.get( 'total' )
1666
+ ) );
1667
+
1668
+ this.setCounter('&#8211;');
1669
+
1670
+ // add images to the controls
1671
+ $.each( new Array(2), function(i) {
1672
+
1673
+ // create a new Picture instance
1674
+ var image = new Galleria.Picture();
1675
+
1676
+ // apply some styles
1677
+ $( image.container ).css({
1678
+ position: 'absolute',
1679
+ top: 0,
1680
+ left: 0
1681
+ });
1682
+
1683
+ // append the image
1684
+ self.$( 'images' ).append( image.container );
1685
+
1686
+ // reload the controls
1687
+ self._controls[i] = image;
1688
+
1689
+ });
1690
+
1691
+ // some forced generic styling
1692
+ this.$( 'images' ).css({
1693
+ position: 'relative',
1694
+ top: 0,
1695
+ left: 0,
1696
+ width: '100%',
1697
+ height: '100%'
1698
+ });
1699
+
1700
+ this.$( 'thumbnails, thumbnails-list' ).css({
1701
+ overflow: 'hidden',
1702
+ position: 'relative'
1703
+ });
1704
+
1705
+ // bind image navigation arrows
1706
+ this.$( 'image-nav-right, image-nav-left' ).bind( CLICK(), function(e) {
1707
+
1708
+ // tune the clicknext option
1709
+ if ( self._options.clicknext ) {
1710
+ e.stopPropagation();
1711
+ }
1712
+
1713
+ // pause if options is set
1714
+ if ( self._options.pause_on_interaction ) {
1715
+ self.pause();
1716
+ }
1717
+
1718
+ // navigate
1719
+ var fn = /right/.test( this.className ) ? 'next' : 'prev';
1720
+ self[ fn ]();
1721
+
1722
+ });
1723
+
1724
+ // hide controls if chosen to
1725
+ $.each( ['info','counter','image-nav'], function( i, el ) {
1726
+ if ( self._options[ 'show_' + el.replace(/-/, '') ] === false ) {
1727
+ Utils.moveOut( self.get( el ) );
1728
+ }
1729
+ });
1730
+
1731
+ // load up target content
1732
+ this.load();
1733
+
1734
+ // now it's usually safe to remove the content
1735
+ // IE will never stop loading if we remove it, so let's keep it hidden for IE (it's usually fast enough anyway)
1736
+ if ( !this._options.keep_source && !IE ) {
1737
+ this._target.innerHTML = '';
1738
+ }
1739
+
1740
+ // append the gallery frame
1741
+ this.$( 'target' ).append( this.get( 'container' ) );
1742
+
1743
+ // parse the carousel on each thumb load
1744
+ if ( this._options.carousel ) {
1745
+ this.bind( Galleria.THUMBNAIL, function() {
1746
+ this.updateCarousel();
1747
+ });
1748
+ }
1749
+
1750
+ // bind on_image helper
1751
+ this.bind( Galleria.IMAGE, function( e ) {
1752
+ this._options.on_image.call( this, e.imageTarget, e.thumbTarget );
1753
+ });
1754
+
1755
+ return this;
1756
+ },
1757
+
1758
+ // the internal _run method should be called after loading data into galleria
1759
+ // creates thumbnails and makes sure the gallery has proper meassurements
1760
+ _run : function() {
1761
+ // shortcuts
1762
+ var self = this,
1763
+ o = this._options,
1764
+
1765
+ // width/height for calculations
1766
+ width = 0,
1767
+ height = 0,
1768
+
1769
+ // cache the thumbnail option
1770
+ optval = typeof o.thumbnails == 'string' ? o.thumbnails.toLowerCase() : null;
1771
+
1772
+ // loop through data and create thumbnails
1773
+ for( var i = 0; this._data[i]; i++ ) {
1774
+
1775
+ var thumb,
1776
+ data = this._data[i],
1777
+ $container;
1778
+
1779
+ if ( o.thumbnails === true ) {
1780
+
1781
+ // add a new Picture instance
1782
+ thumb = new Galleria.Picture(i);
1783
+
1784
+ // get source from thumb or image
1785
+ var src = data.thumb || data.image;
1786
+
1787
+ // append the thumbnail
1788
+ this.$( 'thumbnails' ).append( thumb.container );
1789
+
1790
+ // cache the container
1791
+ $container = $( thumb.container );
1792
+
1793
+ // move some data into the instance
1794
+ // for some reason, jQuery cant handle css(property) when zooming in FF, breaking the gallery
1795
+ // so we resort to getComputedStyle for browsers who support it
1796
+ var getStyle = function( prop ) {
1797
+ return doc.defaultView && doc.defaultView.getComputedStyle ?
1798
+ doc.defaultView.getComputedStyle( thumb.container, null )[ prop ] :
1799
+ $container.css( prop );
1800
+ };
1801
+
1802
+ thumb.data = {
1803
+ width : Utils.parseValue( getStyle( 'width' ) ),
1804
+ height : Utils.parseValue( getStyle( 'height' ) ),
1805
+ order : i
1806
+ };
1807
+
1808
+ // grab & reset size for smoother thumbnail loads
1809
+ $container.css(( o.thumb_fit && o.thumb_crop !== true ) ?
1810
+ { width: 0, height: 0 } :
1811
+ { width: thumb.data.width, height: thumb.data.height });
1812
+
1813
+ // load the thumbnail
1814
+ thumb.load( src, function( thumb ) {
1815
+
1816
+ // scale when ready
1817
+ thumb.scale({
1818
+ width: thumb.data.width,
1819
+ height: thumb.data.height,
1820
+ crop: o.thumb_crop,
1821
+ margin: o.thumb_margin,
1822
+ complete: function( thumb ) {
1823
+
1824
+ // shrink thumbnails to fit
1825
+ var top = ['left', 'top'];
1826
+ var arr = ['Width', 'Height'];
1827
+
1828
+ // calculate shrinked positions
1829
+ $.each(arr, function( i, meassure ) {
1830
+ var m = meassure.toLowerCase();
1831
+ if ( (o.thumb_crop !== true || o.thumb_crop == m ) && o.thumb_fit ) {
1832
+ var css = {};
1833
+ css[m] = thumb[m];
1834
+ $( thumb.container ).css( css );
1835
+ css = {};
1836
+ css[top[i]] = 0;
1837
+ $( thumb.image ).css( css);
1838
+ }
1839
+
1840
+ // cache outer meassures
1841
+ thumb['outer' + meassure] = $( thumb.container )['outer' + meassure]( true );
1842
+ });
1843
+
1844
+ // set high quality if downscale is moderate
1845
+ Utils.toggleQuality( thumb.image,
1846
+ o.thumb_quality === true ||
1847
+ ( o.thumb_quality == 'auto' && thumb.original.width < thumb.width * 3 )
1848
+ );
1849
+
1850
+ // trigger the THUMBNAIL event
1851
+ self.trigger({
1852
+ type: Galleria.THUMBNAIL,
1853
+ thumbTarget: thumb.image,
1854
+ index: thumb.data.order
1855
+ });
1856
+ }
1857
+ });
1858
+ });
1859
+
1860
+ // preload all images here
1861
+ if ( o.preload == 'all' ) {
1862
+ thumb.add( data.image );
1863
+ }
1864
+
1865
+ // create empty spans if thumbnails is set to 'empty'
1866
+ } else if ( optval == 'empty' || optval == 'numbers' ) {
1867
+
1868
+ thumb = {
1869
+ container: Utils.create( 'galleria-image' ),
1870
+ image: Utils.create( 'img', 'span' ),
1871
+ ready: true
1872
+ };
1873
+
1874
+ // create numbered thumbnails
1875
+ if ( optval == 'numbers' ) {
1876
+ $( thumb.image ).text( i + 1 );
1877
+ }
1878
+
1879
+ this.$( 'thumbnails' ).append( thumb.container );
1880
+
1881
+ // we need to "fake" a loading delay before we append and trigger
1882
+ // 50+ should be enough
1883
+
1884
+ window.setTimeout((function(image, index, container) {
1885
+ return function() {
1886
+ $( container ).append( image );
1887
+ self.trigger({
1888
+ type: Galleria.THUMBNAIL,
1889
+ thumbTarget: image,
1890
+ index: index
1891
+ });
1892
+ }
1893
+ })( thumb.image, i, thumb.container ), 50 + (i*20) );
1894
+
1895
+
1896
+ // create null object to silent errors
1897
+ } else {
1898
+ thumb = {
1899
+ container: null,
1900
+ image: null
1901
+ };
1902
+ }
1903
+
1904
+ // add events for thumbnails
1905
+ // you can control the event type using thumb_event_type
1906
+ // we'll add the same event to the source if it's kept
1907
+
1908
+ $( thumb.container ).add( o.keep_source && o.link_source_images ? data.original : null )
1909
+ .data('index', i).bind(o.thumb_event_type, function(e) {
1910
+ // pause if option is set
1911
+ if ( o.pause_on_interaction ) {
1912
+ self.pause();
1913
+ }
1914
+
1915
+ // extract the index from the data
1916
+ var index = $( e.currentTarget ).data( 'index' );
1917
+ if ( self.getIndex() !== index ) {
1918
+ self.show( index );
1919
+ }
1920
+
1921
+ e.preventDefault();
1922
+ });
1923
+
1924
+ this._thumbnails.push( thumb );
1925
+ }
1926
+
1927
+ // make sure we have a stageHeight && stageWidth
1928
+
1929
+ Utils.wait({
1930
+
1931
+ until: function() {
1932
+ self._stageWidth = self.$( 'stage' ).width();
1933
+ self._stageHeight = self.$( 'stage' ).height();
1934
+ return( self._stageWidth &&
1935
+ self._stageHeight > 50 ); // what is an acceptable height?
1936
+ },
1937
+
1938
+ success: function() {
1939
+ self.trigger( Galleria.READY );
1940
+ },
1941
+
1942
+ error: function() {
1943
+ Galleria.raise('stage meassures not found');
1944
+ }
1945
+
1946
+ });
1947
+ },
1948
+
1949
+ /**
1950
+ Loads data into the gallery.
1951
+ You can call this method on an existing gallery to reload the gallery with new data.
1952
+
1953
+ @param {Array or String} source Optional JSON array of data or selector of where to find data in the document.
1954
+ Defaults to the Galleria target or data_source option.
1955
+
1956
+ @param {String} selector Optional element selector of what elements to parse.
1957
+ Defaults to 'img'.
1958
+
1959
+ @param {Function} config Optional function to modify the data extraction proceedure from the selector.
1960
+ See the data_config option for more information.
1961
+
1962
+ @returns {Galleria}
1963
+ */
1964
+
1965
+ load : function( source, selector, config ) {
1966
+
1967
+ var self = this;
1968
+
1969
+ // empty the data array
1970
+ this._data = [];
1971
+
1972
+ // empty the thumbnails
1973
+ this._thumbnails = [];
1974
+ this.$('thumbnails').empty();
1975
+
1976
+ // shorten the arguments
1977
+ if ( typeof selector == 'function' ) {
1978
+ config = selector;
1979
+ selector = null;
1980
+ }
1981
+
1982
+ // use the source set by target
1983
+ source = source || this._options.data_source;
1984
+
1985
+ // use selector set by option
1986
+ selector = selector || this._options.data_selector;
1987
+
1988
+ // use the data_config set by option
1989
+ config = config || this._options.data_config;
1990
+
1991
+ // check if the data is an array already
1992
+ if ( source.constructor == Array ) {
1993
+ if ( this.validate( source) ) {
1994
+ this._data = source;
1995
+ this.trigger( Galleria.DATA );
1996
+ } else {
1997
+ Galleria.raise( 'Load failed: JSON Array not valid.' );
1998
+ }
1999
+ return this;
2000
+ }
2001
+ // loop through images and set data
2002
+ $( source ).find( selector ).each( function( i, img ) {
2003
+ var data = {},
2004
+ img = $( img ),
2005
+ parent = img.parent(),
2006
+ href = parent.attr( 'href' );
2007
+
2008
+ // check if it's a link to another image
2009
+ if ( /\.(png|gif|jpg|jpeg)$/i.test(href) ) {
2010
+ data.image = href;
2011
+
2012
+ // else assign the href as a link if it exists
2013
+ } else if ( href ) {
2014
+ data.link = href;
2015
+ }
2016
+
2017
+ // mix default extractions with the hrefs and config
2018
+ // and push it into the data array
2019
+ self._data.push( $.extend({
2020
+
2021
+ title: img.attr('title'),
2022
+ thumb: img.attr('src'),
2023
+ image: img.attr('src'),
2024
+ description: img.attr('alt'),
2025
+ link: img.attr('longdesc'),
2026
+ original: img.get(0) // saved as a reference
2027
+
2028
+ }, data, config( img ) ) );
2029
+
2030
+ });
2031
+ // trigger the DATA event and return
2032
+ if ( this.getDataLength() ) {
2033
+ this.trigger( Galleria.DATA );
2034
+ } else {
2035
+ Galleria.raise('Load failed: no data found.');
2036
+ }
2037
+ return this;
2038
+
2039
+ },
2040
+
2041
+ _getActive: function() {
2042
+ return this._controls.getActive();
2043
+ },
2044
+
2045
+ validate : function( data ) {
2046
+ // todo: validate a custom data array
2047
+ return true;
2048
+ },
2049
+
2050
+ /**
2051
+ Bind any event to Galleria
2052
+
2053
+ @param {String} type The Event type to listen for
2054
+ @param {Function} fn The function to execute when the event is triggered
2055
+
2056
+ @example this.bind( Galleria.IMAGE, function() { Galleria.log('image shown') });
2057
+
2058
+ @returns {Galleria}
2059
+ */
2060
+
2061
+ bind : function(type, fn) {
2062
+ this.$( 'container' ).bind( type, this.proxy(fn) );
2063
+ return this;
2064
+ },
2065
+
2066
+ /**
2067
+ Unbind any event to Galleria
2068
+
2069
+ @param {String} type The Event type to forget
2070
+
2071
+ @returns {Galleria}
2072
+ */
2073
+
2074
+ unbind : function(type) {
2075
+ this.$( 'container' ).unbind( type );
2076
+ return this;
2077
+ },
2078
+
2079
+ /**
2080
+ Manually trigger a Galleria event
2081
+
2082
+ @param {String} type The Event to trigger
2083
+
2084
+ @returns {Galleria}
2085
+ */
2086
+
2087
+ trigger : function( type ) {
2088
+ type = typeof type == 'object' ?
2089
+ $.extend( type, { scope: this } ) :
2090
+ { type: type, scope: this };
2091
+ this.$( 'container' ).trigger( type );
2092
+ return this;
2093
+ },
2094
+
2095
+ /**
2096
+ Assign an "idle state" to any element.
2097
+ The idle state will be applied after a certain amount of idle time
2098
+ Useful to hide f.ex navigation when the gallery is inactive
2099
+
2100
+ @param {HTML Element or String} elem The Dom node or selector to apply the idle state to
2101
+ @param {Object} styles the CSS styles to apply
2102
+
2103
+ @example addIdleState( this.get('image-nav'), { opacity: 0 });
2104
+ @example addIdleState( '.galleria-image-nav', { top: -200 });
2105
+
2106
+ @returns {Galleria}
2107
+ */
2108
+
2109
+ addIdleState: function( elem, styles ) {
2110
+ this._idle.add.apply( this._idle, Utils.array( arguments ) );
2111
+ return this;
2112
+ },
2113
+
2114
+ /**
2115
+ Removes any idle state previously set using addIdleState()
2116
+
2117
+ @param {HTML Element or String} elem The Dom node or selector to remove the idle state from.
2118
+
2119
+ @returns {Galleria}
2120
+ */
2121
+
2122
+ removeIdleState: function( elem ) {
2123
+ this._idle.remove.apply( this._idle, Utils.array( arguments ) );
2124
+ return this;
2125
+ },
2126
+
2127
+ /**
2128
+ Force Galleria to enter idle mode.
2129
+
2130
+ @returns {Galleria}
2131
+ */
2132
+
2133
+ enterIdleMode: function() {
2134
+ this._idle.hide();
2135
+ return this;
2136
+ },
2137
+
2138
+ /**
2139
+ Force Galleria to exit idle mode.
2140
+
2141
+ @returns {Galleria}
2142
+ */
2143
+
2144
+ exitIdleMode: function() {
2145
+ this.idle._show();
2146
+ return this;
2147
+ },
2148
+
2149
+ /**
2150
+ Enter FullScreen mode
2151
+
2152
+ @param {Function} callback the function to be executed when the fullscreen mode is fully applied.
2153
+
2154
+ @returns {Galleria}
2155
+ */
2156
+
2157
+ enterFullscreen: function( callback ) {
2158
+ this._fullscreen.enter.apply( this, Utils.array( arguments ) );
2159
+ return this;
2160
+ },
2161
+
2162
+ /**
2163
+ Exits FullScreen mode
2164
+
2165
+ @param {Function} callback the function to be executed when the fullscreen mode is fully applied.
2166
+
2167
+ @returns {Galleria}
2168
+ */
2169
+
2170
+ exitFullscreen: function( callback ) {
2171
+ this._fullscreen.exit.apply( this, Utils.array( arguments ) );
2172
+ return this;
2173
+ },
2174
+
2175
+ /**
2176
+ Adds a tooltip to any element.
2177
+ You can also call this method with an object as argument with elemID:value pairs to apply tooltips to (see examples)
2178
+
2179
+ @param {HTML Element} elem The DOM Node to attach the event to
2180
+ @param {String or Function} value The tooltip message. Can also be a function that returns a string.
2181
+
2182
+ @example this.bindTooltip( this.get('thumbnails'), 'My thumbnails');
2183
+ @example this.bindTooltip( this.get('thumbnails'), function() { return 'My thumbs' });
2184
+ @example this.bindTooltip( { image_nav: 'Navigation' });
2185
+
2186
+ @returns {Galleria}
2187
+ */
2188
+
2189
+ bindTooltip: function( elem, value ) {
2190
+ this._tooltip.bind.apply( this._tooltip, Utils.array(arguments) );
2191
+ return this;
2192
+ },
2193
+
2194
+ /**
2195
+ Note: this method is deprecated. Use refreshTooltip() instead.
2196
+
2197
+ Redefine a tooltip.
2198
+ Use this if you want to re-apply a tooltip value to an already bound tooltip element.
2199
+
2200
+ @param {HTML Element} elem The DOM Node to attach the event to
2201
+ @param {String or Function} value The tooltip message. Can also be a function that returns a string.
2202
+
2203
+ @returns {Galleria}
2204
+ */
2205
+
2206
+ defineTooltip: function( elem, value ) {
2207
+ this._tooltip.define.apply( this._tooltip, Utils.array(arguments) );
2208
+ return this;
2209
+ },
2210
+
2211
+ /**
2212
+ Refresh a tooltip value.
2213
+ Use this if you want to change the tooltip value at runtime, f.ex if you have a play/pause toggle.
2214
+
2215
+ @param {HTML Element} elem The DOM Node that has a tooltip that should be refreshed
2216
+
2217
+ @returns {Galleria}
2218
+ */
2219
+
2220
+ refreshTooltip: function() {
2221
+ this._tooltip.show.apply( this._tooltip, Utils.array(arguments) );
2222
+ return this;
2223
+ },
2224
+
2225
+ /**
2226
+ Open a pre-designed lightbox with the currently active image.
2227
+ You can control some visuals using gallery options.
2228
+
2229
+ @returns {Galleria}
2230
+ */
2231
+
2232
+ openLightbox: function() {
2233
+ this._lightbox.show.apply( this._lightbox, Utils.array( arguments ) );
2234
+ return this;
2235
+ },
2236
+
2237
+ /**
2238
+ Close the lightbox.
2239
+
2240
+ @returns {Galleria}
2241
+ */
2242
+
2243
+ closeLightbox: function() {
2244
+ this._lightbox.hide.apply( this._lightbox, Utils.array( arguments ) );
2245
+ return this;
2246
+ },
2247
+
2248
+ /**
2249
+ Get the currently active image element.
2250
+
2251
+ @returns {HTML Element} The image element
2252
+ */
2253
+
2254
+ getActiveImage: function() {
2255
+ return this._getActive().image || undef;
2256
+ },
2257
+
2258
+ /**
2259
+ Get the currently active thumbnail element.
2260
+
2261
+ @returns {HTML Element} The thumbnail element
2262
+ */
2263
+
2264
+ getActiveThumb: function() {
2265
+ return this._thumbnails[ this._active ].image || undef;
2266
+ },
2267
+
2268
+ /**
2269
+ Get the mouse position relative to the gallery container
2270
+
2271
+ @param e The mouse event
2272
+
2273
+ @example
2274
+
2275
+ var gallery = this;
2276
+ $(document).mousemove(function(e) {
2277
+ console.log( gallery.getMousePosition(e).x );
2278
+ });
2279
+
2280
+ @returns {Object} Object with x & y of the relative mouse postion
2281
+ */
2282
+
2283
+ getMousePosition : function(e) {
2284
+ return {
2285
+ x: e.pageX - this.$( 'container' ).offset().left,
2286
+ y: e.pageY - this.$( 'container' ).offset().top
2287
+ };
2288
+ },
2289
+
2290
+ /**
2291
+ Adds a panning effect to the image
2292
+
2293
+ @param img The optional image element. If not specified it takes the currently active image
2294
+
2295
+ @returns {Galleria}
2296
+ */
2297
+
2298
+ addPan : function( img ) {
2299
+
2300
+ if ( this._options.image_crop === false ) {
2301
+ return;
2302
+ }
2303
+
2304
+ img = $( img || this.getActiveImage() );
2305
+
2306
+ // define some variables and methods
2307
+ var self = this,
2308
+ x = img.width() / 2,
2309
+ y = img.height() / 2,
2310
+ curX = destX = parseInt( img.css( 'left' ) ) || 0,
2311
+ curY = destY = parseInt( img.css( 'top' ) ) || 0,
2312
+ distX = 0,
2313
+ distY = 0,
2314
+ active = false,
2315
+ ts = Utils.timestamp(),
2316
+ cache = 0,
2317
+ move = 0,
2318
+
2319
+ // positions the image
2320
+ position = function( dist, cur, pos ) {
2321
+ if ( dist > 0 ) {
2322
+ move = Math.round( Math.max( dist * -1, Math.min( 0, cur ) ) );
2323
+ if ( cache != move ) {
2324
+
2325
+ cache = move;
2326
+
2327
+ if ( IE == 8 ) { // scroll is faster for IE
2328
+ img.parent()[ 'scroll' + pos ]( move * -1 );
2329
+ } else {
2330
+ var css = {};
2331
+ css[ pos.toLowerCase() ] = move;
2332
+ img.css(css);
2333
+ }
2334
+ }
2335
+ }
2336
+ },
2337
+
2338
+ // calculates mouse position after 50ms
2339
+ calculate = function(e) {
2340
+ if (Utils.timestamp() - ts < 50) {
2341
+ return;
2342
+ }
2343
+ active = true;
2344
+ x = self.getMousePosition(e).x;
2345
+ y = self.getMousePosition(e).y;
2346
+ },
2347
+
2348
+ // the main loop to check
2349
+ loop = function(e) {
2350
+
2351
+ if (!active) {
2352
+ return;
2353
+ }
2354
+
2355
+ distX = img.width() - self._stageWidth;
2356
+ distY = img.height() - self._stageHeight;
2357
+ destX = x / self._stageWidth * distX * -1;
2358
+ destY = y / self._stageHeight * distY * -1;
2359
+ curX += ( destX - curX ) / self._options.image_pan_smoothness;
2360
+ curY += ( destY - curY ) / self._options.image_pan_smoothness;
2361
+
2362
+ position( distY, curY, 'Top' );
2363
+ position( distX, curX, 'Left' );
2364
+
2365
+ };
2366
+
2367
+ // we need to use scroll in IE8 to speed things up
2368
+ if ( IE == 8 ) {
2369
+
2370
+ img.parent().scrollTop( curY * -1 ).scrollLeft( curX * -1 );
2371
+ img.css({
2372
+ top: 0,
2373
+ left: 0
2374
+ });
2375
+
2376
+ }
2377
+
2378
+ // unbind and bind event
2379
+ this.$( 'stage' ).unbind( 'mousemove', calculate ).bind( 'mousemove', calculate );
2380
+
2381
+ // loop the loop
2382
+ Utils.addTimer('pan', loop, 50, true);
2383
+
2384
+ return this;
2385
+ },
2386
+
2387
+ /**
2388
+ Brings the scope into any callback
2389
+
2390
+ @param fn The callback to bring the scope into
2391
+ @param scope Optional scope to bring
2392
+
2393
+ @example $('#fullscreen').click( this.proxy(function() { this.enterFullscreen(); }) )
2394
+
2395
+ @returns {Function} Return the callback with the gallery scope
2396
+ */
2397
+
2398
+ proxy : function( fn, scope ) {
2399
+ if ( typeof fn !== 'function' ) {
2400
+ return function() {};
2401
+ }
2402
+ scope = scope || this;
2403
+ return function() {
2404
+ return fn.apply( scope, Utils.array( arguments ) );
2405
+ };
2406
+ },
2407
+
2408
+ /**
2409
+ Removes the panning effect set by addPan()
2410
+
2411
+ @returns {Galleria}
2412
+ */
2413
+
2414
+ removePan: function() {
2415
+
2416
+ if ( IE == 8 ) {
2417
+ // todo: doublecheck this
2418
+ }
2419
+ this.$( 'stage' ).unbind( 'mousemove' );
2420
+
2421
+ Utils.clearTimer('pan');
2422
+
2423
+ return this;
2424
+ },
2425
+
2426
+ /**
2427
+ Adds an element to the Galleria DOM array.
2428
+ When you add an element here, you can access it using element ID in many API calls
2429
+
2430
+ @param {String} id The element ID you wish to use. You can add many elements by adding more arguments.
2431
+
2432
+ @example addElement('mybutton');
2433
+ @example addElement('mybutton','mylink');
2434
+
2435
+ @returns {Galleria}
2436
+ */
2437
+
2438
+ addElement : function( id ) {
2439
+
2440
+ var dom = this._dom;
2441
+
2442
+ $.each( Utils.array(arguments), function( i, blueprint ) {
2443
+ dom[ blueprint ] = Utils.create( 'galleria-' + blueprint );
2444
+ });
2445
+
2446
+ return this;
2447
+ },
2448
+
2449
+ /**
2450
+ Attach keyboard events to Galleria
2451
+
2452
+ @param {Object} map The map object of events.
2453
+ Possible keys are 'UP', 'DOWN', 'LEFT', 'RIGHT', 'RETURN', 'ESCAPE', 'BACKSPACE', and 'SPACE'.
2454
+
2455
+ @example
2456
+
2457
+ this.attachKeyboard({
2458
+ right: this.next,
2459
+ left: this.prev,
2460
+ up: function() {
2461
+ console.log( 'up key pressed' )
2462
+ }
2463
+ });
2464
+
2465
+ @returns {Galleria}
2466
+ */
2467
+
2468
+ attachKeyboard : function( map ) {
2469
+ this._keyboard.attach.apply( this._keyboard, Utils.array( arguments ) );
2470
+ return this;
2471
+ },
2472
+
2473
+ /**
2474
+ Detach all keyboard events to Galleria
2475
+
2476
+ @returns {Galleria}
2477
+ */
2478
+
2479
+ detachKeyboard : function() {
2480
+ this._keyboard.detach.apply( this._keyboard, Utils.array( arguments ) );
2481
+ return this;
2482
+ },
2483
+
2484
+ /**
2485
+ Fast helper for appending galleria elements that you added using addElement()
2486
+
2487
+ @param {String} parentID The parent element ID where the element will be appended
2488
+ @param {String} childID the element ID that should be appended
2489
+
2490
+ @example this.addElement('myElement');
2491
+ this.appendChild( 'info', 'myElement' );
2492
+
2493
+ @returns {Galleria}
2494
+ */
2495
+
2496
+ appendChild : function( parentID, childID ) {
2497
+ this.$( parentID ).append( this.get( childID ) || childID );
2498
+ return this;
2499
+ },
2500
+
2501
+ /**
2502
+ Fast helper for appending galleria elements that you added using addElement()
2503
+
2504
+ @param {String} parentID The parent element ID where the element will be preppended
2505
+ @param {String} childID the element ID that should be preppended
2506
+
2507
+ @example
2508
+
2509
+ this.addElement('myElement');
2510
+ this.prependChild( 'info', 'myElement' );
2511
+
2512
+ @returns {Galleria}
2513
+ */
2514
+
2515
+ prependChild : function( parentID, childID ) {
2516
+ this.$( parentID ).prepend( this.get( childID ) || childID );
2517
+ return this;
2518
+ },
2519
+
2520
+ /**
2521
+ Remove an element by blueprint
2522
+
2523
+ @param {String} elemID The element to be removed.
2524
+ You can remove multiple elements by adding arguments.
2525
+
2526
+ @returns {Galleria}
2527
+ */
2528
+
2529
+ remove : function( elemID ) {
2530
+ this.$( Utils.array( arguments ).join(',') ).remove();
2531
+ return this;
2532
+ },
2533
+
2534
+ // a fast helper for building dom structures
2535
+ // leave this out of the API for now
2536
+
2537
+ append : function( data ) {
2538
+ for( var i in data) {
2539
+ if ( data[i].constructor == Array ) {
2540
+ for( var j = 0; data[i][j]; j++ ) {
2541
+ this.appendChild( i, data[i][j] );
2542
+ }
2543
+ } else {
2544
+ this.appendChild( i, data[i] );
2545
+ }
2546
+ }
2547
+ return this;
2548
+ },
2549
+
2550
+ // an internal helper for scaling according to options
2551
+ _scaleImage : function( image, options ) {
2552
+
2553
+ options = $.extend({
2554
+ width: this._stageWidth,
2555
+ height: this._stageHeight,
2556
+ crop: this._options.image_crop,
2557
+ max: this._options.max_scale_ratio,
2558
+ min: this._options.min_scale_ratio,
2559
+ margin: this._options.image_margin,
2560
+ position: this._options.image_position
2561
+ }, options );
2562
+
2563
+ ( image || this._controls.getActive() ).scale( options );
2564
+
2565
+ return this;
2566
+ },
2567
+
2568
+ /**
2569
+ Updates the carousel,
2570
+ useful if you resize the gallery and want to re-check if the carousel nav is needed.
2571
+
2572
+ @returns {Galleria}
2573
+ */
2574
+
2575
+ updateCarousel : function() {
2576
+ this._carousel.update();
2577
+ return this;
2578
+ },
2579
+
2580
+ /**
2581
+ Rescales the gallery
2582
+
2583
+ @param {Number} width The target width
2584
+ @param {Number} height The target height
2585
+ @param {Function} complete The callback to be called when the scaling is complete
2586
+
2587
+ @returns {Galleria}
2588
+ */
2589
+
2590
+ rescale : function( width, height, complete ) {
2591
+
2592
+ var self = this;
2593
+
2594
+ // allow rescale(fn)
2595
+ if ( typeof width == 'function' ) {
2596
+ complete = width;
2597
+ width = undef;
2598
+ }
2599
+
2600
+ var scale = function() {
2601
+
2602
+ // shortcut
2603
+ var o = self._options;
2604
+
2605
+ // set stagewidth
2606
+ self._stageWidth = width || self.$( 'stage' ).width();
2607
+ self._stageHeight = height || self.$( 'stage' ).height();
2608
+
2609
+ // scale the active image
2610
+ self._scaleImage();
2611
+
2612
+ if ( self._options.carousel ) {
2613
+ self.updateCarousel();
2614
+ }
2615
+
2616
+ self.trigger( Galleria.RESCALE );
2617
+
2618
+ if ( typeof complete == 'function' ) {
2619
+ complete.call( self );
2620
+ }
2621
+ };
2622
+
2623
+ if ( Galleria.WEBKIT && !width && !height ) {
2624
+ Utils.addTimer( 'scale', scale, 5 );// webkit is too fast
2625
+ } else {
2626
+ scale.call( self );
2627
+ }
2628
+
2629
+ return this;
2630
+ },
2631
+
2632
+ /**
2633
+ Refreshes the gallery.
2634
+ Useful if you change image options at runtime and want to apply the changes to the active image.
2635
+
2636
+ @returns {Galleria}
2637
+ */
2638
+
2639
+ refreshImage : function() {
2640
+ this._scaleImage();
2641
+ if ( this._options.image_pan ) {
2642
+ this.addPan();
2643
+ }
2644
+ return this;
2645
+ },
2646
+
2647
+ /**
2648
+ Shows an image by index
2649
+
2650
+ @param {Number} index The index to show
2651
+ @param {Boolean} rewind A boolean that should be true if you want the transition to go back
2652
+
2653
+ @returns {Galleria}
2654
+ */
2655
+
2656
+ show : function( index, rewind, _history ) {
2657
+
2658
+ // do nothing if index is false or queue is false and transition is in progress
2659
+ if ( index === false || !this._options.queue && this._queue.stalled ) {
2660
+ return;
2661
+ }
2662
+
2663
+ index = Math.max( 0, Math.min( parseInt(index), this.getDataLength() - 1 ) );
2664
+
2665
+ rewind = typeof rewind != 'undefined' ? !!rewind : index < this.getIndex();
2666
+
2667
+ _history = _history || false;
2668
+
2669
+ // do the history thing and return
2670
+ if ( !_history && Galleria.History ) {
2671
+ Galleria.History.value( index.toString() );
2672
+ return;
2673
+ }
2674
+
2675
+ this._active = index;
2676
+
2677
+ Array.prototype.push.call( this._queue, {
2678
+ index : index,
2679
+ rewind : rewind
2680
+ });
2681
+ if ( !this._queue.stalled ) {
2682
+ this._show();
2683
+ }
2684
+
2685
+ return this;
2686
+ },
2687
+
2688
+ // the internal _show method does the actual showing
2689
+ _show : function() {
2690
+
2691
+ // shortcuts
2692
+ var self = this,
2693
+ queue = this._queue[ 0 ],
2694
+ data = this.getData( queue.index );
2695
+
2696
+ if ( !data ) {
2697
+ return;
2698
+ }
2699
+
2700
+ var src = data.image,
2701
+ active = this._controls.getActive(),
2702
+ next = this._controls.getNext(),
2703
+ cached = next.isCached( src ),
2704
+ thumb = this._thumbnails[ queue.index ];
2705
+
2706
+ // to be fired when loading & transition is complete:
2707
+ var complete = function() {
2708
+
2709
+ // remove stalled
2710
+ self._queue.stalled = false;
2711
+
2712
+ // optimize quality
2713
+ Utils.toggleQuality( next.image, self._options.image_quality );
2714
+
2715
+ // swap
2716
+ $( active.container ).css({
2717
+ zIndex: 0,
2718
+ opacity: 0
2719
+ });
2720
+ $( next.container ).css({
2721
+ zIndex: 1,
2722
+ opacity: 1
2723
+ });
2724
+ self._controls.swap();
2725
+
2726
+ // add pan according to option
2727
+ if ( self._options.image_pan ) {
2728
+ self.addPan( next.image );
2729
+ }
2730
+
2731
+ // make the image link
2732
+ if ( data.link ) {
2733
+ $( next.image ).css({
2734
+ cursor: 'pointer'
2735
+ }).bind( CLICK(), function() {
2736
+
2737
+ // popup link
2738
+ if ( self._options.popup_links ) {
2739
+ var win = window.open( data.link, '_blank' );
2740
+ } else {
2741
+ window.location.href = data.link;
2742
+ }
2743
+ });
2744
+ }
2745
+
2746
+ // remove the queued image
2747
+ Array.prototype.shift.call( self._queue );
2748
+
2749
+ // if we still have images in the queue, show it
2750
+ if ( self._queue.length ) {
2751
+ self._show();
2752
+ }
2753
+
2754
+ // check if we are playing
2755
+ self._playCheck();
2756
+
2757
+ // trigger IMAGE event
2758
+ self.trigger({
2759
+ type: Galleria.IMAGE,
2760
+ index: queue.index,
2761
+ imageTarget: next.image,
2762
+ thumbTarget: thumb.image
2763
+ });
2764
+ };
2765
+
2766
+ // let the carousel follow
2767
+ if ( this._options.carousel && this._options.carousel_follow ) {
2768
+ this._carousel.follow( queue.index );
2769
+ }
2770
+
2771
+ // preload images
2772
+ if ( this._options.preload ) {
2773
+
2774
+ var p,
2775
+ n = this.getNext();
2776
+
2777
+ try {
2778
+ for ( var i = this._options.preload; i > 0; i-- ) {
2779
+ p = new Galleria.Picture();
2780
+ p.add( self.getData( n ).image );
2781
+ n = self.getNext( n );
2782
+ }
2783
+ } catch(e) {}
2784
+ }
2785
+
2786
+ // show the next image, just in case
2787
+ Utils.show( next.container );
2788
+
2789
+ // add active classes
2790
+ $( self._thumbnails[ queue.index ].container )
2791
+ .addClass( 'active' )
2792
+ .siblings( '.active' )
2793
+ .removeClass( 'active' );
2794
+
2795
+ // trigger the LOADSTART event
2796
+ self.trigger( {
2797
+ type: Galleria.LOADSTART,
2798
+ cached: cached,
2799
+ index: queue.index,
2800
+ imageTarget: next.image,
2801
+ thumbTarget: thumb.image
2802
+ });
2803
+ // begin loading the next image
2804
+ next.load( src, function( next ) {
2805
+ self._scaleImage( next, {
2806
+
2807
+ complete: function( next ) {
2808
+
2809
+ Utils.show( next.container );
2810
+
2811
+ // toggle low quality for IE
2812
+ if ( 'image' in active ) {
2813
+ Utils.toggleQuality( active.image, false );
2814
+ }
2815
+ Utils.toggleQuality( next.image, false );
2816
+
2817
+ // stall the queue
2818
+ self._queue.stalled = true;
2819
+
2820
+ // remove the image panning, if applied
2821
+ // TODO: rethink if this is necessary
2822
+ self.removePan();
2823
+
2824
+ // set the captions and counter
2825
+ self.setInfo( queue.index );
2826
+ self.setCounter( queue.index );
2827
+
2828
+ // trigger the LOADFINISH event
2829
+ self.trigger({
2830
+ type: Galleria.LOADFINISH,
2831
+ cached: cached,
2832
+ index: queue.index,
2833
+ imageTarget: next.image,
2834
+ thumbTarget: self._thumbnails[ queue.index ].image
2835
+ });
2836
+
2837
+ var transition = active.image === null && self._options.transition_initial ?
2838
+ self._options.transition_initial : self._options.transition;
2839
+
2840
+ // validate the transition
2841
+ if ( transition in _transitions === false ) {
2842
+
2843
+ complete();
2844
+
2845
+ } else {
2846
+ var params = {
2847
+ prev: active.image,
2848
+ next: next.image,
2849
+ rewind: queue.rewind,
2850
+ speed: self._options.transition_speed || 400
2851
+ };
2852
+
2853
+ // call the transition function and send some stuff
2854
+ _transitions[ transition ].call(self, params, complete );
2855
+
2856
+ }
2857
+ }
2858
+ });
2859
+ });
2860
+ },
2861
+
2862
+ /**
2863
+ Gets the next index
2864
+
2865
+ @param {Number} base Optional starting point
2866
+
2867
+ @returns {Number} the next index, or the first if you are at the first (looping)
2868
+ */
2869
+
2870
+ getNext : function( base ) {
2871
+ base = typeof base == 'number' ? base : this.getIndex();
2872
+ return base == this.getDataLength() - 1 ? 0 : base + 1;
2873
+ },
2874
+
2875
+ /**
2876
+ Gets the previous index
2877
+
2878
+ @param {Number} base Optional starting point
2879
+
2880
+ @returns {Number} the previous index, or the last if you are at the first (looping)
2881
+ */
2882
+
2883
+ getPrev : function( base ) {
2884
+ base = typeof base == 'number' ? base : this.getIndex();
2885
+ return base === 0 ? this.getDataLength() - 1 : base - 1;
2886
+ },
2887
+
2888
+ /**
2889
+ Shows the next image in line
2890
+
2891
+ @returns {Galleria}
2892
+ */
2893
+
2894
+ next : function() {
2895
+ if ( this.getDataLength() > 1 ) {
2896
+ this.show( this.getNext(), false );
2897
+ }
2898
+ return this;
2899
+ },
2900
+
2901
+ /**
2902
+ Shows the previous image in line
2903
+
2904
+ @returns {Galleria}
2905
+ */
2906
+
2907
+ prev : function() {
2908
+ if ( this.getDataLength() > 1 ) {
2909
+ this.show( this.getPrev(), true );
2910
+ }
2911
+ return this;
2912
+ },
2913
+
2914
+ /**
2915
+ Retrieve a DOM element by element ID
2916
+
2917
+ @param {String} elemId The delement ID to fetch
2918
+
2919
+ @returns {HTML Element} The elements DOM node or null if not found.
2920
+ */
2921
+
2922
+ get : function( elemId ) {
2923
+ return elemId in this._dom ? this._dom[ elemId ] : null;
2924
+ },
2925
+
2926
+ /**
2927
+ Retrieve a data object
2928
+
2929
+ @param {Number} index The data index to retrieve.
2930
+ If no index specified it will take the currently active image
2931
+
2932
+ @returns {Object} The data object
2933
+ */
2934
+
2935
+ getData : function( index ) {
2936
+ return index in this._data ?
2937
+ this._data[ index ] : this._data[ this._active ];
2938
+ },
2939
+
2940
+ /**
2941
+ Retrieve the number of data items
2942
+
2943
+ @returns {Number} The data length
2944
+ */
2945
+ getDataLength : function() {
2946
+ return this._data.length;
2947
+ },
2948
+
2949
+ /**
2950
+ Retrieve the currently active index
2951
+
2952
+ @returns {Number} The active index
2953
+ */
2954
+
2955
+ getIndex : function() {
2956
+ return typeof this._active === 'number' ? this._active : false;
2957
+ },
2958
+
2959
+ /**
2960
+ Retrieve the stage height
2961
+
2962
+ @returns {Number} The stage height
2963
+ */
2964
+
2965
+ getStageHeight : function() {
2966
+ return this._stageHeight;
2967
+ },
2968
+
2969
+ /**
2970
+ Retrieve the stage width
2971
+
2972
+ @returns {Number} The stage width
2973
+ */
2974
+
2975
+ getStageWidth : function() {
2976
+ return this._stageWidth;
2977
+ },
2978
+
2979
+ /**
2980
+ Retrieve the option
2981
+
2982
+ @param {String} key The option key to retrieve. If no key specified it will return all options in an object.
2983
+
2984
+ @returns option or options
2985
+ */
2986
+
2987
+ getOptions : function( key ) {
2988
+ return typeof key == 'undefined' ? this._options : this._options[ key ];
2989
+ },
2990
+
2991
+ /**
2992
+ Set options to the instance.
2993
+ You can set options using a key & value argument or a single object argument (see examples)
2994
+
2995
+ @param {String} key The option key
2996
+ @param {String} value the the options value
2997
+
2998
+ @example setOptions( 'autoplay', true )
2999
+ @example setOptions({ autoplay: true });
3000
+
3001
+ @returns {Galleria}
3002
+ */
3003
+
3004
+ setOptions : function( key, value ) {
3005
+ if ( typeof key == 'object' ) {
3006
+ $.extend( this._options, key );
3007
+ } else {
3008
+ this._options[ key ] = value;
3009
+ }
3010
+ return this;
3011
+ },
3012
+
3013
+ /**
3014
+ Starts playing the slideshow
3015
+
3016
+ @param {Number} delay Sets the slideshow interval in milliseconds.
3017
+ If you set it once, you can just call play() and get the same interval the next time.
3018
+
3019
+ @returns {Galleria}
3020
+ */
3021
+
3022
+ play : function( delay ) {
3023
+
3024
+ this._playing = true;
3025
+
3026
+ this._playtime = delay || this._playtime;
3027
+
3028
+ this._playCheck();
3029
+
3030
+ this.trigger( Galleria.PLAY );
3031
+
3032
+ return this;
3033
+ },
3034
+
3035
+ /**
3036
+ Stops the slideshow if currently playing
3037
+
3038
+ @returns {Galleria}
3039
+ */
3040
+
3041
+ pause : function() {
3042
+
3043
+ this._playing = false;
3044
+
3045
+ this.trigger( Galleria.PAUSE );
3046
+
3047
+ return this;
3048
+ },
3049
+
3050
+ /**
3051
+ Toggle between play and pause events.
3052
+
3053
+ @param {Number} delay Sets the slideshow interval in milliseconds.
3054
+
3055
+ @returns {Galleria}
3056
+ */
3057
+
3058
+ playToggle : function( delay ) {
3059
+ return ( this._playing ) ? this.pause() : this.play( delay );
3060
+ },
3061
+
3062
+ /**
3063
+ Checks if the gallery is currently playing
3064
+
3065
+ @returns {Boolean}
3066
+ */
3067
+
3068
+ isPlaying : function() {
3069
+ return this._playing;
3070
+ },
3071
+
3072
+ _playCheck : function() {
3073
+ var self = this,
3074
+ played = 0,
3075
+ interval = 20,
3076
+ now = Utils.timestamp();
3077
+
3078
+ if ( this._playing ) {
3079
+
3080
+ Utils.clearTimer('play');
3081
+ var fn = function() {
3082
+
3083
+ played = Utils.timestamp() - now;
3084
+ if ( played >= self._playtime && self._playing ) {
3085
+ Utils.clearTimer('play');
3086
+ self.next();
3087
+ return;
3088
+ }
3089
+ if ( self._playing ) {
3090
+
3091
+ // trigger the PROGRESS event
3092
+ self.trigger({
3093
+ type: Galleria.PROGRESS,
3094
+ percent: Math.ceil( played / self._playtime * 100 ),
3095
+ seconds: Math.floor( played / 1000 ),
3096
+ milliseconds: played
3097
+ });
3098
+
3099
+ Utils.addTimer( 'play', fn, interval );
3100
+ }
3101
+ };
3102
+ Utils.addTimer( 'play', fn, interval );
3103
+ }
3104
+ },
3105
+
3106
+ setIndex: function( val ) {
3107
+ this._active = val;
3108
+ return this;
3109
+ },
3110
+
3111
+ /**
3112
+ Manually modify the counter
3113
+
3114
+ @param {Number} index Optional data index to fectch,
3115
+ if no index found it assumes the currently active index
3116
+
3117
+ @returns {Galleria}
3118
+ */
3119
+
3120
+ setCounter: function( index ) {
3121
+
3122
+ if ( typeof index == 'number' ) {
3123
+ index++;
3124
+ } else if ( typeof index == 'undefined' ) {
3125
+ index = this.getIndex()+1;
3126
+ }
3127
+
3128
+ this.get( 'current' ).innerHTML = index;
3129
+
3130
+ if ( IE == 8 ) { // weird IE8 bug
3131
+
3132
+ var opacity = this.$( 'counter' ).css( 'opacity' );
3133
+ this.$( 'counter' ).css( 'opacity', opacity );
3134
+
3135
+ }
3136
+
3137
+ return this;
3138
+ },
3139
+
3140
+ /**
3141
+ Manually set captions
3142
+
3143
+ @param {Number} index Optional data index to fectch and apply as caption,
3144
+ if no index found it assumes the currently active index
3145
+
3146
+ @returns {Galleria}
3147
+ */
3148
+
3149
+ setInfo : function( index ) {
3150
+
3151
+ var self = this,
3152
+ data = this.getData( index );
3153
+
3154
+ $.each( ['title','description','author'], function( i, type ) {
3155
+
3156
+ var elem = self.$( 'info-' + type );
3157
+
3158
+ if ( !!data[type] ) {
3159
+ elem[ data[ type ].length ? 'show' : 'hide' ]().html( data[ type ] );
3160
+ } else {
3161
+ elem.empty().hide();
3162
+ }
3163
+ });
3164
+
3165
+ return this;
3166
+ },
3167
+
3168
+ /**
3169
+ Checks if the data contains any captions
3170
+
3171
+ @param {Number} index Optional data index to fectch,
3172
+ if no index found it assumes the currently active index.
3173
+
3174
+ @returns {Boolean}
3175
+ */
3176
+
3177
+ hasInfo : function( index ) {
3178
+
3179
+ var d = this.getData( index );
3180
+ var check = 'title description'.split(' ');
3181
+ for ( var i = 0; check[i]; i++ ) {
3182
+ if ( !!this.getData( index )[ check[i] ] ) {
3183
+ return true;
3184
+ }
3185
+ }
3186
+ return false;
3187
+
3188
+ },
3189
+
3190
+ jQuery : function( str ) {
3191
+
3192
+ var self = this,
3193
+ ret = [];
3194
+
3195
+ $.each( str.split(','), function( i, elemId ) {
3196
+ elemId = $.trim( elemId );
3197
+
3198
+ if ( self.get( elemId ) ) {
3199
+ ret.push( elemId );
3200
+ }
3201
+ });
3202
+
3203
+ var jQ = $( self.get( ret.shift() ) );
3204
+
3205
+ $.each( ret, function( i, elemId ) {
3206
+ jQ = jQ.add( self.get( elemId ) );
3207
+ });
3208
+
3209
+ return jQ;
3210
+
3211
+ },
3212
+
3213
+ /**
3214
+ Converts element IDs into a jQuery collection
3215
+ You can call for multiple IDs separated with commas.
3216
+
3217
+ @param {String} str One or more element IDs (comma-separated)
3218
+
3219
+ @returns {jQuery}
3220
+
3221
+ @example this.$('info,container').hide();
3222
+ */
3223
+
3224
+ $ : function() {
3225
+ return this.jQuery.apply( this, Utils.array( arguments ) );
3226
+ }
3227
+
3228
+ };
3229
+
3230
+ // End of Galleria prototype
3231
+
3232
+ $.extend( Galleria, {
3233
+
3234
+ // Event placeholders
3235
+ DATA: 'g_data',
3236
+ READY: 'g_ready',
3237
+ THUMBNAIL: 'g_thumbnail',
3238
+ LOADSTART: 'g_loadstart',
3239
+ LOADFINISH: 'g_loadfinish',
3240
+ IMAGE: 'g_image',
3241
+ THEMELOAD: 'g_themeload',
3242
+ PLAY: 'g_play',
3243
+ PAUSE: 'g_pause',
3244
+ PROGRESS: 'g_progress',
3245
+ FULLSCREEN_ENTER: 'g_fullscreen_enter',
3246
+ FULLSCREEN_EXIT: 'g_fullscreen_exit',
3247
+ IDLE_ENTER: 'g_idle_enter',
3248
+ IDLE_EXIT: 'g_idle_exit',
3249
+ RESCALE: 'g_rescale',
3250
+ LIGHTBOX_OPEN: 'g_lightbox_open',
3251
+ LIGHTBOX_CLOSE: 'g_lightbox_close',
3252
+ LIGHTBOX_IMAGE: 'g_lightbox_image',
3253
+
3254
+ // Browser helpers
3255
+ IE9: IE == 9,
3256
+ IE8: IE == 8,
3257
+ IE7: IE == 7,
3258
+ IE6: IE == 6,
3259
+ IE: !!IE,
3260
+ WEBKIT: /webkit/.test( NAV ),
3261
+ SAFARI: /safari/.test( NAV ),
3262
+ CHROME: /chrome/.test( NAV ),
3263
+ QUIRK: ( IE && doc.compatMode && doc.compatMode == "BackCompat" ),
3264
+ MAC: /mac/.test( navigator.platform.toLowerCase() ),
3265
+ OPERA: !!window.opera,
3266
+ IPHONE: /iphone/.test( NAV ),
3267
+ IPAD: /ipad/.test( NAV ),
3268
+ ANDROID: /android/.test( NAV ),
3269
+
3270
+ // Todo detect touch devices in a better way, possibly using event detection
3271
+ TOUCH: !!( /iphone/.test( NAV ) || /ipad/.test( NAV ) || /android/.test( NAV ) )
3272
+
3273
+ });
3274
+
3275
+ // Galleria static methods
3276
+
3277
+ /**
3278
+ Adds a theme that you can use for your Gallery
3279
+
3280
+ @param {Object} theme Object that should contain all your theme settings.
3281
+ <ul>
3282
+ <li>name – name of the theme</li>
3283
+ <li>author - name of the author</li>
3284
+ <li>version - version number</li>
3285
+ <li>css - css file name (not path)</li>
3286
+ <li>defaults - default options to apply, including theme-specific options</li>
3287
+ <li>init - the init function</li>
3288
+ </ul>
3289
+
3290
+ @returns {Object} theme
3291
+ */
3292
+
3293
+ Galleria.addTheme = function( theme ) {
3294
+
3295
+ // make sure we have a name
3296
+ if ( !!theme['name'] === false ) {
3297
+ Galleria.raise('No theme name specified');
3298
+ }
3299
+
3300
+ if ( typeof theme.defaults != 'object' ) {
3301
+ theme.defaults = {};
3302
+ }
3303
+
3304
+ if ( typeof theme.css == 'string' ) {
3305
+
3306
+ var css;
3307
+
3308
+ // look for the absolute path
3309
+ $('script').each(function( i, script ) {
3310
+
3311
+ // look for the theme script
3312
+ var reg = new RegExp( 'galleria\\.' + theme.name.toLowerCase() + '\\.' );
3313
+ if( reg.test( script.src )) {
3314
+
3315
+ // we have a match
3316
+ css = script.src.replace(/[^\/]*$/, '') + theme.css;
3317
+
3318
+ Utils.addTimer( "css", function() {
3319
+ Utils.loadCSS( css, 'galleria-theme', function() {
3320
+ Galleria.theme = theme;
3321
+ $doc.trigger( Galleria.THEMELOAD );
3322
+ });
3323
+ }, 1);
3324
+
3325
+ }
3326
+ });
3327
+
3328
+ if ( !css ) {
3329
+ Galleria.raise('No theme CSS loaded');
3330
+ }
3331
+ } else {
3332
+ Galleria.theme = theme;
3333
+ $doc.trigger( Galleria.THEMELOAD );
3334
+ }
3335
+ return theme;
3336
+ };
3337
+
3338
+ /**
3339
+ loadTheme loads a theme js file and attaches a load event to Galleria
3340
+
3341
+ @param {String} src The relative path to the theme source file
3342
+
3343
+ @param {Object} option Optional options you want to apply
3344
+ */
3345
+
3346
+ Galleria.loadTheme = function( src, options ) {
3347
+
3348
+ var loaded = false,
3349
+ length = _galleries.length;
3350
+
3351
+ // first clear the current theme, if exists
3352
+ Galleria.theme = undef;
3353
+
3354
+ // load the theme
3355
+ Utils.loadScript( src, function() {
3356
+ loaded = true;
3357
+ } );
3358
+
3359
+ // set a 1 sec timeout, then display a hard error if no theme is loaded
3360
+ Utils.wait({
3361
+ until: function() {
3362
+ return loaded;
3363
+ },
3364
+ error: function() {
3365
+ Galleria.raise( "Theme at " + src + " could not load, check theme path.", true );
3366
+ },
3367
+ success: function() {
3368
+
3369
+ // check for existing galleries and reload them with the new theme
3370
+ if ( length ) {
3371
+
3372
+ // temporary save the new galleries
3373
+ var refreshed = [];
3374
+
3375
+ // refresh all instances
3376
+ // when adding a new theme to an existing gallery, all options will be resetted but the data will be kept
3377
+ // you can apply new options as a second argument
3378
+ $.each( Galleria.get(), function(i, instance) {
3379
+
3380
+ // mix the old data and options into the new instance
3381
+ var op = $.extend( instance._original.options, {
3382
+ data_source: instance._data
3383
+ }, options);
3384
+
3385
+ // remove the old container
3386
+ instance.$('container').remove();
3387
+
3388
+ // create a new instance
3389
+ var g = new Galleria();
3390
+
3391
+ // move the id
3392
+ g._id = instance._id;
3393
+
3394
+ // initialize the new instance
3395
+ g.init( instance._original.target, op );
3396
+
3397
+ // push the new instance
3398
+ refreshed.push( g );
3399
+ });
3400
+
3401
+ // now overwrite the old holder with the new instances
3402
+ _galleries = refreshed;
3403
+ }
3404
+ },
3405
+ timeout: 2000
3406
+ });
3407
+ };
3408
+
3409
+ /**
3410
+ Retrieves a Galleria instance.
3411
+
3412
+ @param {Number} index Optional index to retrieve.
3413
+ If no index is supplied, the method will return all instances in an array.
3414
+
3415
+ @returns {Galleria or Array}
3416
+ */
3417
+
3418
+ Galleria.get = function( index ) {
3419
+ if ( !!_galleries[ index ] ) {
3420
+ return _galleries[ index ];
3421
+ } else if ( typeof index !== 'number' ) {
3422
+ return _galleries;
3423
+ } else {
3424
+ Galleria.raise('Gallery index ' + index + ' not found');
3425
+ }
3426
+ };
3427
+
3428
+ /**
3429
+ Creates a transition to be used in your gallery
3430
+
3431
+ @param {String} name The name of the transition that you will use as an option
3432
+
3433
+ @param {Function} fn The function to be executed in the transition.
3434
+ The function contains two arguments, params and complete.
3435
+ Use the params Object to integrate the transition, and then call complete when you are done.
3436
+
3437
+ */
3438
+
3439
+ Galleria.addTransition = function( name, fn ) {
3440
+ _transitions[name] = fn;
3441
+ };
3442
+
3443
+ Galleria.utils = Utils;
3444
+
3445
+ /**
3446
+ A helper metod for cross-browser logging.
3447
+ It uses the console log if available otherwise it falls back to the opera
3448
+ debugger and finally <code>alert()</code>
3449
+
3450
+ @example Galleria.log("hello", document.body, [1,2,3]);
3451
+ */
3452
+
3453
+ Galleria.log = function() {
3454
+ try {
3455
+ window.console.log.apply( window.console, Utils.array(arguments) );
3456
+ } catch( e ) {
3457
+ try {
3458
+ opera.postError.apply( opera, arguments );
3459
+ } catch( er ) {
3460
+ alert( Utils.array(arguments).split(', ') );
3461
+ }
3462
+ }
3463
+ };
3464
+
3465
+ /**
3466
+ Method for raising errors
3467
+
3468
+ @param {String} msg The message to throw
3469
+
3470
+ @param {Boolean} fatal Set this to true to override debug settings and display a fatal error
3471
+ */
3472
+
3473
+ Galleria.raise = function( msg, fatal ) {
3474
+ if ( DEBUG || fatal ) {
3475
+ var type = fatal ? 'Fatal error' : 'Error';
3476
+ throw new Error( type + ': ' + msg );
3477
+ }
3478
+ };
3479
+
3480
+ /**
3481
+ Adds preload, cache, scale and crop functionality
3482
+
3483
+ @constructor
3484
+
3485
+ @requires jQuery
3486
+
3487
+ @param {Number} id Optional id to keep track of instances
3488
+ */
3489
+
3490
+ Galleria.Picture = function( id ) {
3491
+
3492
+ // save the id
3493
+ this.id = id || null;
3494
+
3495
+ // the image should be null until loaded
3496
+ this.image = null;
3497
+
3498
+ // Create a new container
3499
+ this.container = Utils.create('galleria-image');
3500
+
3501
+ // add container styles
3502
+ $( this.container ).css({
3503
+ overflow: 'hidden',
3504
+ position: 'relative' // for IE Standards mode
3505
+ });
3506
+
3507
+ // saves the original meassurements
3508
+ this.original = {
3509
+ width: 0,
3510
+ height: 0
3511
+ };
3512
+
3513
+ // flag when the image is ready
3514
+ this.ready = false;
3515
+
3516
+ // flag when the image is loaded
3517
+ this.loaded = false;
3518
+
3519
+ };
3520
+
3521
+ Galleria.Picture.prototype = {
3522
+
3523
+ // the inherited cache object
3524
+ cache: {},
3525
+
3526
+ // creates a new image and adds it to cache when loaded
3527
+ add: function( src ) {
3528
+
3529
+ var self = this;
3530
+
3531
+ // create the image
3532
+ var image = new Image();
3533
+
3534
+ // force a block display
3535
+ $( image ).css( 'display', 'block');
3536
+
3537
+ if ( self.cache[ src ] ) {
3538
+ // no need to onload if the image is cached
3539
+ image.src = src;
3540
+ self.loaded = true;
3541
+ self.original = {
3542
+ height: image.height,
3543
+ width: image.width
3544
+ };
3545
+ return image;
3546
+ }
3547
+
3548
+ // begin preload and insert in cache when done
3549
+ image.onload = function() {
3550
+ self.original = {
3551
+ height: this.height,
3552
+ width: this.width
3553
+ };
3554
+ self.cache[ src ] = src; // will override old cache
3555
+ self.loaded = true;
3556
+ };
3557
+
3558
+ image.src = src;
3559
+ return image;
3560
+
3561
+ },
3562
+
3563
+ // show the image on stage
3564
+ show: function() {
3565
+ Utils.show( this.image );
3566
+ },
3567
+
3568
+ // hide the image
3569
+ hide: function() {
3570
+ Utils.moveOut( this.image );
3571
+ },
3572
+
3573
+ clear: function() {
3574
+ this.image = null;
3575
+ },
3576
+
3577
+ /**
3578
+ Checks if an image is in cache
3579
+
3580
+ @param {String} src The image source path, ex '/path/to/img.jpg'
3581
+
3582
+ @returns {Boolean}
3583
+ */
3584
+
3585
+ isCached: function( src ) {
3586
+ return !!this.cache[src];
3587
+ },
3588
+
3589
+ /**
3590
+ Loads an image and call the callback when ready.
3591
+ Will also add the image to cache.
3592
+
3593
+ @param {String} src The image source path, ex '/path/to/img.jpg'
3594
+ @param {Function} callback The function to be executed when the image is loaded & scaled
3595
+
3596
+ @returns {jQuery} The image container object
3597
+ */
3598
+
3599
+ load: function(src, callback) {
3600
+
3601
+ // save the instance
3602
+ var self = this;
3603
+
3604
+ $( this.container ).empty(true);
3605
+
3606
+ // add the image to cache and hide it
3607
+ this.image = this.add( src );
3608
+ Utils.hide( this.image );
3609
+
3610
+ // append the image into the container
3611
+ $( this.container ).append( this.image );
3612
+
3613
+ // check for loaded image using a timeout
3614
+ Utils.wait({
3615
+ until: function() {
3616
+ // TODO this should be properly tested in Opera
3617
+ return self.loaded && self.image.complete && self.image.width;
3618
+ },
3619
+ success: function() {
3620
+ // call success
3621
+ window.setTimeout(function() { callback.call( self, self ); }, 50 );
3622
+ },
3623
+ error: function() {
3624
+ window.setTimeout(function() { callback.call( self, self ); }, 50 );
3625
+ Galleria.raise('image not loaded in 10 seconds: '+ src);
3626
+ },
3627
+ timeout: 10000
3628
+ });
3629
+
3630
+ // return the container
3631
+ return this.container;
3632
+ },
3633
+
3634
+ /**
3635
+ Scales and crops the image
3636
+
3637
+ @param {Object} options The method takes an object with a number of options:
3638
+
3639
+ <ul>
3640
+ <li>width - width of the container</li>
3641
+ <li>height - height of the container</li>
3642
+ <li>min - minimum scale ratio</li>
3643
+ <li>max - maximum scale ratio</li>
3644
+ <li>margin - distance in pixels from the image border to the container</li>
3645
+ <li>complete - a callback that fires when scaling is complete</li>
3646
+ <li>position - positions the image, works like the css background-image property.</li>
3647
+ <li>crop - defines how to crop. Can be true, false, 'width' or 'height'</li>
3648
+ </ul>
3649
+
3650
+ @returns {jQuery} The image container object
3651
+ */
3652
+
3653
+ scale: function( options ) {
3654
+
3655
+ // extend some defaults
3656
+ options = $.extend({
3657
+ width: 0,
3658
+ height: 0,
3659
+ min: undef,
3660
+ max: undef,
3661
+ margin: 0,
3662
+ complete: function() {},
3663
+ position: 'center',
3664
+ crop: false
3665
+ }, options);
3666
+
3667
+ // return the element if no image found
3668
+ if (!this.image) {
3669
+ return this.container;
3670
+ }
3671
+
3672
+ // store locale variables of width & height
3673
+ var width,
3674
+ height,
3675
+ self = this,
3676
+ $container = $( self.container );
3677
+
3678
+ // wait for the width/height
3679
+ Utils.wait({
3680
+ until: function() {
3681
+
3682
+ width = options.width
3683
+ || $container.width()
3684
+ || Utils.parseValue( $container.css('width') );
3685
+
3686
+ height = options.height
3687
+ || $container.height()
3688
+ || Utils.parseValue( $container.css('height') );
3689
+
3690
+ return width && height;
3691
+ },
3692
+ success: function() {
3693
+ // calculate some cropping
3694
+ var newWidth = ( width - options.margin * 2 ) / self.original.width,
3695
+ newHeight = ( height - options.margin * 2 ) / self.original.height,
3696
+ cropMap = {
3697
+ 'true' : Math.max( newWidth, newHeight ),
3698
+ 'width' : newWidth,
3699
+ 'height': newHeight,
3700
+ 'false' : Math.min( newWidth, newHeight )
3701
+ },
3702
+ ratio = cropMap[ options.crop.toString() ];
3703
+
3704
+ // allow max_scale_ratio
3705
+ if ( options.max ) {
3706
+ ratio = Math.min( options.max, ratio );
3707
+ }
3708
+
3709
+ // allow min_scale_ratio
3710
+ if ( options.min ) {
3711
+ ratio = Math.max( options.min, ratio );
3712
+ }
3713
+
3714
+ $( self.container ).width( width ).height( height );
3715
+
3716
+ // round up the width / height
3717
+ $.each( ['width','height'], function( i, m ) {
3718
+ $( self.image )[ m ]( self[ m ] = Math.ceil( self.original[ m ] * ratio ) );
3719
+ });
3720
+
3721
+ // calculate image_position
3722
+ var pos = {},
3723
+ mix = {},
3724
+ getPosition = function(value, meassure, margin) {
3725
+ var result = 0;
3726
+ if (/\%/.test(value)) {
3727
+ var flt = parseInt(value) / 100;
3728
+ result = Math.ceil( $( self.image )[ meassure ]() * -1 * flt + margin * flt );
3729
+ } else {
3730
+ result = Utils.parseValue( value );
3731
+ }
3732
+ return result;
3733
+ },
3734
+ positionMap = {
3735
+ 'top': { top: 0 },
3736
+ 'left': { left: 0 },
3737
+ 'right': { left: '100%' },
3738
+ 'bottom': { top: '100%' }
3739
+ };
3740
+
3741
+ $.each( options.position.toLowerCase().split(' '), function( i, value ) {
3742
+ if ( value == 'center' ) {
3743
+ value = '50%';
3744
+ }
3745
+ pos[i ? 'top' : 'left'] = value;
3746
+ });
3747
+
3748
+ $.each( pos, function( i, value ) {
3749
+ if ( positionMap.hasOwnProperty( value ) ) {
3750
+ $.extend( mix, positionMap[ value ] );
3751
+ }
3752
+ });
3753
+
3754
+ pos = pos.top ? $.extend( pos, mix ) : mix;
3755
+
3756
+ pos = $.extend({
3757
+ top: '50%',
3758
+ left: '50%'
3759
+ }, pos);
3760
+
3761
+ // apply position
3762
+ $( self.image ).css({
3763
+ position : 'relative',
3764
+ top : getPosition(pos.top, 'height', height) - options.margin,
3765
+ left : getPosition(pos.left, 'width', width) - options.margin
3766
+ });
3767
+
3768
+ // show the image
3769
+ self.show();
3770
+
3771
+ // flag ready and call the callback
3772
+ self.ready = true;
3773
+ options.complete.call( self, self );
3774
+ },
3775
+ error: function() {
3776
+ Galleria.raise('Could not scale image: '+self.image.src);
3777
+ },
3778
+ timeout: 1000
3779
+ });
3780
+ return this;
3781
+ }
3782
+ };
3783
+
3784
+ // our own easings
3785
+ $.extend( $.easing, {
3786
+ galleria: function (_, t, b, c, d) {
3787
+ if ((t/=d/2) < 1) {
3788
+ return c/2*t*t*t*t + b;
3789
+ }
3790
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
3791
+ },
3792
+ galleriaIn: function (_, t, b, c, d) {
3793
+ return c*(t/=d)*t*t*t + b;
3794
+ },
3795
+ galleriaOut: function (_, t, b, c, d) {
3796
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
3797
+ }
3798
+ });
3799
+
3800
+ // the plugin initializer
3801
+ $.fn.galleria = function( options ) {
3802
+
3803
+ return this.each(function() {
3804
+
3805
+ var gallery = new Galleria();
3806
+ gallery.init( this, options );
3807
+
3808
+ });
3809
+ };
3810
+
3811
+ // expose Galleria
3812
+ window.Galleria = Galleria;
3813
+
3814
+ // phew
3815
+
3816
+ })( jQuery );