album.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /**
  2. * @description Takes care of every action an album can handle and execute.
  3. */
  4. album = {
  5. json: null
  6. }
  7. album.getID = function() {
  8. let id = null
  9. let isID = (id) => {
  10. if (id==='0' || id==='f' || id==='s' || id==='r') return true
  11. return $.isNumeric(id)
  12. }
  13. if (photo.json) id = photo.json.album
  14. else if (album.json) id = album.json.id
  15. // Search
  16. if (isID(id)===false) id = $('.album:hover, .album.active').attr('data-id')
  17. if (isID(id)===false) id = $('.photo:hover, .photo.active').attr('data-album-id')
  18. if (isID(id)===true) return id
  19. else return false
  20. }
  21. album.load = function(albumID, refresh = false) {
  22. password.get(albumID, function() {
  23. if (refresh===false) lychee.animate('.content', 'contentZoomOut')
  24. let startTime = new Date().getTime()
  25. let params = {
  26. albumID,
  27. password: password.value
  28. }
  29. api.post('Album::get', params, function(data) {
  30. let waitTime = 0
  31. if (data==='Warning: Album private!') {
  32. if (document.location.hash.replace('#', '').split('/')[1]!=undefined) {
  33. // Display photo only
  34. lychee.setMode('view')
  35. } else {
  36. // Album not public
  37. lychee.content.show()
  38. lychee.goto()
  39. }
  40. return false
  41. }
  42. if (data==='Warning: Wrong password!') {
  43. album.load(albumID, refresh)
  44. return false
  45. }
  46. album.json = data
  47. // Calculate delay
  48. let durationTime = (new Date().getTime() - startTime)
  49. if (durationTime>300) waitTime = 0
  50. else waitTime = 300 - durationTime
  51. // Skip delay when refresh is true
  52. // Skip delay when opening a blank Lychee
  53. if (refresh===true) waitTime = 0
  54. if (!visible.albums() && !visible.photo() && !visible.album()) waitTime = 0
  55. setTimeout(() => {
  56. view.album.init()
  57. if (refresh===false) {
  58. lychee.animate(lychee.content, 'contentZoomIn')
  59. header.setMode('album')
  60. }
  61. }, waitTime)
  62. })
  63. })
  64. }
  65. album.parse = function() {
  66. if (!album.json.title) album.json.title = 'Untitled'
  67. }
  68. album.add = function() {
  69. const action = function(data) {
  70. let title = data.title
  71. const isNumber = (n) => (!isNaN(parseFloat(n)) && isFinite(n))
  72. basicModal.close()
  73. let params = {
  74. title
  75. }
  76. api.post('Album::add', params, function(data) {
  77. if (data!==false && isNumber(data)) {
  78. albums.refresh()
  79. lychee.goto(data)
  80. } else {
  81. lychee.error(null, params, data)
  82. }
  83. })
  84. }
  85. basicModal.show({
  86. body: `<p>Enter a title for the new album: <input class='text' name='title' type='text' maxlength='50' placeholder='Title' value='Untitled'></p>`,
  87. buttons: {
  88. action: {
  89. title: 'Create Album',
  90. fn: action
  91. },
  92. cancel: {
  93. title: 'Cancel',
  94. fn: basicModal.close
  95. }
  96. }
  97. })
  98. }
  99. album.delete = function(albumIDs) {
  100. let action = {}
  101. let cancel = {}
  102. let msg = ''
  103. if (!albumIDs) return false
  104. if (albumIDs instanceof Array===false) albumIDs = [ albumIDs ]
  105. action.fn = function() {
  106. basicModal.close()
  107. let params = {
  108. albumIDs: albumIDs.join()
  109. }
  110. api.post('Album::delete', params, function(data) {
  111. if (visible.albums()) {
  112. albumIDs.forEach(function(id) {
  113. albums.json.num--
  114. view.albums.content.delete(id)
  115. albums.deleteByID(id)
  116. })
  117. } else {
  118. albums.refresh()
  119. lychee.goto()
  120. }
  121. if (data!==true) lychee.error(null, params, data)
  122. })
  123. }
  124. if (albumIDs.toString()==='0') {
  125. action.title = 'Clear Unsorted'
  126. cancel.title = 'Keep Unsorted'
  127. msg = `<p>Are you sure you want to delete all photos from 'Unsorted'?<br>This action can't be undone!</p>`
  128. } else if (albumIDs.length===1) {
  129. let albumTitle = ''
  130. action.title = 'Delete Album and Photos'
  131. cancel.title = 'Keep Album'
  132. // Get title
  133. if (album.json) albumTitle = album.json.title
  134. else if (albums.json) albumTitle = albums.getByID(albumIDs).title
  135. // Fallback for album without a title
  136. if (albumTitle==='') albumTitle = 'Untitled'
  137. msg = lychee.html`<p>Are you sure you want to delete the album '$${ albumTitle }' and all of the photos it contains? This action can't be undone!</p>`
  138. } else {
  139. action.title = 'Delete Albums and Photos'
  140. cancel.title = 'Keep Albums'
  141. msg = lychee.html`<p>Are you sure you want to delete all $${ albumIDs.length } selected albums and all of the photos they contain? This action can't be undone!</p>`
  142. }
  143. basicModal.show({
  144. body: msg,
  145. buttons: {
  146. action: {
  147. title: action.title,
  148. fn: action.fn,
  149. class: 'red'
  150. },
  151. cancel: {
  152. title: cancel.title,
  153. fn: basicModal.close
  154. }
  155. }
  156. })
  157. }
  158. album.setTitle = function(albumIDs) {
  159. let oldTitle = ''
  160. let msg = ''
  161. if (!albumIDs) return false
  162. if (albumIDs instanceof Array===false) albumIDs = [ albumIDs ]
  163. if (albumIDs.length===1) {
  164. // Get old title if only one album is selected
  165. if (album.json) oldTitle = album.json.title
  166. else if (albums.json) oldTitle = albums.getByID(albumIDs).title
  167. }
  168. const action = function(data) {
  169. basicModal.close()
  170. let newTitle = data.title
  171. if (visible.album()) {
  172. // Rename only one album
  173. album.json.title = newTitle
  174. view.album.title()
  175. if (albums.json) albums.getByID(albumIDs[0]).title = newTitle
  176. } else if (visible.albums()) {
  177. // Rename all albums
  178. albumIDs.forEach(function(id) {
  179. albums.getByID(id).title = newTitle
  180. view.albums.content.title(id)
  181. })
  182. }
  183. let params = {
  184. albumIDs : albumIDs.join(),
  185. title : newTitle
  186. }
  187. api.post('Album::setTitle', params, function(data) {
  188. if (data!==true) lychee.error(null, params, data)
  189. })
  190. }
  191. let input = lychee.html`<input class='text' name='title' type='text' maxlength='50' placeholder='Title' value='$${ oldTitle }'>`
  192. if (albumIDs.length===1) msg = lychee.html`<p>Enter a new title for this album: ${ input }</p>`
  193. else msg = lychee.html`<p>Enter a title for all $${ albumIDs.length } selected albums: ${ input }</p>`
  194. basicModal.show({
  195. body: msg,
  196. buttons: {
  197. action: {
  198. title: 'Set Title',
  199. fn: action
  200. },
  201. cancel: {
  202. title: 'Cancel',
  203. fn: basicModal.close
  204. }
  205. }
  206. })
  207. }
  208. album.setDescription = function(albumID) {
  209. let oldDescription = album.json.description
  210. const action = function(data) {
  211. let description = data.description
  212. basicModal.close()
  213. if (visible.album()) {
  214. album.json.description = description
  215. view.album.description()
  216. }
  217. let params = {
  218. albumID,
  219. description
  220. }
  221. api.post('Album::setDescription', params, function(data) {
  222. if (data!==true) lychee.error(null, params, data)
  223. })
  224. }
  225. basicModal.show({
  226. body: lychee.html`<p>Please enter a description for this album: <input class='text' name='description' type='text' maxlength='800' placeholder='Description' value='$${ oldDescription }'></p>`,
  227. buttons: {
  228. action: {
  229. title: 'Set Description',
  230. fn: action
  231. },
  232. cancel: {
  233. title: 'Cancel',
  234. fn: basicModal.close
  235. }
  236. }
  237. })
  238. }
  239. album.setPublic = function(albumID, modal, e) {
  240. let password = ''
  241. albums.refresh()
  242. if (modal===true) {
  243. let text = ''
  244. let action = {}
  245. action.fn = () => {
  246. // Call setPublic function without showing the modal
  247. album.setPublic(album.getID(), false, e)
  248. }
  249. // Album public = Editing a shared album
  250. if (album.json.public==='1') {
  251. action.title = 'Edit Sharing'
  252. text = 'The sharing-properties of this album will be changed to the following:'
  253. } else {
  254. action.title = 'Share Album'
  255. text = 'This album will be shared with the following properties:'
  256. }
  257. let msg = `
  258. <p class='less'>${ text }</p>
  259. <form>
  260. <div class='choice'>
  261. <label>
  262. <input type='checkbox' name='hidden'>
  263. <span class='checkbox'>${ build.iconic('check') }</span>
  264. <span class='label'>Hidden</span>
  265. </label>
  266. <p>Only people with the direct link can view this album.</p>
  267. </div>
  268. <div class='choice'>
  269. <label>
  270. <input type='checkbox' name='downloadable'>
  271. <span class='checkbox'>${ build.iconic('check') }</span>
  272. <span class='label'>Downloadable</span>
  273. </label>
  274. <p>Visitors of your Lychee can download this album.</p>
  275. </div>
  276. <div class='choice'>
  277. <label>
  278. <input type='checkbox' name='password'>
  279. <span class='checkbox'>${ build.iconic('check') }</span>
  280. <span class='label'>Password protected</span>
  281. </label>
  282. <p>Album only accessible with a valid password.</p>
  283. <input class='text' name='passwordtext' type='password' placeholder='password' value=''>
  284. </div>
  285. </form>
  286. `
  287. basicModal.show({
  288. body: msg,
  289. buttons: {
  290. action: {
  291. title: action.title,
  292. fn: action.fn
  293. },
  294. cancel: {
  295. title: 'Cancel',
  296. fn: basicModal.close
  297. }
  298. }
  299. })
  300. if (album.json.public==='1' && album.json.visible==='0') $('.basicModal .choice input[name="hidden"]').click()
  301. if (album.json.downloadable==='1') $('.basicModal .choice input[name="downloadable"]').click()
  302. $('.basicModal .choice input[name="password"]').on('change', function() {
  303. if ($(this).prop('checked')===true) $('.basicModal .choice input[name="passwordtext"]').show().focus()
  304. else $('.basicModal .choice input[name="passwordtext"]').hide()
  305. })
  306. return true
  307. }
  308. // Set data
  309. if (basicModal.visible()) {
  310. // Visible modal => Set album public
  311. album.json.public = '1'
  312. // Set visible
  313. if ($('.basicModal .choice input[name="hidden"]:checked').length===1) album.json.visible = '0'
  314. else album.json.visible = '1'
  315. // Set downloadable
  316. if ($('.basicModal .choice input[name="downloadable"]:checked').length===1) album.json.downloadable = '1'
  317. else album.json.downloadable = '0'
  318. // Set password
  319. if ($('.basicModal .choice input[name="password"]:checked').length===1) {
  320. password = $('.basicModal .choice input[name="passwordtext"]').val()
  321. album.json.password = '1'
  322. } else {
  323. password = ''
  324. album.json.password = '0'
  325. }
  326. // Modal input has been processed, now it can be closed
  327. basicModal.close()
  328. } else {
  329. // Modal not visible => Set album private
  330. album.json.public = '0'
  331. }
  332. // Set data and refresh view
  333. if (visible.album()) {
  334. album.json.visible = (album.json.public==='0') ? '1' : album.json.visible
  335. album.json.downloadable = (album.json.public==='0') ? '0' : album.json.downloadable
  336. album.json.password = (album.json.public==='0') ? '0' : album.json.password
  337. view.album.public()
  338. view.album.hidden()
  339. view.album.downloadable()
  340. view.album.password()
  341. if (album.json.public==='1') contextMenu.shareAlbum(albumID, e)
  342. }
  343. let params = {
  344. albumID,
  345. public : album.json.public,
  346. password : password,
  347. visible : album.json.visible,
  348. downloadable : album.json.downloadable
  349. }
  350. api.post('Album::setPublic', params, function(data) {
  351. if (data!==true) lychee.error(null, params, data)
  352. })
  353. }
  354. album.share = function(service) {
  355. let url = location.href
  356. switch (service) {
  357. case 'twitter':
  358. window.open(`https://twitter.com/share?url=${ encodeURI(url) }`)
  359. break
  360. case 'facebook':
  361. window.open(`http://www.facebook.com/sharer.php?u=${ encodeURI(url) }&t=${ encodeURI(album.json.title) }`)
  362. break
  363. case 'mail':
  364. location.href = `mailto:?subject=${ encodeURI(album.json.title) }&body=${ encodeURI(url) }`
  365. break
  366. }
  367. }
  368. album.getArchive = function(albumID) {
  369. let link = ''
  370. let url = `${ api.path }?function=Album::getArchive&albumID=${ albumID }`
  371. if (location.href.indexOf('index.html')>0) link = location.href.replace(location.hash, '').replace('index.html', url)
  372. else link = location.href.replace(location.hash, '') + url
  373. if (lychee.publicMode===true) link += `&password=${ encodeURIComponent(password.value) }`
  374. location.href = link
  375. }
  376. album.merge = function(albumIDs) {
  377. let title = ''
  378. let sTitle = ''
  379. let msg = ''
  380. if (!albumIDs) return false
  381. if (albumIDs instanceof Array===false) albumIDs = [ albumIDs ]
  382. // Get title of first album
  383. if (albums.json) title = albums.getByID(albumIDs[0]).title
  384. // Fallback for first album without a title
  385. if (title==='') title = 'Untitled'
  386. if (albumIDs.length===2) {
  387. // Get title of second album
  388. if (albums.json) sTitle = albums.getByID(albumIDs[1]).title
  389. // Fallback for second album without a title
  390. if (sTitle==='') sTitle = 'Untitled'
  391. msg = lychee.html`<p>Are you sure you want to merge the album '$${ sTitle }' into the album '$${ title }'?</p>`
  392. } else {
  393. msg = lychee.html`<p>Are you sure you want to merge all selected albums into the album '$${ title }'?</p>`
  394. }
  395. const action = function() {
  396. basicModal.close()
  397. let params = {
  398. albumIDs: albumIDs.join()
  399. }
  400. api.post('Album::merge', params, function(data) {
  401. if (data!==true) {
  402. lychee.error(null, params, data)
  403. } else {
  404. albums.refresh()
  405. lychee.goto()
  406. }
  407. })
  408. }
  409. basicModal.show({
  410. body: msg,
  411. buttons: {
  412. action: {
  413. title: 'Merge Albums',
  414. fn: action,
  415. class: 'red'
  416. },
  417. cancel: {
  418. title: "Don't Merge",
  419. fn: basicModal.close
  420. }
  421. }
  422. })
  423. }