You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
3.3 KiB

  1. var queryString = require('query-string')
  2. function get () {
  3. var state = {}
  4. // path
  5. if (currentPath) {
  6. state.path = currentPath
  7. }
  8. // location
  9. if (typeof map.getZoom() === 'undefined') {
  10. return
  11. }
  12. var center = map.getCenter()
  13. var zoom = map.getZoom()
  14. state.lat = center.lat
  15. state.lon = center.lng
  16. state.zoom = zoom
  17. // other modules
  18. call_hooks('state-get', state)
  19. // done
  20. return state
  21. }
  22. function apply (state) {
  23. // path
  24. setPath(state.path)
  25. // location
  26. if (state.lat && state.lon && state.zoom) {
  27. if (typeof map.getZoom() === 'undefined') {
  28. map.setView({ lat: state.lat, lng: state.lon }, state.zoom)
  29. } else {
  30. map.flyTo({ lat: state.lat, lng: state.lon }, state.zoom)
  31. }
  32. }
  33. // other modules
  34. call_hooks('state-apply', state)
  35. }
  36. function stringify (state) {
  37. var link = ''
  38. if (!state) {
  39. state = get()
  40. }
  41. var tmpState = JSON.parse(JSON.stringify(state))
  42. // path
  43. if (state.path) {
  44. link += state.path
  45. delete tmpState.path
  46. }
  47. // location
  48. var locPrecision = 5
  49. if (state.zoom) {
  50. locPrecision =
  51. state.zoom > 16 ? 5 :
  52. state.zoom > 8 ? 4 :
  53. state.zoom > 4 ? 3 :
  54. state.zoom > 2 ? 2 :
  55. state.zoom > 1 ? 1 : 0
  56. }
  57. if (state.zoom && state.lat && state.lon) {
  58. link += (link === '' ? '' : '&') + 'map=' +
  59. parseFloat(state.zoom).toFixed(0) + '/' +
  60. state.lat.toFixed(locPrecision) + '/' +
  61. state.lon.toFixed(locPrecision)
  62. delete tmpState.zoom
  63. delete tmpState.lat
  64. delete tmpState.lon
  65. }
  66. var newHash = queryString.stringify(tmpState)
  67. newHash = newHash.replace(/%2F/g, '/')
  68. if (newHash !== '') {
  69. link += (link === '' ? '' : '&') + newHash
  70. }
  71. return link
  72. }
  73. function parse (link) {
  74. var firstEquals = link.search('=')
  75. var firstAmp = link.search('&')
  76. var urlNonPathPart = ''
  77. var newState = {}
  78. var newPath = ''
  79. if (link === '') {
  80. // nothing
  81. } else if (firstEquals === -1) {
  82. if (firstAmp === -1) {
  83. newPath = link
  84. } else {
  85. newPath = link.substr(0, firstAmp)
  86. }
  87. } else {
  88. if (firstAmp === -1) {
  89. urlNonPathPart = link
  90. } else if (firstAmp < firstEquals) {
  91. newPath = link.substr(0, firstAmp)
  92. urlNonPathPart = link.substr(firstAmp + 1)
  93. } else {
  94. urlNonPathPart = link
  95. }
  96. }
  97. newState = queryString.parse(urlNonPathPart)
  98. if (newPath !== '') {
  99. newState.path = newPath
  100. }
  101. if ('map' in newState) {
  102. var parts = newState.map.split('/')
  103. newState.zoom = parts[0]
  104. newState.lat = parts[1]
  105. newState.lon = parts[2]
  106. delete newState.map
  107. }
  108. return newState
  109. }
  110. function update (state, push) {
  111. if (!state) {
  112. state = get()
  113. }
  114. var newHash = '#' + stringify(state)
  115. if (push) {
  116. history.pushState(null, null, newHash)
  117. console.log('push', newHash, state)
  118. } else if (location.hash !== newHash && (location.hash !== '' || newHash !== '#')) {
  119. history.replaceState(null, null, newHash)
  120. console.log('replace', newHash, state)
  121. } else {
  122. console.log('ignore', newHash, state)
  123. }
  124. }
  125. module.exports = {
  126. get: get, // get the current app state
  127. apply: apply, // apply a state to the current app
  128. stringify: stringify, // create a link from a state (or the current state)
  129. parse: parse, // parse a state from a link
  130. update: update // update url (either replace or push)
  131. }