[snowy] Import the first cut of funcooker
- From: Brad Taylor <btaylor src gnome org>
- To: svn-commits-list gnome org
- Subject: [snowy] Import the first cut of funcooker
- Date: Sun, 3 May 2009 18:42:36 -0400 (EDT)
commit 297c08377b7e4b691bf248e678f0b5c4e51d2851
Author: Brad Taylor <brad getcoded net>
Date: Sun May 3 18:38:21 2009 -0400
Import the first cut of funcooker
---
tomboy-note.xsl => data/note2xhtml.xsl | 46 ++----
notes/templates/notes/note_detail.html | 18 ++-
notes/urls.py | 2 +-
notes/views.py | 32 ++++
site_media/js/DUI.js | 303 ++++++++++++++++++++++++++++++++
site_media/js/funcooker.js | 78 ++++++++
templates/base.html | 5 +
7 files changed, 447 insertions(+), 37 deletions(-)
diff --git a/tomboy-note.xsl b/data/note2xhtml.xsl
similarity index 79%
rename from tomboy-note.xsl
rename to data/note2xhtml.xsl
index 0b0b55d..d690afc 100644
--- a/tomboy-note.xsl
+++ b/data/note2xhtml.xsl
@@ -16,32 +16,7 @@
<xsl:param name="newline" select="'
'" />
<xsl:template match="/">
- <html>
- <head>
- <title><xsl:value-of select="/tomboy:note/tomboy:title" /></title>
- <style type="text/css">
- body { <xsl:value-of select="$font" /> }
- h1 { font-size: xx-large;
- font-weight: bold;
- border-bottom: 1px solid black; }
- div.note { overflow: auto;
- position: relative;
- display: block;
- padding: 5pt;
- margin: 5pt;
- white-space: -moz-pre-wrap; /* Mozilla */
- white-space: -pre-wrap; /* Opera 4 - 6 */
- white-space: -o-pre-wrap; /* Opera 7 */
- white-space: pre-wrap; /* CSS3 */
- word-wrap: break-word; /* IE 5.5+ */ }
- </style>
- </head>
- <body>
-
<xsl:apply-templates select="tomboy:note"/>
-
- </body>
- </html>
</xsl:template>
<xsl:template match="text()">
@@ -102,27 +77,28 @@
</xsl:template>
<xsl:template match="tomboy:highlight">
- <span style="background:yellow"><xsl:apply-templates select="node()"/></span>
+ <span class="note-highlight"><xsl:apply-templates select="node()"/></span>
</xsl:template>
<xsl:template match="tomboy:datetime">
- <span style="font-style:italic;font-size:small;color:#888A85">
+ <span class="note-datetime">
<xsl:apply-templates select="node()"/>
</span>
</xsl:template>
<xsl:template match="size:small">
- <span style="font-size:small"><xsl:apply-templates select="node()"/></span>
+ <span class="note-size-small"><xsl:apply-templates select="node()"/></span>
</xsl:template>
<xsl:template match="size:large">
- <span style="font-size:large"><xsl:apply-templates select="node()"/></span>
+ <span class="note-size-large"><xsl:apply-templates select="node()"/></span>
</xsl:template>
<xsl:template match="size:huge">
- <span style="font-size:xx-large"><xsl:apply-templates select="node()"/></span>
+ <span class="note-size-huge"><xsl:apply-templates select="node()"/></span>
</xsl:template>
+<!-- TODO:
<xsl:template match="link:broken">
<span style="color:#555753;text-decoration:underline">
<xsl:value-of select="node()"/>
@@ -156,27 +132,31 @@
<xsl:apply-templates select="node()" />
</li>
</xsl:template>
+-->
<!-- Evolution.dll Plugin -->
+<!--
<xsl:template match="link:evo-mail">
<a href="{./@uri}">
<img alt="Open Email Link" width="16" height="10" border="0">
- <!-- Inline Base64 encoded stock_mail.png =) -->
+ Inline Base64 encoded stock_mail.png =)
<xsl:attribute name="src">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAKCAYAAAC9vt6cAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI WXMAAAsQAAALEAGtI711AAAAB3RJTUUH1QkeAjYaRAvZgAAAALxJREFUKM+NkjGKw1AMRN+GhRS/ 2xP4EHZr0E1UxFVuoiKdikCKfxMfwKdw+3t1gb/F4hASe50BgZjRDEII/jAAtWmaCnxSAy+oZlYj YrfMbAkB4GsJiAjcnfPpRNzvrCHnjIjQdd3De3geUFX8diMdj6tmVX3jD6+EquLXKz9p37waANC2 LRfPpJTIOdP3PXuoEVFLKdXMaills5+m6f8jbq26dcTvRXR3RIR5njcDRIRxHFe14cMHenukX9eX mbvfl0q9AAAAAElFTkSuQmCC</xsl:attribute>
</img>
<xsl:value-of select="node()"/>
</a>
</xsl:template>
+-->
<!-- FixedWidth.dll Plugin -->
<xsl:template match="tomboy:monospace">
- <span style="font-family:monospace"><xsl:apply-templates select="node()"/></span>
+ <span class="note-monospace"><xsl:apply-templates select="node()"/></span>
</xsl:template>
<!-- Bugzilla.dll Plugin -->
+<!--
<xsl:template match="link:bugzilla">
<a href="{ uri}"><xsl:value-of select="node()" /></a>
</xsl:template>
+-->
</xsl:stylesheet>
-
diff --git a/notes/templates/notes/note_detail.html b/notes/templates/notes/note_detail.html
index f79296b..f95aba7 100644
--- a/notes/templates/notes/note_detail.html
+++ b/notes/templates/notes/note_detail.html
@@ -1,12 +1,24 @@
{% extends 'notes/base.html' %}
-{% block title %}{{ object.title }} | Notes | {{ block.super }}{% endblock %}
+{% block extra_head %}
+ <script type="text/javascript" src="{{ MEDIA_URL }}js/DUI.js" charset="utf-8"></script>
+
+ <script type="text/javascript" src="{{ MEDIA_URL }}js/funcooker.js" charset="utf-8"></script>
+{% endblock %}
+
+{% block title %}{{ note.title }} | Notes | {{ block.super }}{% endblock %}
{% block sidebar %}
{{ block.super }}
{% endblock %}
{% block content %}
-<h2>{{ object.title }}</h2>
-<p>{{ object.body }}</p>
+<div id="funcooker">
+{{ body|safe|linebreaksbr }}
+</div>
+<script type="text/javascript">
+$(document).ready(function() {
+ new FunCooker("#funcooker");
+});
+</script>
{% endblock %}
diff --git a/notes/urls.py b/notes/urls.py
index 03be0ab..f3a2072 100644
--- a/notes/urls.py
+++ b/notes/urls.py
@@ -29,5 +29,5 @@ notes_dict = {'queryset': Note.objects.all(), }
urlpatterns = patterns('',
(r'^$', object_list, notes_dict),
- url(r'^(?P<object_id>\d+)/$', object_detail, notes_dict, name='note_detail'),
+ url(r'^(?P<note_id>\d+)/$', 'snowy.notes.views.note_detail', name='note_detail'),
)
diff --git a/notes/views.py b/notes/views.py
index 0eb258e..9db7835 100644
--- a/notes/views.py
+++ b/notes/views.py
@@ -20,3 +20,35 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
+
+from django.template import RequestContext
+from django.shortcuts import render_to_response, get_object_or_404
+
+from snowy.notes.models import *
+
+def note_detail(request, note_id,
+ template_name='notes/note_detail.html'):
+ note = get_object_or_404(Note, pk=note_id)
+
+ # break this out into a function
+ import libxslt
+ import libxml2
+
+ style, doc, result = None, None, None
+
+ try:
+ styledoc = libxml2.parseFile('data/note2xhtml.xsl')
+ style = libxslt.parseStylesheetDoc(styledoc)
+
+ doc = libxml2.parseDoc(note.body)
+ result = style.applyStylesheet(doc, None)
+
+ body = style.saveResultToString(result)
+ finally:
+ if style != None: style.freeStylesheet()
+ if doc != None: doc.freeDoc()
+ if result != None: result.freeDoc()
+
+ return render_to_response(template_name,
+ {'note': note, 'body': body },
+ context_instance=RequestContext(request))
diff --git a/site_media/js/DUI.js b/site_media/js/DUI.js
new file mode 100644
index 0000000..759e07f
--- /dev/null
+++ b/site_media/js/DUI.js
@@ -0,0 +1,303 @@
+/**
+ * DUI: The Digg User Interface Library
+ *
+ * Copyright (c) 2008-2009, Digg, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the Digg, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @module DUI
+ * @author Micah Snyder <micah digg com>
+ * @description The Digg User Interface Library
+ * @version 0.0.4
+ * @link http://code.google.com/p/digg
+ *
+ */
+
+/* Add Array.prototype.indexOf -- Guess which major browser doesn't support it natively yet? */
+[].indexOf || (Array.prototype.indexOf = function(v, n){
+ n = (n == null) ? 0 : n; var m = this.length;
+
+ for(var i = n; i < m; i++) {
+ if(this[i] == v) return i;
+ }
+
+ return -1;
+});
+
+(function($) {
+
+/* Create our top-level namespace */
+DUI = {
+ version: "0.0.4"
+};
+
+/**
+ * @class Class Class creation and management for use with jQuery. Class is a singleton that handles static and dynamic classes, as well as namespaces
+ */
+DUI.Class = {
+ /**
+ * @var {Array} _dontEnum Internal array of keys to omit when looking through a class' properties. Once the real DontEnum bit is writable we won't have to deal with this.
+ */
+ _dontEnum: ['_ident', '_dontEnum', 'create', 'namespace', 'ns', 'supers', 'sup', 'init', 'each'],
+
+ /**
+ * @function create Make a class! Do work son, do work
+ * @param {optional Object} methods Any number of objects can be passed in as arguments to be added to the class upon creation
+ * @param {optional Boolean} static If the last argument is Boolean, it will be treated as the static flag. Defaults to false (dynamic)
+ */
+ create: function() {
+ //Set _this to DUI.Class
+ var _this = this;
+
+ //Figure out if we're creating a static or dynamic class
+ var s = (arguments.length > 0 && //if we have arguments...
+ arguments[arguments.length - 1].constructor == Boolean) ? //...and the last one is Boolean...
+ arguments[arguments.length - 1] : //...then it's the static flag...
+ false; //...otherwise default to a dynamic class
+
+ //Static: Object, dynamic: Function
+ var c = s ? {} : function() {
+ this.init.apply(this, arguments);
+ }
+
+ //All of our classes have these in common
+ var methods = {
+ _ident: {
+ library: "DUI.Class",
+ version: "0.0.4",
+ dynamic: true
+ },
+
+ //_dontEnum should exist in our classes as well
+ _dontEnum: this._dontEnum,
+
+ //A basic namespace container to pass objects through
+ ns: [],
+
+ //A container to hold one level of overwritten methods
+ supers: {},
+
+ //A constructor
+ init: function() {},
+
+ //Our namespace function
+ namespace:function(ns) {
+ //Don't add nothing
+ if (!ns) return null;
+
+ //Set _this to the current class, not the DUI.Class lib itself
+ var _this = this;
+
+ //Handle ['ns1', 'ns2'... 'nsN'] format
+ if(ns.constructor == Array) {
+ //Call namespace normally for each array item...
+ $.each(ns, function() {
+ _this.namespace.apply(_this, [this]);
+ });
+
+ //...then get out of this call to namespace
+ return;
+
+ //Handle {'ns': contents} format
+ } else if(ns.constructor == Object) {
+ //Loop through the object passed to namespace
+ for(var key in ns) {
+ //Only operate on Objects and Functions
+ if([Object, Function].indexOf(ns[key].constructor) > -1) {
+ //In case this.ns has been deleted
+ if(!this.ns) this.ns = [];
+
+ //Copy the namespace into an array holder
+ this.ns[key] = ns[key];
+
+ //Apply namespace, this will be caught by the ['ns1', 'ns2'... 'nsN'] format above
+ this.namespace.apply(this, [key]);
+ }
+ }
+
+ //We're done with namespace for now
+ return;
+ }
+
+ //Note: [{'ns': contents}, {'ns2': contents2}... {'nsN': contentsN}] is inherently handled by the above two cases
+
+ var levels = ns.split(".");
+
+ /* Dynamic classes are Functions, so we'll extend their prototype.
+ Static classes are Objects, so we'll extend them directly */
+ var nsobj = this.prototype ? this.prototype : this;
+
+ $.each(levels, function() {
+ /* When adding a namespace check to see, in order:
+ * 1) Does the ns exist in our ns passthrough object?
+ * 2) Does the ns already exist in our class
+ * 3) Does the ns exist as a global var?
+ * NOTE: Support for this was added so that you can namespace classes
+ * into other classes, i.e. MyContainer.namespace('MyUtilClass'). this
+ * behaviour is dangerously greedy though, so it may be removed.
+ * 4) If none of the above, make a new static class
+ */
+ nsobj[this] = _this.ns[this] || nsobj[this] || window[this] || DUI.Class.create(true);
+
+ /* If our parent and child are both dynamic classes, copy the child out of Parent.prototype and into Parent.
+ * It seems weird at first, but this allows you to instantiate a dynamic sub-class without instantiating
+ * its parent, e.g. var baz = new Foo.Bar();
+ */
+ if(_this.prototype && DUI.isClass(nsobj[this]) && nsobj[this].prototype) {
+ _this[this] = nsobj[this];
+ }
+
+ //Remove our temp passthrough if it exists
+ delete _this.ns[this];
+
+ //Move one level deeper for the next iteration
+ nsobj = nsobj[this];
+ });
+
+ //TODO: Do we really need to return this? It's not that useful anymore
+ return nsobj;
+ },
+
+ /* Create exists inside classes too. neat huh?
+ * Usage differs slightly: MyClass.create('MySubClass', { myMethod: function() }); */
+ create: function() {
+ //Turn arguments into a regular Array
+ var args = Array.prototype.slice.call(arguments);
+
+ //Pull the name of the new class out
+ var name = args.shift();
+
+ //Create a new class with the rest of the arguments
+ var temp = DUI.Class.create.apply(DUI.Class, args);
+
+ //Load our new class into the {name: class} format to pass it into namespace()
+ var ns = {};
+ ns[name] = temp;
+
+ //Put the new class into the current one
+ this.namespace(ns);
+ },
+
+ //Iterate over a class' members, omitting built-ins
+ each: function(cb) {
+ if(!$.isFunction(cb)) {
+ throw new Error('DUI.Class.each must be called with a function as its first argument.');
+ }
+
+ //Set _this to the current class, not the DUI.Class lib itself
+ var _this = this;
+
+ $.each(this, function(key) {
+ if(_this._dontEnum.indexOf(key) != -1) return;
+
+ cb.apply(this, [key, this]);
+ });
+ },
+
+ //Call the super of a method
+ sup: function() {
+ try {
+ var caller = this.sup.caller.name;
+ this.supers[caller].apply(this, arguments);
+ } catch(noSuper) {
+ return false;
+ }
+ }
+ }
+
+ //Static classes don't need a constructor
+ s ? delete methods.init : null;
+
+ //...nor should they be identified as dynamic classes
+ s ? methods._ident.dynamic = false : null;
+
+ /* Put default methods into the class before anything else,
+ * so that they'll be overwritten by the user-specified ones */
+ $.extend(c, methods);
+
+ /* Second copy of methods for dynamic classes: They get our
+ * common utils in their class definition AND their prototype */
+ if(!s) $.extend(c.prototype, methods);
+
+ //Static: extend the Object, Dynamic: extend the prototype
+ var extendee = s ? c : c.prototype;
+
+ //Loop through arguments. If they're the right type, tack them on
+ $.each(arguments, function() {
+ //Either we're passing in an object full of methods, or the prototype of an existing class
+ if(this.constructor == Object || typeof this.init != undefined) {
+ /* Here we're going per-property instead of doing $.extend(extendee, this) so that
+ * we overwrite each property instead of the whole namespace. Also: we omit the 'namespace'
+ * helper method that DUI.Class tacks on, as there's no point in storing it as a super */
+ for(i in this) {
+ /* If a property is a function (other than our built-in helpers) and it already exists
+ * in the class, save it as a super. note that this only saves the last occurrence */
+ if($.isFunction(extendee[i]) && _this._dontEnum.indexOf(i) == -1) {
+ //since Function.name is almost never set for us, do it manually
+ this[i].name = extendee[i].name = i;
+
+ //throw the existing function into this.supers before it's overwritten
+ extendee.supers[i] = extendee[i];
+ }
+
+ //Special case! If 'dontEnum' is passed in as an array, add its contents to DUI.Class._dontEnum
+ if(i == 'dontEnum' && this[i].constructor == Array) {
+ extendee._dontEnum = $.merge(extendee._dontEnum, this[i]);
+ }
+
+ //extend the current property into our class
+ extendee[i] = this[i];
+ }
+ }
+ });
+
+ //Shiny new class, ready to go
+ return c;
+ }
+};
+
+})(jQuery);
+
+//Simple check so see if the object passed in is a DUI Class
+DUI.isClass = function(check, type)
+{
+ type = type || false;
+
+ try {
+ if(check._ident.library == 'DUI.Class') {
+ if((type == 'dynamic' && !check._ident.dynamic)
+ || (type == 'static' && check._ident.dynamic)) {
+ return false;
+ }
+
+ return true;
+ }
+ } catch(noIdentUhOh) {
+ return false;
+ }
+
+ return false;
+}
diff --git a/site_media/js/funcooker.js b/site_media/js/funcooker.js
new file mode 100644
index 0000000..03906a9
--- /dev/null
+++ b/site_media/js/funcooker.js
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2009 Brad Taylor <brad getcoded net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* Here comes the funcooker! */
+var FunCooker = DUI.Class.create({
+ target: null,
+
+ init: function(target) {
+ this.target = $(target);
+
+ if (this.editingEnabled()) {
+ this.target.attr('contenteditable', true);
+ }
+ },
+
+ editingEnabled: function() {
+ // TODO: Support other platforms
+ return $.browser.mozilla;
+ },
+
+ boldSelection: function() {
+ },
+
+ wrapSelection: function(wrapper) {
+ var range = this.getDocumentSelection();
+ if (range) {
+ // insure that the selection range is inside of the editor
+ var parent = this.findParentById(range.commonAncestorContainer,
+ target.id);
+ if (!parent) {
+ return;
+ }
+
+ // TODO: make this work in the general case, e.g.: when sel spans
+ // multiple elements (<li>, <p>, etc)
+ range.surroundContents(wrapper);
+ }
+ },
+
+ getDocumentSelection: function() {
+ if ($.browser.mozilla) {
+ return window.getSelection().getRangeAt(0);
+ }
+ },
+
+ findParentById: function(subject, parentId) {
+ if (subject == null || subject.tagName == "BODY") {
+ return false;
+ }
+
+ if (subject.id == parentId) {
+ return subject;
+ }
+
+ return this.findParentById(subject.parentNode, parentId);
+ },
+});
diff --git a/templates/base.html b/templates/base.html
index ba8dc55..1692e9d 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -5,6 +5,11 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>{% block title %}home{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/screen.css" media="screen">
+{% if DEBUG %}
+ <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.js" charset="utf-8"></script>
+{% else %}
+ <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.min.js" charset="utf-8"></script>
+{% endif %}
{% block extra_head %}
{% endblock %}
</head>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]