Revision 621e7ed6
Added by dsorber about 11 years ago
| software/bookmark_library/bmklib/web/controllers/update_bookmark.py | ||
|---|---|---|
|
import sqlite3
|
||
|
|
||
|
from bmklib.lib.bookmark import Bookmark, BookmarkNotFoundError
|
||
|
from bmklib.lib.tag import Tag
|
||
|
from bmklib.web.base_controller import BaseHTMLController, DB_PATH
|
||
|
|
||
|
class UpdateBookmarkController(BaseHTMLController):
|
||
| ... | ... | |
|
bookmark.description = escape(post_vars['description'][0])
|
||
|
if 'deleted' in post_vars:
|
||
|
bookmark.deleted = bool(escape(post_vars['deleted'][0]))
|
||
|
bookmark.save()
|
||
|
bookmark.save()
|
||
|
|
||
|
# Update category tags
|
||
|
if 'category_tags' in post_vars:
|
||
|
category_tags = escape(post_vars['category_tags'][0])
|
||
|
category_tags = category_tags.split(';')
|
||
|
bookmark.category_tags.clear()
|
||
|
for tag in category_tags:
|
||
|
if tag:
|
||
|
bookmark.category_tags.add(Tag(conn, value=tag))
|
||
|
|
||
|
# Update description tags
|
||
|
if 'description_tags' in post_vars:
|
||
|
description_tags = escape(post_vars['description_tags'][0])
|
||
|
description_tags = description_tags.split(';')
|
||
|
bookmark.description_tags.clear()
|
||
|
for tag in description_tags:
|
||
|
if tag:
|
||
|
bookmark.description_tags.add(Tag(conn, value=tag))
|
||
|
|
||
|
self.content['invalid'] = False
|
||
|
self.content['bookmark'] = bookmark
|
||
|
|
||
|
# Save changes to bookmark
|
||
|
bookmark.save()
|
||
|
|
||
|
except BookmarkNotFoundError:
|
||
|
self.content['invalid'] = True
|
||
|
self.content['error'] = '{:d} is not a valid bookmark ID'.format(bmk_id)
|
||
| software/bookmark_library/bmklib/web/htdocs/css/bmk_form.css | ||
|---|---|---|
|
margin-top: 1.5em;
|
||
|
}
|
||
|
|
||
|
li.tag {
|
||
|
div#category_tag_list, div#description_tag_list {
|
||
|
padding: 1.2em;
|
||
|
}
|
||
|
|
||
|
span.tag {
|
||
|
display: inline-block;
|
||
|
padding: 0.4em 1em;
|
||
|
margin-right: 0.5em;
|
||
|
margin-top: 0.2em;
|
||
|
white-space: pre-wrap;
|
||
|
font-size: 12px;
|
||
|
font-weight: bold;
|
||
|
background-color: #003399;
|
||
|
color: #FFF;
|
||
|
padding: 0.4em 1em;
|
||
|
display: inline;
|
||
|
border-radius: 8px;
|
||
|
margin-right: 0.5em;
|
||
|
}
|
||
|
|
||
|
div.left {
|
||
| ... | ... | |
|
float: right;
|
||
|
display: inline-block;
|
||
|
}
|
||
|
|
||
|
input.tag_box {
|
||
|
width: 60%;
|
||
|
font-size: 16px;
|
||
|
}
|
||
|
|
||
|
input.tag_button {
|
||
|
width: auto;
|
||
|
font-size: 9pt;
|
||
|
margin-left: 0.8em;
|
||
|
}
|
||
|
|
||
|
span#no_tags {
|
||
|
font-style: italic;
|
||
|
font-size: 9pt;
|
||
|
font-weight: bold;
|
||
|
color: #666;
|
||
|
}
|
||
| software/bookmark_library/bmklib/web/htdocs/css/bmk_main.css | ||
|---|---|---|
|
|
||
|
div#nav_bar {
|
||
|
width: 100%;
|
||
|
background-color: #CC0000;
|
||
|
background-color: #FF6600;
|
||
|
padding: 0.2em 0em;
|
||
|
margin-bottom: 1em;
|
||
|
border-top: 1px solid #666666;
|
||
|
border-bottom: 1px solid #666666;
|
||
|
border-top: 1.5px solid #666666;
|
||
|
border-bottom: 1.5px solid #666666;
|
||
|
}
|
||
|
|
||
|
div#nav_bar a {
|
||
| ... | ... | |
|
display: block-inline;
|
||
|
text-decoration: none;
|
||
|
margin-left: 1em;
|
||
|
color: #FFFFFF;
|
||
|
color: #000000;
|
||
|
font-size: 9pt;
|
||
|
font-family: sans-serif;
|
||
|
font-weight: bold;
|
||
| ... | ... | |
|
display: block-inline;
|
||
|
text-decoration: none;
|
||
|
margin-left: 1em;
|
||
|
color: #000;
|
||
|
color: #333333;
|
||
|
font-size: 9pt;
|
||
|
font-family: sans-serif;
|
||
|
font-weight: bold;
|
||
| software/bookmark_library/bmklib/web/htdocs/js/add_tags.js | ||
|---|---|---|
|
$(document).ready(function() {
|
||
|
|
||
|
// Handle the "Cancel" button by making it act like "back" button
|
||
|
$("input[type='button']#back_button").click(function() {
|
||
|
history.back();
|
||
|
return false;
|
||
|
});
|
||
|
|
||
|
// Function to add new tags
|
||
|
// Function to add new category tags
|
||
|
$("input[name='add_category_tag']").click(function() {
|
||
|
// Get list of existing category tags
|
||
|
var category_tags = $("input[name='category_tags']").val().split(";");
|
||
| ... | ... | |
|
// Check if the category tag already exists in the list
|
||
|
for (var idx = 0; idx < category_tags.length; idx++) {
|
||
|
if (category_tags[idx] == new_category_tag) {
|
||
|
alert("already exists");
|
||
|
alert("tag already exists");
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove the none placeholder if it exists
|
||
|
$("div#category_tag_list span#no_tags").remove();
|
||
|
|
||
|
// Add new tag to list and update hidden input list of categor tags
|
||
|
var new_tag = $("<li class='tag'>" + new_category_tag + "</li>")
|
||
|
$("ul#category_tag_list").append(new_tag);
|
||
|
var new_tag = $("<span class='tag'>" + new_category_tag + "</span>")
|
||
|
$("div#category_tag_list").append(new_tag);
|
||
|
category_tags.push(new_category_tag);
|
||
|
var tags_serialized = category_tags.join(";");
|
||
|
$("input[name='category_tags']").val(tags_serialized);
|
||
|
$("input[name='new_category_tag']").val("");
|
||
|
});
|
||
|
|
||
|
// Function to remove tags if you right click on them
|
||
|
$(document).on("contextmenu", "ul#category_tag_list li", function() {
|
||
|
// Function to remove category tags if you right click on them
|
||
|
$(document).on("contextmenu", "div#category_tag_list span.tag", function() {
|
||
|
// Grab value of clicked tag
|
||
|
var tag_value = $(this).text();
|
||
|
|
||
| ... | ... | |
|
|
||
|
// Remove the clicked on tag UI element
|
||
|
$(this).remove();
|
||
|
|
||
|
// Check if all the tags have been removed
|
||
|
var count = $("div#category_tag_list").children("span").length;
|
||
|
if (count <= 0) {
|
||
|
var none_placeholder = $('<span id="no_tags">None</span>');
|
||
|
$("div#category_tag_list").append(none_placeholder);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
return false;
|
||
|
return true;
|
||
|
});
|
||
|
|
||
|
// Function to add new description tags
|
||
|
$("input[name='add_description_tag']").click(function() {
|
||
|
// Get list of existing description tags
|
||
|
var description_tags = $("input[name='description_tags']").val().split(";");
|
||
|
|
||
|
// Get the new description tag
|
||
|
var new_description_tag = $("input[name='new_description_tag']").val();
|
||
|
if (new_description_tag == "") {
|
||
|
alert("No value specified");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Validate the new description tag; make sure it does not contain ";"
|
||
|
if (new_description_tag.indexOf(";") != -1) {
|
||
|
alert("\"" + new_description_tag + "\" is not a valid tag!");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Check if the description tag already exists in the list
|
||
|
for (var idx = 0; idx < description_tags.length; idx++) {
|
||
|
if (description_tags[idx] == new_description_tag) {
|
||
|
alert("tag already exists");
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove the none placeholder if it exists
|
||
|
$("div#description_tag_list span#no_tags").remove();
|
||
|
|
||
|
// Add new tag to list and update hidden input list of description tags
|
||
|
var new_tag = $("<span class='tag'>" + new_description_tag + "</span>")
|
||
|
$("div#description_tag_list").append(new_tag);
|
||
|
description_tags.push(new_description_tag);
|
||
|
var tags_serialized = description_tags.join(";");
|
||
|
$("input[name='description_tags']").val(tags_serialized);
|
||
|
$("input[name='new_description_tag']").val("");
|
||
|
});
|
||
|
|
||
|
// Function to remove description tags if you right click on them
|
||
|
$(document).on("contextmenu", "div#description_tag_list span.tag", function() {
|
||
|
// Grab value of clicked tag
|
||
|
var tag_value = $(this).text();
|
||
|
|
||
|
// Ask for confirmation before removing tag
|
||
|
var r = confirm("Are you sure you want to remove description tag " + tag_value + " ?");
|
||
|
if (r == true) {
|
||
|
// Update hidden input list of category tags
|
||
|
var description_tags = $("input[name='description_tags']").val().split(";");
|
||
|
var updated_description_tags = new Array();
|
||
|
for (idx = 0; idx < description_tags.length; idx++) {
|
||
|
if (description_tags[idx] != tag_value) {
|
||
|
updated_description_tags.push(description_tags[idx]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Rewrite the updated description tags list
|
||
|
var tags_serialized = updated_description_tags.join(";");
|
||
|
$("input[name='description_tags']").val(tags_serialized);
|
||
|
|
||
|
// Remove the clicked on tag UI element
|
||
|
$(this).remove();
|
||
|
|
||
|
// Check if all the tags have been removed
|
||
|
var count = $("div#description_tag_list").children("span").length;
|
||
|
if (count <= 0) {
|
||
|
var none_placeholder = $('<span id="no_tags">None</span>');
|
||
|
$("div#description_tag_list").append(none_placeholder);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
});
|
||
|
});
|
||
| software/bookmark_library/bmklib/web/templates/bookmark.html | ||
|---|---|---|
|
xmlns:py="http://genshi.edgewall.org/">
|
||
|
<xi:include href="layout.html" />
|
||
|
<head>
|
||
|
<title>Bookmark Library</title>
|
||
|
<title>Bookmark ${bookmark.id}</title>
|
||
|
<link rel="stylesheet" type="text/css" href="/htdocs/css/bmk_form.css"></link>
|
||
|
<link rel="stylesheet" type="text/css" href="/htdocs/css/bmk_main.css"></link>
|
||
|
<script src="/htdocs/js/jquery-2.1.3.min.js"></script>
|
||
| ... | ... | |
|
<textarea name="description">${bookmark.description}</textarea>
|
||
|
</div>
|
||
|
|
||
|
<!-- Category tags -->
|
||
|
<div class="not_first">
|
||
|
<input type="hidden" name="category_tags" value="${';'.join([tag.value for tag in bookmark.category_tags])}" />
|
||
|
<span class="form_label">Category Tags:</span>
|
||
|
<ul id="category_tag_list">
|
||
|
<li py:for="cat_tag in bookmark.category_tags" class="tag">${cat_tag.value}</li>
|
||
|
</ul>
|
||
|
<input type="text" name="new_category_tag" /><input type="button" name="add_category_tag" value="Add tag"/>
|
||
|
<div id="category_tag_list">
|
||
|
<py:choose test="not bookmark.category_tags">
|
||
|
<py:when test="True"><span id="no_tags">None</span></py:when>
|
||
|
<py:when test="False">
|
||
|
<span py:for="cat_tag in bookmark.category_tags" class="tag">${cat_tag.value}</span>
|
||
|
</py:when>
|
||
|
</py:choose>
|
||
|
</div>
|
||
|
<input class="tag_box" type="text" name="new_category_tag" /><input class="tag_button" type="button" name="add_category_tag" value="Add tag"/>
|
||
|
</div>
|
||
|
|
||
|
<!-- Description tags -->
|
||
|
<div class="not_first">
|
||
|
<input type="hidden" name="description_tags" value="${';'.join([tag.value for tag in bookmark.description_tags])}" />
|
||
|
<span class="form_label">Description Tags:</span>
|
||
|
<ul>
|
||
|
<li py:for="desc_tag in bookmark.description_tags">${desc_tag.value}</li>
|
||
|
</ul>
|
||
|
<div id="description_tag_list">
|
||
|
<py:choose test="not bookmark.description_tags">
|
||
|
<py:when test="True"><span id="no_tags">None</span></py:when>
|
||
|
<py:when test="False">
|
||
|
<span py:for="desc_tag in bookmark.description_tags" class="tag">${desc_tag.value}</span>
|
||
|
</py:when>
|
||
|
</py:choose>
|
||
|
</div>
|
||
|
<input class="tag_box" type="text" name="new_description_tag" /><input class="tag_button" type="button" name="add_description_tag" value="Add tag"/>
|
||
|
</div>
|
||
|
|
||
|
<div class="not_first">
|
||
|
<input id="back_button" class="button" type="button" value="Cancel" />
|
||
|
<input class="button" type="submit" value="Update" />
|
||
|
</div>
|
||
|
<input id="back_button" class="button" type="button" value="Cancel" />
|
||
|
<input class="button" type="submit" value="Update" />
|
||
|
</div>
|
||
|
</form>
|
||
|
</py:when>
|
||
| software/bookmark_library/bmklib/web/templates/layout.html | ||
|---|---|---|
|
<py:match path="head" once="true">
|
||
|
<head py:attrs="select('@*')">
|
||
|
<title py:with="title = list(select('title/text()'))">
|
||
|
Geddit<py:if test="title">: ${title}</py:if>
|
||
|
Bookmark Library: <py:if test="title">${title}</py:if>
|
||
|
</title>
|
||
|
<!--
|
||
|
<link rel="stylesheet" href="${url('/media/layout.css')}" type="text/css" />
|
||
| ... | ... | |
|
|
||
|
<py:match path="body" once="true">
|
||
|
<body py:attrs="select('@*')">
|
||
|
<h1>Bookmarks</h1>
|
||
|
<h1>Bookmark Library</h1>
|
||
|
<div id="nav_bar">
|
||
|
<a href="/bmk/">Home</a>
|
||
|
<a href="/bmk/bookmarks">All bookmarks</a>
|
||
Finished up the tag adding UI and update backend. Woohoo, progress!