mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-10-31 07:13:02 +00:00 
			
		
		
		
	Use ajax to add/remove books from shelves
Gracefully fall back to standard requests if JavaScript is disabled
This commit is contained in:
		| @@ -53,3 +53,8 @@ span.glyphicon.glyphicon-tags {padding-right: 5px;color: #999;vertical-align: te | ||||
| .spinner2 {margin:0 41%;} | ||||
|  | ||||
| .block-label {display: block;} | ||||
|  | ||||
| #remove-from-shelves .btn, | ||||
| #shelf-action-errors { | ||||
|     margin-left: 5px; | ||||
| } | ||||
|   | ||||
							
								
								
									
										39
									
								
								cps/static/js/details.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								cps/static/js/details.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| $( document ).ready(function() { | ||||
|     $("#have_read_form").ajaxForm(); | ||||
| }); | ||||
|  | ||||
| $("#have_read_cb").on("change", function() { | ||||
|     $(this).closest("form").submit(); | ||||
| }); | ||||
|  | ||||
| $(document).on("click", "[data-shelf-action]", function (e) { | ||||
|     e.preventDefault(); | ||||
|  | ||||
|     $.get(this.href) | ||||
|         .done(() => { | ||||
|             const $this = $(this); | ||||
|             switch ($this.data("shelf-action")) { | ||||
|                 case "add": | ||||
|                     $("#remove-from-shelves").append(`<a href="${$this.data("remove-href")}" | ||||
|                        data-add-href="${this.href}" | ||||
|                        class="btn btn-sm btn-default" data-shelf-action="remove" | ||||
|                     ><span class="glyphicon glyphicon-remove"></span> ${this.textContent}</a>`); | ||||
|                     break; | ||||
|                 case "remove": | ||||
|                     $("#add-to-shelves").append(`<li><a href="${$this.data("add-href")}" | ||||
|                       data-remove-href="${this.href}" | ||||
|                       data-shelf-action="add" | ||||
|                     >${this.textContent}</a></li>`); | ||||
|                     break; | ||||
|             } | ||||
|             this.parentNode.removeChild(this); | ||||
|         }) | ||||
|         .fail(xhr => { | ||||
|             const $msg = $("<span/>", { "class": "text-danger"}).text(xhr.responseText); | ||||
|             $("#shelf-action-status").html($msg); | ||||
|  | ||||
|             setTimeout(() => { | ||||
|                 $msg.remove(); | ||||
|             }, 10000); | ||||
|         }); | ||||
| }); | ||||
| @@ -189,37 +189,58 @@ | ||||
|             <span class="glyphicon glyphicon-list"></span> {{_('Add to shelf')}} | ||||
|             <span class="caret"></span> | ||||
|           </button> | ||||
|               <ul class="dropdown-menu" aria-labelledby="btnGroupDrop2"> | ||||
|           <ul id="add-to-shelves" class="dropdown-menu" aria-labelledby="btnGroupDrop2"> | ||||
|             {% for shelf in g.user.shelf %} | ||||
|               {% if not shelf.id in books_shelfs and shelf.is_public != 1 %} | ||||
|                     <li><a href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}">{{shelf.name}}</a></li> | ||||
|                 <li> | ||||
|                   <a href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}" | ||||
|                      data-remove-href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}" | ||||
|                      data-shelf-action="add" | ||||
|                   > | ||||
|                     {{shelf.name}} | ||||
|                   </a> | ||||
|                 </li> | ||||
|               {% endif %} | ||||
|             {%endfor%} | ||||
|             {% for shelf in g.public_shelfes %} | ||||
|               {% if not shelf.id in books_shelfs %} | ||||
|                     <li><a href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}">{{shelf.name}}</a></li> | ||||
|                 <li> | ||||
|                   <a href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}" | ||||
|                      data-remove-href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}" | ||||
|                      data-shelf-action="add" | ||||
|                   > | ||||
|                     {{shelf.name}} | ||||
|                   </a> | ||||
|                 </li> | ||||
|               {% endif %} | ||||
|             {%endfor%} | ||||
|           </ul> | ||||
|         </div> | ||||
|         <div id="remove-from-shelves" class="btn-group" role="group" aria-label="Remove from shelves"> | ||||
|           {% if books_shelfs %} | ||||
|         <div class="btn-group" role="group" aria-label="Remove from shelves"> | ||||
|             {% for shelf in g.user.shelf %} | ||||
|               {% if shelf.id in books_shelfs and shelf.is_public != 1 %} | ||||
|                   <a href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}" class="btn btn-sm btn-default" role="button"> | ||||
|                 <a href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}" | ||||
|                    data-add-href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}" | ||||
|                    class="btn btn-sm btn-default" role="button" data-shelf-action="remove" | ||||
|                 > | ||||
|                   <span class="glyphicon glyphicon-remove"></span> {{shelf.name}} | ||||
|                 </a> | ||||
|               {% endif %} | ||||
|             {%endfor%} | ||||
|             {% for shelf in g.public_shelfes %} | ||||
|               {% if shelf.id in books_shelfs %} | ||||
|                   <a href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}" class="btn btn-sm btn-default" role="button"> | ||||
|                 <a href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}" | ||||
|                    data-add-href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}" | ||||
|                    class="btn btn-sm btn-default" role="button" data-shelf-action="remove" | ||||
|                 > | ||||
|                   <span class="glyphicon glyphicon-remove"></span> {{shelf.name}} | ||||
|                 </a> | ||||
|               {% endif %} | ||||
|             {%endfor%} | ||||
|           {% endif %} | ||||
|         </div> | ||||
|         <div id="shelf-action-errors" class="pull-left" role="alert"></div> | ||||
|       </div> | ||||
|       {% endif %} | ||||
|  | ||||
| @@ -233,19 +254,12 @@ | ||||
|       {% endif %} | ||||
|       </div> | ||||
|  | ||||
|  | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|  | ||||
| {% block js %} | ||||
| <script src="{{ url_for('static', filename='js/libs/jquery.form.js') }}"></script> | ||||
| <script> | ||||
|   $( document ).ready(function() { | ||||
|     $('#have_read_form').ajaxForm(); | ||||
|   }); | ||||
|   $("#have_read_cb").on('change', function() { | ||||
|     $(this).closest('form').submit(); | ||||
|   }); | ||||
| </script> | ||||
| <script src="{{ url_for('static', filename='js/details.js') }}"></script> | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -99,17 +99,17 @@ | ||||
|     </div> | ||||
|     {% for message in get_flashed_messages(with_categories=True) %} | ||||
|       {%if message[0] == "error" %} | ||||
|       <div class="row-fluid" style="margin-top: -20px; text-align: center;"> | ||||
|       <div class="row-fluid text-center" style="margin-top: -20px;"> | ||||
|         <div id="flash_alert" class="alert alert-danger">{{ message[1] }}</div> | ||||
|       </div> | ||||
|       {%endif%} | ||||
|       {%if message[0] == "info" %} | ||||
|       <div class="row-fluid" style="margin-top: -20px; text-align: center;"> | ||||
|       <div class="row-fluid text-center" style="margin-top: -20px;"> | ||||
|         <div id="flash_info" class="alert alert-info">{{ message[1] }}</div> | ||||
|       </div> | ||||
|       {%endif%} | ||||
|       {%if message[0] == "success" %} | ||||
|       <div class="row-fluid" style="margin-top: -20px; text-align: center;"> | ||||
|       <div class="row-fluid text-center" style="margin-top: -20px;"> | ||||
|         <div id="flash_success" class="alert alert-success">{{ message[1] }}</div> | ||||
|       </div> | ||||
|       {%endif%} | ||||
|   | ||||
							
								
								
									
										45
									
								
								cps/web.py
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								cps/web.py
									
									
									
									
									
								
							| @@ -1949,45 +1949,80 @@ def send_to_kindle(book_id): | ||||
