758 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			758 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html>
 | |
| <head>
 | |
|     {% import "header.html" as header %}
 | |
|     {% import "cards.html" as cards %}
 | |
|     {% import "clipboard_tray.html" as clipboard_tray %}
 | |
|     <title>Search</title>
 | |
|     <meta charset="UTF-8">
 | |
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
 | |
|     <link rel="icon" href="/favicon.png" type="image/png"/>
 | |
|     <link rel="stylesheet" href="/static/css/common.css">
 | |
|     <link rel="stylesheet" href="/static/css/etiquette.css">
 | |
|     <link rel="stylesheet" href="/static/css/cards.css">
 | |
|     <link rel="stylesheet" href="/static/css/clipboard_tray.css">
 | |
|     {% if theme %}<link rel="stylesheet" href="/static/css/theme_{{theme}}.css">{% endif %}
 | |
|     <script src="/static/js/common.js"></script>
 | |
|     <script src="/static/js/api.js"></script>
 | |
|     <script src="/static/js/hotkeys.js"></script>
 | |
|     <script src="/static/js/http.js"></script>
 | |
|     <script src="/static/js/photo_clipboard.js"></script>
 | |
|     <script src="/static/js/tag_autocomplete.js"></script>
 | |
| 
 | |
| <style>
 | |
| #search_builder_form
 | |
| {
 | |
|     display: flex;
 | |
|     flex-direction: column;
 | |
|     justify-content: center;
 | |
| }
 | |
| 
 | |
| #error_message_area
 | |
| {
 | |
|     display: flex;
 | |
|     flex-direction: column;
 | |
|     justify-content: center;
 | |
|     align-items: center;
 | |
| }
 | |
| #happy_message_area
 | |
| {
 | |
|     display: flex;
 | |
|     flex-direction: column;
 | |
|     justify-content: center;
 | |
|     align-items: center;
 | |
| }
 | |
| .error_message
 | |
| {
 | |
|     align-self: center;
 | |
| 
 | |
|     padding: 2px;
 | |
| 
 | |
|     background-color: #f00;
 | |
| 
 | |
|     color: #fff;
 | |
| }
 | |
| #left
 | |
| {
 | |
|     flex: 1;
 | |
| 
 | |
|     display: flex;
 | |
|     flex-direction: column;
 | |
| 
 | |
|     word-wrap: break-word;
 | |
| }
 | |
| #tags_on_this_page_holder
 | |
| {
 | |
|     /*
 | |
|     This allows the search results to dominate the height of the page, and
 | |
|     left will simply match that height then scroll the rest of
 | |
|     tags_on_this_page.
 | |
|     */
 | |
|     position: relative;
 | |
|     flex: 1;
 | |
|     min-height: 200px;
 | |
|     overflow-y: auto;
 | |
| }
 | |
| #tags_on_this_page_list
 | |
| {
 | |
|     list-style-type: none;
 | |
|     margin: 0;
 | |
|     padding: 0;
 | |
|     position: absolute;
 | |
|     top: 0;
 | |
|     bottom: 0;
 | |
|     left: 0;
 | |
|     right: 0;
 | |
| }
 | |
| 
 | |
| #right
 | |
| {
 | |
|     flex: 1;
 | |
| }
 | |
| 
 | |
| @media screen and (min-width: 800px)
 | |
| {
 | |
|     #content_body
 | |
|     {
 | |
|         grid-template:
 | |
|             "left right" 1fr
 | |
|             / 310px 1fr;
 | |
|     }
 | |
| }
 | |
| 
 | |
| @media screen and (max-width: 800px)
 | |
| {
 | |
|     #content_body
 | |
|     {
 | |
|         grid-template:
 | |
|             "right" auto
 | |
|             "left" auto
 | |
|             / auto;
 | |
|     }
 | |
| }
 | |
| 
 | |
| .prev_next_holder
 | |
| {
 | |
|     display: flex;
 | |
|     flex-direction: row;
 | |
| }
 | |
| .prev_page
 | |
| {
 | |
|     margin-right: 10px;
 | |
| }
 | |
| .next_page
 | |
| {
 | |
|     margin-left: 10px;
 | |
| }
 | |
