compass-jquery-plugin 0.3.2.7 → 0.3.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (317) hide show
  1. data/README.md +17 -11
  2. data/VERSION.yml +2 -2
  3. data/lib/handle_js_files.rb +1 -1
  4. data/lib/jquery/emulators.rb +13 -0
  5. data/templates/dynatree/jquery.dynatree.min.js +79 -81
  6. data/templates/emulators/config/initializers/emulators.rb +0 -9
  7. data/templates/emulators/emulators/{blackberry.landscape.scss → blackberry.torch.landscape.scss} +6 -2
  8. data/templates/emulators/emulators/{blackberry.portrait.scss → blackberry.torch.portrait.scss} +6 -1
  9. data/templates/emulators/emulators/galaxy.s.landscape.png +0 -0
  10. data/templates/emulators/emulators/galaxy.s.landscape.scss +20 -0
  11. data/templates/emulators/emulators/galaxy.s.portrait.png +0 -0
  12. data/templates/emulators/emulators/galaxy.s.portrait.scss +20 -0
  13. data/templates/emulators/emulators/galaxy.s2.landscape.png +0 -0
  14. data/templates/emulators/emulators/galaxy.s2.landscape.scss +20 -0
  15. data/templates/emulators/emulators/galaxy.s2.portrait.png +0 -0
  16. data/templates/emulators/emulators/galaxy.s2.portrait.scss +20 -0
  17. data/templates/emulators/emulators/galaxy.tab.10.1.landscape.png +0 -0
  18. data/templates/emulators/emulators/galaxy.tab.10.1.landscape.scss +20 -0
  19. data/templates/emulators/emulators/galaxy.tab.10.1.portrait.png +0 -0
  20. data/templates/emulators/emulators/galaxy.tab.10.1.portrait.scss +20 -0
  21. data/templates/emulators/emulators/galaxy.tab.7.landscape.png +0 -0
  22. data/templates/emulators/emulators/galaxy.tab.7.landscape.scss +20 -0
  23. data/templates/emulators/emulators/galaxy.tab.7.portrait.png +0 -0
  24. data/templates/emulators/emulators/galaxy.tab.7.portrait.scss +20 -0
  25. data/templates/emulators/emulators/galaxy.tab.8.9.landscape.png +0 -0
  26. data/templates/emulators/emulators/galaxy.tab.8.9.landscape.scss +20 -0
  27. data/templates/emulators/emulators/galaxy.tab.8.9.portrait.png +0 -0
  28. data/templates/emulators/emulators/galaxy.tab.8.9.portrait.scss +20 -0
  29. data/templates/emulators/emulators/ipad.landscape.png +0 -0
  30. data/templates/emulators/emulators/ipad.landscape.scss +9 -4
  31. data/templates/emulators/emulators/ipad.portrait.png +0 -0
  32. data/templates/emulators/emulators/ipad.portrait.scss +9 -4
  33. data/templates/emulators/emulators/{iphone.landscape.png → iphone.3.landscape.png} +0 -0
  34. data/templates/emulators/emulators/{iphone.landscape.scss → iphone.3.landscape.scss} +7 -3
  35. data/templates/emulators/emulators/{iphone.portrait.png → iphone.3.portrait.png} +0 -0
  36. data/templates/emulators/emulators/{iphone.portrait.scss → iphone.3.portrait.scss} +7 -3
  37. data/templates/emulators/emulators/iphone.4.landscape .scss +20 -0
  38. data/templates/emulators/emulators/iphone.4.landscape.png +0 -0
  39. data/templates/emulators/emulators/iphone.4.portrait.png +0 -0
  40. data/templates/emulators/emulators/iphone.4.portrait.scss +20 -0
  41. data/templates/emulators/emulators/{palm.pre.landscape.png → palm.pre.2.landscape.png} +0 -0
  42. data/templates/emulators/emulators/{palm.landscape.scss → palm.pre.2.landscape.scss} +7 -3
  43. data/templates/emulators/emulators/{palm.pre.portrait.png → palm.pre.2.portrait.png} +0 -0
  44. data/templates/emulators/emulators/{palm.portrait.scss → palm.pre.2.portrait.scss} +7 -3
  45. data/templates/emulators/manifest.rb +34 -10
  46. data/templates/graphics/config/initializers/graphics.rb +8 -0
  47. data/templates/graphics/highcharts/dark-blue.js +170 -0
  48. data/templates/graphics/highcharts/dark-blue.min.js +4 -0
  49. data/templates/graphics/highcharts/dark-green.js +170 -0
  50. data/templates/graphics/highcharts/dark-green.min.js +4 -0
  51. data/templates/graphics/highcharts/gray.js +164 -0
  52. data/templates/graphics/highcharts/gray.min.js +4 -0
  53. data/templates/graphics/highcharts/grid.js +97 -0
  54. data/templates/graphics/highcharts/grid.min.js +3 -0
  55. data/templates/graphics/highcharts/highslide-config.js +12 -0
  56. data/templates/graphics/highcharts/highslide-config.min.js +1 -0
  57. data/templates/graphics/highcharts/highslide-full.js +3391 -0
  58. data/templates/graphics/highcharts/highslide-full.min.js +132 -0
  59. data/templates/graphics/highcharts/skies.js +89 -0
  60. data/templates/graphics/highcharts/skies.min.js +3 -0
  61. data/templates/graphics/jquery.ganttView.js +1 -1
  62. data/templates/graphics/jquery.ganttView.min.js +61 -61
  63. data/templates/graphics/jquery.highcharts.js +11342 -0
  64. data/templates/graphics/jquery.highcharts.min.js +176 -0
  65. data/templates/graphics/jquery.sparkline.min.js +35 -36
  66. data/templates/graphics/jquery/highcharts/graphics/close.png +0 -0
  67. data/templates/graphics/jquery/highcharts/graphics/closeX.png +0 -0
  68. data/templates/graphics/jquery/highcharts/graphics/controlbar-black-border.gif +0 -0
  69. data/templates/graphics/jquery/highcharts/graphics/controlbar-text-buttons.png +0 -0
  70. data/templates/graphics/jquery/highcharts/graphics/controlbar-white-small.gif +0 -0
  71. data/templates/graphics/jquery/highcharts/graphics/controlbar-white.gif +0 -0
  72. data/templates/graphics/jquery/highcharts/graphics/controlbar2.gif +0 -0
  73. data/templates/graphics/jquery/highcharts/graphics/controlbar3.gif +0 -0
  74. data/templates/graphics/jquery/highcharts/graphics/controlbar4-hover.gif +0 -0
  75. data/templates/graphics/jquery/highcharts/graphics/controlbar4.gif +0 -0
  76. data/templates/graphics/jquery/highcharts/graphics/fullexpand.gif +0 -0
  77. data/templates/graphics/jquery/highcharts/graphics/geckodimmer.png +0 -0
  78. data/templates/graphics/jquery/highcharts/graphics/icon.gif +0 -0
  79. data/templates/graphics/jquery/highcharts/graphics/loader.gif +0 -0
  80. data/templates/graphics/jquery/highcharts/graphics/loader.white.gif +0 -0
  81. data/templates/graphics/jquery/highcharts/graphics/outlines/beveled.png +0 -0
  82. data/templates/graphics/jquery/highcharts/graphics/outlines/drop-shadow.png +0 -0
  83. data/templates/graphics/jquery/highcharts/graphics/outlines/glossy-dark.png +0 -0
  84. data/templates/graphics/jquery/highcharts/graphics/outlines/outer-glow.png +0 -0
  85. data/templates/graphics/jquery/highcharts/graphics/outlines/rounded-black.png +0 -0
  86. data/templates/graphics/jquery/highcharts/graphics/outlines/rounded-white.png +0 -0
  87. data/templates/graphics/jquery/highcharts/graphics/resize.gif +0 -0
  88. data/templates/graphics/jquery/highcharts/graphics/scrollarrows.png +0 -0
  89. data/templates/graphics/jquery/highcharts/graphics/zoomin.cur +0 -0
  90. data/templates/graphics/jquery/highcharts/graphics/zoomout.cur +0 -0
  91. data/templates/graphics/jquery/highcharts/skies.jpg +0 -0
  92. data/templates/graphics/jquery/highslide.scss +763 -0
  93. data/templates/graphics/manifest.rb +43 -0
  94. data/templates/ical/config/initializers/ical.rb +1 -0
  95. data/templates/ical/jquery.ical.js +8401 -8209
  96. data/templates/ical/jquery.ical.min.js +206 -208
  97. data/templates/ical/jquery/ical.print.scss +48 -0
  98. data/templates/ical/jquery/ical.scss +372 -343
  99. data/templates/ical/manifest.rb +1 -0
  100. data/templates/jqgrid/i18n/jqgrid/locale-ar.min.js +2 -2
  101. data/templates/jqgrid/i18n/jqgrid/locale-bg.min.js +1 -1
  102. data/templates/jqgrid/i18n/jqgrid/locale-bg1251.min.js +1 -1
  103. data/templates/jqgrid/i18n/jqgrid/locale-cat.min.js +1 -1
  104. data/templates/jqgrid/i18n/jqgrid/locale-cn.min.js +1 -1
  105. data/templates/jqgrid/i18n/jqgrid/locale-cs.min.js +1 -1
  106. data/templates/jqgrid/i18n/jqgrid/locale-da.min.js +1 -1
  107. data/templates/jqgrid/i18n/jqgrid/locale-de.min.js +1 -1
  108. data/templates/jqgrid/i18n/jqgrid/locale-el.min.js +2 -2
  109. data/templates/jqgrid/i18n/jqgrid/locale-en.min.js +1 -1
  110. data/templates/jqgrid/i18n/jqgrid/locale-es.min.js +2 -2
  111. data/templates/jqgrid/i18n/jqgrid/locale-fa.min.js +1 -1
  112. data/templates/jqgrid/i18n/jqgrid/locale-fi.min.js +1 -1
  113. data/templates/jqgrid/i18n/jqgrid/locale-fr.min.js +2 -2
  114. data/templates/jqgrid/i18n/jqgrid/locale-gl.min.js +2 -2
  115. data/templates/jqgrid/i18n/jqgrid/locale-he.min.js +1 -1
  116. data/templates/jqgrid/i18n/jqgrid/locale-hu.min.js +1 -1
  117. data/templates/jqgrid/i18n/jqgrid/locale-is.min.js +1 -1
  118. data/templates/jqgrid/i18n/jqgrid/locale-it.min.js +2 -2
  119. data/templates/jqgrid/i18n/jqgrid/locale-ja.min.js +1 -1
  120. data/templates/jqgrid/i18n/jqgrid/locale-lt.min.js +2 -2
  121. data/templates/jqgrid/i18n/jqgrid/locale-nl.min.js +1 -1
  122. data/templates/jqgrid/i18n/jqgrid/locale-no.min.js +1 -1
  123. data/templates/jqgrid/i18n/jqgrid/locale-pl.min.js +1 -1
  124. data/templates/jqgrid/i18n/jqgrid/locale-pt-br.min.js +1 -1
  125. data/templates/jqgrid/i18n/jqgrid/locale-pt.min.js +1 -1
  126. data/templates/jqgrid/i18n/jqgrid/locale-ro.min.js +1 -1
  127. data/templates/jqgrid/i18n/jqgrid/locale-ru.min.js +2 -2
  128. data/templates/jqgrid/i18n/jqgrid/locale-sk.min.js +1 -1
  129. data/templates/jqgrid/i18n/jqgrid/locale-sr.min.js +1 -1
  130. data/templates/jqgrid/i18n/jqgrid/locale-sv.min.js +1 -1
  131. data/templates/jqgrid/i18n/jqgrid/locale-tr.min.js +1 -1
  132. data/templates/jqgrid/i18n/jqgrid/locale-ua.min.js +2 -2
  133. data/templates/jqgrid/jquery.jqGrid.js +162 -850
  134. data/templates/jqgrid/jquery.jqGrid.min.js +476 -497
  135. data/templates/jqgrid/jquery/jqGrid.scss +0 -19
  136. data/templates/jquery/amplify.store.js +248 -0
  137. data/templates/jquery/amplify.store.min.js +6 -0
  138. data/templates/jquery/config/initializers/jquery.rb +5 -1
  139. data/templates/jquery/history.adapter.jquery.js +37 -43
  140. data/templates/jquery/history.adapter.jquery.min.js +1 -1
  141. data/templates/jquery/history.html4.js +596 -587
  142. data/templates/jquery/history.html4.min.js +8 -8
  143. data/templates/jquery/history.js +1839 -1669
  144. data/templates/jquery/history.min.js +27 -25
  145. data/templates/jquery/i18n/jquery.ui/datepicker-af.min.js +1 -1
  146. data/templates/jquery/i18n/jquery.ui/datepicker-ar-DZ.min.js +1 -1
  147. data/templates/jquery/i18n/jquery.ui/datepicker-ar.min.js +1 -1
  148. data/templates/jquery/i18n/jquery.ui/datepicker-az.min.js +1 -1
  149. data/templates/jquery/i18n/jquery.ui/datepicker-bg.min.js +1 -1
  150. data/templates/jquery/i18n/jquery.ui/datepicker-bs.min.js +1 -1
  151. data/templates/jquery/i18n/jquery.ui/datepicker-ca.min.js +1 -1
  152. data/templates/jquery/i18n/jquery.ui/datepicker-cs.min.js +1 -1
  153. data/templates/jquery/i18n/jquery.ui/datepicker-da.min.js +1 -1
  154. data/templates/jquery/i18n/jquery.ui/datepicker-de.min.js +1 -1
  155. data/templates/jquery/i18n/jquery.ui/datepicker-el.min.js +1 -1
  156. data/templates/jquery/i18n/jquery.ui/datepicker-en-AU.min.js +1 -1
  157. data/templates/jquery/i18n/jquery.ui/datepicker-en-GB.min.js +1 -1
  158. data/templates/jquery/i18n/jquery.ui/datepicker-en-NZ.min.js +1 -1
  159. data/templates/jquery/i18n/jquery.ui/datepicker-eo.min.js +1 -1
  160. data/templates/jquery/i18n/jquery.ui/datepicker-es.min.js +1 -1
  161. data/templates/jquery/i18n/jquery.ui/datepicker-et.min.js +1 -1
  162. data/templates/jquery/i18n/jquery.ui/datepicker-eu.min.js +1 -1
  163. data/templates/jquery/i18n/jquery.ui/datepicker-fa.min.js +2 -2
  164. data/templates/jquery/i18n/jquery.ui/datepicker-fi.min.js +1 -1
  165. data/templates/jquery/i18n/jquery.ui/datepicker-fo.min.js +1 -1
  166. data/templates/jquery/i18n/jquery.ui/datepicker-fr-CH.min.js +1 -1
  167. data/templates/jquery/i18n/jquery.ui/datepicker-fr.min.js +1 -1
  168. data/templates/jquery/i18n/jquery.ui/datepicker-gl.min.js +1 -1
  169. data/templates/jquery/i18n/jquery.ui/datepicker-he.min.js +1 -1
  170. data/templates/jquery/i18n/jquery.ui/datepicker-hr.min.js +1 -1
  171. data/templates/jquery/i18n/jquery.ui/datepicker-hu.min.js +1 -1
  172. data/templates/jquery/i18n/jquery.ui/datepicker-hy.min.js +1 -1
  173. data/templates/jquery/i18n/jquery.ui/datepicker-id.min.js +1 -1
  174. data/templates/jquery/i18n/jquery.ui/datepicker-is.min.js +1 -1
  175. data/templates/jquery/i18n/jquery.ui/datepicker-it.min.js +1 -1
  176. data/templates/jquery/i18n/jquery.ui/datepicker-ja.min.js +1 -1
  177. data/templates/jquery/i18n/jquery.ui/datepicker-ko.min.js +1 -1
  178. data/templates/jquery/i18n/jquery.ui/datepicker-kz.min.js +1 -1
  179. data/templates/jquery/i18n/jquery.ui/datepicker-lt.min.js +1 -1
  180. data/templates/jquery/i18n/jquery.ui/datepicker-lv.min.js +1 -1
  181. data/templates/jquery/i18n/jquery.ui/datepicker-ml.min.js +2 -2
  182. data/templates/jquery/i18n/jquery.ui/datepicker-ms.min.js +1 -1
  183. data/templates/jquery/i18n/jquery.ui/datepicker-nl.min.js +1 -1
  184. data/templates/jquery/i18n/jquery.ui/datepicker-no.min.js +1 -1
  185. data/templates/jquery/i18n/jquery.ui/datepicker-pl.min.js +1 -1
  186. data/templates/jquery/i18n/jquery.ui/datepicker-pt-BR.min.js +1 -1
  187. data/templates/jquery/i18n/jquery.ui/datepicker-pt.min.js +1 -1
  188. data/templates/jquery/i18n/jquery.ui/datepicker-rm.min.js +1 -1
  189. data/templates/jquery/i18n/jquery.ui/datepicker-ro.min.js +1 -1
  190. data/templates/jquery/i18n/jquery.ui/datepicker-ru.min.js +1 -1
  191. data/templates/jquery/i18n/jquery.ui/datepicker-sk.min.js +1 -1
  192. data/templates/jquery/i18n/jquery.ui/datepicker-sl.min.js +1 -1
  193. data/templates/jquery/i18n/jquery.ui/datepicker-sq.min.js +1 -1
  194. data/templates/jquery/i18n/jquery.ui/datepicker-sr-SR.min.js +1 -1
  195. data/templates/jquery/i18n/jquery.ui/datepicker-sr.min.js +1 -1
  196. data/templates/jquery/i18n/jquery.ui/datepicker-sv.min.js +1 -1
  197. data/templates/jquery/i18n/jquery.ui/datepicker-ta.min.js +1 -1
  198. data/templates/jquery/i18n/jquery.ui/datepicker-th.min.js +1 -1
  199. data/templates/jquery/i18n/jquery.ui/datepicker-tj.min.js +1 -1
  200. data/templates/jquery/i18n/jquery.ui/datepicker-tr.min.js +1 -1
  201. data/templates/jquery/i18n/jquery.ui/datepicker-uk.min.js +1 -1
  202. data/templates/jquery/i18n/jquery.ui/datepicker-vi.min.js +1 -1
  203. data/templates/jquery/i18n/jquery.ui/datepicker-zh-CN.min.js +1 -1
  204. data/templates/jquery/i18n/jquery.ui/datepicker-zh-HK.min.js +1 -1
  205. data/templates/jquery/i18n/jquery.ui/datepicker-zh-TW.min.js +1 -1
  206. data/templates/jquery/jquery-ui.js +217 -104
  207. data/templates/jquery/jquery-ui.min.js +437 -436
  208. data/templates/jquery/jquery.bgiframe.min.js +1 -1
  209. data/templates/jquery/jquery.contextMenu.min.js +7 -7
  210. data/templates/jquery/jquery.cookie.js +60 -58
  211. data/templates/jquery/jquery.cookie.min.js +1 -1
  212. data/templates/jquery/jquery.dotimeout.min.js +2 -2
  213. data/templates/jquery/jquery.dst.min.js +4 -4
  214. data/templates/jquery/jquery.farbtastic.min.js +10 -10
  215. data/templates/jquery/jquery.form.js +15 -5
  216. data/templates/jquery/jquery.form.min.js +20 -20
  217. data/templates/jquery/jquery.haml.min.js +5 -5
  218. data/templates/jquery/jquery.hotkeys.min.js +3 -3
  219. data/templates/jquery/jquery.js +8205 -8170
  220. data/templates/jquery/jquery.layout.min.js +48 -50
  221. data/templates/jquery/jquery.min.js +166 -167
  222. data/templates/jquery/jquery.mousewheel.min.js +2 -2
  223. data/templates/jquery/jquery.offline.min.js +4 -4
  224. data/templates/jquery/jquery.pngFix.js +28 -30
  225. data/templates/jquery/jquery.pngFix.min.js +5 -5
  226. data/templates/jquery/jquery.rails.js +166 -0
  227. data/templates/jquery/jquery.rails.min.js +6 -0
  228. data/templates/jquery/jquery.replacetext.min.js +1 -1
  229. data/templates/jquery/jquery.themeswitchertool.min.js +4 -4
  230. data/templates/jquery/jquery.tmpl.js +14 -12
  231. data/templates/jquery/jquery.tmpl.min.js +12 -12
  232. data/templates/jquery/jquery.tmplPlus.js +2 -2
  233. data/templates/jquery/jquery.tmplPlus.min.js +3 -3
  234. data/templates/jquery/jquery.tokeninput.js +729 -0
  235. data/templates/jquery/jquery.tokeninput.min.js +14 -0
  236. data/templates/jquery/jquery/ui/_theme.scss +23 -16
  237. data/templates/jquery/jquery/ui/black-tie/ui-icons_4ca300_256x240.png +0 -0
  238. data/templates/jquery/jquery/ui/black-tie/ui-icons_bbbbbb_256x240.png +0 -0
  239. data/templates/jquery/jquery/ui/black-tie/ui-icons_ededed_256x240.png +0 -0
  240. data/templates/jquery/jquery/ui/black-tie/ui-icons_ffcf29_256x240.png +0 -0
  241. data/templates/jquery/jquery/ui/tokeninput.facebook.scss +95 -0
  242. data/templates/jquery/jquery/ui/tokeninput.mac.scss +164 -0
  243. data/templates/jquery/jquery/ui/tokeninput.scss +85 -0
  244. data/templates/jquery/jquery/ui/vader/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  245. data/templates/jquery/jquery/ui/vader/ui-icons_bbbbbb_256x240.png +0 -0
  246. data/templates/jquery/jquery/ui/vader/ui-icons_c98000_256x240.png +0 -0
  247. data/templates/jquery/jquery/ui/vader/ui-icons_f29a00_256x240.png +0 -0
  248. data/templates/jquery/json.min.js +6 -6
  249. data/templates/jquery/json2.js +214 -214
  250. data/templates/jquery/json2.min.js +5 -6
  251. data/templates/jquery/manifest.rb +9 -2
  252. data/templates/jstree/jquery.jstree.min.js +222 -224
  253. data/templates/mobile/config/initializers/mobile.rb +1 -1
  254. data/templates/mobile/jquery.mobile.js +887 -404
  255. data/templates/mobile/jquery.mobile.min.js +4 -4
  256. data/templates/mobile/jquery/mobile/_base.scss +50 -26
  257. data/templates/mobile/jquery/mobile/default.scss +59 -63
  258. data/templates/mobile/jquery/mobile/valencia.scss +44 -42
  259. data/templates/ribbon/jquery.ribbon.min.js +14 -14
  260. data/templates/tiny_mce/manifest.rb +4 -0
  261. data/templates/tiny_mce/tiny_mce/langs/de.js +1 -1
  262. data/templates/tiny_mce/tiny_mce/langs/en.js +1 -1
  263. data/templates/tiny_mce/tiny_mce/plugins/advimage/js/image.js +1 -1
  264. data/templates/tiny_mce/tiny_mce/plugins/advimage/langs/de_dlg.js +1 -1
  265. data/templates/tiny_mce/tiny_mce/plugins/advlink/js/advlink.js +1 -1
  266. data/templates/tiny_mce/tiny_mce/plugins/advlink/langs/en_dlg.js +1 -1
  267. data/templates/tiny_mce/tiny_mce/plugins/advlink/link.htm +1 -1
  268. data/templates/tiny_mce/tiny_mce/plugins/advlist/editor_plugin.js +1 -1
  269. data/templates/tiny_mce/tiny_mce/plugins/advlist/editor_plugin_src.js +1 -1
  270. data/templates/tiny_mce/tiny_mce/plugins/autolink/editor_plugin.js +1 -0
  271. data/templates/tiny_mce/tiny_mce/plugins/autolink/editor_plugin_src.js +1 -0
  272. data/templates/tiny_mce/tiny_mce/plugins/autoresize/editor_plugin.js +1 -1
  273. data/templates/tiny_mce/tiny_mce/plugins/autoresize/editor_plugin_src.js +1 -1
  274. data/templates/tiny_mce/tiny_mce/plugins/contextmenu/editor_plugin.js +1 -1
  275. data/templates/tiny_mce/tiny_mce/plugins/contextmenu/editor_plugin_src.js +1 -1
  276. data/templates/tiny_mce/tiny_mce/plugins/fullpage/css/fullpage.css +1 -1
  277. data/templates/tiny_mce/tiny_mce/plugins/fullpage/editor_plugin.js +1 -1
  278. data/templates/tiny_mce/tiny_mce/plugins/fullpage/editor_plugin_src.js +1 -1
  279. data/templates/tiny_mce/tiny_mce/plugins/fullpage/fullpage.htm +1 -1
  280. data/templates/tiny_mce/tiny_mce/plugins/fullpage/js/fullpage.js +1 -1
  281. data/templates/tiny_mce/tiny_mce/plugins/legacyoutput/editor_plugin.js +1 -1
  282. data/templates/tiny_mce/tiny_mce/plugins/legacyoutput/editor_plugin_src.js +1 -1
  283. data/templates/tiny_mce/tiny_mce/plugins/lists/editor_plugin.js +1 -0
  284. data/templates/tiny_mce/tiny_mce/plugins/lists/editor_plugin_src.js +1 -0
  285. data/templates/tiny_mce/tiny_mce/plugins/media/js/media.js +1 -1
  286. data/templates/tiny_mce/tiny_mce/plugins/media/media.htm +1 -1
  287. data/templates/tiny_mce/tiny_mce/plugins/noneditable/editor_plugin.js +1 -1
  288. data/templates/tiny_mce/tiny_mce/plugins/noneditable/editor_plugin_src.js +1 -1
  289. data/templates/tiny_mce/tiny_mce/plugins/paste/editor_plugin.js +1 -1
  290. data/templates/tiny_mce/tiny_mce/plugins/paste/editor_plugin_src.js +1 -1
  291. data/templates/tiny_mce/tiny_mce/plugins/searchreplace/js/searchreplace.js +1 -1
  292. data/templates/tiny_mce/tiny_mce/plugins/spellchecker/editor_plugin.js +1 -1
  293. data/templates/tiny_mce/tiny_mce/plugins/spellchecker/editor_plugin_src.js +1 -1
  294. data/templates/tiny_mce/tiny_mce/plugins/table/editor_plugin.js +1 -1
  295. data/templates/tiny_mce/tiny_mce/plugins/table/editor_plugin_src.js +1 -1
  296. data/templates/tiny_mce/tiny_mce/plugins/xhtmlxtras/editor_plugin.js +1 -1
  297. data/templates/tiny_mce/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js +1 -1
  298. data/templates/tiny_mce/tiny_mce/plugins/xhtmlxtras/js/attributes.js +1 -1
  299. data/templates/tiny_mce/tiny_mce/themes/advanced/editor_template.js +1 -1
  300. data/templates/tiny_mce/tiny_mce/themes/advanced/editor_template_src.js +1 -1
  301. data/templates/tiny_mce/tiny_mce/themes/advanced/js/charmap.js +1 -1
  302. data/templates/tiny_mce/tiny_mce/themes/advanced/langs/de_dlg.js +1 -1
  303. data/templates/tiny_mce/tiny_mce/themes/advanced/langs/en_dlg.js +1 -1
  304. data/templates/tiny_mce/tiny_mce/themes/advanced/skins/default/ui.css +1 -1
  305. data/templates/tiny_mce/tiny_mce/themes/advanced/skins/o2k7/dialog.css +1 -1
  306. data/templates/tiny_mce/tiny_mce/themes/advanced/skins/o2k7/ui.css +1 -1
  307. data/templates/tiny_mce/tiny_mce/themes/advanced/skins/o2k7/ui_black.css +1 -1
  308. data/templates/tiny_mce/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css +1 -1
  309. data/templates/tiny_mce/tiny_mce/tiny_mce.js +1 -1
  310. data/templates/tiny_mce/tiny_mce/utils/form_utils.js +1 -1
  311. data/templates/tiny_mce/tiny_mce/utils/validate.js +1 -1
  312. data/templates/tools/flowplayer.min.js +29 -30
  313. data/templates/tools/jquery.tools.min.js +96 -96
  314. data/templates/tools/swfobject.min.js +18 -19
  315. metadata +95 -16
  316. data/templates/jquery/jrails.js +0 -200
  317. data/templates/jquery/jrails.min.js +0 -8
