0
|
1 local Luan = require "luan:Luan.luan"
|
|
2 local error = Luan.error
|
|
3 local ipairs = Luan.ipairs or error()
|
|
4 local Html = require "luan:Html.luan"
|
|
5 local html_encode = Html.encode or error()
|
|
6 local Table = require "luan:Table.luan"
|
|
7 local concat = Table.concat or error()
|
|
8 local Io = require "luan:Io.luan"
|
|
9 local Http = require "luan:http/Http.luan"
|
|
10 local Shared = require "site:/lib/Shared.luan"
|
|
11 local head = Shared.head or error()
|
|
12 local body_header = Shared.body_header or error()
|
|
13 local footer = Shared.footer or error()
|
|
14 local show_editable_link = Shared.show_editable_link or error()
|
|
15 local User = require "site:/lib/User.luan"
|
|
16 local Link = require "site:/lib/Link.luan"
|
|
17 local get_owner_links = Link.get_owner_links or error()
|
|
18 local Pic = require "site:/lib/Pic.luan"
|
|
19 local Utils = require "site:/lib/Utils.luan"
|
|
20 local to_list = Utils.to_list or error()
|
|
21 local Logging = require "luan:logging/Logging.luan"
|
|
22 local logger = Logging.logger "links.html"
|
|
23
|
|
24
|
|
25 local function hashtags(pic)
|
|
26 local hashtags = to_list(pic.hashtags)
|
|
27 for i, hashtag in ipairs(hashtags) do
|
|
28 hashtags[i] = "#"..hashtag
|
|
29 end
|
|
30 return concat(hashtags," ")
|
|
31 end
|
|
32
|
|
33 local function div_links(links,pic_id)
|
|
34 %>
|
|
35 <div links>
|
|
36 <form add onsubmit="ajaxForm('add_link.js',this)" action="javascript:">
|
|
37 <% if pic_id ~= nil then %>
|
|
38 <input type=hidden name=pic value="<%=pic_id%>">
|
|
39 <% end %>
|
|
40 <input type=text required name=title placeholder="Title">
|
|
41 <input type=url required name=url placeholder="URL">
|
|
42 <button type=submit big>Add link</button>
|
|
43 </form>
|
|
44 <div start></div>
|
|
45 <% for _, link in ipairs(links) do
|
|
46 show_editable_link(link)
|
|
47 end %>
|
|
48 </div>
|
|
49 <%
|
|
50 end
|
|
51
|
|
52 return function()
|
|
53 local user = User.current_required()
|
|
54 if user==nil then return end
|
|
55 local owner = user
|
|
56 local pic = Http.request.parameters.pic
|
|
57 if pic ~= nil then
|
|
58 pic = Pic.get_by_id(pic)
|
|
59 if pic == nil then
|
|
60 logger.warn("pic not found\n"..Http.request.raw_head)
|
|
61 Http.response.send_error(404)
|
|
62 return
|
|
63 end
|
|
64 pic.user_id == user.id or error()
|
|
65 owner = pic
|
|
66 end
|
|
67 local links = get_owner_links(owner.id)
|
|
68 local pic_id = pic and pic.id
|
|
69 Io.stdout = Http.response.text_writer()
|
|
70 %>
|
|
71 <!doctype html>
|
|
72 <html lang="en">
|
|
73 <head>
|
|
74 <% head() %>
|
|
75 <title>Link My Style</title>
|
|
76 <style>
|
|
77 form[add] {
|
|
78 margin-bottom: 40px;
|
|
79 }
|
|
80 input {
|
|
81 margin-bottom: 5px;
|
|
82 }
|
|
83 input[type="url"],
|
|
84 input[type="text"] {
|
|
85 display: block;
|
|
86 }
|
|
87 div[link] {
|
|
88 margin-bottom: 20px;
|
|
89 }
|
|
90 button[small] {
|
|
91 font-size: 12px;
|
|
92 }
|
|
93 div[delete2] p {
|
|
94 margin-bottom: 5px;
|
|
95 }
|
|
96
|
|
97 div[link] > div:first-of-type {
|
|
98 border-radius: 12px / 50%;
|
|
99 margin-bottom: 5px;
|
|
100 overflow: hidden;
|
|
101 position: relative;
|
|
102 border: 1px solid #ebebeb;
|
|
103 }
|
|
104 div[link] a {
|
|
105 border-radius: initial;
|
|
106 margin-bottom: initial;
|
|
107 }
|
|
108 div[link] a:hover {
|
|
109 background-color: #243F47;
|
|
110 }
|
|
111 div[link] img {
|
|
112 position: absolute;
|
|
113 top: 0;
|
|
114 height: 100%;
|
|
115 background-color: white;
|
|
116 opacity: 0.3;
|
|
117 padding: 4px;
|
|
118 touch-action: none;
|
|
119 }
|
|
120
|
|
121 <% if pic == nil then %>
|
|
122 div[links] {
|
|
123 margin-top: 20px;
|
|
124 }
|
|
125 <% else %>
|
|
126 div[msg] {
|
|
127 margin-top: 20px;
|
|
128 margin-left: 5%;
|
|
129 color: darkgreen;
|
|
130 <% if Http.request.parameters.saved == nil then %>
|
|
131 display: none;
|
|
132 <% end %>
|
|
133 }
|
|
134 div[body] {
|
|
135 margin-top: 40px;
|
|
136 margin-bottom: 20px;
|
|
137 }
|
|
138 div[pic] img {
|
|
139 width: 100%;
|
|
140 display: block;
|
|
141 margin-bottom: 5px;
|
|
142 }
|
|
143 div[pic] form {
|
|
144 margin-top: 20px;
|
|
145 }
|
|
146 div[field] {
|
|
147 margin-top: 1px;
|
|
148 margin-bottom: 10px;
|
|
149 }
|
|
150 div[hashtags] {
|
|
151 margin-top: 20px;
|
|
152 }
|
|
153 @media (min-width: 888px) {
|
|
154 div[body] {
|
|
155 display: flex;
|
|
156 }
|
|
157 div[pic] {
|
|
158 width: 45%;
|
|
159 margin-left: 5%;
|
|
160 }
|
|
161 div[outer_links] {
|
|
162 width: 55%;
|
|
163 margin-left: 5%;
|
|
164 margin-right: 5%;
|
|
165 }
|
|
166 }
|
|
167 @media (max-width: 887px) {
|
|
168 div[pic] {
|
|
169 display: block;
|
|
170 width: 90%;
|
|
171 margin-left: auto;
|
|
172 margin-right: auto;
|
|
173 margin-bottom: 40px;
|
|
174 }
|
|
175 }
|
|
176 <% end %>
|
|
177 </style>
|
|
178 <script>
|
|
179 'use strict';
|
|
180
|
|
181 function clearAddForm() {
|
|
182 let form = document.querySelector('form[add]');
|
|
183 form.querySelector('[name="title"]').value = '';
|
|
184 form.querySelector('[name="url"]').value = '';
|
|
185 }
|
|
186
|
|
187 function deleteLink1(button,linkId) {
|
|
188 let div = button.parentNode;
|
|
189 if( div.querySelector('div[delete2]') )
|
|
190 return;
|
|
191 let html = `
|
|
192 <div delete2>
|
|
193 <p>Are you sure that you want to delete this?</p>
|
|
194 <button delete2 small onclick="deleteLink2('${linkId}')">Yes</button>
|
|
195 <button small onclick="undelete1(this)">No</button>
|
|
196 </div>
|
|
197 ` ;
|
|
198 div.insertAdjacentHTML( 'beforeEnd', html );
|
|
199 div.scrollIntoViewIfNeeded(false);
|
|
200 }
|
|
201 function undelete1(button) {
|
|
202 button.parentNode.outerHTML = '';
|
|
203 }
|
|
204 function deleteLink2(linkId) {
|
|
205 ajax( '/delete_link.js?link='+linkId );
|
|
206 }
|
|
207 function deletePic1(button) {
|
|
208 let div = button.parentNode;
|
|
209 if( div.querySelector('div[delete2]') )
|
|
210 return;
|
|
211 let html = `
|
|
212 <div delete2>
|
|
213 <p>Are you sure that you want to delete this?</p>
|
|
214 <button delete2 small onclick="deletePic2('<%=pic_id%>')">Yes</button>
|
|
215 <button small onclick="undelete1(this)">No</button>
|
|
216 </div>
|
|
217 ` ;
|
|
218 div.insertAdjacentHTML( 'beforeEnd', html );
|
|
219 div.scrollIntoViewIfNeeded(false);
|
|
220 }
|
|
221 function deletePic2() {
|
|
222 ajax( '/delete_pic.js?pic=<%=pic_id%>' );
|
|
223 }
|
|
224
|
|
225 function editLink(linkId) {
|
|
226 ajax( '/edit_link.js?link='+linkId );
|
|
227 }
|
|
228
|
|
229 function cancel(linkId) {
|
|
230 ajax( '/cancel_edit_link.js?link='+linkId );
|
|
231 }
|
|
232
|
|
233 dad.onDropped = function(event) {
|
|
234 let dragging = event.original;
|
|
235 if( iDragging === indexOf(dragging.parentNode.querySelectorAll(dropSelector),dragging) )
|
|
236 return;
|
|
237 let linkId = dragging.getAttribute('link');
|
|
238 let prev = dragging.previousElementSibling;
|
|
239 let prevId = prev && prev.getAttribute('link');
|
|
240 ajax( '/move_link.js?link='+linkId+'&prev='+prevId );
|
|
241 };
|
|
242
|
|
243 dad.whatToDrag = function(draggable) {
|
|
244 return draggable.parentNode.parentNode;
|
|
245 };
|
|
246
|
|
247 function dragInit() {
|
|
248 dropSelector = 'div[link]';
|
|
249 let items = document.querySelectorAll('div[link] img');
|
|
250 for( let i=0; i<items.length; i++ ) {
|
|
251 let item = items[i];
|
|
252 dad.setDraggable(item);
|
|
253 dad.setDropzone(item.parentNode.parentNode);
|
|
254 }
|
|
255 }
|
|
256
|
|
257 <% if pic ~= nil then %>
|
|
258 function changePic(uuid,filename) {
|
|
259 ajax( '/change_pic.js', 'pic=<%=pic.id%>&uuid=' + uuid + '&filename=' + encodeURIComponent(filename) );
|
|
260 }
|
|
261 function startChangePic() {
|
|
262 uploadcare.cropprOptions = {};
|
|
263 uploadcare.upload(changePic);
|
|
264 }
|
|
265 <% end %>
|
|
266 </script>
|
|
267 </head>
|
|
268 <body>
|
|
269 <div full>
|
|
270 <%
|
|
271 body_header()
|
|
272 if pic == nil then
|
|
273 %>
|
|
274 <p top>Enter your title and a URL to create a link. Once saved, you can drag-and-drop the icon on the left to change the order. The order on this page will also appear on your page.</p>
|
|
275 <%
|
|
276 div_links(links,pic_id)
|
|
277 else
|
|
278 %>
|
|
279 <div back>
|
|
280 <a href="/pics.html#p-<%=pic.id%>"><img src="/images/keyboard_backspace.svg"></a>
|
|
281 </div>
|
|
282 <div msg>
|
|
283 Your image has been saved.
|
|
284 </div>
|
|
285 <div body>
|
|
286 <div pic>
|
|
287 <img <%=pic.title_attr()%> src="<%=pic.get_url()%>">
|
|
288 <div>
|
|
289 <button type=button small onclick="startChangePic()">Change</button>
|
|
290 <button type=button small onclick="deletePic1(this)">Delete</button>
|
|
291 </div>
|
|
292 <div hashtags><%=pic.hashtags_html("pics.html")%></div>
|
|
293 <form onsubmit="ajaxForm('/save_pic_title.js',this)" action="javascript:">
|
|
294 <input type=hidden name=pic value="<%=pic_id%>">
|
|
295 <label>Photo title</label>
|
|
296 <div field>
|
|
297 <input type=text required name=title placeholder="Title" value="<%= html_encode(pic.title or "") %>">
|
|
298 </div>
|
|
299 <label>Hashtags</label>
|
|
300 <div field>
|
|
301 <textarea name=hashtags placeholder="#hashtag1 #hashtag2"><%= hashtags(pic) %></textarea>
|
|
302 <div error=hashtags></div>
|
|
303 </div>
|
|
304 <div field>
|
|
305 <label clickable><input type=checkbox name=visible <%=pic.is_hidden and "" or "checked"%>> Visible</label>
|
|
306 </div>
|
|
307 <button type=submit small>Save</button>
|
|
308 <div error=success></div>
|
|
309 </form>
|
|
310 </div>
|
|
311 <div outer_links>
|
|
312 <% div_links(links,pic_id) %>
|
|
313 </div>
|
|
314 </div>
|
|
315 <%
|
|
316 end
|
|
317 %>
|
|
318 <% footer() %>
|
|
319 </div>
|
|
320 <script> dragInit(); </script>
|
|
321 </body>
|
|
322 </html>
|
|
323 <%
|
|
324 end
|