| .prev_page, .next_page
 | |
| {
 | |
|     display: flex;
 | |
|     flex: 1;
 | |
|     justify-content: center;
 | |
| 
 | |
|     border: 1px solid black;
 | |
| 
 | |
|     background-color: var(--color_secondary);
 | |
| 
 | |
|     font-size: 20;
 | |
| }
 | |
| 
 | |
| .search_builder_tagger,
 | |
| #search_builder_orderby_ul
 | |
| {
 | |
|     margin: 0;
 | |
| }
 | |
| </style>
 | |
| 
 | |
| {% macro prev_next_buttons() %}
 | |
| {% if prev_page_url or next_page_url %}
 | |
| <div class="prev_next_holder">
 | |
|     {% if prev_page_url %}
 | |
|     <a class="prev_page" href="{{prev_page_url}}">Previous</a>
 | |
|     {% else %}
 | |
|     <a class="prev_page"><br></a>
 | |
|     {% endif %}
 | |
|     {% if next_page_url %}
 | |
|     <a class="next_page" href="{{next_page_url}}">Next</a>
 | |
|     {% else %}
 | |
|     <a class="next_page"><br></a>
 | |
|     {% endif %}
 | |
| </div>
 | |
| {% endif %}
 | |
| {% endmacro %}
 | |
| 
 | |
| {% macro create_orderby_li(selected_column, selected_sorter) %}
 | |
| <li class="search_builder_orderby_li">
 | |
|     <select class="select_orderby_column" onchange="return orderby_hide_direction_hook(event);">
 | |
|         <option value="created" {{"selected" if selected_column=="created" else ""}}>Creation date</option>
 | |
|         <option value="basename" {{"selected" if selected_column=="basename" else ""}}>Filename</option>
 | |
|         <option value="area" {{"selected" if selected_column=="area" else ""}}>Area</option>
 | |
|         <option value="width" {{"selected" if selected_column=="width" else ""}}>Width</option>
 | |
|         <option value="height" {{"selected" if selected_column=="height" else ""}}>Height</option>
 | |
|         <option value="aspectratio" {{"selected" if selected_column=="aspectratio" else ""}}>Aspect Ratio</option>
 | |
|         <option value="bytes" {{"selected" if selected_column=="bytes" else ""}}>File size</option>
 | |
|         <option value="duration" {{"selected" if selected_column=="duration" else ""}}>Duration</option>
 | |
|         <option value="bitrate" {{"selected" if selected_column=="bitrate" else ""}}>Bitrate</option>
 | |
|         <option value="tagged_at" {{"selected" if selected_column=="tagged_at" else ""}}>Recently tagged</option>
 | |
|         <option value="random" {{"selected" if selected_column=="random" else ""}}>Random</option>
 | |
|     </select>
 | |
|     <select class="select_orderby_direction" {% if selected_column=="random" %}class="hidden"{% endif %}>
 | |
|         <option value="desc" {{"selected" if selected_sorter=="desc" else ""}} >Descending</option>
 | |
|         <option value="asc"  {{"selected" if selected_sorter=="asc" else ""}}  >Ascending</option>
 | |
|     </select>
 | |
|     <button class="remove_tag_button_perm red_button" onclick="return orderby_remove_hook(this);"></button>
 | |
| </li>
 | |
| {% endmacro %}
 | |
| </head>
 | |
| 
 | |
| <body>
 | |
| {{header.make_header(session=request.session)}}
 | |
| <div id="content_body">
 | |
|     <div id="left" class="panel">
 | |
|         {% for tagtype in ["musts", "mays", "forbids"] %}
 | |
|         <div id="search_builder_{{tagtype}}" {% if search_kwargs.tag_expression%}class="hidden"{%endif%}>
 | |
|             <span>Tag {{tagtype}}:</span>
 | |
|             <ul class="search_builder_tagger">
 | |
|                 {% set key="tag_" + tagtype %}
 | |
|                 {% if search_kwargs|attr(key) %}
 | |
|                     {% for tag in search_kwargs|attr(key) %}
 | |
|                         <li class="search_builder_{{tagtype}}_inputted">
 | |
