test.html 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. <!DOCTYPE html>
  2. <html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/layout}">
  3. <head>
  4. <title>View Page</title>
  5. <script>
  6. $ = require("jquery");
  7. jQuery = $;
  8. require("jquery-ui");
  9. require("blueimp-gallery"); // CSS?
  10. </script>
  11. <script src="/libs/semantic/dist/semantic.min.js"></script>
  12. <script src="/src/js/test.js" defer></script>
  13. <script src="/src/js/view-page.js" defer></script>
  14. <!-- <link rel="stylesheet" href="./libs/semantic/dist/semantic.css" /> -->
  15. <link rel="stylesheet" href="/node_modules/blueimp-gallery/css/blueimp-gallery.css" />
  16. <link rel="stylesheet" href="/src/css/view-page.css" />
  17. <!-- <script src="/node_modules/blueimp-gallery/js/blueimp-gallery.js"></script> -->
  18. <meta th:if="${preview != null && preview == false}" property="og:title" th:content="${previewTitle}">
  19. <meta th:if="${preview != null && preview == false}" property="og:description" th:content="${previewDescription}">
  20. <meta th:if="${preview != null && preview == false}" property="og:url" th:content="${previewUrl}">
  21. <meta th:if="${preview != null && preview == false}" property="og:image" th:content="${previewImage}">
  22. </head>
  23. <body>
  24. <div layout:fragment="content" class="ui container">
  25. <input type="hidden" id="userId" th:value="${user == null ? '' : user.id}" />
  26. <input type="hidden" id="pageId" th:value="${pageId}" />
  27. <input type="hidden" id="pageState" th:value="${pageState}" />
  28. <input type="hidden" id="preview" th:value="${preview}" />
  29. <div class="ui active dimmer" id="pageLoader">
  30. <div class="ui text blue elastic loader">Loading</div>
  31. </div>
  32. <br />
  33. <div id="app" v-if="page.details != null">
  34. <div class="ui yellow raised padded circular segment" v-if="preview">
  35. <h2>Live Preview</h2>
  36. <p>
  37. This is a preview of your store page and is a visual representation of how the page will look on the store. This page is not visible to
  38. the public. All areas marked in <span style="color: red;">red</span> <b>must be present</b> before your page will be considered for
  39. approval.
  40. </p>
  41. </div>
  42. <h1 class="ui dividing header">Content Detail</h1>
  43. <div>
  44. <div v-if="page.softwareType == 'OpenSource' || page.softwareType == 'Sponsored'">
  45. <p>This software is <b><span class="ui green text">Open Source</span></b> under the following licenses:</p>
  46. <div class="ui inverted segment">
  47. <div class="ui inverted compact accordion">
  48. <div class="title">
  49. <i class="dropdown icon"></i>
  50. <i class="code icon"></i><span class="ui yellow text">Source Code:</span>
  51. <span v-if="page.openSourceData.softwareLicense">{{ page.openSourceData.softwareLicense.name }}</span>
  52. <span v-else style="color: red;">No software license selected.</span>
  53. </div>
  54. <div class="content">
  55. <p v-if="page.openSourceData.softwareLicense">
  56. {{ page.openSourceData.softwareLicense.desc }}
  57. </p>
  58. <p v-else style="color: red;">
  59. No software license selected.
  60. </p>
  61. </div>
  62. <div class="title">
  63. <i class="dropdown icon"></i>
  64. <i class="photo video icon"></i><span class="ui yellow text">Media:</span>
  65. <span v-if="page.openSourceData.mediaLicense">{{ page.openSourceData.mediaLicense.name }}</span>
  66. <span v-else style="color: red;">No media license selected.</span>
  67. </div>
  68. <div class="content">
  69. <p v-if="page.openSourceData.mediaLicense">
  70. {{ page.openSourceData.mediaLicense.desc }}
  71. </p>
  72. <p v-else style="color: red;">
  73. No media license selected.
  74. </p>
  75. </div>
  76. </div>
  77. </div>
  78. <p>
  79. <small><b>This is not legal advice. Always consult a professional.</b></small>
  80. </p>
  81. </div>
  82. <div class="ui pink segment" v-if="page.softwareType == 'Paid'">
  83. <p>In order to use this software you must purchase a copy.</p>
  84. </div>
  85. <div class="ui segment" v-if="page.softwareType == 'Sponsored'">
  86. <p>
  87. This software is <span class="ui yellow text">completely free</span>, however if you wish to
  88. <span class="ui pink text">sponsor the author</span> you may make a one-time payment to them using the button below. Sponsoring is
  89. completely optional, but is a great way give your thanks and encourage them to continue development!
  90. </p>
  91. </div>
  92. <div class="ui segment" v-if="page.softwareType == 'Sponsored' || page.softwareType == 'Paid'">
  93. <p>
  94. <!-- Price / Buy Button -->
  95. <button class="ui pink button">
  96. <span v-if="page.softwareType == 'Sponsored'">Optional:</span>
  97. <span v-if="page.softwareType == 'Paid'">Purchase:</span>
  98. &nbsp;&nbsp;$<span>{{ page.paymentData.price.toFixed(2) }}</span>
  99. </button>
  100. <!-- END: Price / Buy Button -->
  101. </p>
  102. </div>
  103. </div>
  104. <!-- Software Type and Licenses -->
  105. <!-- END: Software Type and Licenses -->
  106. <div class="ui divider"></div>
  107. <div class="ui two column stackable grid">
  108. <div class="row">
  109. <div class="column">
  110. <h1 class="ui header">
  111. <a
  112. class="tooltip"
  113. v-if="page.softwareType == 'Opensource' && page.openSourceData.isFork"
  114. :href="page.openSourceData.forkRepository"
  115. target="_blank"
  116. data-content="This project is a fork of an existing project."
  117. >
  118. <i class="random icon"></i>
  119. </a>
  120. <span>{{ page.details.title }}</span>
  121. &nbsp;-&nbsp;
  122. <span>{{ page.versionData.version }}</span>
  123. <div class="ui label" :class="page.versionData.state == 'Release' ? 'green' : 'grey'">
  124. {{ page.versionData.state }}
  125. </div>
  126. </h1>
  127. <p>
  128. <a :href="'/user/profile/' + page.owner.id">
  129. <img class="ui avatar image" :src="'/image/' + page.owner.avatarId" />
  130. <span>{{ page.owner.username }}</span></a
  131. >
  132. -
  133. </p>
  134. <div>
  135. <b>Created:</b> {{ millisToDate(page.dateCreated) }}
  136. <div v-if="page.dateCreated !== page.dateUpdated"><b>last updated:</b> {{ millisToDate(page.dateUpdated) }}</div>
  137. </div>
  138. <br />
  139. <p v-if="page.owner.badges != null && page.owner.badges.length > 0">
  140. <span
  141. class="ui black label tooltip"
  142. data-variation="inverted"
  143. v-for="badge in page.owner.badges"
  144. :data-content="badge.description"
  145. ><i :class="badge.icon"></i>{{ badge.name }}</span
  146. >
  147. </p>
  148. <!-- Rating -->
  149. <p>
  150. <b>Average Rating:</b>
  151. <span v-if="!preview">{{ page.rating.averageRating.toFixed(1) }} / 5</span>
  152. <span v-if="preview"><i>Not available in preview</i></span>
  153. <span
  154. v-if="!preview"
  155. class="ui star rating tiny disabled tooltip"
  156. id="assetStarRating"
  157. :data-content="page.rating.ratingCount + ' reviews'"
  158. >
  159. <i class="star icon" :class="page.rating.averageRating >= 1 ? 'yellow' : 'black'"></i>
  160. <i class="star icon" :class="page.rating.averageRating >= 2 ? 'yellow' : 'black'"></i>
  161. <i class="star icon" :class="page.rating.averageRating >= 3 ? 'yellow' : 'black'"></i>
  162. <i class="star icon" :class="page.rating.averageRating >= 4 ? 'yellow' : 'black'"></i>
  163. <i class="star icon" :class="page.rating.averageRating >= 5 ? 'yellow' : 'black'"></i>
  164. </span>
  165. </p>
  166. <!-- END: Rating -->
  167. <br />
  168. <!-- Short Description -->
  169. <p v-if="page.details.shortDescription.length > 0">{{ page.details.shortDescription }}</p>
  170. <p style="color: red;" v-if="page.details.shortDescription.length == 0">No short description specified.</p>
  171. <!-- END: Short Description -->
  172. </div>
  173. <div class="column">
  174. <!-- Screenshots and Youtube Videos -->
  175. <div id="gallery-carousel" class="blueimp-gallery blueimp-gallery-carousel blueimp-gallery-controls">
  176. <div class="slides"></div>
  177. <h3 class="title"></h3>
  178. <a class="prev">‹</a>
  179. <a class="next">›</a>
  180. <a class="play-pause"></a>
  181. <ol class="indicator"></ol>
  182. </div>
  183. <div id="carousel-links">
  184. <a
  185. v-if="getArrayLength(page.mediaLinks.imageIds) > 0 && page.mediaLinks.imageIds.split(',').length > 0"
  186. v-for="imgId in page.mediaLinks.imageIds.split(',')"
  187. :href="'/image/' + imgId"
  188. >
  189. </a>
  190. <a
  191. v-if="getArrayLength(page.mediaLinks.videoIds) > 0 && page.mediaLinks.videoIds.split(',').length > 0"
  192. v-for="vidId in page.mediaLinks.videoIds.split(',')"
  193. :data-youtube="vidId"
  194. :href="'https://www.youtube.com/watch/' + vidId"
  195. type="text/html"
  196. ></a>
  197. </div>
  198. <span v-if="getArrayLength(page.mediaLinks.imageIds) === 0" style="color: red;">At least one image is required.</span>
  199. <!-- END Screenshots and Youtube Videos -->
  200. </div>
  201. </div>
  202. </div>
  203. <div class="ui divider"></div>
  204. <!-- External link buttons -->
  205. <div>
  206. <a
  207. v-if="(page.softwareType == 'OpenSource' || page.softwareType == 'Sponsored') && page.openSourceData.gitRepository.length > 0"
  208. :href="page.openSourceData.gitRepository"
  209. target="_blank"
  210. class="ui button blue"
  211. id="viewOnGithubButton"
  212. ><i class="github icon"></i>View on Github</a
  213. >
  214. <span
  215. v-if="(page.softwareType == 'OpenSource' || page.softwareType == 'Sponsored') && page.openSourceData.gitRepository.length == 0"
  216. class="ui red label tag-item"
  217. ><i class="github icon"></i>No Git Repository</span
  218. >
  219. <a v-if="page.externalLinks.docsWebsite.length > 0" :href="page.externalLinks.docsWebsite" target="_blank" class="ui button black"
  220. ><i class="book icon"></i>Documentation</a
  221. >
  222. <span v-if="page.externalLinks.docsWebsite == 0" class="ui grey label tag-item"><i class="book icon"></i>No Documentation</span>
  223. <a v-if="page.externalLinks.publisherWebsite.length > 0" :href="page.externalLinks.publisherWebsite" target="_blank" class="ui button black"
  224. ><i class="external alternate icon"></i>Visit Publisher</a
  225. >
  226. <span v-if="page.externalLinks.publisherWebsite.length == 0" class="ui grey label tag-item"
  227. ><i class="book icon"></i>No Publisher Website</span
  228. >
  229. </div>
  230. <!-- END External link buttons -->
  231. <div class="ui divider"></div>
  232. <!-- Gradle Partial Script -->
  233. <div v-if="(page.softwareType == 'OpenSource' || page.softwareType == 'Sponsored')">
  234. <div v-if="getArrayLength(page.buildData.hostedDependencies) > 0">
  235. <h4 class="ui header">Add this software to your project</h4>
  236. <div v-if="">
  237. <div style="background:#222; color: #ccc; border-radius: 5px; padding: 10px;">
  238. <code>
  239. repositories {
  240. <div v-for="(repository, index) in page.buildData.repositories.split(',')">
  241. <span>&nbsp;&nbsp;&nbsp;&nbsp;{{ repository }}</span>
  242. </div>
  243. }
  244. <br /><br />
  245. dependencies {<br />
  246. <div v-for="dependency in page.buildData.hostedDependencies.split(',')">
  247. <span>&nbsp;&nbsp;&nbsp;&nbsp;{{ dependency.replace("$VERSION", page.versionData.version) }}</span>
  248. </div>
  249. }
  250. </code>
  251. </div>
  252. <div class="ui divider"></div>
  253. </div>
  254. <div v-if="pageData.dependsOn.length > 0" v-for="storePage in pageData.dependsOn">
  255. Depends on:
  256. <span class="tooltip" data-title="Internal Store Page" data-content="This link is safe to click.">
  257. <a :href="'/' + storePage.id"
  258. ><i class="green store icon"></i>
  259. {{ storePage.details.title }}
  260. </a>
  261. </span>
  262. <div class="ui divider"></div>
  263. </div>
  264. </div>
  265. <div v-else>
  266. <p>
  267. This software is not available on any hosted repository service. You must build this software from the
  268. <a :href="page.openSourceData.gitRepository" target="_blank">source code</a>.
  269. </p>
  270. </div>
  271. </div>
  272. <!-- END: Gradle Partial Script -->
  273. <!-- Engine Compatibility -->
  274. <p>
  275. <span class="ui yellow text">Compatible Engine Versions:</span>&nbsp;
  276. <span v-if="page.versionData.engineCompatibility.length > 0">{{ page.versionData.engineCompatibility }}</span>
  277. <span v-else>3.1 and above</span>
  278. </p>
  279. <!-- END Engine Compatibility -->
  280. <div class="ui divider"></div>
  281. <br />
  282. <!-- Description: Markdown Rendered -->
  283. <div id="page-content-div"></div>
  284. <!-- END: Description: Markdown Rendered -->
  285. <p style="color: red;" v-if="page.details.description.length == 0">No Description Specified.</p>
  286. <div class="ui divider"></div>
  287. <!-- Tags -->
  288. <b>Tags:</b>
  289. <span v-if="page.details.tags.length > 0" v-for="tag in page.details.tags.split(',')" class="ui violet label tag-item">
  290. <a :href="'/search/?tag=' + encodeURI(tag)">{{ tag }}</a>
  291. </span>
  292. <span v-if="page.details.tags.length == 0" class="ui label">No Tags Specified</span>
  293. <!-- END: Tags -->
  294. <div class="ui divider"></div>
  295. <!-- Forks of the parent repository -->
  296. <div v-if="pageData.forks.length > 0">
  297. <h4>Other Software Forking This Repository</h4>
  298. <div class="ui horizontal list">
  299. <div class="item" v-for="fork in pageData.forks">
  300. <img class="ui avatar image" :src="'/image/' + fork.owner.avatarId" />
  301. <div class="content">
  302. <div class="header">
  303. <a :href="'/' + fork.id">{{ fork.details.title }}</a>
  304. </div>
  305. by {{ fork.owner.username }}
  306. </div>
  307. </div>
  308. </div>
  309. <div class="ui divider"></div>
  310. </div>
  311. <!-- END: Forks of the parent repository -->
  312. <!-- Pages that depend on this page -->
  313. <div v-if="pageData.addons.length > 0">
  314. <h3>Projects Using This Software</h3>
  315. <div class="ui horizontal list">
  316. <div class="item" v-for="addon in pageData.addons">
  317. <img class="ui avatar image" :src="'/image/' + addon.owner.avatarId" />
  318. <div class="content">
  319. <div class="header">
  320. <a :href="'/' + addon.id">{{ addon.details.title }}</a>
  321. </div>
  322. by {{ addon.owner.username }}
  323. </div>
  324. </div>
  325. </div>
  326. <div class="ui divider"></div>
  327. </div>
  328. <!-- END: Pages that depend on this page -->
  329. <!-- REVIEWS / COMMENTS -->
  330. <div>
  331. <div class="ui comments" style="max-width: 100% !important;" v-if="preview == false">
  332. <h1 class="ui header">
  333. Reviews
  334. <button
  335. class="ui green button right floated tooltip"
  336. v-if="userId.length > 0"
  337. id="writeReviewButton"
  338. :disabled="userId == page.owner.id"
  339. @click="showWriteReviewModal()"
  340. >
  341. <i class="pencil alternate icon"></i>Write Review
  342. </button>
  343. </h1>
  344. <div class="ui info message" v-if="userId == page.owner.id">
  345. You cannot review software on pages that belong to you.
  346. </div>
  347. <div class="ui warning message" v-if="userId == null">
  348. You must be logged in to write a review.
  349. </div>
  350. <div class="ui message" th:if="${user != null}" v-if="reviewData.length == 0">
  351. There are no reviews yet. Be the first!
  352. </div>
  353. <div class="comment" v-for="(review, index) in reviewData">
  354. <a class="ui circular image avatar">
  355. <img v-bind:src="'/image/' + review.user.avatarId" />
  356. </a>
  357. <div class="content">
  358. <a class="author">{{ review.user.name == null ? review.user.username : review.user.name }}</a>
  359. <div class="metadata">
  360. <span v-if="review.dateCreated === review.dateUpdated" class="date">{{ millisToDate(review.dateCreated) }}</span>
  361. <span v-else class="date">(edited) {{ millisToDate(review.dateUpdated) }}</span>
  362. <button
  363. v-on:click="editReview(index)"
  364. id="editReviewButton"
  365. class="ui black mini icon button tooltip"
  366. :data="index"
  367. v-if="userId == review.user.id"
  368. data-content="Edit your review"
  369. >
  370. <i class="edit outline icon"></i>
  371. </button>
  372. <button
  373. v-on:click="deleteReview(index)"
  374. id="deleteReviewButton"
  375. class="ui red mini icon button tooltip"
  376. :data="index"
  377. v-if="userId == review.user.id"
  378. data-content="Permanently delete your review"
  379. >
  380. <i class="trash alternate outline icon"></i>
  381. </button>
  382. </div>
  383. <div class="text">
  384. <div class="ui star rating small disabled">
  385. <i class="yellow star icon" v-for="index in review.rating"></i>
  386. <i class="black star icon" v-for="index in (5 - review.rating)"></i>
  387. </div>
  388. <p style="white-space: pre-line;">
  389. {{ review.content }}
  390. </p>
  391. </div>
  392. </div>
  393. </div>
  394. <!-- Write Review Modal -->
  395. <div class="ui modal" id="writeReviewModal">
  396. <div class="header">
  397. Write A Review
  398. </div>
  399. <div class="content">
  400. <div class="ui form">
  401. <input type="hidden" :value="pageId" name="pageId" />
  402. <div class="field">
  403. <label>Please leave a rating!</label>
  404. <input type="hidden" value="" id="reviewRatingVal" />
  405. <div class="ui yellow star rating" id="reviewRating"></div>
  406. </div>
  407. <div class="field">
  408. <label>Review</label>
  409. <textarea rows="5" id="newReviewContent"></textarea>
  410. </div>
  411. </div>
  412. </div>
  413. <div class="actions">
  414. <button class="ui green ok button">
  415. Submit Review
  416. </button>
  417. <button class="ui red cancel button">
  418. Cancel
  419. </button>
  420. </div>
  421. </div>
  422. <!-- Delete Review Modal -->
  423. <div class="ui modal" id="deleteReviewModal">
  424. <div class="header">
  425. Write A Review
  426. </div>
  427. <div class="content"><b>Warning:</b> This action cannot be un-done. Are you sure you wish to delete your review?<br /></div>
  428. <div class="actions">
  429. <button class="ui green ok button">
  430. Yes, Delete My Review
  431. </button>
  432. <button class="ui red cancel button">
  433. Cancel
  434. </button>
  435. </div>
  436. </div>
  437. <!-- Edit Review modal -->
  438. <div class="ui modal" id="editReviewModal">
  439. <div class="header">
  440. Edit Your Review
  441. </div>
  442. <div class="content">
  443. <div class="ui form">
  444. <input type="hidden" :value="pageId" name="pageId" />
  445. <div class="field">
  446. <label>Please leave a rating!</label>
  447. <input type="hidden" value="" id="edit_reviewRatingVal" />
  448. <div class="ui yellow star rating" id="edit_reviewRating"></div>
  449. </div>
  450. <div class="field">
  451. <label>Review</label>
  452. <textarea rows="5" id="edit_newReviewContent"></textarea>
  453. </div>
  454. </div>
  455. </div>
  456. <div class="actions">
  457. <button class="ui green ok button">
  458. Submit Review
  459. </button>
  460. <button class="ui red cancel button">
  461. Cancel
  462. </button>
  463. </div>
  464. </div>
  465. </div>
  466. </div>
  467. </div>
  468. </div>
  469. </body>
  470. </html>