@@ -1,11 +1,11 @@
1
1
  /*
2
2
  New BSD License <http://creativecommons.org/licenses/BSD/>
3
3
  */
4
- (function(h){var i=h.document,a=h.History=h.History||{};if(typeof a.initHtml4!=="undefined")throw Error("History.js HTML4 Support has already been loaded...");a.initHtml4=function(){if(typeof a.initHtml4.initialized!=="undefined")return false;else a.initHtml4.initialized=true;a.savedHashes=[];a.isLastHash=function(b){var c=a.getHashByIndex();return b===c};a.saveHash=function(b){if(a.isLastHash(b))return false;a.savedHashes.push(b);return true};a.getHashByIndex=function(b){var c=null;return c=typeof b===
5
- "undefined"?a.savedHashes[a.savedHashes.length-1]:b<0?a.savedHashes[a.savedHashes.length+b]:a.savedHashes[b]};a.discardedHashes={};a.discardedStates={};a.discardState=function(b,c,e){var f=a.getHashByState(b);a.discardedStates[f]={discardedState:b,backState:e,forwardState:c};return true};a.discardHash=function(b,c,e){a.discardedHashes[b]={discardedHash:b,backState:e,forwardState:c};return true};a.discardedState=function(b){b=a.getHashByState(b);return a.discardedStates[b]||false};a.discardedHash=
6
- function(b){return a.discardedHashes[b]||false};a.recycleState=function(b){var c=a.getHashByState(b);a.discardedState(b)&&delete a.discardedStates[c];return true};if(a.emulated.hashChange){a.hashChangeInit=function(){a.checkerFunction=null;var b="";if(a.isInternetExplorer()){var c=i.createElement("iframe");c.setAttribute("id","historyjs-iframe");c.style.display="none";i.body.appendChild(c);c.contentWindow.document.open();c.contentWindow.document.close();var e="",f=false;a.checkerFunction=function(){if(f)return false;
7
- f=true;var d=a.getHash()||"",g=a.unescapeHash(c.contentWindow.document.location.hash)||"";if(d!==b){b=d;if(g!==d){e=d;c.contentWindow.document.open();c.contentWindow.document.close();c.contentWindow.document.location.hash=a.escapeHash(d)}a.Adapter.trigger(h,"hashchange")}else if(g!==e){e=g;a.setHash(g,false)}f=false;return true}}else a.checkerFunction=function(){var d=a.getHash();if(d!==b){b=d;a.Adapter.trigger(h,"hashchange")}return true};setInterval(a.checkerFunction,a.options.hashChangeInterval);
8
- return true};a.Adapter.onDomLoad(a.hashChangeInit)}if(a.emulated.pushState){a.onHashChange=function(b){var c=a.getHashByUrl(b&&b.newURL||i.location.href);b=null;if(a.isLastHash(c)){a.busy(false);return false}a.doubleCheckComplete();a.saveHash(c);b=a.extractState(c||i.location.href);if(!b){a.Adapter.trigger(h,"anchorchange");a.busy(false);return false}if(a.isLastSavedState(b)){a.busy(false);return false}a.getHashByState(b);if(c=a.discardedState(b)){a.getHashByIndex(-2)===a.getHashByState(c.forwardState)?
9
- a.back(false):a.forward(false);a.busy(false);return false}a.pushState(b.data,b.title,b.url,false);return true};a.Adapter.bind(h,"hashchange",a.onHashChange);a.pushState=function(b,c,e,f){if(a.getHashByUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==false&&a.busy()){a.pushQueue({scope:a,callback:a.pushState,args:arguments,queue:f});return false}a.busy(true);var d=a.createStateObject(b,c,e),g=a.getHashByState(d),j=a.getState(false);j=a.getHashByState(j);
10
- var k=a.getHash();a.storeState(d);a.expectedStateId=d.id;a.recycleState(d);a.setTitle(d);if(g===j){a.busy(false);return false}if(g!==k&&g!==a.getShortUrl(i.location.href)){a.setHash(g,false);return false}a.saveState(d);a.Adapter.trigger(h,"statechange");a.busy(false);return true};a.replaceState=function(b,c,e,f){if(a.getHashByUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(f!==false&&a.busy()){a.pushQueue({scope:a,callback:a.replaceState,args:arguments,
11
- queue:f});return false}a.busy(true);var d=a.createStateObject(b,c,e),g=a.getState(false),j=a.getStateByIndex(-2);a.discardState(g,d,j);a.pushState(d.data,d.title,d.url,false);return true};a.saveState(a.storeState(a.createStateObject({},"",i.location.href)));a.getHash()&&!a.emulated.hashChange&&a.Adapter.onDomLoad(function(){a.Adapter.trigger(h,"hashchange")})}};a.init()})(window);
4
+ (function(f){var i=f.document,j=f.setInterval||j,a=f.History=f.History||{};if(typeof a.initHtml4!=="undefined")throw Error("History.js HTML4 Support has already been loaded...");a.initHtml4=function(){if(typeof a.initHtml4.initialized!=="undefined")return!1;else a.initHtml4.initialized=!0;a.enabled=!0;a.savedHashes=[];a.isLastHash=function(b){var c=a.getHashByIndex();return b===c};a.saveHash=function(b){if(a.isLastHash(b))return!1;a.savedHashes.push(b);return!0};a.getHashByIndex=function(b){var c=
5
+ null;return c=typeof b==="undefined"?a.savedHashes[a.savedHashes.length-1]:b<0?a.savedHashes[a.savedHashes.length+b]:a.savedHashes[b]};a.discardedHashes={};a.discardedStates={};a.discardState=function(b,c,e){var g=a.getHashByState(b);a.discardedStates[g]={discardedState:b,backState:e,forwardState:c};return!0};a.discardHash=function(b,c,e){a.discardedHashes[b]={discardedHash:b,backState:e,forwardState:c};return!0};a.discardedState=function(b){b=a.getHashByState(b);return a.discardedStates[b]||!1};
6
+ a.discardedHash=function(b){return a.discardedHashes[b]||!1};a.recycleState=function(b){var c=a.getHashByState(b);a.discardedState(b)&&delete a.discardedStates[c];return!0};if(a.emulated.hashChange)a.hashChangeInit=function(){a.checkerFunction=null;var b="";if(a.isInternetExplorer()){var c=i.createElement("iframe");c.setAttribute("id","historyjs-iframe");c.style.display="none";i.body.appendChild(c);c.contentWindow.document.open();c.contentWindow.document.close();var e="",g=!1;a.checkerFunction=function(){if(g)return!1;
7
+ g=!0;var d=a.getHash()||"",h=a.unescapeHash(c.contentWindow.document.location.hash)||"";if(d!==b){b=d;if(h!==d)e=d,c.contentWindow.document.open(),c.contentWindow.document.close(),c.contentWindow.document.location.hash=a.escapeHash(d);a.Adapter.trigger(f,"hashchange")}else h!==e&&(e=h,a.setHash(h,!1));g=!1;return!0}}else a.checkerFunction=function(){var c=a.getHash();c!==b&&(b=c,a.Adapter.trigger(f,"hashchange"));return!0};j(a.checkerFunction,a.options.hashChangeInterval);return!0},a.Adapter.onDomLoad(a.hashChangeInit);
8
+ if(a.emulated.pushState&&(a.onHashChange=function(b){var c=a.getHashByUrl(b&&b.newURL||i.location.href),b=null;if(a.isLastHash(c))return a.busy(!1),!1;a.doubleCheckComplete();a.saveHash(c);if(c&&a.isTraditionalAnchor(c))return a.Adapter.trigger(f,"anchorchange"),a.busy(!1),!1;b=a.extractState(a.getFullUrl(c||i.location.href,!1),!0);if(a.isLastSavedState(b))return a.busy(!1),!1;a.getHashByState(b);if(c=a.discardedState(b))return a.getHashByIndex(-2)===a.getHashByState(c.forwardState)?a.back(!1):a.forward(!1),
9
+ !1;a.pushState(b.data,b.title,b.url,!1);return!0},a.Adapter.bind(f,"hashchange",a.onHashChange),a.pushState=function(b,c,e,g){if(a.getHashByUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(g!==!1&&a.busy())return a.pushQueue({scope:a,callback:a.pushState,args:arguments,queue:g}),!1;a.busy(!0);var d=a.createStateObject(b,c,e),h=a.getHashByState(d),k=a.getState(!1),k=a.getHashByState(k),j=a.getHash();a.storeState(d);a.expectedStateId=d.id;a.recycleState(d);
10
+ a.setTitle(d);if(h===k)return a.busy(!1),!1;if(h!==j&&h!==a.getShortUrl(i.location.href))return a.setHash(h,!1),!1;a.saveState(d);a.Adapter.trigger(f,"statechange");a.busy(!1);return!0},a.replaceState=function(b,c,e,g){if(a.getHashByUrl(e))throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(g!==!1&&a.busy())return a.pushQueue({scope:a,callback:a.replaceState,args:arguments,queue:g}),!1;a.busy(!0);var d=a.createStateObject(b,c,e),h=a.getState(!1),f=a.getStateByIndex(-2);
11
+ a.discardState(h,d,f);a.pushState(d.data,d.title,d.url,!1);return!0},a.getHash()&&!a.emulated.hashChange))a.Adapter.onDomLoad(function(){a.Adapter.trigger(f,"hashchange")})};a.init()})(window);
@@ -5,1674 +5,1844 @@
5
5
  * @license New BSD License <http://creativecommons.org/licenses/BSD/>
6
6
  */
7
7
 
8
- (function(window,undefined){
9
- "use strict";
10
-
11
- // --------------------------------------------------------------------------
12
- // Initialise
13
-
14
- // Localise Globals
15
- var
16
- console = window.console||undefined, // Prevent a JSLint complain
17
- document = window.document, // Make sure we are using the correct document
18
- navigator = window.navigator, // Make sure we are using the correct navigator
19
- History = window.History = window.History||{}, // Public History Object
20
- history = window.history; // Old History Object
21
-
22
- // Check Existence
23
- if ( typeof History.init !== 'undefined' ) {
24
- throw new Error('History.js Core has already been loaded...');
25
- }
26
-
27
- // Initialise History
28
- History.init = function(){
29
- // Check Load Status of Adapter
30
- if ( typeof History.Adapter === 'undefined' ) {
31
- return false;
32
- }
33
-
34
- // Check Load Status of Core
35
- if ( typeof History.initCore !== 'undefined' ) {
36
- History.initCore();
37
- }
38
-
39
- // Check Load Status of HTML4 Support
40
- if ( typeof History.initHtml4 !== 'undefined' ) {
41
- History.initHtml4();
42
- }
43
-
44
- // Return true
45
- return true;
46
- };
47
-
48
- // --------------------------------------------------------------------------
49
- // Initialise Core
50
-
51
- // Initialise Core
52
- History.initCore = function(){
53
- // Initialise
54
- if ( typeof History.initCore.initialized !== 'undefined' ) {
55
- // Already Loaded
56
- return false;
57
- }
58
- else {
59
- History.initCore.initialized = true;
60
- }
61
-
62
- // ----------------------------------------------------------------------
63
- // Options
64
-
65
- /**
66
- * History.options
67
- * Configurable options
68
- */
69
- History.options = History.options||{};
70
-
71
- /**
72
- * History.options.hashChangeInterval
73
- * How long should the interval be before hashchange checks
74
- */
75
- History.options.hashChangeInterval = History.options.hashChangeInterval || 100;
76
-
77
- /**
78
- * History.options.safariPollInterval
79
- * How long should the interval be before safari poll checks
80
- */
81
- History.options.safariPollInterval = History.options.safariPollInterval || 500;
82
-
83
- /**
84
- * History.options.doubleCheckInterval
85
- * How long should the interval be before we perform a double check
86
- */
87
- History.options.doubleCheckInterval = History.options.doubleCheckInterval || 500;
88
-
89
- /**
90
- * History.options.busyDelay
91
- * How long should we wait between busy events
92
- */
93
- History.options.busyDelay = History.options.busyDelay || 250;
94
-
95
- /**
96
- * History.options.debug
97
- * If true will enable debug messages to be logged
98
- */
99
- History.options.debug = History.options.debug || false;
100
-
101
- /**
102
- * History.options.initialTitle
103
- * What is the title of the initial state
104
- */
105
- History.options.initialTitle = History.options.initialTitle || document.title;
106
-
107
-
108
- // ----------------------------------------------------------------------
109
- // Debug
110
-
111
- /**
112
- * History.debug(message,...)
113
- * Logs the passed arguments if debug enabled
114
- */
115
- History.debug = function(){
116
- if ( (History.options.debug||false) ) {
117
- History.log.apply(History,arguments);
118
- }
119
- };
120
-
121
- /**
122
- * History.log(message,...)
123
- * Logs the passed arguments
124
- */
125
- History.log = function(){
126
- // Prepare
127
- var
128
- consoleExists = (typeof console !== 'undefined' && typeof console.log !== 'undefined' && typeof console.log.apply !== 'undefined'),
129
- textarea = document.getElementById('log'),
130
- message,
131
- i,n
132
- ;
133
-
134
- // Write to Console
135
- if ( consoleExists ) {
136
- var args = Array.prototype.slice.call(arguments);
137
- message = args.shift();
138
- if ( typeof console.debug !== 'undefined' ) {
139
- console.debug.apply(console,[message,args]);
140
- }
141
- else {
142
- console.log.apply(console,[message,args]);
143
- }
144
- }
145
- else {
146
- message = ("\n"+arguments[0]+"\n");
147
- }
148
-
149
- // Write to log
150
- for ( i=1,n=arguments.length; i<n; ++i ) {
151
- var arg = arguments[i];
152
- if ( typeof arg === 'object' && typeof JSON !== 'undefined' ) {
153
- try {
154
- arg = JSON.stringify(arg);
155
- }
156
- catch ( Exception ) {
157
- // Recursive Object
158
- }
159
- }
160
- message += "\n"+arg+"\n";
161
- }
162
-
163
- // Textarea
164
- if ( textarea ) {
165
- textarea.value += message+"\n-----\n";
166
- textarea.scrollTop = textarea.scrollHeight - textarea.clientHeight;
167
- }
168
- // No Textarea, No Console
169
- else if ( !consoleExists ) {
170
- alert(message);
171
- }
172
-
173
- // Return true
174
- return true;
175
- };
176
-
177
- // ----------------------------------------------------------------------
178
- // Emulated Status
179
-
180
- /**
181
- * History.getInternetExplorerMajorVersion()
182
- * Get's the major version of Internet Explorer
183
- * @return {integer}
184
- * @license Public Domain
185
- * @author Benjamin Arthur Lupton <contact@balupton.com>
186
- * @author James Padolsey <https://gist.github.com/527683>
187
- */
188
- History.getInternetExplorerMajorVersion = function(){
189
- var result = History.getInternetExplorerMajorVersion.cached =
190
- (typeof History.getInternetExplorerMajorVersion.cached !== 'undefined')
191
- ? History.getInternetExplorerMajorVersion.cached
192
- : (function(){
193
- var v = 3,
194
- div = document.createElement('div'),
195
- all = div.getElementsByTagName('i');
196
- while ( (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->') && all[0] ) {}
197
- return (v > 4) ? v : false;
198
- })()
199
- ;
200
- return result;
201
- };
202
-
203
- /**
204
- * History.isInternetExplorer()
205
- * Are we using Internet Explorer?
206
- * @return {boolean}
207
- * @license Public Domain
208
- * @author Benjamin Arthur Lupton <contact@balupton.com>
209
- */
210
- History.isInternetExplorer = function(){
211
- var result =
212
- History.isInternetExplorer.cached =
213
- (typeof History.isInternetExplorer.cached !== 'undefined')
214
- ? History.isInternetExplorer.cached
215
- : Boolean(History.getInternetExplorerMajorVersion())
216
- ;
217
- return result;
218
- };
219
-
220
- /**
221
- * History.emulated
222
- * Which features require emulating?
223
- */
224
- History.emulated = {
225
- pushState: !Boolean(
226
- window.history && window.history.pushState && window.history.replaceState
227
- && !(/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent) /* disable for versions of iOS before version 4.3 (8F190) */
228
- ),
229
- hashChange: Boolean(
230
- !(('onhashchange' in window) || ('onhashchange' in document))
231
- ||
232
- (History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8)
233
- )
234
- };
235
-
236
- /**
237
- * History.bugs
238
- * Which bugs are present
239
- */
240
- History.bugs = {
241
- /**
242
- * Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call
243
- * https://bugs.webkit.org/show_bug.cgi?id=56249
244
- */
245
- setHash: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2][0-9]|3[0-3])/.test(navigator.userAgent)),
246
-
247
- /**
248
- * Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions
249
- * https://bugs.webkit.org/show_bug.cgi?id=42940
250
- */
251
- safariPoll: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2][0-9]|3[0-3])/.test(navigator.userAgent)),
252
-
253
- /**
254
- * MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)
255
- */
256
- ieDoubleCheck: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8),
257
-
258
- /**
259
- * MSIE 6 requires the entire hash to be encoded for the hashes to trigger the onHashChange event
260
- */
261
- hashEscape: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 7)
262
- };
263
-
264
- /**
265
- * History.isEmptyObject(obj)
266
- * Checks to see if the Object is Empty
267
- * @param {Object} obj
268
- * @return {boolean}
269
- */
270
- History.isEmptyObject = function(obj) {
271
- for ( var name in obj ) {
272
- return false;
273
- }
274
- return true;
275
- };
276
-
277
- /**
278
- * History.cloneObject(obj)
279
- * Clones a object
280
- * @param {Object} obj
281
- * @return {Object}
282
- */
283
- History.cloneObject = function(obj) {
284
- var hash,newObj;
285
- if ( obj ) {
286
- hash = JSON.stringify(obj);
287
- newObj = JSON.parse(hash);
288
- }
289
- else {
290
- newObj = {};
291
- }
292
- return newObj;
293
- };
294
-
295
- // ----------------------------------------------------------------------
296
- // URL Helpers
297
-
298
- /**
299
- * History.getRootUrl()
300
- * Turns "http://mysite.com/dir/page.html?asd" into "http://mysite.com"
301
- * @return {String} rootUrl
302
- */
303
- History.getRootUrl = function(){
304
- // Create
305
- var rootUrl = document.location.protocol+'//'+(document.location.hostname||document.location.host);
306
- if ( document.location.port||false ) {
307
- rootUrl += ':'+document.location.port;
308
- }
309
- rootUrl += '/';
310
-
311
- // Return
312
- return rootUrl;
313
- };
314
-
315
- /**
316
- * History.getBaseHref()
317
- * Fetches the `href` attribute of the `<base href="...">` element if it exists
318
- * @return {String} baseHref
319
- */
320
- History.getBaseHref = function(){
321
- // Create
322
- var
323
- baseElements = document.getElementsByTagName('base'),
324
- baseElement = null,
325
- baseHref = '';
326
-
327
- // Test for Base Element
328
- if ( baseElements.length === 1 ) {
329
- // Prepare for Base Element
330
- baseElement = baseElements[0];
331
- baseHref = baseElement.href.replace(/[^\/]+$/,'');
332
- }
333
-
334
- // Adjust trailing slash
335
- baseHref = baseHref.replace(/\/+$/,'');
336
- if ( baseHref ) baseHref += '/';
337
-
338
- // Return
339
- return baseHref;
340
- };
341
-
342
- /**
343
- * History.getBaseUrl()
344
- * Fetches the baseHref or basePageUrl or rootUrl (whichever one exists first)
345
- * @return {String} baseUrl
346
- */
347
- History.getBaseUrl = function(){
348
- // Create
349
- var baseUrl = History.getBaseHref()||History.getBasePageUrl()||History.getRootUrl();
350
-
351
- // Return
352
- return baseUrl;
353
- };
354
-
355
- /**
356
- * History.getPageUrl()
357
- * Fetches the URL of the current page
358
- * @return {String} pageUrl
359
- */
360
- History.getPageUrl = function(){
361
- // Fetch
362
- var
363
- State = History.getState(),
364
- stateUrl = State.url||document.location.href;
365
-
366
- // Create
367
- var pageUrl = stateUrl.replace(/\/+$/,'').replace(/[^\/]+$/,function(part,index,string){
368
- return (/\./).test(part) ? part : part+'/';
369
- });
370
-
371
- // Return
372
- return pageUrl;
373
- };
374
-
375
- /**
376
- * History.getBasePageUrl()
377
- * Fetches the Url of the directory of the current page
378
- * @return {String} basePageUrl
379
- */
380
- History.getBasePageUrl = function(){
381
- // Create
382
- var basePageUrl = document.location.href.replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
383
- return (/\./).test(part) ? '' : part;
384
- }).replace(/\/+$/,'')+'/';
385
-
386
- // Return
387
- return basePageUrl;
388
- };
389
-
390
- /**
391
- * History.getFullUrl(url)
392
- * Ensures that we have an absolute URL and not a relative URL
393
- * @param {string} url
394
- * @return {string} fullUrl
395
- */
396
- History.getFullUrl = function(url){
397
- // Prepare
398
- var fullUrl = url, firstChar = url.substring(0,1);
399
-
400
- // Check
401
- if ( /[a-z]+\:\/\//.test(url) ) {
402
- // Full URL
403
- }
404
- else if ( firstChar === '/' ) {
405
- // Root URL
406
- fullUrl = History.getRootUrl()+url.replace(/^\/+/,'');
407
- }
408
- else if ( firstChar === '#' ) {
409
- // Anchor URL
410
- fullUrl = History.getPageUrl().replace(/#.*/,'')+url;
411
- }
412
- else if ( firstChar === '?' ) {
413
- // Query URL
414
- fullUrl = History.getPageUrl().replace(/[\?#].*/,'')+url;
415
- }
416
- else {
417
- // Relative URL
418
- fullUrl = History.getBaseUrl()+url;
419
- }
420
-
421
- // Return
422
- return fullUrl.replace(/\#$/,'');
423
- };
424
-
425
- /**
426
- * History.getShortUrl(url)
427
- * Ensures that we have a relative URL and not a absolute URL
428
- * @param {string} url
429
- * @return {string} url
430
- */
431
- History.getShortUrl = function(url){
432
- // Prepare
433
- var shortUrl, rootUrl = History.getRootUrl(); // History.getBaseHref()||History.getBasePageUrl()
434
-
435
- // Adjust
436
- shortUrl = url.replace(rootUrl,'/');
437
-
438
- // Return
439
- return shortUrl.replace(/\#$/,'');
440
- };
441
-
442
- // ----------------------------------------------------------------------
443
- // State Storage
444
-
445
- /**
446
- * History.idToState
447
- * 1-1: State ID to State Object
448
- */
449
- History.idToState = {};
450
-
451
- /**
452
- * History.stateToId
453
- * 1-1: State String to State ID
454
- */
455
- History.stateToId = {};
456
-
457
- /**
458
- * History.urlToId
459
- * 1-1: State URL to State ID
460
- */
461
- History.urlToId = {};
462
-
463
- /**
464
- * History.storedStates
465
- * Store the states in an array
466
- */
467
- History.storedStates = [];
468
-
469
- /**
470
- * History.savedStates
471
- * Saved the states in an array
472
- */
473
- History.savedStates = [];
474
-
475
- /**
476
- * History.getState()
477
- * Get an object containing the data, title and url of the current state
478
- * @return {Object} State
479
- */
480
- History.getState = function(friendly){
481
- // Prepare
482
- if ( typeof friendly === 'undefined' ) { friendly = true; }
483
-
484
- // Fetch
485
- var State = History.getLastSavedState()||History.createStateObject();
486
-
487
- // Adjust
488
- if ( friendly ) {
489
- State = History.cloneObject(State);
490
- State.url = State.cleanUrl||State.url;
491
- }
492
-
493
- // Return
494
- return State;
495
- };
496
-
497
- /**
498
- * History.getIdByState(State)
499
- * Gets a ID for a State
500
- * @param {State} newState
501
- * @return {String} id
502
- */
503
- History.getIdByState = function(newState){
504
-
505
- // Fetch ID
506
- var id = History.extractId(newState.url);
507
- if ( !id ) {
508
- // Find ID via State String
509
- var str = History.getStateString(newState);
510
- if ( typeof History.stateToId[str] !== 'undefined' ) {
511
- id = History.stateToId[str];
512
- }
513
- else {
514
- // Generate a new ID
515
- while ( true ) {
516
- id = String(Math.floor(Math.random()*1000));
517
- if ( typeof History.idToState[id] === 'undefined' ) {
518
- break;
519
- }
520
- }
521
-
522
- // Apply the new State to the ID
523
- History.stateToId[str] = id;
524
- History.idToState[id] = newState;
525
- }
526
- }
527
-
528
- // Return ID
529
- return id;
530
- };
531
-
532
- /**
533
- * History.normalizeState(State)
534
- * Expands a State Object
535
- * @param {object} State
536
- * @return {object}
537
- */
538
- History.normalizeState = function(oldState){
539
- // Prepare
540
- if ( !oldState || (typeof oldState !== 'object') ) {
541
- oldState = {};
542
- }
543
-
544
- // Check
545
- if ( typeof oldState.normalized !== 'undefined' ) {
546
- return oldState;
547
- }
548
-
549
- // Adjust
550
- if ( !oldState.data || (typeof oldState.data !== 'object') ) {
551
- oldState.data = {};
552
- }
553
-
554
- // ----------------------------------------------------------------------
555
-
556
- // Create
557
- var newState = {};
558
- newState.normalized = true;
559
- newState.title = oldState.title||'';
560
- newState.url = History.getFullUrl(oldState.url||document.location.href);
561
- newState.hash = History.getShortUrl(newState.url);
562
- newState.data = History.cloneObject(oldState.data);
563
-
564
- // Fetch ID
565
- newState.id = History.getIdByState(newState);
566
-
567
- // ----------------------------------------------------------------------
568
-
569
- // Check to see if we have more than just a url
570
- var dataNotEmpty = !History.isEmptyObject(newState.data);
571
-
572
- // Apply
573
- if ( newState.title || dataNotEmpty ) {
574
- // Add ID to Hash
575
- newState.hash = History.getShortUrl(newState.url).replace(/\&_suid.*/,'');
576
- if ( !/\?/.test(newState.hash) ) {
577
- newState.hash += '?';
578
- }
579
- newState.hash += '&_suid='+newState.id;
580
- }
581
-
582
- // Create the Hashed URL
583
- newState.hashedUrl = History.getFullUrl(newState.hash);
584
- newState.cleanUrl = newState.url.replace(/\&_suid.*/,'');
585
-
586
- // ----------------------------------------------------------------------
587
-
588
- // Update the URL if we have a duplicate
589
- if ( History.hasUrlDuplicate(newState) ) {
590
- newState.url = newState.hashedUrl;
591
- }
592
-
593
- // ----------------------------------------------------------------------
594
-
595
- // Return
596
- return newState;
597
- };
598
-
599
- /**
600
- * History.createStateObject(data,title,url)
601
- * Creates a object based on the data, title and url state params
602
- * @param {object} data
603
- * @param {string} title
604
- * @param {string} url
605
- * @return {object}
606
- */
607
- History.createStateObject = function(data,title,url){
608
- // Hashify
609
- var State = {
610
- 'data': data,
611
- 'title': title,
612
- 'url': url
613
- };
614
-
615
- // Expand the State
616
- State = History.normalizeState(State);
617
-
618
- // Return object
619
- return State;
620
- };
621
-
622
- /**
623
- * History.getStateById(id)
624
- * Get a state by it's UID
625
- * @param {String} id
626
- */
627
- History.getStateById = function(id){
628
- id = String(id);
629
- var State = History.idToState[id]||undefined;
630
- return State;
631
- };
632
-
633
- /**
634
- * Get a State's String
635
- * @param {State} passedState
636
- */
637
- History.getStateString = function(passedState){
638
- // Prepare
639
- var State = History.normalizeState(passedState);
640
-
641
- // Clean
642
- var cleanedState = {
643
- data: State.data,
644
- title: passedState.title,
645
- url: passedState.url
646
- };
647
-
648
- // Fetch
649
- var str = JSON.stringify(cleanedState);
650
-
651
- // Return
652
- return str;
653
- };
654
-
655
- /**
656
- * Get a State's ID
657
- * @param {State} passedState
658
- * @return {String} id
659
- */
660
- History.getStateId = function(passedState){
661
- // Prepare
662
- var State = History.normalizeState(passedState);
663
-
664
- // Fetch
665
- var id = State.id;
666
-
667
- // Return
668
- return id;
669
- };
670
-
671
- /**
672
- * History.getHashByState(State)
673
- * Creates a Hash for the State Object
674
- * @param {State} passedState
675
- * @return {String} hash
676
- */
677
- History.getHashByState = function(passedState){
678
- // Prepare
679
- var hash, State = History.normalizeState(passedState);
680
-
681
- // Fetch
682
- hash = State.hash;
683
-
684
- // Return
685
- return hash;
686
- };
687
-
688
- /**
689
- * History.extractId(url_or_hash)
690
- * Get a State ID by it's URL or Hash
691
- * @param {string} url_or_hash
692
- * @return {string} id
693
- */
694
- History.extractId = function ( url_or_hash ) {
695
- // Prepare
696
- var id;
697
-
698
- // Extract
699
- var parts,url;
700
- parts = /(.*)\&_suid=([0-9]+)$/.exec(url_or_hash);
701
- url = parts ? (parts[1]||url_or_hash) : url_or_hash;
702
- id = parts ? String(parts[2]||'') : '';
703
-
704
- // Return
705
- return id||false;
706
- };
707
-
708
- /**
709
- * History.extractState
710
- * Get a State by it's URL or Hash
711
- */
712
- History.extractState = function(url_or_hash,create){
713
- // Prepare
714
- var State = null;
715
- create = create||false;
716
-
717
- // Fetch SUID
718
- var id = History.extractId(url_or_hash);
719
- if ( id ) {
720
- State = History.getStateById(id);
721
- }
722
-
723
- // Fetch SUID returned no State
724
- if ( !State ) {
725
- // Fetch URL
726
- var url = History.getFullUrl(url_or_hash);
727
-
728
- // Check URL
729
- id = History.getIdByUrl(url)||false;
730
- if ( id ) {
731
- State = History.getStateById(id);
732
- }
733
- // Create State
734
- else if ( create && /\//.test(url_or_hash) ) {
735
- State = History.createStateObject(null,null,url.replace(/\&_suid.*/,''));
736
- }
737
- }
738
-
739
- // Return
740
- return State;
741
- };
742
-
743
- /**
744
- * History.getIdByUrl()
745
- * Get a State ID by a State URL
746
- */
747
- History.getIdByUrl = function(url){
748
- var id = History.urlToId[url]||false;
749
- return id;
750
- };
751
-
752
- /**
753
- * History.getLastSavedState()
754
- * Get an object containing the data, title and url of the current state
755
- * @return {Object} State
756
- */
757
- History.getLastSavedState = function(){
758
- return History.savedStates[History.savedStates.length-1]||undefined;
759
- };
760
-
761
- /**
762
- * History.getLastStoredState()
763
- * Get an object containing the data, title and url of the current state
764
- * @return {Object} State
765
- */
766
- History.getLastStoredState = function(){
767
- return History.storedStates[History.storedStates.length-1]||undefined;
768
- };
769
-
770
- /**
771
- * History.hasUrlDuplicate
772
- * Checks if a Url will have a url conflict
773
- * @param {Object} newState
774
- * @return {Boolean} hasDuplicate
775
- */
776
- History.hasUrlDuplicate = function(newState) {
777
- // Prepare
778
- var hasDuplicate = false;
779
-
780
- // Fetch
781
- var oldState = History.extractState(newState.url);
782
-
783
- // Check
784
- hasDuplicate = oldState && oldState.id !== newState.id;
785
-
786
- // Return
787
- return hasDuplicate;
788
- };
789
-
790
- /**
791
- * History.storeState
792
- * Store a State
793
- * @param {Object} newState
794
- * @return {Object} newState
795
- */
796
- History.storeState = function(newState){
797
- // Store the State
798
- History.urlToId[newState.url] = newState.id;
799
-
800
- // Push the State
801
- History.storedStates.push(History.cloneObject(newState));
802
-
803
- // Return newState
804
- return newState;
805
- };
806
-
807
- /**
808
- * History.isLastSavedState(newState)
809
- * Tests to see if the state is the last state
810
- * @param {Object} newState
811
- * @return {boolean} isLast
812
- */
813
- History.isLastSavedState = function(newState){
814
- // Prepare
815
- var isLast = false;
816
-
817
- // Check
818
- if ( History.savedStates.length ) {
819
- var
820
- newId = newState.id,
821
- oldState = History.getLastSavedState(),
822
- oldId = oldState.id;
823
-
824
- // Check
825
- isLast = (newId === oldId);
826
- }
827
-
828
- // Return
829
- return isLast;
830
- };
831
-
832
- /**
833
- * History.saveState
834
- * Push a State
835
- * @param {Object} newState
836
- * @return {boolean} changed
837
- */
838
- History.saveState = function(newState){
839
- // Check Hash
840
- if ( History.isLastSavedState(newState) ) {
841
- return false;
842
- }
843
-
844
- // Push the State
845
- History.savedStates.push(History.cloneObject(newState));
846
-
847
- // Return true
848
- return true;
849
- };
850
-
851
- /**
852
- * History.getStateByIndex()
853
- * Gets a state by the index
854
- * @param {integer} index
855
- * @return {Object}
856
- */
857
- History.getStateByIndex = function(index){
858
- // Prepare
859
- var State = null;
860
-
861
- // Handle
862
- if ( typeof index === 'undefined' ) {
863
- // Get the last inserted
864
- State = History.savedStates[History.savedStates.length-1];
865
- }
866
- else if ( index < 0 ) {
867
- // Get from the end
868
- State = History.savedStates[History.savedStates.length+index];
869
- }
870
- else {
871
- // Get from the beginning
872
- State = History.savedStates[index];
873
- }
874
-
875
- // Return State
876
- return State;
877
- };
878
-
879
- // ----------------------------------------------------------------------
880
- // Hash Helpers
881
-
882
- /**
883
- * History.getHash()
884
- * Gets the current document hash
885
- * @return {string}
886
- */
887
- History.getHash = function(){
888
- var hash = History.unescapeHash(document.location.hash);
889
- return hash;
890
- };
891
-
892
- /**
893
- * History.unescapeHash()
894
- * normalize and Unescape a Hash
895
- * @return {string}
896
- */
897
- History.unescapeHash = function(hash){
898
- var result = History.normalizeHash(hash);
899
-
900
- // Unescape hash
901
- if ( /\%[^2][^5]/.test(result) ) {
902
- result = window.unescape(result);
903
- }
904
-
905
- // Return result
906
- return result;
907
- };
908
-
909
- /**
910
- * History.normalizeHash()
911
- * normalize a hash across browsers
912
- * @return {string}
913
- */
914
- History.normalizeHash = function(hash){
915
- var result = hash.replace(/[^#]*#/,'').replace(/#.*/, '');
916
-
917
- // Return result
918
- return result;
919
- };
920
-
921
- /**
922
- * History.setHash(hash)
923
- * Sets the document hash
924
- * @param {string} hash
925
- * @return {History}
926
- */
927
- History.setHash = function(hash,queue){
928
- // Handle Queueing
929
- if ( queue !== false && History.busy() ) {
930
- // Wait + Push to Queue
931
- //History.debug('History.setHash: we must wait', arguments);
932
- History.pushQueue({
933
- scope: History,
934
- callback: History.setHash,
935
- args: arguments,
936
- queue: queue
937
- });
938
- return false;
939
- }
940
-
941
- // Log
942
- //History.debug('History.setHash: called',hash);
943
-
944
- // Prepare
945
- var adjustedHash = History.escapeHash(hash);
946
-
947
- // Make Busy + Continue
948
- History.busy(true);
949
-
950
- // Check if hash is a state
951
- var State = History.extractState(hash,true);
952
- if ( State && !History.emulated.pushState ) {
953
- // Hash is a state so skip the setHash
954
- //History.debug('History.setHash: Hash is a state so skipping the hash set with a direct pushState call',arguments);
955
-
956
- // PushState
957
- History.pushState(State.data,State.title,State.url,false);
958
- }
959
- else if ( document.location.hash !== adjustedHash ) {
960
- // Hash is a proper hash, so apply it
961
-
962
- // Handle browser bugs
963
- if ( History.bugs.setHash ) {
964
- // Fix Safari Bug https://bugs.webkit.org/show_bug.cgi?id=56249
965
-
966
- // Fetch the base page
967
- var pageUrl = History.getPageUrl();
968
-
969
- // Safari hash apply
970
- History.pushState(null,null,pageUrl+'#'+adjustedHash,false);
971
- }
972
- else {
973
- // Normal hash apply
974
- document.location.hash = adjustedHash;
975
- }
976
- }
977
-
978
- // Chain
979
- return History;
980
- };
981
-
982
- /**
983
- * History.escape()
984
- * normalize and Escape a Hash
985
- * @return {string}
986
- */
987
- History.escapeHash = function(hash){
988
- var result = History.normalizeHash(hash);
989
-
990
- // Escape hash
991
- result = window.escape(result);
992
-
993
- // IE6 Escape Bug
994
- if ( !History.bugs.hashEscape ) {
995
- // Restore common parts
996
- result = result
997
- .replace('%21','!')
998
- .replace('%26','&')
999
- .replace('%3D','=')
1000
- .replace('%3F','?');
1001
- }
1002
-
1003
- // Return result
1004
- return result;
1005
- };
1006
-
1007
- /**
1008
- * History.getHashByUrl(url)
1009
- * Extracts the Hash from a URL
1010
- * @param {string} url
1011
- * @return {string} url
1012
- */
1013
- History.getHashByUrl = function(url){
1014
- // Extract the hash
1015
- var hash = String(url)
1016
- .replace(/([^#]*)#?([^#]*)#?(.*)/, '$2')
1017
- ;
1018
-
1019
- // Unescape hash
1020
- hash = History.unescapeHash(hash);
1021
-
1022
- // Return hash
1023
- return hash;
1024
- };
1025
-
1026
- /**
1027
- * History.isTraditionalAnchor(url)
1028
- * Checks to see if the url is a traditional anchor
1029
- * @param {string} url
1030
- * @return {boolean}
1031
- */
1032
- History.isTraditionalAnchor = function(url){
1033
- var
1034
- hash = History.getHashByUrl(url),
1035
- el = document.getElementById(hash),
1036
- isTraditionalAnchor = typeof el !== 'undefined';
1037
-
1038
- // Return isTraditionalAnchor
1039
- return isTraditionalAnchor;
1040
- };
1041
-
1042
- /**
1043
- * History.setTitle(title)
1044
- * Applies the title to the document
1045
- * @param {State} newState
1046
- * @return {Boolean}
1047
- */
1048
- History.setTitle = function(newState){
1049
- // Prepare
1050
- var title = newState.title;
1051
-
1052
- // Initial
1053
- if ( !title ) {
1054
- var firstState = History.getStateByIndex(0);
1055
- if ( firstState && firstState.url === newState.url ) {
1056
- title = firstState.title||History.options.initialTitle;
1057
- }
1058
- }
1059
-
1060
- // Apply
1061
- try {
1062
- document.getElementsByTagName('title')[0].innerHTML = title.replace('<','&lt;').replace('>','&gt;').replace(' & ',' &amp; ');
1063
- }
1064
- catch ( Exception ) { }
1065
- document.title = title;
1066
-
1067
- // Chain
1068
- return History;
1069
- };
1070
-
1071
- // ----------------------------------------------------------------------
1072
- // Queueing
1073
-
1074
- /**
1075
- * History.queues
1076
- * The list of queues to use
1077
- * First In, First Out
1078
- */
1079
- History.queues = [];
1080
-
1081
- /**
1082
- * History.busy(value)
1083
- * @param {boolean} value [optional]
1084
- * @return {boolean} busy
1085
- */
1086
- History.busy = function(value){
1087
- // Apply
1088
- if ( typeof value !== 'undefined' ) {
1089
- //History.debug('History.busy: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues.length);
1090
- History.busy.flag = value;
1091
- }
1092
- // Default
1093
- else if ( typeof History.busy.flag === 'undefined' ) {
1094
- History.busy.flag = false;
1095
- }
1096
-
1097
- // Queue
1098
- if ( !History.busy.flag ) {
1099
- // Execute the next item in the queue
1100
- clearTimeout(History.busy.timeout);
1101
- var fireNext = function(){
1102
- if ( History.busy.flag ) return;
1103
- for ( var i=History.queues.length-1; i >= 0; --i ) {
1104
- var queue = History.queues[i];
1105
- if ( queue.length === 0 ) continue;
1106
- var item = queue.shift();
1107
- History.fireQueueItem(item);
1108
- History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);
1109
- }
1110
- };
1111
- History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);
1112
- }
1113
-
1114
- // Return
1115
- return History.busy.flag;
1116
- };
1117
-
1118
- /**
1119
- * History.fireQueueItem(item)
1120
- * Fire a Queue Item
1121
- * @param {Object} item
1122
- * @return {Mixed} result
1123
- */
1124
- History.fireQueueItem = function(item){
1125
- return item.callback.apply(item.scope||History,item.args||[]);
1126
- };
1127
-
1128
- /**
1129
- * History.pushQueue(callback,args)
1130
- * Add an item to the queue
1131
- * @param {Object} item [scope,callback,args,queue]
1132
- */
1133
- History.pushQueue = function(item){
1134
- // Prepare the queue
1135
- History.queues[item.queue||0] = History.queues[item.queue||0]||[];
1136
-
1137
- // Add to the queue
1138
- History.queues[item.queue||0].push(item);
1139
-
1140
- // Chain
1141
- return History;
1142
- };
1143
-
1144
- /**
1145
- * History.queue (item,queue), (func,queue), (func), (item)
1146
- * Either firs the item now if not busy, or adds it to the queue
1147
- */
1148
- History.queue = function(item,queue){
1149
- // Prepare
1150
- if ( typeof item === 'function' ) {
1151
- item = {
1152
- callback: item
1153
- };
1154
- }
1155
- if ( typeof queue !== 'undefined' ) {
1156
- item.queue = queue;
1157
- }
1158
-
1159
- // Handle
1160
- if ( History.busy() ) {
1161
- History.pushQueue(item);
1162
- } else {
1163
- History.fireQueueItem(item);
1164
- }
1165
-
1166
- // Chain
1167
- return History;
1168
- };
1169
-
1170
- /**
1171
- * History.clearQueue()
1172
- * Clears the Queue
1173
- */
1174
- History.clearQueue = function(){
1175
- History.busy.flag = false;
1176
- History.queues = [];
1177
- return History;
1178
- };
1179
-
1180
-
1181
- // ----------------------------------------------------------------------
1182
- // IE Bug Fix
1183
-
1184
- /**
1185
- * History.stateChanged
1186
- * States whether or not the state has changed since the last double check was initialised
1187
- */
1188
- History.stateChanged = false;
1189
-
1190
- /**
1191
- * History.doubleChecker
1192
- * Contains the timeout used for the double checks
1193
- */
1194
- History.doubleChecker = false;
1195
-
1196
- /**
1197
- * History.doubleCheckComplete()
1198
- * Complete a double check
1199
- * @return {History}
1200
- */
1201
- History.doubleCheckComplete = function(){
1202
- // Update
1203
- History.stateChanged = true;
1204
-
1205
- // Clear
1206
- History.doubleCheckClear();
1207
-
1208
- // Chain
1209
- return History;
1210
- };
1211
-
1212
- /**
1213
- * History.doubleCheckClear()
1214
- * Clear a double check
1215
- * @return {History}
1216
- */
1217
- History.doubleCheckClear = function(){
1218
- // Clear
1219
- if ( History.doubleChecker ) {
1220
- clearTimeout(History.doubleChecker);
1221
- History.doubleChecker = false;
1222
- }
1223
-
1224
- // Chain
1225
- return History;
1226
- };
1227
-
1228
- /**
1229
- * History.doubleCheck()
1230
- * Create a double check
1231
- * @return {History}
1232
- */
1233
- History.doubleCheck = function(tryAgain){
1234
- // Reset
1235
- History.stateChanged = false;
1236
- History.doubleCheckClear();
1237
-
1238
- // Fix IE6,IE7 bug where calling history.back or history.forward does not actually change the hash (whereas doing it manually does)
1239
- // Fix Safari 5 bug where sometimes the state does not change: https://bugs.webkit.org/show_bug.cgi?id=42940
1240
- if ( History.bugs.ieDoubleCheck ) {
1241
- // Apply Check
1242
- History.doubleChecker = setTimeout(
1243
- function(){
1244
- History.doubleCheckClear();
1245
- if ( !History.stateChanged ) {
1246
- //History.debug('History.doubleCheck: State has not yet changed, trying again', arguments);
1247
- // Re-Attempt
1248
- tryAgain();
1249
- }
1250
- return true;
1251
- },
1252
- History.options.doubleCheckInterval
1253
- );
1254
- }
1255
-
1256
- // Chain
1257
- return History;
1258
- };
1259
-
1260
- // ----------------------------------------------------------------------
1261
- // Safari Bug Fix
1262
-
1263
- /**
1264
- * History.safariStatePoll()
1265
- * Poll the current state
1266
- * @return {History}
1267
- */
1268
- History.safariStatePoll = function(){
1269
- // Poll the URL
1270
-
1271
- // Get the Last State which has the new URL
1272
- var
1273
- urlState = History.extractState(document.location.href),
1274
- newState;
1275
-
1276
- // Check for a difference
1277
- if ( !History.isLastSavedState(urlState) ) {
1278
- newState = urlState;
1279
- }
1280
- else {
1281
- return;
1282
- }
1283
-
1284
- // Check if we have a state with that url
1285
- // If not create it
1286
- if ( !newState ) {
1287
- //History.debug('History.safariStatePoll: new');
1288
- newState = History.createStateObject();
1289
- }
1290
-
1291
- // Apply the New State
1292
- //History.debug('History.safariStatePoll: trigger');
1293
- History.Adapter.trigger(window,'popstate');
1294
-
1295
- // Chain
1296
- return History;
1297
- };
1298
-
1299
- // ----------------------------------------------------------------------
1300
- // State Aliases
1301
-
1302
- /**
1303
- * History.back(queue)
1304
- * Send the browser history back one item
1305
- * @param {Integer} queue [optional]
1306
- */
1307
- History.back = function(queue){
1308
- //History.debug('History.back: called', arguments);
1309
-
1310
- // Handle Queueing
1311
- if ( queue !== false && History.busy() ) {
1312
- // Wait + Push to Queue
1313
- //History.debug('History.back: we must wait', arguments);
1314
- History.pushQueue({
1315
- scope: History,
1316
- callback: History.back,
1317
- args: arguments,
1318
- queue: queue
1319
- });
1320
- return false;
1321
- }
1322
-
1323
- // Make Busy + Continue
1324
- History.busy(true);
1325
-
1326
- // Fix certain browser bugs that prevent the state from changing
1327
- History.doubleCheck(function(){
1328
- History.back(false);
1329
- });
1330
-
1331
- // Go back
1332
- history.go(-1);
1333
-
1334
- // End back closure
1335
- return true;
1336
- };
1337
-
1338
- /**
1339
- * History.forward(queue)
1340
- * Send the browser history forward one item
1341
- * @param {Integer} queue [optional]
1342
- */
1343
- History.forward = function(queue){
1344
- //History.debug('History.forward: called', arguments);
1345
-
1346
- // Handle Queueing
1347
- if ( queue !== false && History.busy() ) {
1348
- // Wait + Push to Queue
1349
- //History.debug('History.forward: we must wait', arguments);
1350
- History.pushQueue({
1351
- scope: History,
1352
- callback: History.forward,
1353
- args: arguments,
1354
- queue: queue
1355
- });
1356
- return false;
1357
- }
1358
-
1359
- // Make Busy + Continue
1360
- History.busy(true);
1361
-
1362
- // Fix certain browser bugs that prevent the state from changing
1363
- History.doubleCheck(function(){
1364
- History.forward(false);
1365
- });
1366
-
1367
- // Go forward
1368
- history.go(1);
1369
-
1370
- // End forward closure
1371
- return true;
1372
- };
1373
-
1374
- /**
1375
- * History.go(index,queue)
1376
- * Send the browser history back or forward index times
1377
- * @param {Integer} queue [optional]
1378
- */
1379
- History.go = function(index,queue){
1380
- //History.debug('History.go: called', arguments);
1381
-
1382
- // Prepare
1383
- var i;
1384
-
1385
- // Handle
1386
- if ( index > 0 ) {
1387
- // Forward
1388
- for ( i=1; i<=index; ++i ) {
1389
- History.forward(queue);
1390
- }
1391
- }
1392
- else if ( index < 0 ) {
1393
- // Backward
1394
- for ( i=-1; i>=index; --i ) {
1395
- History.back(queue);
1396
- }
1397
- }
1398
- else {
1399
- throw new Error('History.go: History.go requires a positive or negative integer passed.');
1400
- }
1401
-
1402
- // Chain
1403
- return History;
1404
- };
1405
-
1406
-
1407
- // ----------------------------------------------------------------------
1408
- // HTML5 State Support
1409
-
1410
- if ( History.emulated.pushState ) {
1411
- /*
1412
- * Provide Skeleton for HTML4 Browsers
1413
- */
1414
-
1415
- // Prepare
1416
- var emptyFunction = function(){};
1417
- History.pushState = History.pushState||emptyFunction;
1418
- History.replaceState = History.replaceState||emptyFunction;
1419
- }
1420
- else {
1421
- /*
1422
- * Use native HTML5 History API Implementation
1423
- */
1424
-
1425
- /**
1426
- * History.onPopState(event,extra)
1427
- * Refresh the Current State
1428
- */
1429
- History.onPopState = function(event){
1430
- // Reset the double check
1431
- History.doubleCheckComplete();
1432
-
1433
- // Check for a Hash, and handle apporiatly
1434
- var currentHash = History.getHash();
1435
- if ( currentHash ) {
1436
- // Expand Hash
1437
- var currentState = History.extractState(currentHash||document.location.href,true);
1438
- if ( currentState ) {
1439
- // We were able to parse it, it must be a State!
1440
- // Let's forward to replaceState
1441
- //History.debug('History.onPopState: state anchor', currentHash, currentState);
1442
- History.replaceState(currentState.data, currentState.title, currentState.url, false);
1443
- }
1444
- else {
1445
- // Traditional Anchor
1446
- //History.debug('History.onPopState: traditional anchor', currentHash);
1447
- History.Adapter.trigger(window,'anchorchange');
1448
- History.busy(false);
1449
- }
1450
-
1451
- // We don't care for hashes
1452
- History.expectedStateId = false;
1453
- return false;
1454
- }
1455
-
1456
- // Prepare
1457
- var newState = null;
1458
-
1459
- // Prepare
1460
- event = event||{};
1461
- if ( typeof event.state === 'undefined' ) {
1462
- // jQuery
1463
- if ( typeof event.originalEvent !== 'undefined' && typeof event.originalEvent.state !== 'undefined' ) {
1464
- event.state = event.originalEvent.state||false;
1465
- }
1466
- // MooTools
1467
- else if ( typeof event.event !== 'undefined' && typeof event.event.state !== 'undefined' ) {
1468
- event.state = event.event.state||false;
1469
- }
1470
- }
1471
-
1472
- // Ensure
1473
- event.state = (event.state||false);
1474
-
1475
- // Fetch State
1476
- if ( event.state ) {
1477
- // Vanilla: Back/forward button was used
1478
- newState = History.getStateById(event.state);
1479
- }
1480
- else if ( History.expectedStateId ) {
1481
- // Vanilla: A new state was pushed, and popstate was called manually
1482
- newState = History.getStateById(History.expectedStateId);
1483
- }
1484
- else {
1485
- // Initial State
1486
- newState = History.extractState(document.location.href);
1487
- }
1488
-
1489
- // Clean
1490
- History.expectedStateId = false;
1491
-
1492
- // Check if we are the same state
1493
- if ( History.isLastSavedState(newState) ) {
1494
- // There has been no change (just the page's hash has finally propagated)
1495
- //History.debug('History.onPopState: no change', newState, History.savedStates);
1496
- History.busy(false);
1497
- return false;
1498
- }
1499
-
1500
- // Store the State
1501
- History.storeState(newState);
1502
- History.saveState(newState);
1503
-
1504
- // Force update of the title
1505
- History.setTitle(newState);
1506
-
1507
- // Fire Our Event
1508
- History.Adapter.trigger(window,'statechange');
1509
- History.busy(false);
1510
-
1511
- // Return true
1512
- return true;
1513
- };
1514
- History.Adapter.bind(window,'popstate',History.onPopState);
1515
-
1516
- /**
1517
- * History.pushState(data,title,url)
1518
- * Add a new State to the history object, become it, and trigger onpopstate
1519
- * We have to trigger for HTML4 compatibility
1520
- * @param {object} data
1521
- * @param {string} title
1522
- * @param {string} url
1523
- * @return {true}
1524
- */
1525
- History.pushState = function(data,title,url,queue){
1526
- //History.debug('History.pushState: called', arguments);
1527
-
1528
- // Check the State
1529
- if ( History.getHashByUrl(url) && History.emulated.pushState ) {
1530
- throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
1531
- }
1532
-
1533
- // Handle Queueing
1534
- if ( queue !== false && History.busy() ) {
1535
- // Wait + Push to Queue
1536
- //History.debug('History.pushState: we must wait', arguments);
1537
- History.pushQueue({
1538
- scope: History,
1539
- callback: History.pushState,
1540
- args: arguments,
1541
- queue: queue
1542
- });
1543
- return false;
1544
- }
1545
-
1546
- // Make Busy + Continue
1547
- History.busy(true);
1548
-
1549
- // Create the newState
1550
- var newState = History.createStateObject(data,title,url);
1551
-
1552
- // Check it
1553
- if ( History.isLastSavedState(newState) ) {
1554
- // Won't be a change
1555
- History.busy(false);
1556
- }
1557
- else {
1558
- // Store the newState
1559
- History.storeState(newState);
1560
- History.expectedStateId = newState.id;
1561
-
1562
- // Push the newState
1563
- var pushUrl =
1564
- (History.bugs.safariPoll && History.hasUrlDuplicate(newState))
1565
- ? newState.hashedUrl
1566
- : newState.url;
1567
- history.pushState(newState.id,newState.title,pushUrl);
1568
-
1569
- // Fire HTML5 Event
1570
- History.Adapter.trigger(window,'popstate');
1571
- }
1572
-
1573
- // End pushState closure
1574
- return true;
1575
- };
1576
-
1577
- /**
1578
- * History.replaceState(data,title,url)
1579
- * Replace the State and trigger onpopstate
1580
- * We have to trigger for HTML4 compatibility
1581
- * @param {object} data
1582
- * @param {string} title
1583
- * @param {string} url
1584
- * @return {true}
1585
- */
1586
- History.replaceState = function(data,title,url,queue){
1587
- //History.debug('History.replaceState: called', arguments);
1588
-
1589
- // Check the State
1590
- if ( History.getHashByUrl(url) && History.emulated.pushState ) {
1591
- throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
1592
- }
1593
-
1594
- // Handle Queueing
1595
- if ( queue !== false && History.busy() ) {
1596
- // Wait + Push to Queue
1597
- //History.debug('History.replaceState: we must wait', arguments);
1598
- History.pushQueue({
1599
- scope: History,
1600
- callback: History.replaceState,
1601
- args: arguments,
1602
- queue: queue
1603
- });
1604
- return false;
1605
- }
1606
-
1607
- // Make Busy + Continue
1608
- History.busy(true);
1609
-
1610
- // Create the newState
1611
- var newState = History.createStateObject(data,title,url);
1612
-
1613
- // Check it
1614
- if ( History.isLastSavedState(newState) ) {
1615
- // Won't be a change
1616
- History.busy(false);
1617
- }
1618
- else {
1619
- // Store the newState
1620
- History.storeState(newState);
1621
- History.expectedStateId = newState.id;
1622
-
1623
- // Push the newState
1624
- var pushUrl =
1625
- (History.bugs.safariPoll && History.hasUrlDuplicate(newState))
1626
- ? newState.hashedUrl
1627
- : newState.url;
1628
- history.replaceState(newState.id,newState.title,pushUrl);
1629
-
1630
- // Fire HTML5 Event
1631
- History.Adapter.trigger(window,'popstate');
1632
- }
1633
-
1634
- // End replaceState closure
1635
- return true;
1636
- };
1637
-
1638
- /**
1639
- * Create the initial State
1640
- */
1641
- History.saveState(History.storeState(History.createStateObject({},'',document.location.href)));
1642
-
1643
- /**
1644
- * Setup Safari Fix
1645
- */
1646
- if ( History.bugs.safariPoll ) {
1647
- setInterval(History.safariStatePoll, History.options.safariPollInterval);
1648
- }
1649
-
1650
- /**
1651
- * Ensure Cross Browser Compatibility
1652
- */
1653
- if ( navigator.vendor === 'Apple Computer, Inc.' || (navigator.appCodeName||'') === 'Mozilla' ) {
1654
- /**
1655
- * Fix Safari HashChange Issue
1656
- */
1657
-
1658
- // Setup Alias
1659
- History.Adapter.bind(window,'hashchange',function(){
1660
- History.Adapter.trigger(window,'popstate');
1661
- });
1662
-
1663
- // Initialise Alias
1664
- if ( History.getHash() ) {
1665
- History.Adapter.onDomLoad(function(){
1666
- History.Adapter.trigger(window,'hashchange');
1667
- });
1668
- }
1669
- }
1670
-
1671
- } // !History.emulated.pushState
1672
-
1673
- }; // History.initCore
1674
-
1675
- // Try and Initialise History
1676
- History.init();
8
+ (function(window, undefined) {
9
+ "use strict";
10
+
11
+ // --------------------------------------------------------------------------
12
+ // Initialise
13
+
14
+ // Localise Globals
15
+ var
16
+ console = window.console || undefined, // Prevent a JSLint complain
17
+ document = window.document, // Make sure we are using the correct document
18
+ navigator = window.navigator, // Make sure we are using the correct navigator
19
+ amplify = window.amplify || false, // Amplify.js
20
+ setTimeout = window.setTimeout,
21
+ clearTimeout = window.clearTimeout,
22
+ setInterval = window.setInterval,
23
+ JSON = window.JSON,
24
+ History = window.History = window.History || {}, // Public History Object
25
+ history = window.history; // Old History Object
26
+
27
+ // MooTools Compatibility
28
+ JSON.stringify = JSON.stringify || JSON.encode;
29
+ JSON.parse = JSON.parse || JSON.decode;
30
+
31
+ // Check Existence
32
+ if (typeof History.init !== 'undefined') {
33
+ throw new Error('History.js Core has already been loaded...');
34
+ }
35
+
36
+ // Initialise History
37
+ History.init = function() {
38
+ // Check Load Status of Adapter
39
+ if (typeof History.Adapter === 'undefined') {
40
+ return false;
41
+ }
42
+
43
+ // Check Load Status of Core
44
+ if (typeof History.initCore !== 'undefined') {
45
+ History.initCore();
46
+ }
47
+
48
+ // Check Load Status of HTML4 Support
49
+ if (typeof History.initHtml4 !== 'undefined') {
50
+ History.initHtml4();
51
+ }
52
+
53
+ // Return true
54
+ return true;
55
+ };
56
+
57
+ // --------------------------------------------------------------------------
58
+ // Initialise Core
59
+
60
+ // Initialise Core
61
+ History.initCore = function() {
62
+ // Initialise
63
+ if (typeof History.initCore.initialized !== 'undefined') {
64
+ // Already Loaded
65
+ return false;
66
+ }
67
+ else {
68
+ History.initCore.initialized = true;
69
+ }
70
+
71
+ // ----------------------------------------------------------------------
72
+ // Options
73
+
74
+ /**
75
+ * History.options
76
+ * Configurable options
77
+ */
78
+ History.options = History.options || {};
79
+
80
+ /**
81
+ * History.options.hashChangeInterval
82
+ * How long should the interval be before hashchange checks
83
+ */
84
+ History.options.hashChangeInterval = History.options.hashChangeInterval || 100;
85
+
86
+ /**
87
+ * History.options.safariPollInterval
88
+ * How long should the interval be before safari poll checks
89
+ */
90
+ History.options.safariPollInterval = History.options.safariPollInterval || 500;
91
+
92
+ /**
93
+ * History.options.doubleCheckInterval
94
+ * How long should the interval be before we perform a double check
95
+ */
96
+ History.options.doubleCheckInterval = History.options.doubleCheckInterval || 500;
97
+
98
+ /**
99
+ * History.options.storeInterval
100
+ * How long should we wait between store calls
101
+ */
102
+ History.options.storeInterval = History.options.storeInterval || 1000;
103
+
104
+ /**
105
+ * History.options.busyDelay
106
+ * How long should we wait between busy events
107
+ */
108
+ History.options.busyDelay = History.options.busyDelay || 250;
109
+
110
+ /**
111
+ * History.options.debug
112
+ * If true will enable debug messages to be logged
113
+ */
114
+ History.options.debug = History.options.debug || false;
115
+
116
+ /**
117
+ * History.options.initialTitle
118
+ * What is the title of the initial state
119
+ */
120
+ History.options.initialTitle = History.options.initialTitle || document.title;
121
+
122
+
123
+ // ----------------------------------------------------------------------
124
+ // Debug
125
+
126
+ /**
127
+ * History.debug(message,...)
128
+ * Logs the passed arguments if debug enabled
129
+ */
130
+ History.debug = function() {
131
+ if ((History.options.debug || false)) {
132
+ History.log.apply(History, arguments);
133
+ }
134
+ };
135
+
136
+ /**
137
+ * History.log(message,...)
138
+ * Logs the passed arguments
139
+ */
140
+ History.log = function() {
141
+ // Prepare
142
+ var
143
+ consoleExists = !(typeof console === 'undefined' || typeof console.log === 'undefined' || typeof console.log.apply === 'undefined'),
144
+ textarea = document.getElementById('log'),
145
+ message,
146
+ i,n
147
+ ;
148
+
149
+ // Write to Console
150
+ if (consoleExists) {
151
+ var args = Array.prototype.slice.call(arguments);
152
+ message = args.shift();
153
+ if (typeof console.debug !== 'undefined') {
154
+ console.debug.apply(console, [message,args]);
155
+ }
156
+ else {
157
+ console.log.apply(console, [message,args]);
158
+ }
159
+ }
160
+ else {
161
+ message = ("\n" + arguments[0] + "\n");
162
+ }
163
+
164
+ // Write to log
165
+ for (i = 1,n = arguments.length; i < n; ++i) {
166
+ var arg = arguments[i];
167
+ if (typeof arg === 'object' && typeof JSON !== 'undefined') {
168
+ try {
169
+ arg = JSON.stringify(arg);
170
+ }
171
+ catch (Exception) {
172
+ // Recursive Object
173
+ }
174
+ }
175
+ message += "\n" + arg + "\n";
176
+ }
177
+
178
+ // Textarea
179
+ if (textarea) {
180
+ textarea.value += message + "\n-----\n";
181
+ textarea.scrollTop = textarea.scrollHeight - textarea.clientHeight;
182
+ }
183
+ // No Textarea, No Console
184
+ else if (!consoleExists) {
185
+ alert(message);
186
+ }
187
+
188
+ // Return true
189
+ return true;
190
+ };
191
+
192
+ // ----------------------------------------------------------------------
193
+ // Emulated Status
194
+
195
+ /**
196
+ * History.getInternetExplorerMajorVersion()
197
+ * Get's the major version of Internet Explorer
198
+ * @return {integer}
199
+ * @license Public Domain
200
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
201
+ * @author James Padolsey <https://gist.github.com/527683>
202
+ */
203
+ History.getInternetExplorerMajorVersion = function() {
204
+ var result = History.getInternetExplorerMajorVersion.cached =
205
+ (typeof History.getInternetExplorerMajorVersion.cached !== 'undefined')
206
+ ? History.getInternetExplorerMajorVersion.cached
207
+ : (function() {
208
+ var v = 3,
209
+ div = document.createElement('div'),
210
+ all = div.getElementsByTagName('i');
211
+ while ((div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->') && all[0]) {
212
+ }
213
+ return (v > 4) ? v : false;
214
+ })()
215
+ ;
216
+ return result;
217
+ };
218
+
219
+ /**
220
+ * History.isInternetExplorer()
221
+ * Are we using Internet Explorer?
222
+ * @return {boolean}
223
+ * @license Public Domain
224
+ * @author Benjamin Arthur Lupton <contact@balupton.com>
225
+ */
226
+ History.isInternetExplorer = function() {
227
+ var result =
228
+ History.isInternetExplorer.cached =
229
+ (typeof History.isInternetExplorer.cached !== 'undefined')
230
+ ? History.isInternetExplorer.cached
231
+ : Boolean(History.getInternetExplorerMajorVersion())
232
+ ;
233
+ return result;
234
+ };
235
+
236
+ /**
237
+ * History.emulated
238
+ * Which features require emulating?
239
+ */
240
+ History.emulated = {
241
+ pushState: !Boolean(
242
+ window.history && window.history.pushState && window.history.replaceState
243
+ && !(
244
+ (/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent) /* disable for versions of iOS before version 4.3 (8F190) */
245
+ || (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent) /* disable for the mercury iOS browser, or at least older versions of the webkit engine */
246
+ )
247
+ ),
248
+ hashChange: Boolean(
249
+ !(('onhashchange' in window) || ('onhashchange' in document))
250
+ ||
251
+ (History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8)
252
+ )
253
+ };
254
+
255
+ /**
256
+ * History.enabled
257
+ * Is History enabled?
258
+ */
259
+ History.enabled = !History.emulated.pushState;
260
+
261
+ /**
262
+ * History.bugs
263
+ * Which bugs are present
264
+ */
265
+ History.bugs = {
266
+ /**
267
+ * Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call
268
+ * https://bugs.webkit.org/show_bug.cgi?id=56249
269
+ */
270
+ setHash: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),
271
+
272
+ /**
273
+ * Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions
274
+ * https://bugs.webkit.org/show_bug.cgi?id=42940
275
+ */
276
+ safariPoll: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),
277
+
278
+ /**
279
+ * MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)
280
+ */
281
+ ieDoubleCheck: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8),
282
+
283
+ /**
284
+ * MSIE 6 requires the entire hash to be encoded for the hashes to trigger the onHashChange event
285
+ */
286
+ hashEscape: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 7)
287
+ };
288
+
289
+ /**
290
+ * History.isEmptyObject(obj)
291
+ * Checks to see if the Object is Empty
292
+ * @param {Object} obj
293
+ * @return {boolean}
294
+ */
295
+ History.isEmptyObject = function(obj) {
296
+ for (var name in obj) {
297
+ return false;
298
+ }
299
+ return true;
300
+ };
301
+
302
+ /**
303
+ * History.cloneObject(obj)
304
+ * Clones a object
305
+ * @param {Object} obj
306
+ * @return {Object}
307
+ */
308
+ History.cloneObject = function(obj) {
309
+ var hash,newObj;
310
+ if (obj) {
311
+ hash = JSON.stringify(obj);
312
+ newObj = JSON.parse(hash);
313
+ }
314
+ else {
315
+ newObj = {};
316
+ }
317
+ return newObj;
318
+ };
319
+
320
+ // ----------------------------------------------------------------------
321
+ // URL Helpers
322
+
323
+ /**
324
+ * History.getRootUrl()
325
+ * Turns "http://mysite.com/dir/page.html?asd" into "http://mysite.com"
326
+ * @return {String} rootUrl
327
+ */
328
+ History.getRootUrl = function() {
329
+ // Create
330
+ var rootUrl = document.location.protocol + '//' + (document.location.hostname || document.location.host);
331
+ if (document.location.port || false) {
332
+ rootUrl += ':' + document.location.port;
333
+ }
334
+ rootUrl += '/';
335
+
336
+ // Return
337
+ return rootUrl;
338
+ };
339
+
340
+ /**
341
+ * History.getBaseHref()
342
+ * Fetches the `href` attribute of the `<base href="...">` element if it exists
343
+ * @return {String} baseHref
344
+ */
345
+ History.getBaseHref = function() {
346
+ // Create
347
+ var
348
+ baseElements = document.getElementsByTagName('base'),
349
+ baseElement = null,
350
+ baseHref = '';
351
+
352
+ // Test for Base Element
353
+ if (baseElements.length === 1) {
354
+ // Prepare for Base Element
355
+ baseElement = baseElements[0];
356
+ baseHref = baseElement.href.replace(/[^\/]+$/, '');
357
+ }
358
+
359
+ // Adjust trailing slash
360
+ baseHref = baseHref.replace(/\/+$/, '');
361
+ if (baseHref) baseHref += '/';
362
+
363
+ // Return
364
+ return baseHref;
365
+ };
366
+
367
+ /**
368
+ * History.getBaseUrl()
369
+ * Fetches the baseHref or basePageUrl or rootUrl (whichever one exists first)
370
+ * @return {String} baseUrl
371
+ */
372
+ History.getBaseUrl = function() {
373
+ // Create
374
+ var baseUrl = History.getBaseHref() || History.getBasePageUrl() || History.getRootUrl();
375
+
376
+ // Return
377
+ return baseUrl;
378
+ };
379
+
380
+ /**
381
+ * History.getPageUrl()
382
+ * Fetches the URL of the current page
383
+ * @return {String} pageUrl
384
+ */
385
+ History.getPageUrl = function() {
386
+ // Fetch
387
+ var
388
+ State = History.getState(false, false),
389
+ stateUrl = (State || {}).url || document.location.href;
390
+
391
+ // Create
392
+ var pageUrl = stateUrl.replace(/\/+$/, '').replace(/[^\/]+$/, function(part, index, string) {
393
+ return (/\./).test(part) ? part : part + '/';
394
+ });
395
+
396
+ // Return
397
+ return pageUrl;
398
+ };
399
+
400
+ /**
401
+ * History.getBasePageUrl()
402
+ * Fetches the Url of the directory of the current page
403
+ * @return {String} basePageUrl
404
+ */
405
+ History.getBasePageUrl = function() {
406
+ // Create
407
+ var basePageUrl = document.location.href.replace(/[#\?].*/, '').replace(/[^\/]+$/,
408
+ function(part, index, string) {
409
+ return (/[^\/]$/).test(part) ? '' : part;
410
+ }).replace(/\/+$/, '') + '/';
411
+
412
+ // Return
413
+ return basePageUrl;
414
+ };
415
+
416
+ /**
417
+ * History.getFullUrl(url)
418
+ * Ensures that we have an absolute URL and not a relative URL
419
+ * @param {string} url
420
+ * @param {Boolean} allowBaseHref
421
+ * @return {string} fullUrl
422
+ */
423
+ History.getFullUrl = function(url, allowBaseHref) {
424
+ // Prepare
425
+ var fullUrl = url, firstChar = url.substring(0, 1);
426
+ allowBaseHref = (typeof allowBaseHref === 'undefined') ? true : allowBaseHref;
427
+
428
+ // Check
429
+ if (/[a-z]+\:\/\//.test(url)) {
430
+ // Full URL
431
+ }
432
+ else if (firstChar === '/') {
433
+ // Root URL
434
+ fullUrl = History.getRootUrl() + url.replace(/^\/+/, '');
435
+ }
436
+ else if (firstChar === '#') {
437
+ // Anchor URL
438
+ fullUrl = History.getPageUrl().replace(/#.*/, '') + url;
439
+ }
440
+ else if (firstChar === '?') {
441
+ // Query URL
442
+ fullUrl = History.getPageUrl().replace(/[\?#].*/, '') + url;
443
+ }
444
+ else {
445
+ // Relative URL
446
+ if (allowBaseHref) {
447
+ fullUrl = History.getBaseUrl() + url.replace(/^(\.\/)+/, '');
448
+ } else {
449
+ fullUrl = History.getBasePageUrl() + url.replace(/^(\.\/)+/, '');
450
+ }
451
+ // We have an if condition above as we do not want hashes
452
+ // which are relative to the baseHref in our URLs
453
+ // as if the baseHref changes, then all our bookmarks
454
+ // would now point to different locations
455
+ // whereas the basePageUrl will always stay the same
456
+ }
457
+
458
+ // Return
459
+ return fullUrl.replace(/\#$/, '');
460
+ };
461
+
462
+ /**
463
+ * History.getShortUrl(url)
464
+ * Ensures that we have a relative URL and not a absolute URL
465
+ * @param {string} url
466
+ * @return {string} url
467
+ */
468
+ History.getShortUrl = function(url) {
469
+ // Prepare
470
+ var shortUrl = url, baseUrl = History.getBaseUrl(), rootUrl = History.getRootUrl();
471
+
472
+ // Trim baseUrl
473
+ if (History.emulated.pushState) {
474
+ // We are in a if statement as when pushState is not emulated
475
+ // The actual url these short urls are relative to can change
476
+ // So within the same session, we the url may end up somewhere different
477
+ shortUrl = shortUrl.replace(baseUrl, '');
478
+ }
479
+
480
+ // Trim rootUrl
481
+ shortUrl = shortUrl.replace(rootUrl, '/');
482
+
483
+ // Ensure we can still detect it as a state
484
+ if (History.isTraditionalAnchor(shortUrl)) {
485
+ shortUrl = './' + shortUrl;
486
+ }
487
+
488
+ // Clean It
489
+ shortUrl = shortUrl.replace(/^(\.\/)+/g, './').replace(/\#$/, '');
490
+
491
+ // Return
492
+ return shortUrl;
493
+ };
494
+
495
+ // ----------------------------------------------------------------------
496
+ // State Storage
497
+
498
+ /**
499
+ * History.store
500
+ * The store for all session specific data
501
+ */
502
+ History.store = amplify ? (amplify.store('History.store') || {}) : {};
503
+ History.store.idToState = History.store.idToState || {};
504
+ History.store.urlToId = History.store.urlToId || {};
505
+ History.store.stateToId = History.store.stateToId || {};
506
+
507
+ /**
508
+ * History.idToState
509
+ * 1-1: State ID to State Object
510
+ */
511
+ History.idToState = History.idToState || {};
512
+
513
+ /**
514
+ * History.stateToId
515
+ * 1-1: State String to State ID
516
+ */
517
+ History.stateToId = History.stateToId || {};
518
+
519
+ /**
520
+ * History.urlToId
521
+ * 1-1: State URL to State ID
522
+ */
523
+ History.urlToId = History.urlToId || {};
524
+
525
+ /**
526
+ * History.storedStates
527
+ * Store the states in an array
528
+ */
529
+ History.storedStates = History.storedStates || [];
530
+
531
+ /**
532
+ * History.savedStates
533
+ * Saved the states in an array
534
+ */
535
+ History.savedStates = History.savedStates || [];
536
+
537
+ /**
538
+ * History.getState()
539
+ * Get an object containing the data, title and url of the current state
540
+ * @param {Boolean} friendly
541
+ * @param {Boolean} create
542
+ * @return {Object} State
543
+ */
544
+ History.getState = function(friendly, create) {
545
+ // Prepare
546
+ if (typeof friendly === 'undefined') {
547
+ friendly = true;
548
+ }
549
+ if (typeof create === 'undefined') {
550
+ create = true;
551
+ }
552
+
553
+ // Fetch
554
+ var State = History.getLastSavedState();
555
+
556
+ // Create
557
+ if (!State && create) {
558
+ State = History.createStateObject();
559
+ }
560
+
561
+ // Adjust
562
+ if (friendly) {
563
+ State = History.cloneObject(State);
564
+ State.url = State.cleanUrl || State.url;
565
+ }
566
+
567
+ // Return
568
+ return State;
569
+ };
570
+
571
+ /**
572
+ * History.getIdByState(State)
573
+ * Gets a ID for a State
574
+ * @param {State} newState
575
+ * @return {String} id
576
+ */
577
+ History.getIdByState = function(newState) {
578
+
579
+ // Fetch ID
580
+ var id = History.extractId(newState.url);
581
+ if (!id) {
582
+ // Find ID via State String
583
+ var str = History.getStateString(newState);
584
+ if (typeof History.stateToId[str] !== 'undefined') {
585
+ id = History.stateToId[str];
586
+ }
587
+ else if (typeof History.store.stateToId[str] !== 'undefined') {
588
+ id = History.store.stateToId[str];
589
+ }
590
+ else {
591
+ // Generate a new ID
592
+ while (true) {
593
+ id = String(Math.floor(Math.random() * 1000));
594
+ if (typeof History.idToState[id] === 'undefined' && typeof History.store.idToState[id] === 'undefined') {
595
+ break;
596
+ }
597
+ }
598
+
599
+ // Apply the new State to the ID
600
+ History.stateToId[str] = id;
601
+ History.idToState[id] = newState;
602
+ }
603
+ }
604
+
605
+ // Return ID
606
+ return id;
607
+ };
608
+
609
+ /**
610
+ * History.normalizeState(State)
611
+ * Expands a State Object
612
+ * @param {object} State
613
+ * @return {object}
614
+ */
615
+ History.normalizeState = function(oldState) {
616
+ // Prepare
617
+ if (!oldState || (typeof oldState !== 'object')) {
618
+ oldState = {};
619
+ }
620
+
621
+ // Check
622
+ if (typeof oldState.normalized !== 'undefined') {
623
+ return oldState;
624
+ }
625
+
626
+ // Adjust
627
+ if (!oldState.data || (typeof oldState.data !== 'object')) {
628
+ oldState.data = {};
629
+ }
630
+
631
+ // ----------------------------------------------------------------------
632
+
633
+ // Create
634
+ var newState = {};
635
+ newState.normalized = true;
636
+ newState.title = oldState.title || '';
637
+ newState.url = History.getFullUrl(History.unescapeString(oldState.url || document.location.href));
638
+ newState.hash = History.getShortUrl(newState.url);
639
+ newState.data = History.cloneObject(oldState.data);
640
+
641
+ // Fetch ID
642
+ newState.id = History.getIdByState(newState);
643
+
644
+ // ----------------------------------------------------------------------
645
+
646
+ // Clean the URL
647
+ newState.cleanUrl = newState.url.replace(/\??\&_suid.*/, '');
648
+ newState.url = newState.cleanUrl;
649
+
650
+ // Check to see if we have more than just a url
651
+ var dataNotEmpty = !History.isEmptyObject(newState.data);
652
+
653
+ // Apply
654
+ if (newState.title || dataNotEmpty) {
655
+ // Add ID to Hash
656
+ newState.hash = History.getShortUrl(newState.url).replace(/\??\&_suid.*/, '');
657
+ if (!/\?/.test(newState.hash)) {
658
+ newState.hash += '?';
659
+ }
660
+ newState.hash += '&_suid=' + newState.id;
661
+ }
662
+
663
+ // Create the Hashed URL
664
+ newState.hashedUrl = History.getFullUrl(newState.hash);
665
+
666
+ // ----------------------------------------------------------------------
667
+
668
+ // Update the URL if we have a duplicate
669
+ if ((History.emulated.pushState || History.bugs.safariPoll) && History.hasUrlDuplicate(newState)) {
670
+ newState.url = newState.hashedUrl;
671
+ }
672
+
673
+ // ----------------------------------------------------------------------
674
+
675
+ // Return
676
+ return newState;
677
+ };
678
+
679
+ /**
680
+ * History.createStateObject(data,title,url)
681
+ * Creates a object based on the data, title and url state params
682
+ * @param {object} data
683
+ * @param {string} title
684
+ * @param {string} url
685
+ * @return {object}
686
+ */
687
+ History.createStateObject = function(data, title, url) {
688
+ // Hashify
689
+ var State = {
690
+ 'data': data,
691
+ 'title': title,
692
+ 'url': url
693
+ };
694
+
695
+ // Expand the State
696
+ State = History.normalizeState(State);
697
+
698
+ // Return object
699
+ return State;
700
+ };
701
+
702
+ /**
703
+ * History.getStateById(id)
704
+ * Get a state by it's UID
705
+ * @param {String} id
706
+ */
707
+ History.getStateById = function(id) {
708
+ // Prepare
709
+ id = String(id);
710
+
711
+ // Retrieve
712
+ var State = History.idToState[id] || History.store.idToState[id] || undefined;
713
+
714
+ // Return State
715
+ return State;
716
+ };
717
+
718
+ /**
719
+ * Get a State's String
720
+ * @param {State} passedState
721
+ */
722
+ History.getStateString = function(passedState) {
723
+ // Prepare
724
+ var State = History.normalizeState(passedState);
725
+
726
+ // Clean
727
+ var cleanedState = {
728
+ data: State.data,
729
+ title: passedState.title,
730
+ url: passedState.url
731
+ };
732
+
733
+ // Fetch
734
+ var str = JSON.stringify(cleanedState);
735
+
736
+ // Return
737
+ return str;
738
+ };
739
+
740
+ /**
741
+ * Get a State's ID
742
+ * @param {State} passedState
743
+ * @return {String} id
744
+ */
745
+ History.getStateId = function(passedState) {
746
+ // Prepare
747
+ var State = History.normalizeState(passedState);
748
+
749
+ // Fetch
750
+ var id = State.id;
751
+
752
+ // Return
753
+ return id;
754
+ };
755
+
756
+ /**
757
+ * History.getHashByState(State)
758
+ * Creates a Hash for the State Object
759
+ * @param {State} passedState
760
+ * @return {String} hash
761
+ */
762
+ History.getHashByState = function(passedState) {
763
+ // Prepare
764
+ var hash, State = History.normalizeState(passedState);
765
+
766
+ // Fetch
767
+ hash = State.hash;
768
+
769
+ // Return
770
+ return hash;
771
+ };
772
+
773
+ /**
774
+ * History.extractId(url_or_hash)
775
+ * Get a State ID by it's URL or Hash
776
+ * @param {string} url_or_hash
777
+ * @return {string} id
778
+ */
779
+ History.extractId = function (url_or_hash) {
780
+ // Prepare
781
+ var id;
782
+
783
+ // Extract
784
+ var parts,url;
785
+ parts = /(.*)\&_suid=([0-9]+)$/.exec(url_or_hash);
786
+ url = parts ? (parts[1] || url_or_hash) : url_or_hash;
787
+ id = parts ? String(parts[2] || '') : '';
788
+
789
+ // Return
790
+ return id || false;
791
+ };
792
+
793
+ /**
794
+ * History.isTraditionalAnchor
795
+ * Checks to see if the url is a traditional anchor or not
796
+ * @param {String} url_or_hash
797
+ * @return {Boolean}
798
+ */
799
+ History.isTraditionalAnchor = function(url_or_hash) {
800
+ // Check
801
+ var isTraditional = !(/[\/\?\.]/.test(url_or_hash));
802
+
803
+ // Return
804
+ return isTraditional;
805
+ };
806
+
807
+ /**
808
+ * History.extractState
809
+ * Get a State by it's URL or Hash
810
+ * @param {String} url_or_hash
811
+ * @return {State|null}
812
+ */
813
+ History.extractState = function(url_or_hash, create) {
814
+ // Prepare
815
+ var State = null;
816
+ create = create || false;
817
+
818
+ // Fetch SUID
819
+ var id = History.extractId(url_or_hash);
820
+ if (id) {
821
+ State = History.getStateById(id);
822
+ }
823
+
824
+ // Fetch SUID returned no State
825
+ if (!State) {
826
+ // Fetch URL
827
+ var url = History.getFullUrl(url_or_hash);
828
+
829
+ // Check URL
830
+ id = History.getIdByUrl(url) || false;
831
+ if (id) {
832
+ State = History.getStateById(id);
833
+ }
834
+
835
+ // Create State
836
+ if (!State && create && !History.isTraditionalAnchor(url_or_hash)) {
837
+ State = History.createStateObject(null, null, url);
838
+ }
839
+ }
840
+
841
+ // Return
842
+ return State;
843
+ };
844
+
845
+ /**
846
+ * History.getIdByUrl()
847
+ * Get a State ID by a State URL
848
+ */
849
+ History.getIdByUrl = function(url) {
850
+ // Fetch
851
+ var id = History.urlToId[url] || History.store.urlToId[url] || undefined;
852
+
853
+ // Return
854
+ return id;
855
+ };
856
+
857
+ /**
858
+ * History.getLastSavedState()
859
+ * Get an object containing the data, title and url of the current state
860
+ * @return {Object} State
861
+ */
862
+ History.getLastSavedState = function() {
863
+ return History.savedStates[History.savedStates.length - 1] || undefined;
864
+ };
865
+
866
+ /**
867
+ * History.getLastStoredState()
868
+ * Get an object containing the data, title and url of the current state
869
+ * @return {Object} State
870
+ */
871
+ History.getLastStoredState = function() {
872
+ return History.storedStates[History.storedStates.length - 1] || undefined;
873
+ };
874
+
875
+ /**
876
+ * History.hasUrlDuplicate
877
+ * Checks if a Url will have a url conflict
878
+ * @param {Object} newState
879
+ * @return {Boolean} hasDuplicate
880
+ */
881
+ History.hasUrlDuplicate = function(newState) {
882
+ // Prepare
883
+ var hasDuplicate = false;
884
+
885
+ // Fetch
886
+ var oldState = History.extractState(newState.url);
887
+
888
+ // Check
889
+ hasDuplicate = oldState && oldState.id !== newState.id;
890
+
891
+ // Return
892
+ return hasDuplicate;
893
+ };
894
+
895
+ /**
896
+ * History.storeState
897
+ * Store a State
898
+ * @param {Object} newState
899
+ * @return {Object} newState
900
+ */
901
+ History.storeState = function(newState) {
902
+ // Store the State
903
+ History.urlToId[newState.url] = newState.id;
904
+
905
+ // Push the State
906
+ History.storedStates.push(History.cloneObject(newState));
907
+
908
+ // Return newState
909
+ return newState;
910
+ };
911
+
912
+ /**
913
+ * History.isLastSavedState(newState)
914
+ * Tests to see if the state is the last state
915
+ * @param {Object} newState
916
+ * @return {boolean} isLast
917
+ */
918
+ History.isLastSavedState = function(newState) {
919
+ // Prepare
920
+ var isLast = false;
921
+
922
+ // Check
923
+ if (History.savedStates.length) {
924
+ var
925
+ newId = newState.id,
926
+ oldState = History.getLastSavedState(),
927
+ oldId = oldState.id;
928
+
929
+ // Check
930
+ isLast = (newId === oldId);
931
+ }
932
+
933
+ // Return
934
+ return isLast;
935
+ };
936
+
937
+ /**
938
+ * History.saveState
939
+ * Push a State
940
+ * @param {Object} newState
941
+ * @return {boolean} changed
942
+ */
943
+ History.saveState = function(newState) {
944
+ // Check Hash
945
+ if (History.isLastSavedState(newState)) {
946
+ return false;
947
+ }
948
+
949
+ // Push the State
950
+ History.savedStates.push(History.cloneObject(newState));
951
+
952
+ // Return true
953
+ return true;
954
+ };
955
+
956
+ /**
957
+ * History.getStateByIndex()
958
+ * Gets a state by the index
959
+ * @param {integer} index
960
+ * @return {Object}
961
+ */
962
+ History.getStateByIndex = function(index) {
963
+ // Prepare
964
+ var State = null;
965
+
966
+ // Handle
967
+ if (typeof index === 'undefined') {
968
+ // Get the last inserted
969
+ State = History.savedStates[History.savedStates.length - 1];
970
+ }
971
+ else if (index < 0) {
972
+ // Get from the end
973
+ State = History.savedStates[History.savedStates.length + index];
974
+ }
975
+ else {
976
+ // Get from the beginning
977
+ State = History.savedStates[index];
978
+ }
979
+
980
+ // Return State
981
+ return State;
982
+ };
983
+
984
+ // ----------------------------------------------------------------------
985
+ // Hash Helpers
986
+
987
+ /**
988
+ * History.getHash()
989
+ * Gets the current document hash
990
+ * @return {string}
991
+ */
992
+ History.getHash = function() {
993
+ var hash = History.unescapeHash(document.location.hash);
994
+ return hash;
995
+ };
996
+
997
+ /**
998
+ * History.unescapeString()
999
+ * Unescape a string
1000
+ * @param {String} str
1001
+ * @return {string}
1002
+ */
1003
+ History.unescapeString = function(str) {
1004
+ // Prepare
1005
+ var result = str;
1006
+
1007
+ // Unescape hash
1008
+ var tmp;
1009
+ while (true) {
1010
+ tmp = window.unescape(result);
1011
+ if (tmp === result) {
1012
+ break;
1013
+ }
1014
+ result = tmp;
1015
+ }
1016
+
1017
+ // Return result
1018
+ return result;
1019
+ };
1020
+
1021
+ /**
1022
+ * History.unescapeHash()
1023
+ * normalize and Unescape a Hash
1024
+ * @param {String} hash
1025
+ * @return {string}
1026
+ */
1027
+ History.unescapeHash = function(hash) {
1028
+ // Prepare
1029
+ var result = History.normalizeHash(hash);
1030
+
1031
+ // Unescape hash
1032
+ result = History.unescapeString(result);
1033
+
1034
+ // Return result
1035
+ return result;
1036
+ };
1037
+
1038
+ /**
1039
+ * History.normalizeHash()
1040
+ * normalize a hash across browsers
1041
+ * @return {string}
1042
+ */
1043
+ History.normalizeHash = function(hash) {
1044
+ var result = hash.replace(/[^#]*#/, '').replace(/#.*/, '');
1045
+
1046
+ // Return result
1047
+ return result;
1048
+ };
1049
+
1050
+ /**
1051
+ * History.setHash(hash)
1052
+ * Sets the document hash
1053
+ * @param {string} hash
1054
+ * @return {History}
1055
+ */
1056
+ History.setHash = function(hash, queue) {
1057
+ // Handle Queueing
1058
+ if (queue !== false && History.busy()) {
1059
+ // Wait + Push to Queue
1060
+ //History.debug('History.setHash: we must wait', arguments);
1061
+ History.pushQueue({
1062
+ scope: History,
1063
+ callback: History.setHash,
1064
+ args: arguments,
1065
+ queue: queue
1066
+ });
1067
+ return false;
1068
+ }
1069
+
1070
+ // Log
1071
+ //History.debug('History.setHash: called',hash);
1072
+
1073
+ // Prepare
1074
+ var adjustedHash = History.escapeHash(hash);
1075
+
1076
+ // Make Busy + Continue
1077
+ History.busy(true);
1078
+
1079
+ // Check if hash is a state
1080
+ var State = History.extractState(hash, true);
1081
+ if (State && !History.emulated.pushState) {
1082
+ // Hash is a state so skip the setHash
1083
+ //History.debug('History.setHash: Hash is a state so skipping the hash set with a direct pushState call',arguments);
1084
+
1085
+ // PushState
1086
+ History.pushState(State.data, State.title, State.url, false);
1087
+ }
1088
+ else if (document.location.hash !== adjustedHash) {
1089
+ // Hash is a proper hash, so apply it
1090
+
1091
+ // Handle browser bugs
1092
+ if (History.bugs.setHash) {
1093
+ // Fix Safari Bug https://bugs.webkit.org/show_bug.cgi?id=56249
1094
+
1095
+ // Fetch the base page
1096
+ var pageUrl = History.getPageUrl();
1097
+
1098
+ // Safari hash apply
1099
+ History.pushState(null, null, pageUrl + '#' + adjustedHash, false);
1100
+ }
1101
+ else {
1102
+ // Normal hash apply
1103
+ document.location.hash = adjustedHash;
1104
+ }
1105
+ }
1106
+
1107
+ // Chain
1108
+ return History;
1109
+ };
1110
+
1111
+ /**
1112
+ * History.escape()
1113
+ * normalize and Escape a Hash
1114
+ * @return {string}
1115
+ */
1116
+ History.escapeHash = function(hash) {
1117
+ var result = History.normalizeHash(hash);
1118
+
1119
+ // Escape hash
1120
+ result = window.escape(result);
1121
+
1122
+ // IE6 Escape Bug
1123
+ if (!History.bugs.hashEscape) {
1124
+ // Restore common parts
1125
+ result = result
1126
+ .replace(/\%21/g, '!')
1127
+ .replace(/\%26/g, '&')
1128
+ .replace(/\%3D/g, '=')
1129
+ .replace(/\%3F/g, '?');
1130
+ }
1131
+
1132
+ // Return result
1133
+ return result;
1134
+ };
1135
+
1136
+ /**
1137
+ * History.getHashByUrl(url)
1138
+ * Extracts the Hash from a URL
1139
+ * @param {string} url
1140
+ * @return {string} url
1141
+ */
1142
+ History.getHashByUrl = function(url) {
1143
+ // Extract the hash
1144
+ var hash = String(url)
1145
+ .replace(/([^#]*)#?([^#]*)#?(.*)/, '$2')
1146
+ ;
1147
+
1148
+ // Unescape hash
1149
+ hash = History.unescapeHash(hash);
1150
+
1151
+ // Return hash
1152
+ return hash;
1153
+ };
1154
+
1155
+ /**
1156
+ * History.setTitle(title)
1157
+ * Applies the title to the document
1158
+ * @param {State} newState
1159
+ * @return {Boolean}
1160
+ */
1161
+ History.setTitle = function(newState) {
1162
+ // Prepare
1163
+ var title = newState.title;
1164
+
1165
+ // Initial
1166
+ if (!title) {
1167
+ var firstState = History.getStateByIndex(0);
1168
+ if (firstState && firstState.url === newState.url) {
1169
+ title = firstState.title || History.options.initialTitle;
1170
+ }
1171
+ }
1172
+
1173
+ // Apply
1174
+ try {
1175
+ document.getElementsByTagName('title')[0].innerHTML = title.replace('<', '&lt;').replace('>', '&gt;').replace(' & ', ' &amp; ');
1176
+ }
1177
+ catch (Exception) {
1178
+ }
1179
+ document.title = title;
1180
+
1181
+ // Chain
1182
+ return History;
1183
+ };
1184
+
1185
+ // ----------------------------------------------------------------------
1186
+ // Queueing
1187
+
1188
+ /**
1189
+ * History.queues
1190
+ * The list of queues to use
1191
+ * First In, First Out
1192
+ */
1193
+ History.queues = [];
1194
+
1195
+ /**
1196
+ * History.busy(value)
1197
+ * @param {boolean} value [optional]
1198
+ * @return {boolean} busy
1199
+ */
1200
+ History.busy = function(value) {
1201
+ // Apply
1202
+ if (typeof value !== 'undefined') {
1203
+ //History.debug('History.busy: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues.length);
1204
+ History.busy.flag = value;
1205
+ }
1206
+ // Default
1207
+ else if (typeof History.busy.flag === 'undefined') {
1208
+ History.busy.flag = false;
1209
+ }
1210
+
1211
+ // Queue
1212
+ if (!History.busy.flag) {
1213
+ // Execute the next item in the queue
1214
+ clearTimeout(History.busy.timeout);
1215
+ var fireNext = function() {
1216
+ if (History.busy.flag) return;
1217
+ for (var i = History.queues.length - 1; i >= 0; --i) {
1218
+ var queue = History.queues[i];
1219
+ if (queue.length === 0) continue;
1220
+ var item = queue.shift();
1221
+ History.fireQueueItem(item);
1222
+ History.busy.timeout = setTimeout(fireNext, History.options.busyDelay);
1223
+ }
1224
+ };
1225
+ History.busy.timeout = setTimeout(fireNext, History.options.busyDelay);
1226
+ }
1227
+
1228
+ // Return
1229
+ return History.busy.flag;
1230
+ };
1231
+
1232
+ /**
1233
+ * History.fireQueueItem(item)
1234
+ * Fire a Queue Item
1235
+ * @param {Object} item
1236
+ * @return {Mixed} result
1237
+ */
1238
+ History.fireQueueItem = function(item) {
1239
+ return item.callback.apply(item.scope || History, item.args || []);
1240
+ };
1241
+
1242
+ /**
1243
+ * History.pushQueue(callback,args)
1244
+ * Add an item to the queue
1245
+ * @param {Object} item [scope,callback,args,queue]
1246
+ */
1247
+ History.pushQueue = function(item) {
1248
+ // Prepare the queue
1249
+ History.queues[item.queue || 0] = History.queues[item.queue || 0] || [];
1250
+
1251
+ // Add to the queue
1252
+ History.queues[item.queue || 0].push(item);
1253
+
1254
+ // Chain
1255
+ return History;
1256
+ };
1257
+
1258
+ /**
1259
+ * History.queue (item,queue), (func,queue), (func), (item)
1260
+ * Either firs the item now if not busy, or adds it to the queue
1261
+ */
1262
+ History.queue = function(item, queue) {
1263
+ // Prepare
1264
+ if (typeof item === 'function') {
1265
+ item = {
1266
+ callback: item
1267
+ };
1268
+ }
1269
+ if (typeof queue !== 'undefined') {
1270
+ item.queue = queue;
1271
+ }
1272
+
1273
+ // Handle
1274
+ if (History.busy()) {
1275
+ History.pushQueue(item);
1276
+ } else {
1277
+ History.fireQueueItem(item);
1278
+ }
1279
+
1280
+ // Chain
1281
+ return History;
1282
+ };
1283
+
1284
+ /**
1285
+ * History.clearQueue()
1286
+ * Clears the Queue
1287
+ */
1288
+ History.clearQueue = function() {
1289
+ History.busy.flag = false;
1290
+ History.queues = [];
1291
+ return History;
1292
+ };
1293
+
1294
+
1295
+ // ----------------------------------------------------------------------
1296
+ // IE Bug Fix
1297
+
1298
+ /**
1299
+ * History.stateChanged
1300
+ * States whether or not the state has changed since the last double check was initialised
1301
+ */
1302
+ History.stateChanged = false;
1303
+
1304
+ /**
1305
+ * History.doubleChecker
1306
+ * Contains the timeout used for the double checks
1307
+ */
1308
+ History.doubleChecker = false;
1309
+
1310
+ /**
1311
+ * History.doubleCheckComplete()
1312
+ * Complete a double check
1313
+ * @return {History}
1314
+ */
1315
+ History.doubleCheckComplete = function() {
1316
+ // Update
1317
+ History.stateChanged = true;
1318
+
1319
+ // Clear
1320
+ History.doubleCheckClear();
1321
+
1322
+ // Chain
1323
+ return History;
1324
+ };
1325
+
1326
+ /**
1327
+ * History.doubleCheckClear()
1328
+ * Clear a double check
1329
+ * @return {History}
1330
+ */
1331
+ History.doubleCheckClear = function() {
1332
+ // Clear
1333
+ if (History.doubleChecker) {
1334
+ clearTimeout(History.doubleChecker);
1335
+ History.doubleChecker = false;
1336
+ }
1337
+
1338
+ // Chain
1339
+ return History;
1340
+ };
1341
+
1342
+ /**
1343
+ * History.doubleCheck()
1344
+ * Create a double check
1345
+ * @return {History}
1346
+ */
1347
+ History.doubleCheck = function(tryAgain) {
1348
+ // Reset
1349
+ History.stateChanged = false;
1350
+ History.doubleCheckClear();
1351
+
1352
+ // Fix IE6,IE7 bug where calling history.back or history.forward does not actually change the hash (whereas doing it manually does)
1353
+ // Fix Safari 5 bug where sometimes the state does not change: https://bugs.webkit.org/show_bug.cgi?id=42940
1354
+ if (History.bugs.ieDoubleCheck) {
1355
+ // Apply Check
1356
+ History.doubleChecker = setTimeout(
1357
+ function() {
1358
+ History.doubleCheckClear();
1359
+ if (!History.stateChanged) {
1360
+ //History.debug('History.doubleCheck: State has not yet changed, trying again', arguments);
1361
+ // Re-Attempt
1362
+ tryAgain();
1363
+ }
1364
+ return true;
1365
+ },
1366
+ History.options.doubleCheckInterval
1367
+ );
1368
+ }
1369
+
1370
+ // Chain
1371
+ return History;
1372
+ };
1373
+
1374
+ // ----------------------------------------------------------------------
1375
+ // Safari Bug Fix
1376
+
1377
+ /**
1378
+ * History.safariStatePoll()
1379
+ * Poll the current state
1380
+ * @return {History}
1381
+ */
1382
+ History.safariStatePoll = function() {
1383
+ // Poll the URL
1384
+
1385
+ // Get the Last State which has the new URL
1386
+ var
1387
+ urlState = History.extractState(document.location.href),
1388
+ newState;
1389
+
1390
+ // Check for a difference
1391
+ if (!History.isLastSavedState(urlState)) {
1392
+ newState = urlState;
1393
+ }
1394
+ else {
1395
+ return;
1396
+ }
1397
+
1398
+ // Check if we have a state with that url
1399
+ // If not create it
1400
+ if (!newState) {
1401
+ //History.debug('History.safariStatePoll: new');
1402
+ newState = History.createStateObject();
1403
+ }
1404
+
1405
+ // Apply the New State
1406
+ //History.debug('History.safariStatePoll: trigger');
1407
+ History.Adapter.trigger(window, 'popstate');
1408
+
1409
+ // Chain
1410
+ return History;
1411
+ };
1412
+
1413
+ // ----------------------------------------------------------------------
1414
+ // State Aliases
1415
+
1416
+ /**
1417
+ * History.back(queue)
1418
+ * Send the browser history back one item
1419
+ * @param {Integer} queue [optional]
1420
+ */
1421
+ History.back = function(queue) {
1422
+ //History.debug('History.back: called', arguments);
1423
+
1424
+ // Handle Queueing
1425
+ if (queue !== false && History.busy()) {
1426
+ // Wait + Push to Queue
1427
+ //History.debug('History.back: we must wait', arguments);
1428
+ History.pushQueue({
1429
+ scope: History,
1430
+ callback: History.back,
1431
+ args: arguments,
1432
+ queue: queue
1433
+ });
1434
+ return false;
1435
+ }
1436
+
1437
+ // Make Busy + Continue
1438
+ History.busy(true);
1439
+
1440
+ // Fix certain browser bugs that prevent the state from changing
1441
+ History.doubleCheck(function() {
1442
+ History.back(false);
1443
+ });
1444
+
1445
+ // Go back
1446
+ history.go(-1);
1447
+
1448
+ // End back closure
1449
+ return true;
1450
+ };
1451
+
1452
+ /**
1453
+ * History.forward(queue)
1454
+ * Send the browser history forward one item
1455
+ * @param {Integer} queue [optional]
1456
+ */
1457
+ History.forward = function(queue) {
1458
+ //History.debug('History.forward: called', arguments);
1459
+
1460
+ // Handle Queueing
1461
+ if (queue !== false && History.busy()) {
1462
+ // Wait + Push to Queue
1463
+ //History.debug('History.forward: we must wait', arguments);
1464
+ History.pushQueue({
1465
+ scope: History,
1466
+ callback: History.forward,
1467
+ args: arguments,
1468
+ queue: queue
1469
+ });
1470
+ return false;
1471
+ }
1472
+
1473
+ // Make Busy + Continue
1474
+ History.busy(true);
1475
+
1476
+ // Fix certain browser bugs that prevent the state from changing
1477
+ History.doubleCheck(function() {
1478
+ History.forward(false);
1479
+ });
1480
+
1481
+ // Go forward
1482
+ history.go(1);
1483
+
1484
+ // End forward closure
1485
+ return true;
1486
+ };
1487
+
1488
+ /**
1489
+ * History.go(index,queue)
1490
+ * Send the browser history back or forward index times
1491
+ * @param {Integer} queue [optional]
1492
+ */
1493
+ History.go = function(index, queue) {
1494
+ //History.debug('History.go: called', arguments);
1495
+
1496
+ // Prepare
1497
+ var i;
1498
+
1499
+ // Handle
1500
+ if (index > 0) {
1501
+ // Forward
1502
+ for (i = 1; i <= index; ++i) {
1503
+ History.forward(queue);
1504
+ }
1505
+ }
1506
+ else if (index < 0) {
1507
+ // Backward
1508
+ for (i = -1; i >= index; --i) {
1509
+ History.back(queue);
1510
+ }
1511
+ }
1512
+ else {
1513
+ throw new Error('History.go: History.go requires a positive or negative integer passed.');
1514
+ }
1515
+
1516
+ // Chain
1517
+ return History;
1518
+ };
1519
+
1520
+
1521
+ // ----------------------------------------------------------------------
1522
+ // Initialise
1523
+
1524
+ /**
1525
+ * Create the initial State
1526
+ */
1527
+ History.saveState(History.storeState(History.extractState(document.location.href, true)));
1528
+
1529
+ /**
1530
+ * Bind for Saving Store
1531
+ */
1532
+ if (amplify) {
1533
+ History.onUnload = function() {
1534
+ // Prepare
1535
+ var
1536
+ currentStore = amplify.store('History.store') || {},
1537
+ item;
1538
+
1539
+ // Ensure
1540
+ currentStore.idToState = currentStore.idToState || {};
1541
+ currentStore.urlToId = currentStore.urlToId || {};
1542
+ currentStore.stateToId = currentStore.stateToId || {};
1543
+
1544
+ // Sync
1545
+ for (item in History.idToState) {
1546
+ if (!History.idToState.hasOwnProperty(item)) {
1547
+ continue;
1548
+ }
1549
+ currentStore.idToState[item] = History.idToState[item];
1550
+ }
1551
+ for (item in History.urlToId) {
1552
+ if (!History.urlToId.hasOwnProperty(item)) {
1553
+ continue;
1554
+ }
1555
+ currentStore.urlToId[item] = History.urlToId[item];
1556
+ }
1557
+ for (item in History.stateToId) {
1558
+ if (!History.stateToId.hasOwnProperty(item)) {
1559
+ continue;
1560
+ }
1561
+ currentStore.stateToId[item] = History.stateToId[item];
1562
+ }
1563
+
1564
+ // Update
1565
+ History.store = currentStore;
1566
+
1567
+ // Store
1568
+ amplify.store('History.store', currentStore);
1569
+ };
1570
+ // For Internet Explorer
1571
+ setInterval(History.onUnload, History.options.storeInterval);
1572
+ // For Other Browsers
1573
+ History.Adapter.bind(window, 'beforeunload', History.onUnload);
1574
+ History.Adapter.bind(window, 'unload', History.onUnload);
1575
+ // Both are enabled for consistency
1576
+ }
1577
+
1578
+
1579
+ // ----------------------------------------------------------------------
1580
+ // HTML5 State Support
1581
+
1582
+ if (History.emulated.pushState) {
1583
+ /*
1584
+ * Provide Skeleton for HTML4 Browsers
1585
+ */
1586
+
1587
+ // Prepare
1588
+ var emptyFunction = function() {
1589
+ };
1590
+ History.pushState = History.pushState || emptyFunction;
1591
+ History.replaceState = History.replaceState || emptyFunction;
1592
+ }
1593
+ else {
1594
+ /*
1595
+ * Use native HTML5 History API Implementation
1596
+ */
1597
+
1598
+ /**
1599
+ * History.onPopState(event,extra)
1600
+ * Refresh the Current State
1601
+ */
1602
+ History.onPopState = function(event) {
1603
+ // Reset the double check
1604
+ History.doubleCheckComplete();
1605
+
1606
+ // Check for a Hash, and handle apporiatly
1607
+ var currentHash = History.getHash();
1608
+ if (currentHash) {
1609
+ // Expand Hash
1610
+ var currentState = History.extractState(currentHash || document.location.href, true);
1611
+ if (currentState) {
1612
+ // We were able to parse it, it must be a State!
1613
+ // Let's forward to replaceState
1614
+ //History.debug('History.onPopState: state anchor', currentHash, currentState);
1615
+ History.replaceState(currentState.data, currentState.title, currentState.url, false);
1616
+ }
1617
+ else {
1618
+ // Traditional Anchor
1619
+ //History.debug('History.onPopState: traditional anchor', currentHash);
1620
+ History.Adapter.trigger(window, 'anchorchange');
1621
+ History.busy(false);
1622
+ }
1623
+
1624
+ // We don't care for hashes
1625
+ History.expectedStateId = false;
1626
+ return false;
1627
+ }
1628
+
1629
+ // Prepare
1630
+ var newState = false;
1631
+
1632
+ // Prepare
1633
+ event = event || {};
1634
+ if (typeof event.state === 'undefined') {
1635
+ // jQuery
1636
+ if (typeof event.originalEvent !== 'undefined' && typeof event.originalEvent.state !== 'undefined') {
1637
+ event.state = event.originalEvent.state || false;
1638
+ }
1639
+ // MooTools
1640
+ else if (typeof event.event !== 'undefined' && typeof event.event.state !== 'undefined') {
1641
+ event.state = event.event.state || false;
1642
+ }
1643
+ }
1644
+
1645
+ // Ensure
1646
+ event.state = (event.state || false);
1647
+
1648
+ // Fetch State
1649
+ if (event.state) {
1650
+ // Vanilla: Back/forward button was used
1651
+ newState = History.getStateById(event.state);
1652
+ }
1653
+ else if (History.expectedStateId) {
1654
+ // Vanilla: A new state was pushed, and popstate was called manually
1655
+ newState = History.getStateById(History.expectedStateId);
1656
+ }
1657
+ else {
1658
+ // Initial State
1659
+ newState = History.extractState(document.location.href);
1660
+ }
1661
+
1662
+ // The State did not exist in our store
1663
+ if (!newState) {
1664
+ // Regenerate the State
1665
+ newState = History.createStateObject(null, null, document.location.href);
1666
+ }
1667
+
1668
+ // Clean
1669
+ History.expectedStateId = false;
1670
+
1671
+ // Check if we are the same state
1672
+ if (History.isLastSavedState(newState)) {
1673
+ // There has been no change (just the page's hash has finally propagated)
1674
+ //History.debug('History.onPopState: no change', newState, History.savedStates);
1675
+ History.busy(false);
1676
+ return false;
1677
+ }
1678
+
1679
+ // Store the State
1680
+ History.storeState(newState);
1681
+ History.saveState(newState);
1682
+
1683
+ // Force update of the title
1684
+ History.setTitle(newState);
1685
+
1686
+ // Fire Our Event
1687
+ History.Adapter.trigger(window, 'statechange');
1688
+ History.busy(false);
1689
+
1690
+ // Return true
1691
+ return true;
1692
+ };
1693
+ History.Adapter.bind(window, 'popstate', History.onPopState);
1694
+
1695
+ /**
1696
+ * History.pushState(data,title,url)
1697
+ * Add a new State to the history object, become it, and trigger onpopstate
1698
+ * We have to trigger for HTML4 compatibility
1699
+ * @param {object} data
1700
+ * @param {string} title
1701
+ * @param {string} url
1702
+ * @return {true}
1703
+ */
1704
+ History.pushState = function(data, title, url, queue) {
1705
+ //History.debug('History.pushState: called', arguments);
1706
+
1707
+ // Check the State
1708
+ if (History.getHashByUrl(url) && History.emulated.pushState) {
1709
+ throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
1710
+ }
1711
+
1712
+ // Handle Queueing
1713
+ if (queue !== false && History.busy()) {
1714
+ // Wait + Push to Queue
1715
+ //History.debug('History.pushState: we must wait', arguments);
1716
+ History.pushQueue({
1717
+ scope: History,
1718
+ callback: History.pushState,
1719
+ args: arguments,
1720
+ queue: queue
1721
+ });
1722
+ return false;
1723
+ }
1724
+
1725
+ // Make Busy + Continue
1726
+ History.busy(true);
1727
+
1728
+ // Create the newState
1729
+ var newState = History.createStateObject(data, title, url);
1730
+
1731
+ // Check it
1732
+ if (History.isLastSavedState(newState)) {
1733
+ // Won't be a change
1734
+ History.busy(false);
1735
+ }
1736
+ else {
1737
+ // Store the newState
1738
+ History.storeState(newState);
1739
+ History.expectedStateId = newState.id;
1740
+
1741
+ // Push the newState
1742
+ history.pushState(newState.id, newState.title, newState.url);
1743
+
1744
+ // Fire HTML5 Event
1745
+ History.Adapter.trigger(window, 'popstate');
1746
+ }
1747
+
1748
+ // End pushState closure
1749
+ return true;
1750
+ };
1751
+
1752
+ /**
1753
+ * History.replaceState(data,title,url)
1754
+ * Replace the State and trigger onpopstate
1755
+ * We have to trigger for HTML4 compatibility
1756
+ * @param {object} data
1757
+ * @param {string} title
1758
+ * @param {string} url
1759
+ * @return {true}
1760
+ */
1761
+ History.replaceState = function(data, title, url, queue) {
1762
+ //History.debug('History.replaceState: called', arguments);
1763
+
1764
+ // Check the State
1765
+ if (History.getHashByUrl(url) && History.emulated.pushState) {
1766
+ throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
1767
+ }
1768
+
1769
+ // Handle Queueing
1770
+ if (queue !== false && History.busy()) {
1771
+ // Wait + Push to Queue
1772
+ //History.debug('History.replaceState: we must wait', arguments);
1773
+ History.pushQueue({
1774
+ scope: History,
1775
+ callback: History.replaceState,
1776
+ args: arguments,
1777
+ queue: queue
1778
+ });
1779
+ return false;
1780
+ }
1781
+
1782
+ // Make Busy + Continue
1783
+ History.busy(true);
1784
+
1785
+ // Create the newState
1786
+ var newState = History.createStateObject(data, title, url);
1787
+
1788
+ // Check it
1789
+ if (History.isLastSavedState(newState)) {
1790
+ // Won't be a change
1791
+ History.busy(false);
1792
+ }
1793
+ else {
1794
+ // Store the newState
1795
+ History.storeState(newState);
1796
+ History.expectedStateId = newState.id;
1797
+
1798
+ // Push the newState
1799
+ history.replaceState(newState.id, newState.title, newState.url);
1800
+
1801
+ // Fire HTML5 Event
1802
+ History.Adapter.trigger(window, 'popstate');
1803
+ }
1804
+
1805
+ // End replaceState closure
1806
+ return true;
1807
+ };
1808
+
1809
+ // Be aware, the following is only for native pushState implementations
1810
+ // If you are wanting to include something for all browsers
1811
+ // Then include it above this if block
1812
+
1813
+ /**
1814
+ * Setup Safari Fix
1815
+ */
1816
+ if (History.bugs.safariPoll) {
1817
+ setInterval(History.safariStatePoll, History.options.safariPollInterval);
1818
+ }
1819
+
1820
+ /**
1821
+ * Ensure Cross Browser Compatibility
1822
+ */
1823
+ if (navigator.vendor === 'Apple Computer, Inc.' || (navigator.appCodeName || '') === 'Mozilla') {
1824
+ /**
1825
+ * Fix Safari HashChange Issue
1826
+ */
1827
+
1828
+ // Setup Alias
1829
+ History.Adapter.bind(window, 'hashchange', function() {
1830
+ History.Adapter.trigger(window, 'popstate');
1831
+ });
1832
+
1833
+ // Initialise Alias
1834
+ if (History.getHash()) {
1835
+ History.Adapter.onDomLoad(function() {
1836
+ History.Adapter.trigger(window, 'hashchange');
1837
+ });
1838
+ }
1839
+ }
1840
+
1841
+ } // !History.emulated.pushState
1842
+
1843
+ }; // History.initCore
1844
+
1845
+ // Try and Initialise History
1846
+ History.init();
1677
1847
 
1678
1848
  })(window);