|                             {{cards.create_tag_card(tag, link='info', with_alt_description=True)}}<!--
 | |
|                             --><button class="remove_tag_button red_button"
 | |
|                             onclick="return remove_searchtag(ul_{{tagtype}}, '{{tag.name}}', inputted_{{tagtype}});"></button>
 | |
|                         </li>
 | |
|                     {% endfor %}
 | |
|                 {% endif %}
 | |
|                 <li><input id="search_builder_{{tagtype}}_input" class="entry_with_tagname_replacements" type="text" list="tag_autocomplete_datalist"></li>
 | |
|             </ul>
 | |
|         </div>
 | |
|         {% endfor %}
 | |
|         <div id="search_builder_expression" {% if not search_kwargs.tag_expression%}class="hidden"{%endif%}>
 | |
|             <span>Tag Expression:</span>
 | |
|             <input id="search_builder_expression_input" name="tag_expression" type="text"
 | |
|             value="{{search_kwargs.tag_expression or ''}}"
 | |
|             >
 | |
|         </div>
 | |
|         <div id="search_builder_orderby">
 | |
|             <span>Order by</span>
 | |
|             <ul id="search_builder_orderby_ul">
 | |
|                 {% if search_kwargs.orderby %}
 | |
|                     {% for orderby in search_kwargs.orderby %}
 | |
|                         {% set column, sorter=orderby.split("-") %}
 | |
|                         {{ create_orderby_li(selected_column=column, selected_sorter=sorter) }}
 | |
|                     {% endfor %}
 | |
|                 {% else %}
 | |
|                     {{ create_orderby_li(selected_column=0, selected_sorter=0) }}
 | |
|                 {% endif %}
 | |
|                 <li id="search_builder_orderby_newrow"><button class="green_button" onclick="return add_new_orderby();">+</button></li>
 | |
|             </ul>
 | |
|         </div>
 | |
|         <br>
 | |
|         <form id="search_builder_form" action="" onsubmit="return submit_search();">
 | |
| 
 | |
|             <span>Min-max values</span>
 | |
|             <input type="text" class="basic_param"
 | |
|             {%if search_kwargs.area%} value="{{search_kwargs.area}}" {%endif%}
 | |
|             name="area" placeholder="Area: 1m..2m">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             {%if search_kwargs.width%} value="{{search_kwargs.width}}" {%endif%}
 | |
|             name="width" placeholder="Width: 1k..2k">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             {%if search_kwargs.height%} value="{{search_kwargs.height}}" {%endif%}
 | |
|             name="height" placeholder="Height: 1k..2k">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             {%if search_kwargs.aspectratio%} value="{{search_kwargs.aspectratio}}" {%endif%}
 | |
|             name="aspectratio" placeholder="Aspect Ratio: 1.7..2">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             {%if search_kwargs.bytes%} value="{{search_kwargs.bytes}}" {%endif%}
 | |
|             name="bytes" placeholder="File Size: 1mb..2mb">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             {%if search_kwargs.duration%} value="{{search_kwargs.duration}}" {%endif%}
 | |
|             name="duration" placeholder="Duration: 10:00..20:00">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             {%if search_kwargs.created%} value="{{search_kwargs.created}}" {%endif%}
 | |
|             name="created" placeholder="Created: 1483228800..1514764800">
 | |
| 
 | |
|             <br>
 | |
| 
 | |
|             <span>Other filters</span>
 | |
|             <input type="text" class="basic_param"
 | |
|             value="{{search_kwargs.filename or ''}}"
 | |
|             name="filename" placeholder="Filename">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             value="{{search_kwargs.mimetype|comma_join}}"
 | |
|             name="mimetype" placeholder="Mimetype (archive, audio, image, text, video)">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             value="{{search_kwargs.extension|comma_join}}"
 | |
|             name="extension" placeholder="Extension(s)">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             value="{{search_kwargs.extension_not|comma_join}}"
 | |
|             name="extension_not" placeholder="Forbid extension(s)">
 | |
| 
 | |
|             <input type="text" class="basic_param"
 | |
|             value="{{search_kwargs.author|users_to_usernames|comma_join}}"
 | |
