Created
June 1, 2009 12:10
-
-
Save FND/121370 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> | |
<html lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<title>Cork - virtual pinboard</title> | |
<link rel="stylesheet" type="text/css" href="styles/main.css"> | |
<link rel="stylesheet" type="text/css" href="styles/jquery.ui.css"> | |
</head> | |
<body> | |
<div id="pinboard" class="board"> | |
<div class="toolbar"></div> | |
</div> | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script> | |
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js" type="text/javascript"></script> | |
<script src="scripts/lib/jquery-json.js" type="text/javascript"></script> | |
<script src="scripts/main.js" type="text/javascript"></script> | |
<script src="scripts/util.js" type="text/javascript"></script> | |
<script src="scripts/pinboard.js" type="text/javascript"></script> | |
<script src="scripts/backends/tiddlyweb.js" type="text/javascript"></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($){function toIntegersAtLease(n) | |
{return n<10?'0'+n:n;} | |
Date.prototype.toJSON=function(date) | |
{return this.getUTCFullYear()+'-'+ | |
toIntegersAtLease(this.getUTCMonth())+'-'+ | |
toIntegersAtLease(this.getUTCDate());};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};$.quoteString=function(string) | |
{if(escapeable.test(string)) | |
{return'"'+string.replace(escapeable,function(a) | |
{var c=meta[a];if(typeof c==='string'){return c;} | |
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';} | |
return'"'+string+'"';};$.toJSON=function(o,compact) | |
{var type=typeof(o);if(type=="undefined") | |
return"undefined";else if(type=="number"||type=="boolean") | |
return o+"";else if(o===null) | |
return"null";if(type=="string") | |
{return $.quoteString(o);} | |
if(type=="object"&&typeof o.toJSON=="function") | |
return o.toJSON(compact);if(type!="function"&&typeof(o.length)=="number") | |
{var ret=[];for(var i=0;i<o.length;i++){ret.push($.toJSON(o[i],compact));} | |
if(compact) | |
return"["+ret.join(",")+"]";else | |
return"["+ret.join(", ")+"]";} | |
if(type=="function"){throw new TypeError("Unable to convert object of type 'function' to json.");} | |
var ret=[];for(var k in o){var name;type=typeof(k);if(type=="number") | |
name='"'+k+'"';else if(type=="string") | |
name=$.quoteString(k);else | |
continue;var val=$.toJSON(o[k],compact);if(typeof(val)!="string"){continue;} | |
if(compact) | |
ret.push(name+":"+val);else | |
ret.push(name+": "+val);} | |
return"{"+ret.join(", ")+"}";};$.compactJSON=function(o) | |
{return $.toJSON(o,true);};$.evalJSON=function(src) | |
{return eval("("+src+")");};$.secureEvalJSON=function(src) | |
{var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered)) | |
return eval("("+src+")");else | |
throw new SyntaxError("Error parsing JSON, source is not valid.");};})(jQuery); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.ui-resizable { position: relative; } | |
.ui-resizable-handle { position: absolute; font-size: 0.1px; z-index: 99999; display: block; } | |
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } | |
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; } | |
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; } | |
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; } | |
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; } | |
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } | |
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } | |
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } | |
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px; } | |
.ui-draggable { cursor: move; } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { | |
margin: 0; | |
padding: 0; | |
} | |
html, | |
body, | |
.board { | |
height: 100%; | |
} | |
.board { | |
position: relative; | |
background-color: #FFE; | |
} | |
.snippet { | |
width: 300px; | |
height: 200px; | |
overflow: hidden; | |
border: 1px solid #AAA; | |
padding: 5px; | |
background-color: #EEF; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jQuery.noConflict(); | |
jQuery(function() { | |
var $ = jQuery; // alias | |
var container = $("#pinboard"); | |
var pb = new Pinboard(container); | |
$(document).trigger("startup", { pinboard: pb }); // XXX: rename event!? | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($) { | |
/* Pinboard object */ | |
Pinboard = function(container) { | |
this.snippets = []; // XXX: redundant? (cf. Pinboard.snippets - also, YAGNI) | |
this.container = container; | |
this.render(container); | |
return this; | |
}; | |
Pinboard.snippets = {}; // required to bridge DOM events -- XXX: ugly hack? | |
Pinboard.prototype.add = function(snippet) { | |
this.snippets.push(snippet); | |
Pinboard.snippets[snippet.id] = snippet; // XXX: renders ID attribute redundant!? | |
snippet.render(this.container); | |
}; | |
Pinboard.prototype.render = function(container) { | |
var self = this; | |
// populate toolbar | |
var createNewSnippet = function(ev) { | |
var snippet = new Snippet(); | |
self.add(snippet); | |
}; | |
$('<input type="button" value="new">'). | |
click(createNewSnippet). | |
appendTo("#pinboard .toolbar"); | |
// render snippets -- XXX: snippets always empty on startup!? | |
for(var i = 0; i < this.snippets.length; i++) { | |
this.snippets[i].render(container); | |
} | |
}; | |
/* Snippet object */ | |
Snippet = function(attr) { // XXX: rename "attr" | |
attr = attr || {}; | |
this.id = attr.id || _generateId(); | |
this.caption = attr.caption || this.id; | |
this.content = attr.content || "N/A"; | |
this.dimensions = attr.dimensions || {}; // XXX: separate size and position? | |
return this; | |
}; | |
Snippet.prototype.render = function(container) { | |
var el = $('<li class="snippet" />').attr("id", this.id); | |
$("<h3 />").text(this.caption).editable().appendTo(el); | |
$("<p />").text(this.content).editable({ multiLine: true, autosize: true }). | |
appendTo(el); | |
var dim = this.dimensions; // alias -- XXX: unnecessary? | |
if(dim.h && dim.v) { | |
el.css({ width: dim.h, height: dim.v }); | |
} | |
if(dim.x && dim.y) { | |
el.css({ position: "absolute", left: dim.x, top: dim.y }); | |
} | |
var resizeCallback = function(ev, ui) { | |
$(this).trigger("edit", { type: "resize", size: ui.size }); | |
}; | |
var dragCallback = function(ev, ui) { | |
$(this).trigger("edit", { type: "drag", position: ui.position }); | |
}; | |
$(el).resizable({ stop: resizeCallback }).draggable({ stop: dragCallback }). | |
appendTo(container); | |
}; | |
/* event handling */ | |
$(document).bind("edit", function(ev, data) { | |
var snippetEl = _findContainingSnippet(ev.target); | |
var snippet = _resolveSnippet(snippetEl); | |
switch(data.type) { | |
case "content": | |
snippet.caption = $("h3", snippetEl).text(); | |
snippet.content = $("p", snippetEl).text(); | |
break; | |
case "resize": | |
snippet.dimensions.h = data.size.width; | |
snippet.dimensions.v = data.size.height; | |
break; | |
case "drag": | |
var pos = $(snippetEl).position(); | |
snippet.dimensions.x = pos.left; | |
snippet.dimensions.y = pos.top; | |
break; | |
default: | |
break; | |
} | |
$(document).trigger("snippetEdit", { type: data.type, snippet: snippet }); // XXX: rename event | |
}); | |
/* utilities */ | |
// retrieve DOM element representing snippet | |
var _findContainingSnippet = function(el) { // XXX: rename; should be Pinboard method!? | |
return $(el).hasClass(".snippet") ? el : $(el).parent(".snippet")[0]; | |
}; | |
// determine Snippet instance from jQuery object | |
var _resolveSnippet = function(el) { // XXX: rename; should be Pinboard method!? | |
var id = $(el).attr("id"); | |
return Pinboard.snippets[id]; | |
}; | |
// generate pseudo-unique ID | |
var _generateId = function() { | |
return parseInt(Math.random() * new Date().valueOf(), 10); // XXX: safe enough? | |
}; | |
})(jQuery); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($) { | |
// settings -- XXX: hardcoded | |
var host = "http://localhost:8080"; | |
var recipe = "default"; | |
// event subscriptions | |
$(document).bind("snippetEdit", function(ev, data) { | |
saveSnippet(data.snippet); | |
}); | |
$(document).bind("startup", function(ev, data) { | |
loadSnippets(recipe, data.pinboard); | |
}); | |
// utility functions -- XXX: should not all be private!? | |
var loadSnippets = function(recipe, pinboard) { | |
var uri = generateURI(host, recipe); | |
var callback = function(xhr, statusText) { | |
if(xhr.status == 200 || xhr.status == 304) { | |
var json = $.evalJSON(xhr.responseText); // XXX: obsolete when using success callback!? | |
$.each(json, function(i, item) { | |
loadSnippet(item.title, pinboard); | |
}); | |
} else { | |
console.log(statusText, xhr.responseText, xhr); // XXX: should be UI notification | |
} | |
}; | |
$.localAjax({ | |
url: uri, | |
type: "GET", | |
dataType: "json", | |
complete: callback // XXX: use success instead!? | |
}); | |
}; | |
var loadSnippet = function(id, pinboard) { | |
var uri = generateURI(host, recipe, id); | |
var callback = function(xhr, statusText) { | |
if(xhr.status == 200 || xhr.status == 304) { | |
var json = $.evalJSON(xhr.responseText); // XXX: obsolete when using success callback!? | |
var snippet = internalize(json); | |
pinboard.add(snippet); | |
} | |
}; | |
$.localAjax({ | |
url: uri, | |
type: "GET", | |
dataType: "json", | |
complete: callback // XXX: use success instead!? | |
}); | |
}; | |
var saveSnippet = function(snippet) { | |
var uri = generateURI(host, recipe, snippet.id); | |
$.localAjax({ | |
url: uri, | |
type: "PUT", | |
contentType: "application/json", | |
data: externalize(snippet), | |
complete: console.log // DEBUG | |
}); | |
}; | |
var externalize = function(snippet) { // XXX: rename | |
var tiddler = { | |
fields: {} | |
}; | |
for(var key in snippet) { | |
switch(key) { | |
case "id": // title in URL | |
break; | |
case "content": | |
tiddler.text = snippet[key]; | |
break; | |
default: | |
if(snippet.hasOwnProperty(key)) { | |
tiddler.fields[key] = snippet[key]; | |
} | |
break; | |
} | |
} | |
tiddler.fields = flattenJSON(tiddler.fields); // XXX: hacky workaround | |
for(key in tiddler.fields) { | |
tiddler.fields[key] = tiddler.fields[key].toString(); // XXX: hacky workaround | |
} | |
return $.toJSON(tiddler); | |
}; | |
var internalize = function(json) { | |
var snippet = new Snippet({ | |
id: json.title, | |
caption: json.fields.caption, | |
content: json.text, | |
dimensions: { // XXX: not always present - leads to NaN | |
h: parseInt(json.fields["dimensions.h"], 10), | |
v: parseInt(json.fields["dimensions.v"], 10), | |
x: parseInt(json.fields["dimensions.x"], 10), | |
y: parseInt(json.fields["dimensions.y"], 10) | |
} | |
}); | |
// TODO: revision, created, modified, bag, modifier | |
return snippet; | |
}; | |
var generateURI = function(host, recipe, title) { // XXX: not very generic at this point | |
var uri = host + "/recipes/" + encodeURIComponent(recipe) + "/tiddlers"; // XXX: doesn't work with server_prefix!? | |
if(title) { | |
uri += "/" + encodeURIComponent(title); | |
} | |
return uri; | |
}; | |
})(jQuery); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($) { | |
/* | |
* enable editing functionality on element | |
* | |
* Switching from edit to view mode triggers "edit" event. | |
* | |
* options argument members | |
* multiLine: multi-line content editing (defaults to false) | |
* autosize: automatically resize input box (defaults to false) | |
* editTrigger: event type(s) triggering edit mode (defaults to "dblclick") | |
* viewTrigger: event type(s) triggering view mode (defaults to "blur") | |
*/ | |
$.fn.editable = function(options) { | |
options = options || {}; | |
var editTrigger = options.editTrigger || "dblclick"; | |
var viewTrigger = options.viewTrigger || "blur"; | |
return this.bind(editTrigger, function(ev) { | |
$(this)._edit(viewTrigger, options.multiLine, options.autosize); | |
}); | |
}; | |
$.fn._edit = function(trigger, multiLine, autosize) { // TODO: combine arguments -- XXX: rename method to avoid namespace polution? | |
var oldTag = this[0].tagName; | |
var newTag = multiLine ? "textarea" : "input"; | |
var width = this.width() - 5; // XXX: "padding" hardcoded | |
var height = multiLine ? this.height() : null; // XXX: does not compensate for scroll bars | |
var triggerCallback = function(ev) { | |
$(this)._render(oldTag). | |
editable({ multiLine: multiLine, viewTrigger: trigger }). // XXX: original element's events are lost | |
trigger("edit", { type: "content" }); // XXX: rename event!? | |
}; | |
var el = $("<" + newTag + "/>").val(this.text()). | |
width(width).height(height).bind(trigger, triggerCallback). | |
replaceAll(this); | |
if(autosize) { // DEBUG: inverted for testing purposes | |
el.keypress(function(ev) { $(this)._autosize(); }); | |
} | |
return el; | |
}; | |
$.fn._render = function(nodeType) { // XXX: rename method to avoid namespace polution? | |
nodeType = nodeType || "div"; | |
return $("<" + nodeType + "/>").text(this.val()).replaceAll(this); | |
}; | |
// XXX: feature creep!? | |
// TODO: optional maxWidth/maxHeight | |
$.fn._autosize = function(horizontal) { // XXX: rename method to avoid namespace polution? | |
if(horizontal) { | |
this.width(this[0].scrollWidth); | |
} else { | |
this.height(this[0].scrollHeight); | |
} | |
return this; | |
}; | |
/* | |
* enable AJAX calls from a local file | |
* triggers regular $.ajax call after requesting enhanced privileges | |
*/ | |
$.localAjax = function(args) { | |
if(document.location.protocol.indexOf("http") == -1 && window.Components && | |
window.netscape && window.netscape.security) { | |
window.netscape.security.PrivilegeManager. | |
enablePrivilege("UniversalBrowserRead"); | |
} | |
return $.ajax(args); | |
}; | |
flattenJSON = function(obj, options) { | |
options = options || {}; | |
var target = options.target || {}; | |
var prefix = options.prefix || ""; | |
for(var key in obj) { | |
if(obj.hasOwnProperty(key)) { | |
var prop = obj[key]; | |
var exclude = prop instanceof Array || prop instanceof RegExp || | |
prop instanceof Date; | |
if(typeof prop === "object" && !exclude) { | |
flattenJSON(prop, { | |
target: target, | |
prefix: prefix + key + "." | |
}); | |
} else { | |
target[prefix + key] = prop; | |
} | |
} | |
} | |
return target; | |
}; | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment