Added tagging, and a nice tag editor component.

This commit is contained in:
Raoul Snyman 2010-01-21 23:40:15 +02:00
parent d2907d72e8
commit 91338e7691
14 changed files with 231 additions and 16 deletions

View File

@ -31,7 +31,7 @@ beaker.session.secret = somesecret
#beaker.session.data_dir = %(here)s/data/sessions
# SQLAlchemy database URL
sqlalchemy.url = sqlite:///%(here)s/scribeengine.sqlite
sqlalchemy.url = sqlite:///%(here)s/code365.sqlite
# Images directory
paths.images = %(here)s/images
@ -39,7 +39,7 @@ paths.images = %(here)s/images
paths.themes = %(here)s/themes
# Security settings
security.salt = secretsalt
security.salt = xgH,{@1pgtU9,nLd
mail.on = false
mail.manager = immediate

View File

@ -25,13 +25,18 @@ from datetime import datetime
from scribeengine.lib.base import *
from scribeengine.lib import utils
from scribeengine.model import Post
from scribeengine.model import Post, Tag
from scribeengine.model.meta import Session
log = logging.getLogger(__name__)
class PostController(BaseController):
def __before__(self):
BaseController.__before__(self)
self._add_javascript(u'jquery.tag.editor.js')
self._add_javascript(u'ScribeEngine.Post.js')
def index(self):
h.redirect_to('/')
@ -61,6 +66,13 @@ class PostController(BaseController):
post.body = c.form_values[u'body']
post.status = u'published'
post.url = url
tags = c.form_values[u'tags']
tag_list = [tag_name.strip() for tag_name in tags.split(u',')]
for tag in post.tags:
if tag.name in tag_list:
del tag_list[tag.name]
for tag in tag_list:
post.tags.append(Tag(name=tag, url=utils.generate_url(tag)))
Session.add(post)
Session.commit()
h.redirect_to(str('/archive/%s/%s' % (post.created.strftime('%Y/%m/%d'), post.url)))

View File

@ -63,8 +63,8 @@ class BaseController(WSGIController):
self._add_javascript(u'jquery.js')
if c.jsvalidation:
self._add_javascript(u'jquery.validate.js')
self._add_javascript(u'scribeengine.js')
self._add_jsinit(u'init.js')
self._add_javascript(u'ScribeEngine.js')
self._add_jsinit(u'ScribeEngine.Init.js')
def __call__(self, environ, start_response):
"""Invoke the Controller"""
@ -178,14 +178,14 @@ class BaseController(WSGIController):
return False, {u'values': params, u'errors': error_dict}
return True, {u'values': values, u'errors': {}}
def _add_javascript(self, filename, subdir=u'global'):
def _add_javascript(self, filename):
"""
This method dynamically adds javascript files to the <head> section
of the template.
"""
if not getattr(c, u'scripts', None):
c.scripts = []
c.scripts.append((filename, subdir))
c.scripts.append(filename)
def _add_jsinit(self, filename):
"""

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

View File

@ -16,3 +16,11 @@
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
*****************************************************************************/
ScribeEngine.Namespace.create("ScribeEngine.Post", {
});
ScribeEngine.Events.load(function () {
ScribeEngine.Widgets.tagEditor("#post-tags");
});

View File

@ -90,7 +90,7 @@ ScribeEngine.Namespace.create("ScribeEngine.Events", {
keypress: function (selector, func) {
$(selector).bind("keypress", func);
},
get_element: function(event) {
getElement: function(event) {
var targ;
if (!event) {
var event = window.event;
@ -122,6 +122,10 @@ ScribeEngine.Namespace.create("ScribeEngine.Widgets", {
datepicker: function (selector)
{
$(selector).datepicker({showButtonPanel: true, dateFormat: "dd/mm/yy"});
},
tagEditor: function (selector)
{
$(selector).tagEditor({confirmRemoval: true, completeOnBlur: true, initialParse: true});
}
});
@ -226,12 +230,4 @@ ScribeEngine.Namespace.create("ScribeEngine.General", {
* This function below will be executed on all page views.
*/
ScribeEngine.Events.load(function () {
// Hide hidden elements
ScribeEngine.General.hide_elements();
// Initialise collapsible fieldsets
ScribeEngine.General.init_fieldsets();
// Initialise elastic textareas
ScribeEngine.General.init_textareas();
// Show any flash messages
ScribeEngine.General.show_message();
});

19
scribeengine/public/scripts/jquery.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,114 @@
/*
@author: Karl-Johan Sjögren / http://blog.crazybeavers.se/
@url: http://blog.crazybeavers.se/wp-content/demos/jquery.tag.editor/
@license: Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/
@version: 1.1
*/
(function($) {
$.fn.extend({
tagEditor: function(options) {
var defaults = {
separator: ',',
items: [],
className: 'tagEditor',
confirmRemoval: false,
completeOnSeparator: false,
completeOnBlur: false
}
var options = $.extend(defaults, options);
var listBase, textBase = this, hiddenText;
var itemBase = [];
return this.each(function() {
textBase.id = options.formField;
hiddenText = $(document.createElement('input'));
hiddenText.attr('type', 'hidden');
textBase.after(hiddenText);
listBase = $(document.createElement('ul'));
listBase.attr('class', options.className);
$(this).after(listBase);
for (var i = 0; i < options.items.length; i++) {
addTag(jQuery.trim(options.items[i]));
}
buildArray();
$(this).keypress(handleKeys);
$(this).blur(parse);
var form = $(this).parents("form");
form.submit(function() {
parse();
hiddenText.val(itemBase.join(options.separator));
hiddenText.attr("id", textBase.attr("id"));
hiddenText.attr("name", textBase.attr("name"));
textBase.attr("id", textBase.attr("id") + '_old');
textBase.attr("name", textBase.attr("name") + '_old');
});
function addTag(tag) {
tag = jQuery.trim(tag);
for (var i = 0; i < itemBase.length; i++) {
if (itemBase[i].toLowerCase() == tag.toLowerCase())
return;
}
var item = $(document.createElement('li'));
item.text(tag);
item.attr('title', 'Remove tag');
item.click(function() {
if (options.confirmRemoval)
if (!confirm("Do you really want to remove the tag?"))
return;
item.remove();
parse();
});
listBase.append(item);
}
function buildArray() {
itemBase = [];
var items = $("li", listBase);
for (var i = 0; i < items.length; i++) {
itemBase.push(jQuery.trim($(items[i]).text()));
}
}
function parse() {
var items = textBase.val().split(options.separator);
for (var i = 0; i < items.length; i++) {
var trimmedItem = jQuery.trim(items[i]);
if (trimmedItem.length > 0)
addTag(trimmedItem);
}
textBase.val("");
buildArray();
}
function handleKeys(ev) {
if (options.completeOnSeparator) {
if (String.fromCharCode(ev.keyCode) == options.separator) {
parse();
return false;
}
}
switch (ev.keyCode) {
case 13:
{
parse();
return false;
}
}
}
});
}
});
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -404,6 +404,34 @@ fieldset {
color: #fff;
}
/* Tag Editor */
.tagEditor
{
margin: 4px 0;
padding: 0;
}
.tagEditor li
{
display: inline;
background-image: url(/images/minus_small.png);
background-color: #454545;
background-position: right center;
background-repeat: no-repeat;
list-style-type: none;
padding: 2px 18px 2px 6px;
margin: 0 4px;
cursor: pointer;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
.tagEditor li:hover
{
background-color: #eee;
}
/* Miscellaneous Styles */
.hidden {

View File

@ -7,6 +7,15 @@
<meta name="keywords" content="" />
<meta name="description" content="" />
<link href="${h.url_for('/styles/style.css')}" rel="stylesheet" type="text/css" media="screen" />
% for script in c.scripts:
<script src="/scripts/${script}" type="text/javascript"></script>
% endfor
% if c.jsvalidation:
<script src="/scripts/${c.jsvalidation}" type="text/javascript"></script>
% endif
% if c.jsinit:
<script src="/scripts/${c.jsinit}" type="text/javascript"></script>
% endif
</head>
<body>
<div id="header">

View File

@ -6,6 +6,11 @@
<div class="entry">
${h.literal(c.post.body)}
</div>
<div class="tags">
% for tag in c.post.tags:
<a href="/tag/${tag.url}">${tag.name}</a>
% endfor
</div>
% if len(c.post.comments) == 0:
<h3 id="comments">No Responses</h3>
% elif len(c.post.comments) == 1:

View File

@ -13,6 +13,10 @@
<!-- <label for="post-body">Body:</label> -->
<textarea name="body" id="post-body" class="form-textarea">${c.post.body}</textarea>
</div>
<div class="form-item">
<label for="post-tags">Tags:</label>
<input type="text" name="tags" id="post-tags" class="form-text" value="${c.post.tags_list}" />
</div>
<div class="form-item">
<input type="submit" name="action" value="Save Draft"/>
<input type="submit" name="action" value="Save &amp; Publish"/>

View File

@ -13,6 +13,10 @@
<!-- <label for="post-body">Body:</label> -->
<textarea name="body" id="post-body" class="form-textarea"></textarea>
</div>
<div class="form-item">
<label for="post-tags">Tags:</label>
<input type="text" name="tags" id="post-tags" class="form-text" />
</div>
<div class="form-item">
<input type="submit" name="action" value="Save Draft" class="form-button"/>
<input type="submit" name="action" value="Save &amp; Publish" class="form-button"/>