|             name="author" placeholder="Author">
 | |
| 
 | |
|             <select name="limit" class="basic_param">
 | |
|                 {% set limit_options = [20, 50, 100, 200, 500, 1000] %}
 | |
|                 {% if search_kwargs.limit not in limit_options %}
 | |
|                     {% do limit_options.append(search_kwargs.limit) %}
 | |
|                     {% do limit_options.sort() %}
 | |
|                 {% endif %}
 | |
|                 {% for limit_option in limit_options %}
 | |
|                 <option value="{{limit_option}}" {{"selected" if search_kwargs.limit == limit_option else ""}}>
 | |
|                 {{- limit_option }} items{{''-}}
 | |
|                 </option>
 | |
|                 {% endfor %}
 | |
|             </select>
 | |
|             <select name="has_albums" class="basic_param" onchange="return disable_yield_albums_if_not_has_albums();">
 | |
|                 <option value=""    {{"selected" if search_kwargs.has_albums==None else ""}}>Album or no album</option>
 | |
|                 <option value="yes" {{"selected" if search_kwargs.has_albums==True else ""}}>Photos contained in albums</option>
 | |
|                 <option value="no"  {{"selected" if search_kwargs.has_albums==False else ""}}>Photos not in albums</option>
 | |
|             </select>
 | |
|             <select name="has_tags" class="basic_param">
 | |
|                 <option value=""    {{"selected" if search_kwargs.has_tags==None else ""}}>Tagged or untagged</option>
 | |
|                 <option value="yes" {{"selected" if search_kwargs.has_tags==True else ""}}>Tagged only</option>
 | |
|                 <option value="no"  {{"selected" if search_kwargs.has_tags==False else ""}}>Untagged only</option>
 | |
|             </select>
 | |
|             <select name="has_thumbnail" class="basic_param">
 | |
|                 <option value=""    {{"selected" if search_kwargs.has_thumbnail==None else ""}}>Thumbnail or no thumbnail</option>
 | |
|                 <option value="yes" {{"selected" if search_kwargs.has_thumbnail==True else ""}}>Has thumbnail</option>
 | |
|                 <option value="no"  {{"selected" if search_kwargs.has_thumbnail==False else ""}}>No thumbnail</option>
 | |
|             </select>
 | |
|             <select name="yield_albums" class="basic_param">
 | |
|                 <option value="yes" {{"selected" if search_kwargs.yield_albums==True else ""}}>Include albums</option>
 | |
|                 <option value="no" {{"selected" if search_kwargs.yield_albums==False else ""}}>Don't include albums</option>
 | |
|             </select>
 | |
|             <select name="yield_photos" class="basic_param">
 | |
|                 <option value="yes" {{"selected" if search_kwargs.yield_photos==True else ""}}>Include photos</option>
 | |
|                 <option value="no" {{"selected" if search_kwargs.yield_photos==False else ""}}>Don't include photos</option>
 | |
|             </select>
 | |
|             <select name="view" class="basic_param">
 | |
|                 <option value="grid"  {{"selected" if search_kwargs.view=="grid" else ""}}>Grid view</option>
 | |
|                 <option value="list"  {{"selected" if search_kwargs.view=="list" else ""}}>List view</option>
 | |
|             </select>
 | |
|             <button type="submit" id="search_go_button" class="green_button" value="">Search</button>
 | |
|             <button type="button" id="swipe_go_button" class="green_button" value="" onclick="return submit_swipe();">Swipe UI</button>
 | |
|             <div style="text-align:center"><a href="/search.atom" class="merge_params">Atom</a></div>
 | |
|         </form>
 | |
|         {% if total_tags %}
 | |
|         <h4>Tags on this page:</h4>
 | |
|         <div id="tags_on_this_page_holder">
 | |
|         <ul id="tags_on_this_page_list">
 | |
|             {% for tag in total_tags %}
 | |
|             <li>
 | |
|                 {{cards.create_tag_card(
 | |
|                     tag,
 | |
|                     link=None,
 | |
|                     onclick="return tags_on_this_page_add_must(event, '" + tag.name + "');",
 | |
|                     innertext="(+)",
 | |
|                 )}}
 | |