| @login_required | ||||
| def add_to_shelf(shelf_id, book_id): | ||||
|     shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() | ||||
|     if shelf is None: | ||||
|         app.logger.info("Invalid shelf specified") | ||||
|         if not request.is_xhr: | ||||
|             return redirect(url_for('index')) | ||||
|         return "Invalid shelf specified", 400 | ||||
|  | ||||
|     if not shelf.is_public and not shelf.user_id == int(current_user.id): | ||||
|         app.logger.info("Sorry you are not allowed to add a book to the the shelf: %s" % shelf.name) | ||||
|         if not request.is_xhr: | ||||
|             return redirect(url_for('index')) | ||||
|     maxOrder = ub.session.query(func.max(ub.BookShelf.order)).filter(ub.BookShelf.shelf == shelf_id).first() | ||||
|         return "Sorry you are not allowed to add a book to the the shelf: %s" % shelf.name, 403 | ||||
|  | ||||
|     if shelf.is_public and not current_user.role_edit_shelfs(): | ||||
|         app.logger.info("User is not allowed to edit public shelves") | ||||
|         if not request.is_xhr: | ||||
|             return redirect(url_for('index')) | ||||
|         return "User is not allowed to edit public shelves", 403 | ||||
|  | ||||
|     book_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id, | ||||
|                                           ub.BookShelf.book_id == book_id).first() | ||||
|     if book_in_shelf: | ||||
|         app.logger.info("Book is already part of the shelf: %s" % shelf.name) | ||||
|         if not request.is_xhr: | ||||
|             return redirect(url_for('index')) | ||||
|         return "Book is already part of the shelf: %s" % shelf.name, 400 | ||||
|  | ||||
|     maxOrder = ub.session.query(func.max(ub.BookShelf.order)).filter(ub.BookShelf.shelf == shelf_id).first() | ||||
|     if maxOrder[0] is None: | ||||
|         maxOrder = 0 | ||||
|     else: | ||||
|         maxOrder = maxOrder[0] | ||||
|     if (shelf.is_public and current_user.role_edit_shelfs()) or not shelf.is_public: | ||||
|  | ||||
|     ins = ub.BookShelf(shelf=shelf.id, book_id=book_id, order=maxOrder + 1) | ||||
|     ub.session.add(ins) | ||||
|     ub.session.commit() | ||||
|     if not request.is_xhr: | ||||
|         flash(_(u"Book has been added to shelf: %(sname)s", sname=shelf.name), category="success") | ||||
|         return redirect(request.environ["HTTP_REFERER"]) | ||||
|     else: | ||||
|         app.logger.info("User is not allowed to edit public shelfs") | ||||
|         return redirect(url_for('index')) | ||||
|     return "", 204 | ||||
|  | ||||
|  | ||||
| @app.route("/shelf/remove/<int:shelf_id>/<int:book_id>") | ||||
| @login_required | ||||
| def remove_from_shelf(shelf_id, book_id): | ||||
|     shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() | ||||
|     if shelf is None: | ||||
|         app.logger.info("Invalid shelf specified") | ||||
|         if not request.is_xhr: | ||||
|             return redirect(url_for('index')) | ||||
|         return "Invalid shelf specified", 400 | ||||
|  | ||||
|     if not shelf.is_public and not shelf.user_id == int(current_user.id) \ | ||||
|             or (shelf.is_public and current_user.role_edit_shelfs()): | ||||
|         if not request.is_xhr: | ||||
|             app.logger.info("Sorry you are not allowed to remove a book from this shelf: %s" % shelf.name) | ||||
|             return redirect(url_for('index')) | ||||
|         return "Sorry you are not allowed to add a book to the the shelf: %s" % shelf.name, 403 | ||||
|  | ||||
|     book_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id, | ||||
|                                                        ub.BookShelf.book_id == book_id).first() | ||||
|  | ||||
|     if book_shelf is None: | ||||
|         app.logger.info("Book already removed from shelf") | ||||
|         if not request.is_xhr: | ||||
|             return redirect(url_for('index')) | ||||
|         return "Book already removed from shelf", 410 | ||||
|  | ||||
|     ub.session.delete(book_shelf) | ||||
|     ub.session.commit() | ||||
|  | ||||
|     if not request.is_xhr: | ||||
|         flash(_(u"Book has been removed from shelf: %(sname)s", sname=shelf.name), category="success") | ||||
|         return redirect(request.environ["HTTP_REFERER"]) | ||||
|     return "", 204 | ||||
|  | ||||
|  | ||||
| @app.route("/shelf/create", methods=["GET", "POST"]) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Rehm
					Jonathan Rehm