Project

General

Profile

« Previous | Next » 

Revision 621e7ed6

Added by dsorber about 11 years ago

Finished up the tag adding UI and update backend. Woohoo, progress!

View differences:

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>

Also available in: Unified diff