| 
 | |
|                 {{cards.create_tag_card(
 | |
|                     tag,
 | |
|                     link=None,
 | |
|                     onclick="return tags_on_this_page_add_may(event, '" + tag.name + "');",
 | |
|                     innertext="(~)",
 | |
|                 )}}
 | |
| 
 | |
|                 {{cards.create_tag_card(
 | |
|                     tag,
 | |
|                     link=None,
 | |
|                     onclick="return tags_on_this_page_add_forbid(event, '" + tag.name + "');",
 | |
|                     innertext="(x)",
 | |
|                 )}}
 | |
| 
 | |
|                 {{cards.create_tag_card(
 | |
|                     tag,
 | |
|                     link="info",
 | |
|                     with_alt_description=True,
 | |
|                 )}}
 | |
|             </li>
 | |
|             {% endfor %}
 | |
|         </ul>
 | |
|         </div>
 | |
|         {% endif %}
 | |
|     </div>
 | |
|     <div id="right" class="panel">
 | |
|         <div id="error_message_area">
 | |
|             {% for warning in warnings %}
 | |
|             <p class="error_message">{{warning}}</p>
 | |
|             {% endfor %}
 | |
|         </div>
 | |
| 
 | |
|         <div id="happy_message_area">
 | |
|             <p>You got {{results|length}} items.</p>
 | |
|         </div>
 | |
| 
 | |
|         {{prev_next_buttons()}}
 | |
| 
 | |
|         <div id="search_results_holder" class="photos_holder">
 | |
|             {% for result in results %}
 | |
|                 {% if result.__class__.__name__ == 'Photo' %}
 | |
|                 {{cards.create_photo_card(result, view=search_kwargs.view)}}
 | |
|                 {% elif result.__class__.__name__ == 'Album' %}
 | |
|                 {{cards.create_album_card(result, view=search_kwargs.view)}}
 | |
|                 {% endif %}
 | |
|             {% endfor %}
 | |
|         </div>
 | |
| 
 | |
|         {{prev_next_buttons()}}
 | |
|     </div>
 | |
| </div>
 | |
| {{clipboard_tray.clipboard_tray()}}
 | |
| </body>
 | |
| 
 | |
| <script type="text/javascript">
 | |
| /*
 | |
| These values should match those of the server itself. The purpose of this dict
 | |
| is to know that we DON'T need to include these parameters in the url if the
 | |
| selected form values are these.
 | |
| */
 | |
| const PARAM_DEFAULTS = {
 | |
|     'limit': 50,
 | |
|     'view': 'grid',
 | |
|     'yield_albums': 'no',
 | |
|     'yield_photos': 'yes'
 | |
| }
 | |
| 
 | |
| const MAX_ORDERBY_ULS = document.getElementsByClassName("select_orderby_column")[0].children.length;
 | |
| 
 | |
| function add_searchtag(ul, value, inputted_list, li_class)
 | |
| {
 | |
|     console.log("adding " + value);
 | |
|     const already_have = inputted_list.indexOf(value) !== -1;
 | |
|     if (already_have)
 | |
|     {return;}
 | |
| 
 | |
|     inputted_list.push(value);
 | |
|     const new_li = document.createElement("li");
 | |
|     new_li.className = li_class;
 | |
| 
 | |
|     const new_span = document.createElement("span");
 | |
|     new_span.className = "tag_card";
 | |
|     new_span.innerHTML = value;
 | |
| 
 | |
|     const new_delbutton = document.createElement("button")
 | |
|     new_delbutton.classList.add("remove_tag_button");
 | |
|     new_delbutton.classList.add("red_button");
 | |
|     new_delbutton.onclick = function(){remove_searchtag(ul, value, inputted_list)};
 | |
| 
 | |
|     new_li.appendChild(new_span);
 | |
|     new_li.appendChild(new_delbutton);
 | |
| 
 | |
|     ul.insertBefore(new_li, ul.lastElementChild);
 | |
| }
 | |
| function add_searchtag_from_box(box, inputted_list, li_class)
 | |
| {
 | |
|     if (box.offsetParent === null)
 | |
|     {
 | |
|         // The box is hidden probably because we're in Expression mode.
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (!box.value)
 | |
|     {return;}
 | |
| 
 | |
|     let value = box.value;
 | |
|     if (tag_autocomplete.datalist !== null)
 | |
|     {
 | |
|         // If the autocomplete failed for whatever reason, or is simply taking
 | |
|         // too long, let's just let it slide.
 | |
|         value = tag_autocomplete.resolve(value);
 | |
|         if (value === null)
 | |
|         {return;}
 | |
|     }
 | |
| 
 | |
|     console.log(inputted_list);
 | |
|     ul = box.parentElement.parentElement;
 | |
|     add_searchtag(ul, value, inputted_list, li_class)
 | |
|     box.value = "";
 | |
|     // The datalist autocomplete box can sometimes stick around after the
 | |
|     // tag has already been submitted and the input box moves down -- now
 | |
|     // covered by the autocomplete. So we temporarily unfocus it to make
 | |
|     // that thing go away.
 | |
|     box.blur();
 | |
|     box.focus();
 | |
| }
 | |
| 
 | |
| function remove_searchtag(ul, value, inputted_list)
 | |
| {
 | |
|     console.log("removing " + value);
 | |
|     const lis = ul.children;
 | |
|     //console.log(lis);
 | |
|     for (const li of lis)
 | |
|     {
 | |
|         const tag_card = li.children[0];
 | |
|         if (! tag_card.classList.contains("tag_card"))
 | |
|         {continue}
 | |
| 
 | |
|         const tagname = tag_card.innerHTML;
 | |
|         if (tagname != value)
 | |
|         {continue}
 | |
| 
 | |
|         ul.removeChild(li);
 | |
|         splice_at = inputted_list.indexOf(tagname);
 | |
|         if (splice_at == -1)
 | |
|         {continue}
 | |
| 
 | |
|         inputted_list.splice(splice_at, 1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| function add_new_orderby()
 | |
| {
 | |
|     /* Called by the green + button */
 | |
|     const ul = document.getElementById("search_builder_orderby_ul");
 | |
|     const lis = ul.getElementsByClassName("search_builder_orderby_li");
 | |
|     if (lis.length >= MAX_ORDERBY_ULS)
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
|     prev_li = lis[lis.length - 1];
 | |
|     const new_li = prev_li.cloneNode(true);
 | |
|     ul.insertBefore(new_li, prev_li.nextSibling);
 | |
| }
 | |
| 
 | |
| function orderby_remove_hook(button)
 | |
| {
 | |
|     /* Called by the red button next to orderby dropdowns */
 | |
|     const li = button.parentElement;
 | |
|     const ul = li.parentElement;
 | |
|     // 2 because keep 1 row and the adder button
 | |
|     if (ul.children.length>2)
 | |
|     {
 | |
|         /* You can't remove the only one left */
 | |
|         ul.removeChild(li);
 | |
|     }
 | |
| }
 | |
| 
 | |
| function disable_yield_albums_if_not_has_albums()
 | |
| {
 | |
|     const has_albums = document.querySelector("select[name='has_albums']");
 | |
|     const yield_albums = document.querySelector("select[name='yield_albums']");
 | |
|     if (has_albums.value == "no")
 | |
|     {
 | |
|         yield_albums.value = "no";
 | |
|         yield_albums.disabled = true;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         yield_albums.disabled = false;
 | |
|     }
 | |
| }
 | |
| 
 | |
| function orderby_hide_direction_hook(event)
 | |
| {
 | |
|     if (event.target.value == "random")
 | |
|     {
 | |
|         event.target.nextElementSibling.classList.add("hidden");
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         event.target.nextElementSibling.classList.remove("hidden");
 | |
|     }
 | |
| }
 | |
| 
 | |
| function simplify_tagnames(tags)
 | |
| {
 | |
|     const new_tags = [];
 | |
|     for (let tag of tags)
 | |
|     {
 | |
|         tag = tag.split(".");
 | |
|         tag = tag[tag.length - 1];
 | |
|         new_tags.push(tag);
 | |
|     }
 | |
|     return new_tags;
 | |
| }
 | |
| 
 | |
| function build_search_params()
 | |
| {
 | |
|     /*
 | |
|     Gather up all the form data and tags and compose the URL parameters.
 | |
|     */
 | |
|     const parameters = new URLSearchParams();
 | |
| 
 | |
|     // If the user has left any text in the tag boxes, but not hit Enter on
 | |
|     // them, then they will not be in the `inputted_` lists and would get
 | |
|     // ignored. So let's run through each of their hooks to get them all saved.
 | |
|     add_searchtag_from_box(input_musts, inputted_musts, "search_builder_musts_inputted");
 | |
|     add_searchtag_from_box(input_mays, inputted_mays, "search_builder_mays_inputted");
 | |
|     add_searchtag_from_box(input_forbids, inputted_forbids, "search_builder_forbids_inputted");
 | |
| 
 | |
|     let has_tag_params = false;
 | |
|     const musts = simplify_tagnames(inputted_musts).join(",");
 | |
|     if (musts) {parameters.set("tag_musts", musts); has_tag_params = true;}
 | |
| 
 | |
|     const mays = simplify_tagnames(inputted_mays).join(",");
 | |
|     if (mays) {parameters.set("tag_mays", mays); has_tag_params = true;}
 | |
| 
 | |
|     const forbids = simplify_tagnames(inputted_forbids).join(",");
 | |
|     if (forbids) {parameters.set("tag_forbids", forbids); has_tag_params = true;}
 | |
| 
 | |
|     const expression = document.getElementsByName("tag_expression")[0].value;
 | |
|     if (expression)
 | |
|     {
 | |
|         //expression = expression.replace(new RegExp(" ", 'g'), "-");
 | |
|         parameters.set("tag_expression", expression);
 | |
|         has_tag_params = true;
 | |
|     }
 | |
| 
 | |
|     const basic_inputs = document.getElementsByClassName("basic_param");
 | |
|     for (const basic_input of basic_inputs)
 | |
|     {
 | |
|         let value = basic_input.value;
 | |
|         value = value.split("&").join("%26");
 | |
|         console.log(value);
 | |
|         if (PARAM_DEFAULTS[basic_input.name] == value)
 | |
|         {
 | |
|             // Don't clutter url with default values.
 | |
|             continue;
 | |
|         }
 | |
|         if (value == "")
 | |
|         {
 | |
|             continue;
 | |
|         }
 | |
|         parameters.set(basic_input.name, value);
 | |
|     }
 | |
| 
 | |
|     const orderby_rows = document.getElementsByClassName("search_builder_orderby_li");
 | |
|     let orderby_params = [];
 | |
|     for (const orderby_row of orderby_rows)
 | |
|     {
 | |
|         const column = orderby_row.children[0].value;
 | |
|         if (column == "random")
 | |
|         {
 | |
|             orderby_params.push(column);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             const sorter = orderby_row.children[1].value;
 | |
|             orderby_params.push(column + "-" + sorter);
 | |
|         }
 | |
|     }
 | |
|     orderby_params = orderby_params.join(",");
 | |
|     if (orderby_params && orderby_params != "created-desc")
 | |
|     {
 | |
|         // Don't clutter url with default of created-desc
 | |
|         parameters.set("orderby", orderby_params);
 | |
|     }
 | |
| 
 | |
|     return parameters;
 | |
| }
 | |
| 
 | |
| function submit_search()
 | |
| {
 | |
|     const parameters = build_search_params().toString();
 | |
|     let url = "/search";
 | |
|     if (parameters !== "")
 | |
|     {
 | |
|         url += "?" + parameters.toString();
 | |
|     }
 | |
|     console.log(url);
 | |
|     window.location.href = url;
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| function submit_swipe()
 | |
| {
 | |
|     const parameters = build_search_params().toString();
 | |
|     let url = "/swipe";
 | |
|     if (parameters !== "")
 | |
|     {
 | |
|         url += "?" + parameters.toString();
 | |
|     }
 | |
|     console.log(url);
 | |
|     window.location.href = url;
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| function tags_on_this_page_add_must(event, tagname)
 | |
| {
 | |
|     add_searchtag(
 | |
|         ul_musts,
 | |
|         tagname,
 | |
|         inputted_musts,
 | |
|         "search_builder_musts_inputted"
 | |
|     );
 | |
|     submit_search();
 | |
|     return false;
 | |
| }
 | |
| function tags_on_this_page_add_may(event, tagname)
 | |
| {
 | |
|     add_searchtag(
 | |
|         ul_mays,
 | |
|         tagname,
 | |
|         inputted_mays,
 | |
|         "search_builder_mays_inputted"
 | |
|     );
 | |
|     submit_search();
 | |
|     return false;
 | |
| }
 | |
| function tags_on_this_page_add_forbid(event, tagname)
 | |
| {
 | |
|     add_searchtag(
 | |
|         ul_forbids,
 | |
|         tagname,
 | |
|         inputted_forbids,
 | |
|         "search_builder_forbids_inputted"
 | |
|     );
 | |
|     submit_search();
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| function tag_input_hook(box, inputted_list, li_class)
 | |
| {
 | |
|     /*
 | |
|     Assigned to the input boxes for musts, mays, forbids.
 | |
|     Hitting Enter will add the resovled tag to the search form.
 | |
|     */
 | |
|     if (event.key !== "Enter")
 | |
|     {return;}
 | |
| 
 | |
|     add_searchtag_from_box(box, inputted_list, li_class)
 | |
| }
 | |
| 
 | |
| function tag_input_hook_musts()
 | |
| {
 | |
|     tag_input_hook(this, inputted_musts, "search_builder_musts_inputted");
 | |
| }
 | |
| function tag_input_hook_mays()
 | |
| {
 | |
|     tag_input_hook(this, inputted_mays, "search_builder_mays_inputted");
 | |
| }
 | |
| function tag_input_hook_forbids()
 | |
| {
 | |
|     tag_input_hook(this, inputted_forbids, "search_builder_forbids_inputted");
 | |
| }
 | |
| 
 | |
| const input_musts = document.getElementById("search_builder_musts_input");
 | |
| const ul_musts = input_musts.parentElement.parentElement;
 | |
| const input_mays = document.getElementById("search_builder_mays_input");
 | |
| const ul_mays = input_mays.parentElement.parentElement;
 | |
| const input_forbids = document.getElementById("search_builder_forbids_input");
 | |
| const ul_forbids = input_forbids.parentElement.parentElement;
 | |
| const input_expression = document.getElementById("search_builder_expression_input");
 | |
| 
 | |
| /* Prefix the form with the parameters from last search */
 | |
| const inputted_musts = [];
 | |
| const inputted_mays = [];
 | |
| const inputted_forbids = [];
 | |
| {% for tagtype in ["musts", "mays", "forbids"] %}
 | |
|     {% set key="tag_" + tagtype %}
 | |
|     {% if search_kwargs|attr(key) %}
 | |
|     {% for tag in search_kwargs|attr(key) %}
 | |
|         inputted_{{tagtype}}.push("{{tag.name|safe}}");
 | |
|     {% endfor %}
 | |
|     {% endif %}
 | |
| {% endfor %}
 | |
| 
 | |
| const search_go_button = document.getElementById("search_go_button");
 | |
| input_musts.addEventListener("keyup", tag_input_hook_musts);
 | |
| common.bind_box_to_button(input_musts, search_go_button, true);
 | |
| 
 | |
| input_mays.addEventListener("keyup", tag_input_hook_mays);
 | |
| common.bind_box_to_button(input_mays, search_go_button, true);
 | |
| 
 | |
| input_forbids.addEventListener("keyup", tag_input_hook_forbids);
 | |
| common.bind_box_to_button(input_forbids, search_go_button, true);
 | |
| 
 | |
| common.bind_box_to_button(input_expression, search_go_button);
 | |
| 
 | |
| function on_pageload()
 | |
| {
 | |
|     photo_clipboard.register_hotkeys();
 | |
|     disable_yield_albums_if_not_has_albums();
 | |
| }
 | |
| document.addEventListener("DOMContentLoaded", on_pageload);
 | |
| </script>
 | |
| </html>
 |