mirror of
https://github.com/kennethreitz-archive/wp-s3.git
synced 2026-06-05 23:50:19 +00:00
add s3ajax libaries
This commit is contained in:
@@ -0,0 +1,428 @@
|
||||
/**
|
||||
S3Ajax v0.1 - An AJAX wrapper package for Amazon S3
|
||||
|
||||
http://decafbad.com/trac/wiki/S3Ajax
|
||||
l.m.orchard@pobox.com
|
||||
Share and Enjoy.
|
||||
|
||||
Requires:
|
||||
http://pajhome.org.uk/crypt/md5/sha1.js
|
||||
*/
|
||||
|
||||
// TODO: Figure out if Safari doesn't support PUT and DELETE
|
||||
|
||||
S3Ajax = {
|
||||
|
||||
// Defeat caching with query params on GET requests?
|
||||
DEFEAT_CACHE: false,
|
||||
|
||||
// Default ACL to use when uploading keys.
|
||||
DEFAULT_ACL: 'public-read',
|
||||
|
||||
// Default content-type to use in uploading keys.
|
||||
DEFAULT_CONTENT_TYPE: 'text/plain',
|
||||
|
||||
/**
|
||||
DANGER WILL ROBINSON - Do NOT fill in your KEY_ID and SECRET_KEY
|
||||
here. These should be supplied by client-side code, and not
|
||||
stored in any server-side files. Failure to protect your S3
|
||||
credentials will result in surly people doing nasty things
|
||||
on your tab.
|
||||
|
||||
For example, scoop values up from un-submitted form fields like so:
|
||||
|
||||
S3Ajax.KEY_ID = $('key_id').value;
|
||||
S3Ajax.SECRET_KEY = $('secret_key').value;
|
||||
*/
|
||||
URL: 'http://s3.amazonaws.com',
|
||||
KEY_ID: '',
|
||||
SECRET_KEY: '',
|
||||
|
||||
// Flip this to true to potentially get lots of wonky logging.
|
||||
DEBUG: false,
|
||||
|
||||
/**
|
||||
Get contents of a key in a bucket.
|
||||
*/
|
||||
get: function(bucket, key, cb, err_cb) {
|
||||
return this.httpClient({
|
||||
method: 'GET',
|
||||
resource: '/' + bucket + '/' + key,
|
||||
load: function(req, obj) {
|
||||
if (cb) return cb(req, req.responseText);
|
||||
},
|
||||
error: function(req, obj) {
|
||||
if (err_cb) return err_cb(req, obj);
|
||||
if (cb) return cb(req, req.responseText);
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
Head the meta of a key in a bucket.
|
||||
*/
|
||||
head: function(bucket, key, cb, err_cb) {
|
||||
return this.httpClient({
|
||||
method: 'HEAD',
|
||||
resource: '/' + bucket + '/' + key,
|
||||
load: function(req, obj) {
|
||||
if (cb) return cb(req, req.responseText);
|
||||
},
|
||||
error: function(req, obj) {
|
||||
if (err_cb) return err_cb(req, obj);
|
||||
if (cb) return cb(req, req.responseText);
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
Put data into a key in a bucket.
|
||||
*/
|
||||
put: function(bucket, key, content/*, [params], cb, [err_cb]*/) {
|
||||
|
||||
// Process variable arguments for optional params.
|
||||
var idx = 3;
|
||||
var params = {};
|
||||
if (typeof arguments[idx] == 'object')
|
||||
params = arguments[idx++];
|
||||
var cb = arguments[idx++];
|
||||
var err_cb = arguments[idx++];
|
||||
|
||||
if (!params.content_type)
|
||||
params.content_type = this.DEFAULT_CONTENT_TYPE;
|
||||
if (!params.acl)
|
||||
params.acl = this.DEFAULT_ACL;
|
||||
|
||||
return this.httpClient({
|
||||
method: 'PUT',
|
||||
resource: '/' + bucket + '/' + key,
|
||||
content: content,
|
||||
content_type: params.content_type,
|
||||
meta: params.meta,
|
||||
acl: params.acl,
|
||||
load: function(req, obj) {
|
||||
if (cb) return cb(req);
|
||||
},
|
||||
error: function(req, obj) {
|
||||
if (err_cb) return err_cb(req, obj);
|
||||
if (cb) return cb(req, obj);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
List buckets belonging to the account.
|
||||
*/
|
||||
listBuckets: function(cb, err_cb) {
|
||||
return this.httpClient({
|
||||
method:'GET', resource:'/',
|
||||
force_lists: [ 'ListAllMyBucketsResult.Buckets.Bucket' ],
|
||||
load: cb, error:err_cb
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Create a new bucket for this account.
|
||||
*/
|
||||
createBucket: function(bucket, cb, err_cb) {
|
||||
return this.httpClient({
|
||||
method:'PUT', resource:'/'+bucket, load:cb, error:err_cb
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Delete an empty bucket.
|
||||
*/
|
||||
deleteBucket: function(bucket, cb, err_cb) {
|
||||
return this.httpClient({
|
||||
method:'DELETE', resource:'/'+bucket, load:cb, error:err_cb
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Given a bucket name and parameters, list keys in the bucket.
|
||||
*/
|
||||
listKeys: function(bucket, params, cb, err_cb) {
|
||||
return this.httpClient({
|
||||
method:'GET', resource: '/'+bucket,
|
||||
force_lists: [ 'ListBucketResult.Contents' ],
|
||||
params:params, load:cb, error:err_cb
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Delete a single key in a bucket.
|
||||
*/
|
||||
deleteKey: function(bucket, key, cb, err_cb) {
|
||||
return this.httpClient({
|
||||
method:'DELETE', resource: '/'+bucket+'/'+key, load:cb, error:err_cb
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Delete a list of keys in a bucket, with optional callbacks
|
||||
for each deleted key and when list deletion is complete.
|
||||
*/
|
||||
deleteKeys: function(bucket, list, one_cb, all_cb) {
|
||||
var _this = this;
|
||||
|
||||
// If the list is empty, then fire off the callback.
|
||||
if (!list.length && all_cb) return all_cb();
|
||||
|
||||
// Fire off key deletion with a callback to delete the
|
||||
// next part of list.
|
||||
var key = list.shift();
|
||||
this.deleteKey(bucket, key, function() {
|
||||
if (one_cb) one_cb(key);
|
||||
_this.deleteKeys(bucket, list, one_cb, all_cb);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Perform an authenticated S3 HTTP query.
|
||||
*/
|
||||
httpClient: function(kwArgs) {
|
||||
var _this = this;
|
||||
|
||||
// If need to defeat cache, toss in a date param on GET.
|
||||
if (this.DEFEAT_CACHE && ( kwArgs.method == "GET" || kwArgs.method == "HEAD" ) ) {
|
||||
if (!kwArgs.params) kwArgs.params = {};
|
||||
kwArgs.params["___"] = new Date().getTime();
|
||||
}
|
||||
|
||||
// Prepare the query string and URL for this request.
|
||||
var qs = (kwArgs.params) ? '?'+queryString(kwArgs.params) : '';
|
||||
var url = this.URL + kwArgs.resource + qs;
|
||||
var hdrs = {};
|
||||
|
||||
// Handle Content-Type header
|
||||
if (!kwArgs.content_type && kwArgs.method == 'PUT')
|
||||
kwArgs.content_type = 'text/plain';
|
||||
if (kwArgs.content_type)
|
||||
hdrs['Content-Type'] = kwArgs.content_type;
|
||||
else
|
||||
kwArgs.content_type = '';
|
||||
|
||||
// Set the timestamp for this request.
|
||||
var http_date = this.httpDate();
|
||||
hdrs['Date'] = http_date;
|
||||
|
||||
var content_MD5 = '';
|
||||
/*
|
||||
// TODO: Fix this Content-MD5 stuff.
|
||||
if (kwArgs.content && kwArgs.content.hashMD5) {
|
||||
content_MD5 = kwArgs.content.hashMD5();
|
||||
hdrs['Content-MD5'] = content_MD5;
|
||||
}
|
||||
*/
|
||||
|
||||
// Handle the ACL parameter
|
||||
var acl_header_to_sign = '';
|
||||
if (kwArgs.acl) {
|
||||
hdrs['x-amz-acl'] = kwArgs.acl;
|
||||
acl_header_to_sign = "x-amz-acl:"+kwArgs.acl+"\n";
|
||||
}
|
||||
|
||||
// Handle the metadata headers
|
||||
var meta_to_sign = '';
|
||||
if (kwArgs.meta) {
|
||||
for (var k in kwArgs.meta) {
|
||||
hdrs['x-amz-meta-'+k] = kwArgs.meta[k];
|
||||
meta_to_sign += "x-amz-meta-"+k+":"+kwArgs.meta[k]+"\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Only perform authentication if non-anonymous and credentials available
|
||||
if (kwArgs['anonymous'] != true && this.KEY_ID && this.SECRET_KEY) {
|
||||
|
||||
// Build the string to sign for authentication.
|
||||
var s;
|
||||
s = kwArgs.method + "\n";
|
||||
s += content_MD5 + "\n";
|
||||
s += kwArgs.content_type + "\n";
|
||||
s += http_date + "\n";
|
||||
s += acl_header_to_sign;
|
||||
s += meta_to_sign;
|
||||
s += kwArgs.resource;
|
||||
|
||||
// Sign the string with our SECRET_KEY.
|
||||
var signature = this.hmacSHA1(s, this.SECRET_KEY);
|
||||
hdrs['Authorization'] = "AWS "+this.KEY_ID+":"+signature;
|
||||
}
|
||||
|
||||
// Perform the HTTP request.
|
||||
var req = getXMLHttpRequest();alert('test');
|
||||
req.open(kwArgs.method, url, true);
|
||||
for (var k in hdrs) req.setRequestHeader(k, hdrs[k]);
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState == 4) {
|
||||
|
||||
// Pre-digest the XML if needed.
|
||||
var obj = null;
|
||||
if (req.responseXML && kwArgs.parseXML != false)
|
||||
obj = _this.xmlToObj(req.responseXML, kwArgs.force_lists);
|
||||
|
||||
// Stash away the last request details, if DEBUG active.
|
||||
if (_this.DEBUG) {
|
||||
window._lastreq = req;
|
||||
window._lastobj = obj;
|
||||
}
|
||||
|
||||
// Dispatch to appropriate handler callback
|
||||
if ( (req.status >= 400 || (obj && obj.Error) ) && kwArgs.error)
|
||||
return kwArgs.error(req, obj);
|
||||
else
|
||||
return kwArgs.load(req, obj);
|
||||
|
||||
}
|
||||
}
|
||||
req.send(kwArgs.content);
|
||||
return req;
|
||||
},
|
||||
|
||||
/**
|
||||
Turn a simple structure of nested XML elements into a
|
||||
JavaScript object.
|
||||
|
||||
TODO: Handle attributes?
|
||||
*/
|
||||
xmlToObj: function(parent, force_lists, path) {
|
||||
var obj = {};
|
||||
var cdata = '';
|
||||
var is_struct = false;
|
||||
|
||||
for(var i=0,node; node=parent.childNodes[i]; i++) {
|
||||
if (3 == node.nodeType) {
|
||||
cdata += node.nodeValue;
|
||||
} else {
|
||||
is_struct = true;
|
||||
var name = node.nodeName;
|
||||
var cpath = (path) ? path+'.'+name : name;
|
||||
var val = arguments.callee(node, force_lists, cpath);
|
||||
|
||||
if (!obj[name]) {
|
||||
var do_force_list = false;
|
||||
if (force_lists) {
|
||||
for (var j=0,item; item=force_lists[j]; j++) {
|
||||
if (item == cpath) {
|
||||
do_force_list=true; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
obj[name] = (do_force_list) ? [ val ] : val;
|
||||
} else if (obj[name].length) {
|
||||
// This is a list of values to append this one to the end.
|
||||
obj[name].push(val);
|
||||
} else {
|
||||
// Has been a single value up till now, so convert to list.
|
||||
obj[name] = [ obj[name], val ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If any subnodes were found, return a struct - else return cdata.
|
||||
return (is_struct) ? obj : cdata;
|
||||
},
|
||||
|
||||
/**
|
||||
Abstract HMAC SHA1 signature calculation.
|
||||
*/
|
||||
hmacSHA1: function(data, secret) {
|
||||
// TODO: Alternate Dojo implementation?
|
||||
return b64_hmac_sha1(secret, data)+'=';
|
||||
},
|
||||
|
||||
/**
|
||||
Return a date formatted appropriately for HTTP Date header.
|
||||
Inspired by: http://www.svendtofte.com/code/date_format/
|
||||
|
||||
TODO: Should some/all of this go into common.js?
|
||||
*/
|
||||
httpDate: function(d) {
|
||||
// Use now as default date/time.
|
||||
if (!d) d = new Date();
|
||||
|
||||
// Date abbreviations.
|
||||
var daysShort = ["Sun", "Mon", "Tue", "Wed",
|
||||
"Thu", "Fri", "Sat"];
|
||||
var monthsShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||
|
||||
// See: http://www.quirksmode.org/js/introdate.html#sol
|
||||
function takeYear(theDate) {
|
||||
var x = theDate.getYear();
|
||||
var y = x % 100;
|
||||
y += (y < 38) ? 2000 : 1900;
|
||||
return y;
|
||||
};
|
||||
|
||||
// Number padding function
|
||||
function zeropad(num, sz) {
|
||||
return ( (sz - (""+num).length) > 0 ) ?
|
||||
arguments.callee("0"+num, sz) : num;
|
||||
};
|
||||
|
||||
function gmtTZ(d) {
|
||||
// Difference to Greenwich time (GMT) in hours
|
||||
var os = Math.abs(d.getTimezoneOffset());
|
||||
var h = ""+Math.floor(os/60);
|
||||
var m = ""+(os%60);
|
||||
h.length == 1? h = "0"+h:1;
|
||||
m.length == 1? m = "0"+m:1;
|
||||
return d.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
|
||||
};
|
||||
|
||||
var s;
|
||||
s = daysShort[d.getDay()] + ", ";
|
||||
s += d.getDate() + " ";
|
||||
s += monthsShort[d.getMonth()] + " ";
|
||||
s += takeYear(d) + " ";
|
||||
s += zeropad(d.getHours(), 2) + ":";
|
||||
s += zeropad(d.getMinutes(), 2) + ":";
|
||||
s += zeropad(d.getSeconds(), 2) + " ";
|
||||
s += gmtTZ(d);
|
||||
|
||||
return s;
|
||||
},
|
||||
|
||||
/* Help protect against errant end-commas */
|
||||
EOF: null
|
||||
|
||||
};
|
||||
|
||||
if (!window['queryString']) {
|
||||
// Swiped from MochiKit
|
||||
function queryString(params) {
|
||||
var l = [];
|
||||
for (k in params)
|
||||
l.push(k+'='+encodeURIComponent(params[k]))
|
||||
return l.join("&");
|
||||
}
|
||||
}
|
||||
|
||||
if (!window['getXMLHttpRequest']) {
|
||||
// Shamelessly swiped from MochiKit/Async.js
|
||||
function getXMLHttpRequest() {
|
||||
var self = arguments.callee;
|
||||
if (!self.XMLHttpRequest) {
|
||||
var tryThese = [
|
||||
function () { return new XMLHttpRequest(); },
|
||||
function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
|
||||
function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
|
||||
function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
|
||||
function () { return null; }
|
||||
];
|
||||
for (var i = 0; i < tryThese.length; i++) {
|
||||
var func = tryThese[i];
|
||||
try {
|
||||
self.XMLHttpRequest = func;
|
||||
return func();
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
return self.XMLHttpRequest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
Common can't-live-without stuff from MochiKit, Dojo, etal.
|
||||
Share and Enjoy
|
||||
*/
|
||||
|
||||
if (!window.Node) {
|
||||
window.Node = {
|
||||
ELEMENT_NODE : 1,
|
||||
ATTRIBUTE_NODE : 2,
|
||||
TEXT_NODE : 3,
|
||||
CDATA_SECTION_NODE : 4,
|
||||
ENTITY_REFERENCE_NODE : 5,
|
||||
ENTITY_NODE : 6,
|
||||
PROCESSING_INSTRUCTIONS_NODE : 7,
|
||||
COMMENT_NODE : 8,
|
||||
DOCUMENT_NODE : 9,
|
||||
DOCUMENT_TYPE_NODE : 10,
|
||||
DOCUMENT_FRAGMENT_NODE : 11,
|
||||
NOTATION_NODE : 12
|
||||
}
|
||||
}
|
||||
|
||||
if (!window['addLoadEvent']) {
|
||||
// See: http://simon.incutio.com/archive/2004/05/26/addLoadEvent
|
||||
function addLoadEvent(func) {
|
||||
var oldonload = window.onload;
|
||||
if (typeof window.onload != 'function') {
|
||||
window.onload = func;
|
||||
} else {
|
||||
window.onload = function() {
|
||||
oldonload();
|
||||
func();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!window['$']) {
|
||||
// Swiped from MochiKit / Prototype
|
||||
function $(id) { return document.getElementById(id); }
|
||||
}
|
||||
|
||||
/**
|
||||
Get the parsed XML response from an HTTP request, even if
|
||||
the server claimed a non-XML mimetype.
|
||||
*/
|
||||
function getResponseXML(rv) {
|
||||
if (rv.responseXML) return rv.responseXML;
|
||||
else return loadXML(rv.responseText);
|
||||
}
|
||||
|
||||
function loadXML(data) {
|
||||
if (DOMParser) return (new DOMParser()).parseFromString(data, 'text/xml');
|
||||
if (ActiveXObject) return (new ActiveXObject("microsoft.XMLDOM")).loadXML(data);
|
||||
return null;
|
||||
}
|
||||
|
||||
function clearList(lid) {
|
||||
$(lid).options.length = 0;
|
||||
}
|
||||
|
||||
function addToList(lid, label, key) {
|
||||
var list = $(lid);
|
||||
list.options[list.options.length] = new Option(label, key);
|
||||
}
|
||||
|
||||
function setList(lid, items) {
|
||||
var list = $(lid);
|
||||
this.clearList(lid);
|
||||
for(i=0;i<items.length;i+=2) {
|
||||
list.options[i/2] = new Option(items[i],items[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
function getSelected(lid) {
|
||||
var sel = [];
|
||||
var options = $(lid).options;
|
||||
for (var i=0, item; item=options[i]; i++) {
|
||||
if (item.selected) sel.push(item.value);
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
|
||||
/*
|
||||
Mini MochiKit
|
||||
*/
|
||||
|
||||
function forEach(list, fn) {
|
||||
for (var i=0; i<list.length; i++) fn(list[i]);
|
||||
}
|
||||
|
||||
function filter(fn, list) {
|
||||
var rv = [];
|
||||
for (var i=0; i<list.length; i++)
|
||||
if (fn(list[i]))
|
||||
rv[rv.length] = list[i];
|
||||
return rv;
|
||||
}
|
||||
|
||||
function map(fn, list) {
|
||||
var rv = [];
|
||||
for (var i=0; i<list.length; i++) rv[rv.length] = fn(list[i]);
|
||||
return rv;
|
||||
}
|
||||
|
||||
function appendChildNodes(parent, nodes) {
|
||||
for (var i=0; i<nodes.length; i++) {
|
||||
var node = nodes[i];
|
||||
if (node.nodeType)
|
||||
parent.appendChild(node);
|
||||
else if ( (typeof(node) == 'object') && node.length)
|
||||
appendChildNodes(parent, node);
|
||||
else
|
||||
parent.appendChild(document.createTextNode(''+node));
|
||||
}
|
||||
}
|
||||
|
||||
function createDOM(name, attrs, nodes) {
|
||||
var elem = document.createElement(name);
|
||||
if (attrs) for (k in attrs) {
|
||||
var v = attrs[k];
|
||||
|
||||
if (k.substring(0, 2) == "on") {
|
||||
if (typeof(v) == "string") {
|
||||
v = new Function(v);
|
||||
}
|
||||
elem[k] = v;
|
||||
} else {
|
||||
elem.setAttribute(k, v);
|
||||
}
|
||||
|
||||
switch(k) {
|
||||
// MSIE seems to want this.
|
||||
case 'class': elem.className = v; break;
|
||||
}
|
||||
}
|
||||
if (nodes) appendChildNodes(elem, nodes);
|
||||
return elem;
|
||||
}
|
||||
|
||||
function createDOMFunc(name) {
|
||||
return function(attrs) {
|
||||
var nodes = [];
|
||||
for (var i=1; i<arguments.length; i++)
|
||||
nodes[nodes.length] = arguments[i];
|
||||
return createDOM(name, attrs, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
forEach([
|
||||
'A', 'BUTTON', 'BR', 'CANVAS', 'DIV', 'FIELDSET', 'FORM',
|
||||
'H1', 'H2', 'H3', 'HR', 'IMG', 'INPUT', 'LABEL', 'LEGEND', 'LI', 'OL',
|
||||
'OPTGROUP', 'OPTION', 'P', 'PRE', 'SELECT', 'SPAN', 'STRONG', 'TABLE', 'TBODY',
|
||||
'TD', 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TR', 'TT', 'UL'
|
||||
], function(n) { window[n] = createDOMFunc(n); });
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
Logging hooks for Firebug.
|
||||
*/
|
||||
useFireBug = true;
|
||||
|
||||
printfire = function() {
|
||||
printfire.args = arguments;
|
||||
// Opera8 does not support dispatchEvent()
|
||||
// as global method (not required by W3C).
|
||||
// This helps to sort it out.
|
||||
try {
|
||||
if (!useFireBug) {
|
||||
// Mozilla installations without FireBug extension
|
||||
throw 'useAlertFunction';
|
||||
}
|
||||
var ev = document.createEvent("Events");
|
||||
ev.initEvent("printfire", false, true);
|
||||
// FireBug needs dispatchEvent() to be global
|
||||
// otherwise it fails
|
||||
dispatchEvent(ev);
|
||||
} catch (noConsole) {
|
||||
alert(arguments[0]);
|
||||
}
|
||||
}
|
||||
logFire = function() {
|
||||
if (window.printfire) {
|
||||
printfire( arguments[0], arguments[1]);
|
||||
}
|
||||
}
|
||||
if (window['logger'] && logger.addListener) {
|
||||
logger.addListener('firebug', null, function (msg) {
|
||||
printfire(msg.level + sum(map(function (i) { return ', ' + i; }, msg.info)));
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
Array.prototype.exists = function (x) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this[i] == x) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Date.prototype.formatDate = function (input,time) {
|
||||
// formatDate :
|
||||
// a PHP date like function, for formatting date strings
|
||||
// See: http://www.php.net/date
|
||||
//
|
||||
// input : format string
|
||||
// time : epoch time (seconds, and optional)
|
||||
//
|
||||
// if time is not passed, formatting is based on
|
||||
// the current "this" date object's set time.
|
||||
//
|
||||
// supported:
|
||||
// a, A, B, d, D, F, g, G, h, H, i, j, l (lowercase L), L,
|
||||
// m, M, n, O, r, s, S, t, U, w, W, y, Y, z
|
||||
//
|
||||
// unsupported:
|
||||
// I (capital i), T, Z
|
||||
|
||||
var switches = ["a", "A", "B", "d", "D", "F", "g", "G", "h", "H",
|
||||
"i", "j", "l", "L", "m", "M", "n", "O", "r", "s",
|
||||
"S", "t", "U", "w", "W", "y", "Y", "z"];
|
||||
var daysLong = ["Sunday", "Monday", "Tuesday", "Wednesday",
|
||||
"Thursday", "Friday", "Saturday"];
|
||||
var daysShort = ["Sun", "Mon", "Tue", "Wed",
|
||||
"Thu", "Fri", "Sat"];
|
||||
var monthsShort = ["Jan", "Feb", "Mar", "Apr",
|
||||
"May", "Jun", "Jul", "Aug", "Sep",
|
||||
"Oct", "Nov", "Dec"];
|
||||
var monthsLong = ["January", "February", "March", "April",
|
||||
"May", "June", "July", "August", "September",
|
||||
"October", "November", "December"];
|
||||
var daysSuffix = ["st", "nd", "rd", "th", "th", "th", "th", // 1st - 7th
|
||||
"th", "th", "th", "th", "th", "th", "th", // 8th - 14th
|
||||
"th", "th", "th", "th", "th", "th", "st", // 15th - 21st
|
||||
"nd", "rd", "th", "th", "th", "th", "th", // 22nd - 28th
|
||||
"th", "th", "st"]; // 29th - 31st
|
||||
|
||||
function a() {
|
||||
// Lowercase Ante meridiem and Post meridiem
|
||||
return self.getHours() > 11? "pm" : "am";
|
||||
}
|
||||
function A() {
|
||||
// Uppercase Ante meridiem and Post meridiem
|
||||
return self.getHours() > 11? "PM" : "AM";
|
||||
}
|
||||
|
||||
function B(){
|
||||
// Swatch internet time. code simply grabbed from ppk,
|
||||
// since I was feeling lazy:
|
||||
// http://www.xs4all.nl/~ppk/js/beat.html
|
||||
var off = (self.getTimezoneOffset() + 60)*60;
|
||||
var theSeconds = (self.getHours() * 3600) +
|
||||
(self.getMinutes() * 60) +
|
||||
self.getSeconds() + off;
|
||||
var beat = Math.floor(theSeconds/86.4);
|
||||
if (beat > 1000) beat -= 1000;
|
||||
if (beat < 0) beat += 1000;
|
||||
if ((""+beat).length == 1) beat = "00"+beat;
|
||||
if ((""+beat).length == 2) beat = "0"+beat;
|
||||
return beat;
|
||||
}
|
||||
|
||||
function d() {
|
||||
// Day of the month, 2 digits with leading zeros
|
||||
return new String(self.getDate()).length == 1?
|
||||
"0"+self.getDate() : self.getDate();
|
||||
}
|
||||
function D() {
|
||||
// A textual representation of a day, three letters
|
||||
return daysShort[self.getDay()];
|
||||
}
|
||||
function F() {
|
||||
// A full textual representation of a month
|
||||
return monthsLong[self.getMonth()];
|
||||
}
|
||||
function g() {
|
||||
// 12-hour format of an hour without leading zeros
|
||||
return self.getHours() > 12? self.getHours()-12 : self.getHours();
|
||||
}
|
||||
function G() {
|
||||
// 24-hour format of an hour without leading zeros
|
||||
return self.getHours();
|
||||
}
|
||||
function h() {
|
||||
// 12-hour format of an hour with leading zeros
|
||||
if (self.getHours() > 12) {
|
||||
var s = new String(self.getHours()-12);
|
||||
return s.length == 1?
|
||||
"0"+ (self.getHours()-12) : self.getHours()-12;
|
||||
} else {
|
||||
var s = new String(self.getHours());
|
||||
return s.length == 1?
|
||||
"0"+self.getHours() : self.getHours();
|
||||
}
|
||||
}
|
||||
function H() {
|
||||
// 24-hour format of an hour with leading zeros
|
||||
return new String(self.getHours()).length == 1?
|
||||
"0"+self.getHours() : self.getHours();
|
||||
}
|
||||
function i() {
|
||||
// Minutes with leading zeros
|
||||
return new String(self.getMinutes()).length == 1?
|
||||
"0"+self.getMinutes() : self.getMinutes();
|
||||
}
|
||||
function j() {
|
||||
// Day of the month without leading zeros
|
||||
return self.getDate();
|
||||
}
|
||||
function l() {
|
||||
// A full textual representation of the day of the week
|
||||
return daysLong[self.getDay()];
|
||||
}
|
||||
function L() {
|
||||
// leap year or not. 1 if leap year, 0 if not.
|
||||
// the logic should match iso's 8601 standard.
|
||||
var y_ = Y();
|
||||
if (
|
||||
(y_ % 4 == 0 && y_ % 100 != 0) ||
|
||||
(y_ % 4 == 0 && y_ % 100 == 0 && y_ % 400 == 0)
|
||||
) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
function m() {
|
||||
// Numeric representation of a month, with leading zeros
|
||||
return self.getMonth() < 9?
|
||||
"0"+(self.getMonth()+1) :
|
||||
self.getMonth()+1;
|
||||
}
|
||||
function M() {
|
||||
// A short textual representation of a month, three letters
|
||||
return monthsShort[self.getMonth()];
|
||||
}
|
||||
function n() {
|
||||
// Numeric representation of a month, without leading zeros
|
||||
return self.getMonth()+1;
|
||||
}
|
||||
function O() {
|
||||
// Difference to Greenwich time (GMT) in hours
|
||||
var os = Math.abs(self.getTimezoneOffset());
|
||||
var h = ""+Math.floor(os/60);
|
||||
var m = ""+(os%60);
|
||||
h.length == 1? h = "0"+h:1;
|
||||
m.length == 1? m = "0"+m:1;
|
||||
return self.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
|
||||
}
|
||||
function r() {
|
||||
// RFC 822 formatted date
|
||||
var r; // result
|
||||
// Thu , 21 Dec 2000
|
||||
r = D() + ", " + j() + " " + M() + " " + Y() +
|
||||
// 16 : 01 : 07 +0200
|
||||
" " + H() + ":" + i() + ":" + s() + " " + O();
|
||||
return r;
|
||||
}
|
||||
function S() {
|
||||
// English ordinal suffix for the day of the month, 2 characters
|
||||
return daysSuffix[self.getDate()-1];
|
||||
}
|
||||
function s() {
|
||||
// Seconds, with leading zeros
|
||||
return new String(self.getSeconds()).length == 1?
|
||||
"0"+self.getSeconds() : self.getSeconds();
|
||||
}
|
||||
function t() {
|
||||
|
||||
// thanks to Matt Bannon for some much needed code-fixes here!
|
||||
var daysinmonths = [null,31,28,31,30,31,30,31,31,30,31,30,31];
|
||||
if (L()==1 && n()==2) return 29; // leap day
|
||||
return daysinmonths[n()];
|
||||
}
|
||||
function U() {
|
||||
// Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
|
||||
return Math.round(self.getTime()/1000);
|
||||
}
|
||||
function W() {
|
||||
// Weeknumber, as per ISO specification:
|
||||
// http://www.cl.cam.ac.uk/~mgk25/iso-time.html
|
||||
|
||||
// if the day is three days before newyears eve,
|
||||
// there's a chance it's "week 1" of next year.
|
||||
// here we check for that.
|
||||
var beforeNY = 364+L() - z();
|
||||
var afterNY = z();
|
||||
var weekday = w()!=0?w()-1:6; // makes sunday (0), into 6.
|
||||
if (beforeNY <= 2 && weekday <= 2-beforeNY) {
|
||||
return 1;
|
||||
}
|
||||
// similarly, if the day is within threedays of newyears
|
||||
// there's a chance it belongs in the old year.
|
||||
var ny = new Date("January 1 " + Y() + " 00:00:00");
|
||||
var nyDay = ny.getDay()!=0?ny.getDay()-1:6;
|
||||
if (
|
||||
(afterNY <= 2) &&
|
||||
(nyDay >=4) &&
|
||||
(afterNY >= (6-nyDay))
|
||||
) {
|
||||
// Since I'm not sure we can just always return 53,
|
||||
// i call the function here again, using the last day
|
||||
// of the previous year, as the date, and then just
|
||||
// return that week.
|
||||
var prevNY = new Date("December 31 " + (Y()-1) + " 00:00:00");
|
||||
return prevNY.formatDate("W");
|
||||
}
|
||||
|
||||
// week 1, is the week that has the first thursday in it.
|
||||
// note that this value is not zero index.
|
||||
if (nyDay <= 3) {
|
||||
// first day of the year fell on a thursday, or earlier.
|
||||
return 1 + Math.floor( ( z() + nyDay ) / 7 );
|
||||
} else {
|
||||
// first day of the year fell on a friday, or later.
|
||||
return 1 + Math.floor( ( z() - ( 7 - nyDay ) ) / 7 );
|
||||
}
|
||||
}
|
||||
function w() {
|
||||
// Numeric representation of the day of the week
|
||||
return self.getDay();
|
||||
}
|
||||
|
||||
function Y() {
|
||||
// A full numeric representation of a year, 4 digits
|
||||
|
||||
// we first check, if getFullYear is supported. if it
|
||||
// is, we just use that. ppks code is nice, but wont
|
||||
// work with dates outside 1900-2038, or something like that
|
||||
if (self.getFullYear) {
|
||||
var newDate = new Date("January 1 2001 00:00:00 +0000");
|
||||
var x = newDate .getFullYear();
|
||||
if (x == 2001) {
|
||||
// i trust the method now
|
||||
return self.getFullYear();
|
||||
}
|
||||
}
|
||||
// else, do this:
|
||||
// codes thanks to ppk:
|
||||
// http://www.xs4all.nl/~ppk/js/introdate.html
|
||||
var x = self.getYear();
|
||||
var y = x % 100;
|
||||
y += (y < 38) ? 2000 : 1900;
|
||||
return y;
|
||||
}
|
||||
function y() {
|
||||
// A two-digit representation of a year
|
||||
var y = Y()+"";
|
||||
return y.substring(y.length-2,y.length);
|
||||
}
|
||||
function z() {
|
||||
// The day of the year, zero indexed! 0 through 366
|
||||
var t = new Date("January 1 " + Y() + " 00:00:00");
|
||||
var diff = self.getTime() - t.getTime();
|
||||
return Math.floor(diff/1000/60/60/24);
|
||||
}
|
||||
|
||||
var self = this;
|
||||
if (time) {
|
||||
// save time
|
||||
var prevTime = self.getTime();
|
||||
self.setTime(time);
|
||||
}
|
||||
|
||||
var ia = input.split("");
|
||||
var ij = 0;
|
||||
while (ia[ij]) {
|
||||
if (ia[ij] == "\\") {
|
||||
// this is our way of allowing users to escape stuff
|
||||
ia.splice(ij,1);
|
||||
} else {
|
||||
if (switches.exists(ia[ij])) {
|
||||
ia[ij] = eval(ia[ij] + "()");
|
||||
}
|
||||
}
|
||||
ij++;
|
||||
}
|
||||
// reset time, back to what it was
|
||||
if (prevTime) {
|
||||
self.setTime(prevTime);
|
||||
}
|
||||
return ia.join("");
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
Play around with S3Ajax!
|
||||
|
||||
TODO: Remove Dojo dependency
|
||||
*/
|
||||
|
||||
if (window.dojo) {
|
||||
// dojo.setModulePrefix("dojo", "js/dojo");
|
||||
// dojo.require("dojo.io.*");
|
||||
// dojo.require("dojo.crypto.SHA1");
|
||||
dojo.require("dojo.storage.*");
|
||||
}
|
||||
|
||||
Play = {
|
||||
|
||||
/**
|
||||
Initialize the play app.
|
||||
*/
|
||||
init: function() {
|
||||
var _this = this;
|
||||
|
||||
S3Ajax.DEBUG = true;
|
||||
|
||||
// HACK: Wait for the storage flash to become available.
|
||||
// TODO: Look for an official Dojo event to make this happen.
|
||||
if (window.dojo) {
|
||||
this._storage_wait = setInterval(function() {
|
||||
if ($('dojo-storeContainer')) {
|
||||
clearInterval(_this._storage_wait);
|
||||
_this._storage_wait = null;
|
||||
_this.recall();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Make an attempt to recall S3 credentials.
|
||||
*/
|
||||
recall: function() {
|
||||
if (window.dojo && dojo.storage.get('key_id', '/S3Ajax')) {
|
||||
S3Ajax.KEY_ID = dojo.storage.get('key_id', '/S3Ajax');
|
||||
S3Ajax.SECRET_KEY = dojo.storage.get('secret_key', '/S3Ajax');
|
||||
$('key_id').value = S3Ajax.KEY_ID;
|
||||
$('update_msg').innerHTML = 'Credentials fetched from local storage: '+(new Date());
|
||||
|
||||
// this.listbuckets();
|
||||
// this.list();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Accept new credentials from the form in the page.
|
||||
*/
|
||||
login: function() {
|
||||
S3Ajax.KEY_ID = $('key_id').value;
|
||||
S3Ajax.SECRET_KEY = $('secret_key').value;
|
||||
|
||||
// Try to stash the credentials away for next time.
|
||||
if (window.dojo) {
|
||||
dojo.storage.set('key_id', S3Ajax.KEY_ID, '/S3Ajax');
|
||||
dojo.storage.set('secret_key', S3Ajax.SECRET_KEY, '/S3Ajax');
|
||||
}
|
||||
|
||||
$('update_msg').innerHTML = 'Last updated: '+(new Date());
|
||||
},
|
||||
|
||||
/**
|
||||
Download the specified resource.
|
||||
*/
|
||||
download: function() {
|
||||
var bucket = $('list_bucket').value;
|
||||
var key = $('key').value;
|
||||
|
||||
$('content').value = "Loading...";
|
||||
|
||||
S3Ajax.get(bucket, key,
|
||||
function(req, content) {
|
||||
$('content').value = content;
|
||||
$('xfer_msg').innerHTML = "Download succeeded at "+(new Date());
|
||||
},
|
||||
function(req, objc) {
|
||||
$('xfer_msg').innerHTML = "Download failed at "+(new Date());
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
Upload the specified resource.
|
||||
*/
|
||||
upload: function() {
|
||||
var bucket = $('list_bucket').value;
|
||||
var key = $('key').value;
|
||||
var content = $('content').value;
|
||||
|
||||
S3Ajax.put(bucket, key, content,
|
||||
function(req) {
|
||||
$('xfer_msg').innerHTML = "Upload succeeded at "+(new Date());
|
||||
},
|
||||
function(req, obj) {
|
||||
$('xfer_msg').innerHTML = "Upload failed at "+(new Date());
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
S3Ajax.put(bucket, key, content,
|
||||
{
|
||||
content_type: "text/plain",
|
||||
meta: {'posted-by':'S3Ajax'},
|
||||
acl: "public-read",
|
||||
},
|
||||
function(req) {
|
||||
$('xfer_msg').innerHTML = "Upload succeeded at "+(new Date());
|
||||
},
|
||||
function(req, obj) {
|
||||
$('xfer_msg').innerHTML = "Upload failed at "+(new Date());
|
||||
}
|
||||
);
|
||||
*/
|
||||
},
|
||||
|
||||
/**
|
||||
List available buckets
|
||||
*/
|
||||
listbuckets: function() {
|
||||
var _this = this;
|
||||
|
||||
setList('buckets_list',['Loading...','']);
|
||||
|
||||
S3Ajax.listBuckets(
|
||||
function(req, obj) {
|
||||
clearList('buckets_list');
|
||||
if (obj.ListAllMyBucketsResult) {
|
||||
var buckets = obj.ListAllMyBucketsResult.Buckets.Bucket;
|
||||
for (var i=0, bucket; bucket=buckets[i]; i++) {
|
||||
addToList(
|
||||
'buckets_list',
|
||||
bucket.Name + ' ['+bucket.CreationDate+']',
|
||||
bucket.Name
|
||||
);
|
||||
}
|
||||
}
|
||||
keys_list = null;
|
||||
},
|
||||
function(req) {
|
||||
setList('buckets_list', ["Buckets list failed at "+(new Date()),'']);
|
||||
}
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
Change the current bucket to one selected in list.
|
||||
*/
|
||||
selectbucket: function() {
|
||||
var sel = getSelected('buckets_list');
|
||||
if (sel.length) $('list_bucket').value = sel[0];
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
deletebucket: function() {
|
||||
var _this = this;
|
||||
var sel = getSelected('buckets_list');
|
||||
if (!sel.length) return;
|
||||
|
||||
setList('buckets_list',['Deleting...','']);
|
||||
S3Ajax.deleteBucket(sel[0], function() {
|
||||
_this.listbuckets();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
createbucket: function() {
|
||||
var _this = this;
|
||||
var bucket = $('list_bucket').value;
|
||||
|
||||
setList('buckets_list',['Creating...','']);
|
||||
S3Ajax.createBucket(bucket, function() {
|
||||
_this.listbuckets();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
List a bucket's contents.
|
||||
*/
|
||||
list: function() {
|
||||
var _this = this;
|
||||
setList('keys_list', ['Loading...','']);
|
||||
|
||||
var bucket = $('list_bucket').value;
|
||||
|
||||
var params = {};
|
||||
if ($('list_prefix').value) params['prefix'] = $('list_prefix').value;
|
||||
if ($('list_maxkeys').value) params['max-keys'] = $('list_maxkeys').value;
|
||||
if ($('list_marker').value) params['marker'] = $('list_marker').value;
|
||||
|
||||
S3Ajax.listKeys(bucket, params,
|
||||
function(req, obj) {
|
||||
clearList('keys_list');
|
||||
var contents = obj.ListBucketResult.Contents;
|
||||
for (var i=0, item; item=contents[i]; i++) {
|
||||
addToList(
|
||||
'keys_list',
|
||||
/*item.LastModified + ' ' +*/ item.Key + ' (' + item.Size + ')',
|
||||
item.Key
|
||||
);
|
||||
}
|
||||
},
|
||||
function(req, obj) {
|
||||
setList('keys_list', ["Keys list failed at "+(new Date()),'']);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
Download the selected key.
|
||||
*/
|
||||
downloadSelectedKey: function() {
|
||||
var sel = getSelected('keys_list');
|
||||
if (sel.length) {
|
||||
$('key').value = sel[0];
|
||||
this.download();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Delete seleted keys.
|
||||
*/
|
||||
deleteSelectedKeys: function() {
|
||||
var _this = this;
|
||||
var sel_keys = getSelected('keys_list');
|
||||
|
||||
if (!window.confirm("Delete " + sel_keys.length + " selected items?")) return;
|
||||
|
||||
S3Ajax.deleteKeys($('list_bucket').value, sel_keys,
|
||||
function(key) { /*logFire("Deleted "+key);*/ },
|
||||
function(req, obj) { /*logFire("Deleted all");*/ _this.list(); }
|
||||
);
|
||||
},
|
||||
|
||||
/* Help protect against errant end-commas */
|
||||
EOF: null
|
||||
}
|
||||
addLoadEvent(function(){ Play.init() });
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
||||
* in FIPS PUB 180-1
|
||||
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
* Distributed under the BSD License
|
||||
* See http://pajhome.org.uk/crypt/md5 for details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Configurable variables. You may need to tweak these to be compatible with
|
||||
* the server-side, but the defaults work in most cases.
|
||||
*/
|
||||
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
|
||||
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
|
||||
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
|
||||
|
||||
/*
|
||||
* These are the functions you'll usually want to call
|
||||
* They take string arguments and return either hex or base-64 encoded strings
|
||||
*/
|
||||
function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
|
||||
function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
|
||||
function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
|
||||
function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
|
||||
function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
|
||||
function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
|
||||
|
||||
/*
|
||||
* Perform a simple self-test to see if the VM is working
|
||||
*/
|
||||
function sha1_vm_test()
|
||||
{
|
||||
return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the SHA-1 of an array of big-endian words, and a bit length
|
||||
*/
|
||||
function core_sha1(x, len)
|
||||
{
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << (24 - len % 32);
|
||||
x[((len + 64 >> 9) << 4) + 15] = len;
|
||||
|
||||
var w = Array(80);
|
||||
var a = 1732584193;
|
||||
var b = -271733879;
|
||||
var c = -1732584194;
|
||||
var d = 271733878;
|
||||
var e = -1009589776;
|
||||
|
||||
for(var i = 0; i < x.length; i += 16)
|
||||
{
|
||||
var olda = a;
|
||||
var oldb = b;
|
||||
var oldc = c;
|
||||
var oldd = d;
|
||||
var olde = e;
|
||||
|
||||
for(var j = 0; j < 80; j++)
|
||||
{
|
||||
if(j < 16) w[j] = x[i + j];
|
||||
else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
|
||||
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
|
||||
safe_add(safe_add(e, w[j]), sha1_kt(j)));
|
||||
e = d;
|
||||
d = c;
|
||||
c = rol(b, 30);
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
|
||||
a = safe_add(a, olda);
|
||||
b = safe_add(b, oldb);
|
||||
c = safe_add(c, oldc);
|
||||
d = safe_add(d, oldd);
|
||||
e = safe_add(e, olde);
|
||||
}
|
||||
return Array(a, b, c, d, e);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the appropriate triplet combination function for the current
|
||||
* iteration
|
||||
*/
|
||||
function sha1_ft(t, b, c, d)
|
||||
{
|
||||
if(t < 20) return (b & c) | ((~b) & d);
|
||||
if(t < 40) return b ^ c ^ d;
|
||||
if(t < 60) return (b & c) | (b & d) | (c & d);
|
||||
return b ^ c ^ d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the appropriate additive constant for the current iteration
|
||||
*/
|
||||
function sha1_kt(t)
|
||||
{
|
||||
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
|
||||
(t < 60) ? -1894007588 : -899497514;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the HMAC-SHA1 of a key and some data
|
||||
*/
|
||||
function core_hmac_sha1(key, data)
|
||||
{
|
||||
var bkey = str2binb(key);
|
||||
if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
|
||||
|
||||
var ipad = Array(16), opad = Array(16);
|
||||
for(var i = 0; i < 16; i++)
|
||||
{
|
||||
ipad[i] = bkey[i] ^ 0x36363636;
|
||||
opad[i] = bkey[i] ^ 0x5C5C5C5C;
|
||||
}
|
||||
|
||||
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
|
||||
return core_sha1(opad.concat(hash), 512 + 160);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
||||
* to work around bugs in some JS interpreters.
|
||||
*/
|
||||
function safe_add(x, y)
|
||||
{
|
||||
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
||||
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||
return (msw << 16) | (lsw & 0xFFFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*/
|
||||
function rol(num, cnt)
|
||||
{
|
||||
return (num << cnt) | (num >>> (32 - cnt));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an 8-bit or 16-bit string to an array of big-endian words
|
||||
* In 8-bit function, characters >255 have their hi-byte silently ignored.
|
||||
*/
|
||||
function str2binb(str)
|
||||
{
|
||||
var bin = Array();
|
||||
var mask = (1 << chrsz) - 1;
|
||||
for(var i = 0; i < str.length * chrsz; i += chrsz)
|
||||
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
|
||||
return bin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an array of big-endian words to a string
|
||||
*/
|
||||
function binb2str(bin)
|
||||
{
|
||||
var str = "";
|
||||
var mask = (1 << chrsz) - 1;
|
||||
for(var i = 0; i < bin.length * 32; i += chrsz)
|
||||
str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an array of big-endian words to a hex string.
|
||||
*/
|
||||
function binb2hex(binarray)
|
||||
{
|
||||
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
var str = "";
|
||||
for(var i = 0; i < binarray.length * 4; i++)
|
||||
{
|
||||
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
|
||||
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an array of big-endian words to a base-64 string
|
||||
*/
|
||||
function binb2b64(binarray)
|
||||
{
|
||||
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
var str = "";
|
||||
for(var i = 0; i < binarray.length * 4; i += 3)
|
||||
{
|
||||
var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16)
|
||||
| (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
|
||||
| ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
|
||||
for(var j = 0; j < 4; j++)
|
||||
{
|
||||
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
|
||||
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
S3AjaxWiki site-specific configuration
|
||||
*/
|
||||
with (S3AjaxWiki) {
|
||||
DEBUG = true;
|
||||
ANONYMOUS = true;
|
||||
BUCKET = 's3wiki';
|
||||
DEFAULT_ACL = 'public-read-write';
|
||||
}
|
||||
@@ -0,0 +1,573 @@
|
||||
/**
|
||||
S3AjaxWiki v0.1 - A client-side wiki for S3
|
||||
|
||||
http://decafbad.com/trac/wiki/S3Ajax
|
||||
l.m.orchard@pobox.com
|
||||
Share and Enjoy.
|
||||
*/
|
||||
|
||||
/*
|
||||
// TODO: Find a way to minimize the number of JS includes on wiki pages.
|
||||
|
||||
function $import() {
|
||||
for (var i=0, path; path=arguments[i]; i++) {
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = path;
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
}
|
||||
}
|
||||
|
||||
$import("js/firebug.js", "js/dojo.js", "js/sha1.js", "js/S3Ajax.js",
|
||||
"js/wiky.js", "js/wiky.s3wiki.js");
|
||||
*/
|
||||
|
||||
if (window.dojo) {
|
||||
dojo.require("dojo.storage.*");
|
||||
}
|
||||
|
||||
S3AjaxWiki = {
|
||||
|
||||
DEBUG: true,
|
||||
|
||||
ANONYMOUS: false,
|
||||
BUCKET: 'decafbad',
|
||||
TEMPLATE_KEY: 'wiki-template.html',
|
||||
KEY_PREFIX: 'wiki/',
|
||||
DEFAULT_ACL: 'public-read',
|
||||
DEFAULT_TYPE: 'text/html',
|
||||
DEFAULT_META: {'posted-by':'S3AjaxWiki'},
|
||||
|
||||
/*
|
||||
These are the IDs of elements injected as a part of the wiki
|
||||
editing framework, and should not end up in serialized pages.
|
||||
*/
|
||||
IGNORED_ELEMENT_IDS: [
|
||||
'content_edit', 'credentials', 'toc', 'page_options',
|
||||
'xfer_msg', 'dojo-storeContainer'
|
||||
],
|
||||
|
||||
/*
|
||||
These are attribute names that cause problems in MSIE.
|
||||
We'll ignore them during page serialization.
|
||||
TODO: Make this a per-element hash? Need more sophistication here.
|
||||
*/
|
||||
IGNORED_ATTRIBUTE_NAMES: [
|
||||
'hideFocus', 'contentEditable', 'disabled', 'tabIndex',
|
||||
'bottomMargin', 'noWrap', 'leftMargin', 'topMargin',
|
||||
'rightMargin', 'defer'
|
||||
],
|
||||
|
||||
/**
|
||||
Initialize the wiki app
|
||||
*/
|
||||
init: function() {
|
||||
// Debounce init calls.
|
||||
if (arguments.callee.done) return;
|
||||
arguments.callee.done = true;
|
||||
|
||||
S3Ajax.DEBUG = this.DEBUG;
|
||||
S3Ajax.DEFEAT_CACHE = true;
|
||||
|
||||
forEach([ 'FIELDSET' ], function(n) {
|
||||
window[n] = createDOMFunc(n);
|
||||
});
|
||||
|
||||
this.injectEditingFramework();
|
||||
if (!this.ANONYMOUS) this.autoLoadCredentials();
|
||||
else this.onLogin();
|
||||
},
|
||||
|
||||
/**
|
||||
Try to load stored credentials when using dojo.storage.
|
||||
TODO: Scoop out dojo.storage to work separately from dojo proper.
|
||||
*/
|
||||
autoLoadCredentials: function() {
|
||||
var _this = this;
|
||||
|
||||
$('credentials_msg').innerHTML = 'No credentials.';
|
||||
this.hideCredentials();
|
||||
|
||||
// HACK: Wait for the storage flash to become available.
|
||||
// TODO: Look for an official Dojo event to make this happen.
|
||||
this.hideCredentials();
|
||||
if (window.dojo) {
|
||||
this._storage_wait = setInterval(function() {
|
||||
if ($('dojo-storeContainer')) {
|
||||
clearInterval(_this._storage_wait);
|
||||
_this._storage_wait = null;
|
||||
try {
|
||||
_this.recall();
|
||||
} catch(e) {
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
} else {
|
||||
this.onLogin();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Some things to perform upon (un)successful login.
|
||||
*/
|
||||
onLogin: function() {
|
||||
this.scanWikiWords();
|
||||
this.refreshPageList();
|
||||
},
|
||||
|
||||
/**
|
||||
Scan wiki word links on the page, with the intent to discover
|
||||
which actually exist.
|
||||
*/
|
||||
scanWikiWords: function() {
|
||||
// Empty the list of words to scan
|
||||
this._scan_words = {};
|
||||
|
||||
// Scan through wiki word links and gather unique list.
|
||||
var links = document.getElementsByTagName('a');
|
||||
for (var i=0, link; link=links[i]; i++) {
|
||||
if ('wikiword' == link.className) {
|
||||
this._scan_words[link.innerHTML] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect a plain list of unique words.
|
||||
var words = [];
|
||||
for (var word in this._scan_words) { words.push(word); }
|
||||
this._doWordScan(words);
|
||||
},
|
||||
|
||||
/**
|
||||
Perform S3 HEAD requests to determine the existence of a given
|
||||
list of wiki words. Collect the results, make a note of which
|
||||
words exist or not.
|
||||
*/
|
||||
_doWordScan: function(words) {
|
||||
var _this = this;
|
||||
|
||||
// If the words list is empty, stop.
|
||||
if (!words.length) {
|
||||
return this.updateWikiWords();
|
||||
}
|
||||
|
||||
// Search for existence of a word, marking it appropriately.
|
||||
var word = words.shift();
|
||||
S3Ajax.head(this.BUCKET, this.KEY_PREFIX + word,
|
||||
function() {
|
||||
_this.markWikiWord(word, true);
|
||||
_this._doWordScan(words);
|
||||
},
|
||||
function() {
|
||||
_this.markWikiWord(word, false);
|
||||
_this._doWordScan(words);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
Mark a given wiki word as found, or not.
|
||||
*/
|
||||
markWikiWord: function(word, found) {
|
||||
this._scan_words[word] = found;
|
||||
// HACK: Doing this for every found word might be too often.
|
||||
this.updateWikiWords();
|
||||
},
|
||||
|
||||
/**
|
||||
Scan through wiki word links on the page. For every link not
|
||||
found in S3, wire it up as a new page creation link.
|
||||
*/
|
||||
updateWikiWords: function() {
|
||||
var links = document.getElementsByTagName('a');
|
||||
for (var i=0, link; link=links[i]; i++) {
|
||||
if ('wikiword' == link.className) {
|
||||
var word = link.innerHTML;
|
||||
if (!this._scan_words[word])
|
||||
this.wireUpNewWord(link, word)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Wire up a wiki word link as a new page creation link, changing
|
||||
its CSS style and hooking its click event up to createNewPage().
|
||||
*/
|
||||
wireUpNewWord: function(link, word) {
|
||||
var _this = this;
|
||||
link.className = 'newword';
|
||||
link.onclick = function() {
|
||||
_this.createNewPage(word); return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
For a given wiki word, create a new page. Load up the wiki page
|
||||
template, change the header and body titles, save to S3 as a new
|
||||
key, redirect browser to the new page.
|
||||
|
||||
TODO: Simply redirect if the page already exists?
|
||||
*/
|
||||
createNewPage: function(word) {
|
||||
// Do not create unnamed pages.
|
||||
if (!word) return;
|
||||
|
||||
var _this = this;
|
||||
S3Ajax.get(_this.BUCKET, _this.TEMPLATE_KEY,
|
||||
function(req, data) {
|
||||
var xml = getResponseXML(req);
|
||||
|
||||
// Update document head title
|
||||
var page_title = xml.getElementsByTagName('title')[0];
|
||||
page_title.firstChild.nodeValue = word;
|
||||
|
||||
// Update page header title.
|
||||
/*
|
||||
// HACK: Should getElementById work here? Seems not to.
|
||||
var head_title = xml.getElementById('page_title');
|
||||
head_title.nodeValue = word;
|
||||
*/
|
||||
var h1s = xml.getElementsByTagName('h1');
|
||||
for (var i=0,h1; h1=h1s[i]; i++)
|
||||
if ('page_title' == h1.getAttribute('id'))
|
||||
h1.firstChild.nodeValue = word;
|
||||
|
||||
// Get serialized HTML content from the page DOM
|
||||
var data = _this.fromDOMtoHTML(xml);
|
||||
|
||||
// Upload to S3, redirect if successful.
|
||||
S3Ajax.put(_this.BUCKET, _this.KEY_PREFIX + word, data,
|
||||
{
|
||||
content_type: _this.DEFAULT_TYPE,
|
||||
acl: _this.DEFAULT_ACL,
|
||||
meta: _this.DEFAULT_META
|
||||
},
|
||||
function(req) {
|
||||
location.href = word;
|
||||
},
|
||||
function(req, obj) {
|
||||
$('xfer_msg').innerHTML = "Upload failed at "+(new Date());
|
||||
}
|
||||
);
|
||||
},
|
||||
function(req, data) {
|
||||
// TODO: Do something useful on not finding the template.
|
||||
$('xfer_msg').innerHTML = "Template fetch failed at "+(new Date());
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
Refresh the list of available pages.
|
||||
*/
|
||||
refreshPageList: function() {
|
||||
var _this = this;
|
||||
setList('page_list', ['Loading...','']);
|
||||
S3Ajax.listKeys(
|
||||
this.BUCKET, { prefix:this.KEY_PREFIX },
|
||||
function(req, obj) {
|
||||
clearList('page_list');
|
||||
|
||||
// Sort in reverse-chronological change order.
|
||||
var contents = obj.ListBucketResult.Contents;
|
||||
contents.sort(function(a,b) {
|
||||
if (b.LastModified > a.LastModified) return 1;
|
||||
if (b.LastModified < a.LastModified) return -1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
for (var i=0, item; item=contents[i]; i++) {
|
||||
var key = item.Key;
|
||||
var title = key.substr(_this.KEY_PREFIX.length)
|
||||
addToList('page_list', title, key);
|
||||
}
|
||||
},
|
||||
function(req, obj) {
|
||||
setList('page_list', ['Failed to load list of pages.','']);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
Navigate to a new wiki page.
|
||||
*/
|
||||
selectPage: function(key) {
|
||||
var _this = this;
|
||||
|
||||
if (!key) key = getSelected('page_list')[0];
|
||||
|
||||
// Page title is key, sans prefix
|
||||
var title = (key.indexOf(_this.KEY_PREFIX) == 0) ?
|
||||
key.substr(_this.KEY_PREFIX.length) : key;
|
||||
|
||||
location.href = title;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
editPage: function() {
|
||||
var content = $('content').innerHTML;
|
||||
$('editor').value = Wiky.toWiki(content);
|
||||
this.showEditor();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
cancelEdit: function() {
|
||||
this.hideEditor();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
previewPage: function() {
|
||||
var content = $('editor').value;
|
||||
$('content').innerHTML = Wiky.toHtml(content);
|
||||
this.scanWikiWords();
|
||||
this.hideEditor();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
updatePage: function(key) {
|
||||
var _this = this;
|
||||
if (!key) key = this.KEY_PREFIX + $('page_title').innerHTML;
|
||||
// if (!key) key = getSelected('page_list')[0];
|
||||
|
||||
// Convert the wiki text to HTML and replace in page.
|
||||
$('content').innerHTML = Wiky.toHtml($('editor').value);
|
||||
this.hideEditor();
|
||||
|
||||
// Get serialized HTML content from the page DOM
|
||||
var content = _this.fromDOMtoHTML();
|
||||
|
||||
// Upload to S3, redirect if successful.
|
||||
S3Ajax.put(_this.BUCKET, key, content,
|
||||
{
|
||||
content_type: _this.DEFAULT_TYPE,
|
||||
acl: _this.DEFAULT_ACL,
|
||||
meta: {'posted-by':'S3AjaxWiki'}
|
||||
},
|
||||
function(req) {
|
||||
_this.scanWikiWords();
|
||||
$('xfer_msg').innerHTML = ""; // "Upload succeeded at "+(new Date());
|
||||
},
|
||||
function(req, obj) {
|
||||
$('xfer_msg').innerHTML = "Upload failed at "+(new Date());
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
Make an attempt to recall S3 credentials.
|
||||
*/
|
||||
recall: function() {
|
||||
if (window.dojo) {
|
||||
if (dojo.storage && dojo.storage.get && dojo.storage.get('key_id', '/S3Ajax')) {
|
||||
S3Ajax.KEY_ID = dojo.storage.get('key_id', '/S3Ajax');
|
||||
S3Ajax.SECRET_KEY = dojo.storage.get('secret_key', '/S3Ajax');
|
||||
$('key_id').value = S3Ajax.KEY_ID;
|
||||
$('credentials_msg').innerHTML = 'Credentials restored.';
|
||||
this.hideCredentials();
|
||||
this.onLogin();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Accept new credentials from the form in the page.
|
||||
*/
|
||||
login: function() {
|
||||
S3Ajax.KEY_ID = $('key_id').value;
|
||||
S3Ajax.SECRET_KEY = $('secret_key').value;
|
||||
|
||||
// Try to stash the credentials away for next time.
|
||||
if (window.dojo) {
|
||||
dojo.storage.set('key_id', S3Ajax.KEY_ID, '/S3Ajax');
|
||||
dojo.storage.set('secret_key', S3Ajax.SECRET_KEY, '/S3Ajax');
|
||||
}
|
||||
|
||||
$('credentials_msg').innerHTML = 'Credentials supplied.';
|
||||
this.hideCredentials();
|
||||
this.onLogin();
|
||||
},
|
||||
|
||||
showEditor: function() {
|
||||
$('content_edit').style.display = "block";
|
||||
$('content').style.display = "none";
|
||||
},
|
||||
|
||||
hideEditor: function() {
|
||||
$('content_edit').style.display = "none";
|
||||
$('content').style.display = "";
|
||||
},
|
||||
|
||||
showCredentials: function() {
|
||||
$('credentials_fields').style.display = "block";
|
||||
},
|
||||
|
||||
hideCredentials: function() {
|
||||
$('credentials_fields').style.display = "none";
|
||||
},
|
||||
|
||||
/**
|
||||
Serialize a given DOM to HTML source. If no node given, assume
|
||||
the current page should be serialized. Note that this makes efforts
|
||||
using IGNORED_ELEMENT_IDS to avoid including the injected editor framework.
|
||||
|
||||
TODO: Steal more ideas from MochiKit.DOM.emitHTML()
|
||||
*/
|
||||
fromDOMtoHTML: function(node) {
|
||||
|
||||
if (!node) node = document;
|
||||
|
||||
switch (node.nodeType) {
|
||||
|
||||
case Node.DOCUMENT_NODE:
|
||||
// HACK: Look for the first <html> in a document node.
|
||||
return this.fromDOMtoHTML(node.getElementsByTagName('html')[0]);
|
||||
|
||||
case Node.TEXT_NODE:
|
||||
return node.nodeValue;
|
||||
|
||||
case Node.ELEMENT_NODE:
|
||||
var node_name = node.nodeName.toLowerCase();
|
||||
|
||||
// Skip elements with ignored IDs
|
||||
for (var j=0, skip_id; skip_id=this.IGNORED_ELEMENT_IDS[j]; j++) {
|
||||
if (skip_id == node.id) { return ''; }
|
||||
}
|
||||
|
||||
// HACK: Firefox kept dropping in Firebug stylesheets
|
||||
if ('link'==node_name && /chrome:/.test(node.getAttribute('href')))
|
||||
return '';
|
||||
|
||||
// Start serializing the current node.
|
||||
var out = '<' + node_name;
|
||||
|
||||
// Serialize the attributes of the node.
|
||||
for (var i=0, attr; attr=node.attributes[i]; i++) {
|
||||
var name = attr.name;
|
||||
|
||||
// Skip ignored attributes
|
||||
var skip = false;
|
||||
for (var j=0, skip_name; skip_name=this.IGNORED_ATTRIBUTE_NAMES[j]; j++) {
|
||||
if (skip_name == name) { skip=true; break; }
|
||||
}
|
||||
if (skip) continue;
|
||||
|
||||
var value = attr.value;
|
||||
if (value && value!=null && value!="null")
|
||||
out += ' '+name+'="'+value+'"';
|
||||
}
|
||||
|
||||
// Serialize all child nodes found.
|
||||
var sub_out = '';
|
||||
|
||||
if ( ('script'==node_name || 'title'==node_name) && node.innerHTML) {
|
||||
// HACK: MSIE gives me troubles in scooping out these tags contents.
|
||||
sub_out = ''+node.innerHTML;
|
||||
} else {
|
||||
for (var i=0, child; child=node.childNodes[i]; i++) {
|
||||
sub_out += this.fromDOMtoHTML(child);
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize the current node.
|
||||
if (sub_out || 'script'==node_name || 'title'==node_name)
|
||||
return out + '>' + sub_out + '</' + node_name + '>';
|
||||
else
|
||||
return out + '/>';
|
||||
|
||||
default:
|
||||
return '';
|
||||
/*
|
||||
// TODO: Err... Is this even what I should be doing here?
|
||||
try {
|
||||
return node.parentNode.innerHTML;
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
Build and inject the DOM structures necessary for editing
|
||||
wiki pages. The events wired up are a little bit of a hack.
|
||||
*/
|
||||
injectEditingFramework: function() {
|
||||
|
||||
var body = document.getElementsByTagName('body')[0];
|
||||
|
||||
appendChildNodes(body, [
|
||||
|
||||
// Build the content editing form.
|
||||
FORM({"id":"content_edit", "onsubmit":"return false"},
|
||||
TEXTAREA({"id":"editor", "name":"editor", "cols":"80", "rows":"20"}),
|
||||
BR(),
|
||||
FIELDSET({},
|
||||
BUTTON({"id":"preview", "onclick":"S3AjaxWiki.previewPage(); return false"}, "Preview Changes"),
|
||||
BUTTON({"id":"submit", "onclick":"S3AjaxWiki.updatePage(); return false"}, "Save Changes"),
|
||||
BUTTON({"id":"cancel", "onclick":"S3AjaxWiki.cancelEdit(); return false"}, "Cancel")
|
||||
)
|
||||
),
|
||||
|
||||
// Build the login credentials form.
|
||||
(this.ANONYMOUS) ? '' :
|
||||
FORM({"id":"credentials", "onsubmit":"S3AjaxWiki.login(); return false;"},
|
||||
DIV({"id":"cals_status"},
|
||||
SPAN({"id":"credentials_msg"}),
|
||||
" ",
|
||||
A({"href":"#", "onclick":"S3AjaxWiki.showCredentials(); return false"}, "Login.")
|
||||
),
|
||||
FIELDSET({"id":"credentials_fields"},
|
||||
|
||||
LEGEND({}, "Credentials"),
|
||||
|
||||
LABEL({"for":"key_id"}, "AWSAccessKey"), BR(),
|
||||
INPUT({"type":"text", "size":"25", "id":"key_id", "name":"key_id"}), BR(),
|
||||
|
||||
LABEL({"for":"secret_key"}, "SecretAccessKey"), BR(),
|
||||
INPUT({"type":"password", "size":"25", "id":"secret_key", "name":"secret_key"}), BR(),
|
||||
|
||||
BUTTON({"id":"store", "onclick":"S3AjaxWiki.login(); return false"}, " Store "),
|
||||
BUTTON({"id":"recall", "onclick":"S3AjaxWiki.recall(); return false"}, " Recall "),
|
||||
BUTTON({"id":"cancel", "onclick":"S3AjaxWiki.hideCredentials(); return false"}, " Cancel ")
|
||||
)
|
||||
),
|
||||
|
||||
// Build the page list box.
|
||||
FORM({'id':'toc', 'onsubmit':'return false'},
|
||||
"Recent Changes: ", /* BR(), */
|
||||
SELECT({'id':'page_list', 'name':'page_list', 'onchange':'S3AjaxWiki.selectPage(); return false'}),
|
||||
BUTTON({'id':'get_pages', 'onclick':'S3AjaxWiki.selectPage(); return false'}, 'Go' ) /*,
|
||||
BUTTON({'id':'list_pages', 'onclick':'S3AjaxWiki.refreshPageList(); return false'}, 'Refresh' )
|
||||
*/
|
||||
),
|
||||
|
||||
// Set up the page options div
|
||||
FORM({'id':'page_options', 'onsubmit':'return false'},
|
||||
BUTTON({'onclick':'S3AjaxWiki.editPage(); return false;'}, "Edit Page"),
|
||||
" | ",
|
||||
INPUT({'type':'text', 'size':'15', 'id':'new_page_name', 'name':'new_page_name', 'value':'NewPage'}),
|
||||
BUTTON({'onclick':'S3AjaxWiki.createNewPage($("new_page_name").value); return false;'}, "Create Page")
|
||||
),
|
||||
|
||||
// Inject the xfer message div.
|
||||
SPAN({'id':'xfer_msg'})
|
||||
|
||||
]);
|
||||
|
||||
},
|
||||
|
||||
/* Help protect against errant end-commas */
|
||||
EOF: null
|
||||
};
|
||||
|
||||
/**
|
||||
Schedule the whole mess to fire up on load.
|
||||
*/
|
||||
addLoadEvent(function(){ S3AjaxWiki.init() });
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
/* This work is licensed under Creative Commons GNU LGPL License.
|
||||
|
||||
License: http://creativecommons.org/licenses/LGPL/2.1/
|
||||
|
||||
Author: Stefan Goessner/2005-06
|
||||
Web: http://goessner.net/
|
||||
*/
|
||||
var Wiky = {
|
||||
version: 0.95,
|
||||
blocks: null,
|
||||
rules: {
|
||||
all: [
|
||||
"Wiky.rules.pre",
|
||||
"Wiky.rules.nonwikiblocks",
|
||||
"Wiky.rules.wikiblocks",
|
||||
"Wiky.rules.post",
|
||||
],
|
||||
pre: [
|
||||
{ rex:/(\r?\n)/g, tmplt:"\xB6" }, // replace line breaks with '¶' ..
|
||||
],
|
||||
post: [
|
||||
{ rex:/(^\xB6)|(\xB6$)/g, tmplt:"" }, // .. remove linebreaks at BOS and EOS ..
|
||||
{ rex:/@([0-9]+)@/g, tmplt:function($0,$1){return Wiky.restore($1);} }, // resolve blocks ..
|
||||
{ rex:/\xB6/g, tmplt:"\n" } // replace '¶' with line breaks ..
|
||||
],
|
||||
nonwikiblocks: [
|
||||
{ rex:/\\([%])/g, tmplt:function($0,$1){return Wiky.store($1);} },
|
||||
{ rex:/\[(?:\{([^}]*)\})?(?:\(([^)]*)\))?%(.*?)%\]/g, tmplt:function($0,$1,$2,$3){return ":p]"+Wiky.store("<pre"+($2?(" lang=\"x-"+Wiky.attr($2)+"\""):"")+Wiky.style($1)+">" + Wiky.apply($3, $2?Wiky.rules.lang[Wiky.attr($2)]:Wiky.rules.code) + "</pre>")+"[p:";} } //programm code block
|
||||
],
|
||||
wikiblocks: [
|
||||
"Wiky.rules.nonwikiinlines",
|
||||
"Wiky.rules.escapes",
|
||||
{ rex:/(?:^|\xB6)(={1,6})(.*?)[=]*(?=\xB6|$)/g, tmplt:function($0,$1,$2){ var h=$1.length; return ":p]\xB6<h"+h+">"+$2+"</h"+h+">\xB6[p:";} }, // <h1> .. <h6>
|
||||
{ rex:/(?:^|\xB6)[-]{4}(?:\xB6|$)/g, tmplt:"\xB6<hr/>\xB6" }, // horizontal ruler ..
|
||||
{ rex:/\\\\([ \xB6])/g, tmplt:"<br/>$1" }, // forced line break ..
|
||||
{ rex:/(^|\xB6)([*01aAiIg]*[\.*])[ ]/g, tmplt:function($0,$1,$2){var state=$2.replace(/([*])/g,"u").replace(/([\.])/,"");return ":"+state+"]"+$1+"["+state+":";}},
|
||||
{ rex:/(?:^|\xB6);[ ](.*?):[ ]/g, tmplt:"\xB6:l][l:$1:d][d:"}, // ; term : definition
|
||||
{ rex:/\[(?:\{([^}]*)\})?(?:\(([^)]*)\))?\"/g, tmplt:function($0,$1,$2){return ":p]<blockquote"+Wiky.attr($2,"cite",0)+Wiky.attr($2,"title",1)+Wiky.style($1)+">[p:"; } }, // block quotation start
|
||||
{ rex:/\"\]/g, tmplt:":p]</blockquote>[p:" }, // block quotation end
|
||||
{ rex:/\[(\{[^}]*\})?\|/g, tmplt:":t]$1[r:" }, // .. start table ..
|
||||
{ rex:/\|\]/g, tmplt:":r][t:" }, // .. end table ..
|
||||
{ rex:/\|\xB6[ ]?\|/g, tmplt:":r]\xB6[r:" }, // .. end/start table row ..
|
||||
{ rex:/\|/g, tmplt:":c][c:" }, // .. end/start table cell ..
|
||||
{ rex:/^(.*)$/g, tmplt:"[p:$1:p]" }, // start paragraph '[p:' at BOS .. end paragraph ':p]' at EOS ..
|
||||
{ rex:/(([\xB6])([ \t\f\v\xB6]*?)){2,}/g, tmplt:":p]$1[p:" }, // .. separate paragraphs at blank lines ..
|
||||
{ rex:/\[([01AIacdgilprtu]+)[:](.*?)[:]([01AIacdgilprtu]+)\]/g, tmplt:function($0,$1,$2,$3){return Wiky.sectionRule($1==undefined?"":$1,"",Wiky.apply($2,Wiky.rules.wikiinlines),!$3?"":$3);} },
|
||||
{ rex:/\[[01AIacdgilprtu]+[:]|[:][01AIacdgilprtu]+\]/g, tmplt:"" }, // .. remove singular section delimiters (they frequently exist with incomplete documents while typing) ..
|
||||
{ rex:/<td>(?:([0-9]*)[>])?([ ]?)(.*?)([ ]?)<\/td>/g, tmplt:function($0,$1,$2,$3,$4){return "<td"+($1?" colspan=\""+$1+"\"":"")+($2==" "?(" style=\"text-align:"+($2==$4?"center":"right")+";\""):($4==" "?" style=\"text-align:left;\"":""))+">"+$2+$3+$4+"</td>";} },
|
||||
{ rex:/<(p|table)>(?:\xB6)?(?:\{(.*?)\})/g, tmplt:function($0,$1,$2){return "<"+$1+Wiky.style($2)+">";} },
|
||||
{ rex:/<p>([ \t\f\v\xB6]*?)<\/p>/g, tmplt:"$1" }, // .. remove empty paragraphs ..
|
||||
"Wiky.rules.shortcuts"
|
||||
],
|
||||
nonwikiinlines: [
|
||||
{ rex:/%(?:\{([^}]*)\})?(?:\(([^)]*)\))?(.*?)%/g, tmplt:function($0,$1,$2,$3){return Wiky.store("<code"+($2?(" lang=\"x-"+Wiky.attr($2)+"\""):"")+Wiky.style($1)+">" + Wiky.apply($3, $2?Wiky.rules.lang[Wiky.attr($2)]:Wiky.rules.code) + "</code>");} }, // inline code
|
||||
{ rex:/%(.*?)%/g, tmplt:function($0,$1){return Wiky.store("<code>" + Wiky.apply($2, Wiky.rules.code) + "</code>");} }
|
||||
],
|
||||
wikiinlines: [
|
||||
{ rex:/\*([^*]+)\*/g, tmplt:"<strong>$1</strong>" }, // .. strong ..
|
||||
{ rex:/_([^_]+)_/g, tmplt:"<em>$1</em>" },
|
||||
{ rex:/\^([^^]+)\^/g, tmplt:"<sup>$1</sup>" },
|
||||
{ rex:/~([^~]+)~/g, tmplt:"<sub>$1</sub>" },
|
||||
{ rex:/\(-(.+?)-\)/g, tmplt:"<del>$1</del>" },
|
||||
{ rex:/\?([^ \t\f\v\xB6]+)\((.+)\)\?/g, tmplt:"<abbr title=\"$2\">$1</abbr>" }, // .. abbreviation ..
|
||||
{ rex:/\[(?:\{([^}]*)\})?[Ii]ma?ge?\:([^ ,\]]*)(?:[, ]([^\]]*))?\]/g, tmplt:function($0,$1,$2,$3){return Wiky.store("<img"+Wiky.style($1)+" src=\""+$2+"\" alt=\""+($3?$3:$2)+"\" title=\""+($3?$3:$2)+"\"/>");} }, // wikimedia image style ..
|
||||
{ rex:/\[([^ ,]+)[, ]([^\]]*)\]/g, tmplt:function($0,$1,$2){return Wiky.store("<a href=\""+$1+"\">"+$2+"</a>");}}, // wiki block style uri's ..
|
||||
{ rex:/(((http(s?))\:\/\/)?[A-Za-z0-9\._\/~\-:]+\.(?:png|jpg|jpeg|gif|bmp))/g, tmplt:function($0,$1,$2){return Wiky.store("<img src=\""+$1+"\" alt=\""+$1+"\"/>");} }, // simple images ..
|
||||
{ rex:/((mailto\:|javascript\:|(news|file|(ht|f)tp(s?))\:\/\/)[A-Za-z0-9\.:_\/~%\-+&#?!=()@\x80-\xB5\xB7\xFF]+)/g, tmplt:"<a href=\"$1\">$1</a>" } // simple uri's ..
|
||||
],
|
||||
escapes: [
|
||||
{ rex:/\\([|*_~\^])/g, tmplt:function($0,$1){return Wiky.store($1);} },
|
||||
{ rex:/\\&/g, tmplt:"&" },
|
||||
{ rex:/\\>/g, tmplt:">" },
|
||||
{ rex:/\\</g, tmplt:"<" }
|
||||
],
|
||||
shortcuts: [
|
||||
{ rex:/---/g, tmplt:"—" }, // —
|
||||
{ rex:/--/g, tmplt:"–" }, // –
|
||||
{ rex:/[\.]{3}/g, tmplt:"…"}, // …
|
||||
{ rex:/<->/g, tmplt:"↔"}, // $harr;
|
||||
{ rex:/<-/g, tmplt:"←"}, // ←
|
||||
{ rex:/->/g, tmplt:"→"}, //→
|
||||
],
|
||||
code: [
|
||||
{ rex:/&/g, tmplt:"&"},
|
||||
{ rex:/</g, tmplt:"<"},
|
||||
{ rex:/>/g, tmplt:">"}
|
||||
],
|
||||
lang: {}
|
||||
},
|
||||
|
||||
inverse: {
|
||||
all: [
|
||||
"Wiky.inverse.pre",
|
||||
"Wiky.inverse.nonwikiblocks",
|
||||
"Wiky.inverse.wikiblocks",
|
||||
"Wiky.inverse.post"
|
||||
],
|
||||
pre: [
|
||||
{ rex:/(\r?\n)/g, tmplt:"\xB6" } // replace line breaks with '¶' ..
|
||||
],
|
||||
post: [
|
||||
{ rex:/@([0-9]+)@/g, tmplt:function($0,$1){return Wiky.restore($1);} }, // resolve blocks ..
|
||||
{ rex:/\xB6/g, tmplt:"\n" } // replace '¶' with line breaks ..
|
||||
],
|
||||
nonwikiblocks: [
|
||||
{ rex:/<pre([^>]*)>(.*?)<\/pre>/mgi, tmplt:function($0,$1,$2){return Wiky.store("["+Wiky.invStyle($1)+Wiky.invAttr($1,["lang"]).replace(/x\-/,"")+"%"+Wiky.apply($2, Wiky.hasAttr($1,"lang")?Wiky.inverse.lang[Wiky.attrVal($1,"lang").substr(2)]:Wiky.inverse.code)+"%]");} } //code block
|
||||
],
|
||||
wikiblocks: [
|
||||
"Wiky.inverse.nonwikiinlines",
|
||||
"Wiky.inverse.escapes",
|
||||
"Wiky.inverse.wikiinlines",
|
||||
{ rex:/<h1>(.*?)<\/h1>/mgi, tmplt:"=$1=" },
|
||||
{ rex:/<h2>(.*?)<\/h2>/mgi, tmplt:"==$1==" },
|
||||
{ rex:/<h3>(.*?)<\/h3>/mgi, tmplt:"===$1===" },
|
||||
{ rex:/<h4>(.*?)<\/h4>/mgi, tmplt:"====$1====" },
|
||||
{ rex:/<h5>(.*?)<\/h5>/mgi, tmplt:"=====$1=====" },
|
||||
{ rex:/<h6>(.*?)<\/h6>/mgi, tmplt:"======$1======" },
|
||||
{ rex:/<(p|table)[^>]+(style=\"[^\"]*\")[^>]*>/mgi, tmplt:function($0,$1,$2){return "<"+$1+">"+Wiky.invStyle($2);} },
|
||||
{ rex:/\xB6{2}<li/mgi, tmplt:"\xB6<li" }, // ie6 only ..
|
||||
{ rex:/<li class=\"?([^ >\"]*)\"?[^>]*?>([^<]*)/mgi, tmplt:function($0,$1,$2){return $1.replace(/u/g,"*").replace(/([01aAiIg])$/,"$1.")+" "+$2;}}, // list items ..
|
||||
{ rex:/(^|\xB6)<(u|o)l[^>]*?>\xB6/mgi, tmplt:"$1" }, // only outer level list start at BOL ...
|
||||
{ rex:/(<\/(?:dl|ol|ul|p)>[ \xB6]*<(?:p)>)/gi, tmplt:"\xB6\xB6" },
|
||||
{ rex:/<dt>(.*?)<\/dt>[ \f\n\r\t\v]*<dd>/mgi, tmplt:"; $1: " },
|
||||
{ rex:/<blockquote([^>]*)>/mgi, tmplt:function($0,$1){return Wiky.store("["+Wiky.invStyle($1)+Wiky.invAttr($1,["cite","title"])+"\"");} },
|
||||
{ rex:/<\/blockquote>/mgi, tmplt:"\"]" },
|
||||
{ rex:/<td class=\"?lft\"?>\xB6*[ ]?|<\/tr>/mgi, tmplt:"|" }, // ie6 only ..
|
||||
{ rex:/\xB6<tr(?:[^>]*?)>/mgi, tmplt:"\xB6" },
|
||||
{ rex:/<td colspan=\"([0-9]+)\"(?:[^>]*?)>/mgi, tmplt:"|$1>" },
|
||||
{ rex:/<td(?:[^>]*?)>/mgi, tmplt:"|" },
|
||||
{ rex:/<table>/mgi, tmplt:"[" },
|
||||
{ rex:/<\/table>/mgi, tmplt:"]" },
|
||||
{ rex:/<tr(?:[^>]*?)>\xB6*|<\/td>\xB6*|<tbody>\xB6*|<\/tbody>/mgi, tmplt:"" },
|
||||
{ rex:/<hr\/?>/mgi, tmplt:"----" },
|
||||
{ rex:/<br\/?>/mgi, tmplt:"\\\\" },
|
||||
{ rex:/(<p>|<(d|o|u)l[^>]*>|<\/(dl|ol|ul|p)>|<\/(li|dd)>)/mgi, tmplt:"" },
|
||||
"Wiky.inverse.shortcuts"
|
||||
],
|
||||
nonwikiinlines: [
|
||||
{ rex:/<code>(.*?)<\/code>/g, tmplt:function($0,$1){return Wiky.store("%"+Wiky.apply($1, Wiky.inverse["code"])+"%");} }
|
||||
],
|
||||
wikiinlines: [
|
||||
{ rex:/<strong[^>]*?>(.*?)<\/strong>/mgi, tmplt:"*$1*" },
|
||||
{ rex:/<b[^>]*?>(.*?)<\/b>/mgi, tmplt:"*$1*" },
|
||||
{ rex:/<em[^>]*?>(.*?)<\/em>/mgi, tmplt:"_$1_" },
|
||||
{ rex:/<i[^>]*?>(.*?)<\/i>/mgi, tmplt:"_$1_" },
|
||||
{ rex:/<sup[^>]*?>(.*?)<\/sup>/mgi, tmplt:"^$1^" },
|
||||
{ rex:/<sub[^>]*?>(.*?)<\/sub>/mgi, tmplt:"~$1~" },
|
||||
{ rex:/<del[^>]*?>(.*?)<\/del>/mgi, tmplt:"(-$1-)" },
|
||||
{ rex:/<abbr title=\"([^\"]*)\">(.*?)<\/abbr>/mgi, tmplt:"?$2($1)?" },
|
||||
{ rex:/<a href=\"([^\"]*)\"[^>]*?>(.*?)<\/a>/mgi, tmplt:function($0,$1,$2){return $1==$2?$1:"["+$1+","+$2+"]";}},
|
||||
{ rex:/<img([^>]*)\/>/mgi, tmplt:function($0,$1){var a=Wiky.attrVal($1,"alt"),h=Wiky.attrVal($1,"src"),t=Wiky.attrVal($1,"title"),s=Wiky.attrVal($1,"style");return s||(t&&h!=t)?("["+Wiky.invStyle($1)+"img:"+h+(t&&(","+t))+"]"):h;}},
|
||||
],
|
||||
escapes: [
|
||||
{ rex:/([|*_~%\^])/g, tmplt:"\\$1" },
|
||||
{ rex:/&/g, tmplt:"\\&" },
|
||||
{ rex:/>/g, tmplt:"\\>" },
|
||||
{ rex:/</g, tmplt:"\\<" }
|
||||
],
|
||||
shortcuts: [
|
||||
{ rex:/–|\u2013/g, tmplt:"--"},
|
||||
{ rex:/—|\u2014/g, tmplt:"---"},
|
||||
{ rex:/…|\u2026/g, tmplt:"..."},
|
||||
{ rex:/↔|\u2194/g, tmplt:"<->"},
|
||||
{ rex:/←|\u2190/g, tmplt:"<-"},
|
||||
{ rex:/→|\u2192/g, tmplt:"->"}
|
||||
],
|
||||
code: [
|
||||
{ rex:/&/g, tmplt:"&"},
|
||||
{ rex:/</g, tmplt:"<"},
|
||||
{ rex:/>/g, tmplt:">"}
|
||||
],
|
||||
lang: {}
|
||||
},
|
||||
|
||||
toHtml: function(str) {
|
||||
Wiky.blocks = [];
|
||||
return Wiky.apply(str, Wiky.rules.all);
|
||||
},
|
||||
|
||||
toWiki: function(str) {
|
||||
Wiky.blocks = [];
|
||||
return Wiky.apply(str, Wiky.inverse.all);
|
||||
},
|
||||
|
||||
apply: function(str, rules) {
|
||||
if (str && rules)
|
||||
for (var i in rules) {
|
||||
if (typeof(rules[i]) == "string")
|
||||
str = Wiky.apply(str, eval(rules[i]));
|
||||
else
|
||||
str = str.replace(rules[i].rex, rules[i].tmplt);
|
||||
}
|
||||
return str;
|
||||
},
|
||||
store: function(str, unresolved) {
|
||||
return unresolved ? "@" + (Wiky.blocks.push(str)-1) + "@"
|
||||
: "@" + (Wiky.blocks.push(str.replace(/@([0-9]+)@/g, function($0,$1){return Wiky.restore($1);}))-1) + "@";
|
||||
},
|
||||
restore: function(idx) {
|
||||
return Wiky.blocks[idx];
|
||||
},
|
||||
attr: function(str, name, idx) {
|
||||
var a = str && str.split(",")[idx||0];
|
||||
return a ? (name ? (" "+name+"=\""+a+"\"") : a) : "";
|
||||
},
|
||||
hasAttr: function(str, name) {
|
||||
return new RegExp(name+"=").test(str);
|
||||
},
|
||||
attrVal: function(str, name) {
|
||||
return str.replace(new RegExp("^.*?"+name+"=\"(.*?)\".*?$"), "$1");
|
||||
},
|
||||
invAttr: function(str, names) {
|
||||
var a=[], x;
|
||||
for (var i in names)
|
||||
if (str.indexOf(names[i]+"=")>=0)
|
||||
a.push(str.replace(new RegExp("^.*?"+names[i]+"=\"(.*?)\".*?$"), "$1"));
|
||||
return a.length ? ("("+a.join(",")+")") : "";
|
||||
},
|
||||
style: function(str) {
|
||||
var s = str && str.split(/,|;/), p, style = "";
|
||||
for (var i in s) {
|
||||
p = s[i].split(":");
|
||||
if (p[0] == ">") style += "margin-left:4em;";
|
||||
else if (p[0] == "<") style += "margin-right:4em;";
|
||||
else if (p[0] == ">>") style += "float:right;";
|
||||
else if (p[0] == "<<") style += "float:left;";
|
||||
else if (p[0] == "=") style += "display:block;margin:0 auto;";
|
||||
else if (p[0] == "_") style += "text-decoration:underline;";
|
||||
else if (p[0] == "b") style += "border:solid 1px;";
|
||||
else if (p[0] == "c") style += "color:"+p[1]+";";
|
||||
else if (p[0] == "C") style += "background:"+p[1]+";";
|
||||
else if (p[0] == "w") style += "width:"+p[1]+";";
|
||||
else style += p[0]+":"+p[1]+";";
|
||||
}
|
||||
return style ? " style=\""+style+"\"" : "";
|
||||
},
|
||||
invStyle: function(str) {
|
||||
var s = /style=/.test(str) ? str.replace(/^.*?style=\"(.*?)\".*?$/, "$1") : "",
|
||||
p = s && s.split(";"), pi, prop = [];
|
||||
for (var i in p) {
|
||||
pi = p[i].split(":");
|
||||
if (pi[0] == "margin-left" && pi[1]=="4em") prop.push(">");
|
||||
else if (pi[0] == "margin-right" && pi[1]=="4em") prop.push("<");
|
||||
else if (pi[0] == "float" && pi[1]=="right") prop.push(">>");
|
||||
else if (pi[0] == "float" && pi[1]=="left") prop.push("<<");
|
||||
else if (pi[0] == "margin" && pi[1]=="0 auto") prop.push("=");
|
||||
else if (pi[0] == "display" && pi[1]=="block") ;
|
||||
else if (pi[0] == "text-decoration" && pi[1]=="underline") prop.push("_");
|
||||
else if (pi[0] == "border" && pi[1]=="solid 1px") prop.push("b");
|
||||
else if (pi[0] == "color") prop.push("c:"+pi[1]);
|
||||
else if (pi[0] == "background") prop.push("C:"+pi[1]);
|
||||
else if (pi[0] == "width") prop.push("w:"+pi[1]);
|
||||
else if (pi[0]) prop.push(pi[0]+":"+pi[1]);
|
||||
}
|
||||
return prop.length ? ("{" + prop.join(",") + "}") : "";
|
||||
},
|
||||
sectionRule: function(fromLevel, style, content, toLevel) {
|
||||
var trf = { p_p: "<p>$1</p>",
|
||||
p_u: "<p>$1</p><ul$3>",
|
||||
p_o: "<p>$1</p><ol$3>",
|
||||
// p - ul
|
||||
// ul - p
|
||||
u_p: "<li$2>$1</li></ul>",
|
||||
u_c: "<li$2>$1</li></ul></td>",
|
||||
u_r: "<li$2>$1</li></ul></td></tr>",
|
||||
uu_p: "<li$2>$1</li></ul></li></ul>",
|
||||
uo_p: "<li$2>$1</li></ol></li></ul>",
|
||||
uuu_p: "<li$2>$1</li></ul></li></ul></li></ul>",
|
||||
uou_p: "<li$2>$1</li></ul></li></ol></li></ul>",
|
||||
uuo_p: "<li$2>$1</li></ol></li></ul></li></ul>",
|
||||
uoo_p: "<li$2>$1</li></ol></li></ol></li></ul>",
|
||||
// ul - ul
|
||||
u_u: "<li$2>$1</li>",
|
||||
uu_u: "<li$2>$1</li></ul></li>",
|
||||
uo_u: "<li$2>$1</li></ol></li>",
|
||||
uuu_u: "<li$2>$1</li></ul></li></ul></li>",
|
||||
uou_u: "<li$2>$1</li></ul></li></ol></li>",
|
||||
uuo_u: "<li$2>$1</li></ol></li></ul></li>",
|
||||
uoo_u: "<li$2>$1</li></ol></li></ol></li>",
|
||||
u_uu: "<li$2>$1<ul$3>",
|
||||
// ul - ol
|
||||
u_o: "<li$2>$1</li></ul><ol$3>",
|
||||
uu_o: "<li$2>$1</li></ul></li></ul><ol$3>",
|
||||
uo_o: "<li$2>$1</li></ol></li></ul><ol$3>",
|
||||
uuu_o: "<li$2>$1</li></ul></li></ul></li></ul><ol$3>",
|
||||
uou_o: "<li$2>$1</li></ul></li></ol></li></ul><ol$3>",
|
||||
uuo_o: "<li$2>$1</li></ol></li></ul></li></ul><ol$3>",
|
||||
uoo_o: "<li$2>$1</li></ol></li></ol></li></ul><ol$3>",
|
||||
u_uo: "<li$2>$1<ol$3>",
|
||||
// ol - p
|
||||
o_p: "<li$2>$1</li></ol>",
|
||||
oo_p: "<li$2>$1</li></ol></li></ol>",
|
||||
ou_p: "<li$2>$1</li></ul></li></ol>",
|
||||
ooo_p: "<li$2>$1</li></ol></li></ol>",
|
||||
ouo_p: "<li$2>$1</li></ol></li></ul></li></ol>",
|
||||
oou_p: "<li$2>$1</li></ul></li></ol></li></ol>",
|
||||
ouu_p: "<li$2>$1</li></ul></li></ul></li></ol>",
|
||||
// ol - ul
|
||||
o_u: "<li$2>$1</li></ol><ul$3>",
|
||||
oo_u: "<li$2>$1</li></ol></li></ol><ul$3>",
|
||||
ou_u: "<li$2>$1</li></ul></li></ol><ul$3>",
|
||||
ooo_u: "<li$2>$1</li></ol></li></ol></li></ol><ul$3>",
|
||||
ouo_u: "<li$2>$1</li></ol></li></ul></li></ol><ul$3>",
|
||||
oou_u: "<li$2>$1</li></ul></li></ol></li></ol><ul$3>",
|
||||
ouu_u: "<li$2>$1</li></ul></li></ul></li></ol><ul$3>",
|
||||
o_ou: "<li$2>$1<ul$3>",
|
||||
// -- ol - ol --
|
||||
o_o: "<li$2>$1</li>",
|
||||
oo_o: "<li$2>$1</li></ol></li>",
|
||||
ou_o: "<li$2>$1</li></ul></li>",
|
||||
ooo_o: "<li$2>$1</li></ol></li></ol></li>",
|
||||
ouo_o: "<li$2>$1</li></ol></li></ul></li>",
|
||||
oou_o: "<li$2>$1</li></ul></li></ol></li>",
|
||||
ouu_o: "<li$2>$1</li></ul></li></ul></li>",
|
||||
o_oo: "<li$2>$1<ol$3>",
|
||||
// -- dl --
|
||||
l_d: "<dt>$1</dt>",
|
||||
d_l: "<dd>$1</dd>",
|
||||
d_u: "<dd>$1</dd></dl><ul>",
|
||||
d_o: "<dd>$1</dd></dl><ol>",
|
||||
p_l: "<p>$1</p><dl>",
|
||||
u_l: "<li$2>$1</li></ul><dl>",
|
||||
o_l: "<li$2>$1</li></ol><dl>",
|
||||
uu_l: "<li$2>$1</li></ul></li></ul><dl>",
|
||||
uo_l: "<li$2>$1</li></ol></li></ul><dl>",
|
||||
ou_l: "<li$2>$1</li></ul></li></ol><dl>",
|
||||
oo_l: "<li$2>$1</li></ol></li></ol><dl>",
|
||||
d_p: "<dd>$1</dd></dl>",
|
||||
// -- table --
|
||||
p_t: "<p>$1</p><table>",
|
||||
p_r: "<p>$1</p></td></tr>",
|
||||
p_c: "<p>$1</p></td>",
|
||||
t_p: "</table><p>$1</p>",
|
||||
r_r: "<tr><td>$1</td></tr>",
|
||||
r_p: "<tr><td><p>$1</p>",
|
||||
r_c: "<tr><td>$1</td>",
|
||||
r_u: "<tr><td>$1<ul>",
|
||||
c_p: "<td><p>$1</p>",
|
||||
c_r: "<td>$1</td></tr>",
|
||||
c_c: "<td>$1</td>",
|
||||
// c_u: "<td>$1<ul>",
|
||||
u_t: "<li$2>$1</li></ul><table>",
|
||||
o_t: "<li$2>$1</li></ol><table>",
|
||||
d_t: "<dd>$1</dd></dl><table>",
|
||||
t_u: "</table><p>$1</p><ul>",
|
||||
t_o: "</table><p>$1</p><ol>",
|
||||
t_l: "</table><p>$1</p><dl>"
|
||||
};
|
||||
var type = { "0": "decimal-leading-zero",
|
||||
"1": "decimal",
|
||||
"a": "lower-alpha",
|
||||
"A": "upper-alpha",
|
||||
"i": "lower-roman",
|
||||
"I": "upper-roman",
|
||||
"g": "lower-greek" };
|
||||
|
||||
var from = "", to = "", maxlen = Math.max(fromLevel.length, toLevel.length), sync = true, sectiontype = type[toLevel.charAt(toLevel.length-1)], transition;
|
||||
|
||||
for (var i=0; i<maxlen; i++)
|
||||
if (fromLevel.charAt(i+1) != toLevel.charAt(i+1) || !sync || i == maxlen-1)
|
||||
{
|
||||
from += fromLevel.charAt(i) == undefined ? " " : fromLevel.charAt(i);
|
||||
to += toLevel.charAt(i) == undefined ? " " : toLevel.charAt(i);
|
||||
sync = false;
|
||||
}
|
||||
transition = (from + "_" + to).replace(/([01AIagi])/g, "o");
|
||||
return !trf[transition] ? ("?(" + transition + ")") // error string !
|
||||
: trf[transition].replace(/\$2/, " class=\"" + fromLevel + "\"")
|
||||
.replace(/\$3/, !sectiontype ? "" : (" style=\"list-style-type:" + sectiontype + ";\""))
|
||||
.replace(/\$1/, content)
|
||||
.replace(/<p><\/p>/, "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* This work is licensed under Creative Commons GNU LGPL License.
|
||||
|
||||
License: http://creativecommons.org/licenses/LGPL/2.1/
|
||||
|
||||
Author: Stefan Goessner/2005-06
|
||||
Web: http://goessner.net/
|
||||
|
||||
credits: http://www.regular-expressions.info/examplesprogrammer.html
|
||||
*/
|
||||
Wiky.rules.lang.js = [
|
||||
"Wiky.rules.code",
|
||||
{ rex:/"([^"\\\xB6]*(\\.[^"\\\xB6]*)*)"/g, tmplt:function($0,$1){return Wiky.store("<span class=\"str\">\""+$1+"\"</span>");}}, // string delimited by '"' with '\"' allowed ..
|
||||
{ rex:/'([^'\\\xB6]*(\\.[^'\\\xB6]*)*)'/g, tmplt:function($0,$1){return Wiky.store("<span class=\"str\">\'"+$1+"\'</span>");}}, // string delimited by "'" with "\'" allowed ..
|
||||
{ rex:/\/\/(.*?)(?:\xB6|$)/g, tmplt:function($0,$1){return Wiky.store("<span class\=\"cmt\">//"+$1+"</span>\xB6");}}, // single line comment
|
||||
{ rex:/\/\*(.*?)\*\//g, tmplt:function($0,$1){return Wiky.store("<span class\=\"cmt\">\/*"+$1+"*\/</span>");}}, // multi-line comment
|
||||
// { rex:/([\]\[\-+\|*!%<>=\{\}?:,\)\(]+)|("|/|=)+/g, tmplt:"<span class=\"op\">$1</span>"}, // operators
|
||||
{ rex:/\b(break|case|catch|continue|do|else|false|for|function|if|in|new|return|switch|this|throw|true|try|var|while|with)\b/g, tmplt:"<span class=\"kwd\">$1</span>" }, // keywords
|
||||
{ rex:/\b(arguments|Array|Boolean|Date|Error|Function|Global|Math|Number|Object|RegExp|String)\b/g, tmplt:"<span class=\"obj\">$1</span>" }, // objects
|
||||
{ rex:/\.(abs|acos|anchor|arguments|asin|atan|atan2|big|blink|bold|callee|caller|ceil|charAt|charCodeAt|concat|constructor|cos|E|escape|eval|exp|fixed|floor|fontcolor|fontsize|fromCharCode|getDate|getDay|getFullYear|getHours|getMilliseconds|getMinutes|getMonth|getSeconds|getTime|getTimezoneOffset|getUTCDate|getUTCDay|getUTCFullYear|getUTCHours|getUTCMilliseconds|getUTCMinutes|getUTCMonth|getUTCSeconds|getVarDate|getYear|index|indexOf|Infinity|input|isFinite|isNaN|italics|join|lastIndex|lastIndexOf|lastMatch|lastParen|leftContext|length|link|LN10|LN2|log|LOG10E|LOG2E|match|max|MAX_VALUE|min|MIN_VALUE|NaN|NaN|NEGATIVE_INFINITY|parse|parseFloat|parseInt|PI|pop|POSITIVE_INFINITY|pow|prototype|push|random|replace|reverse|rightContext|round|search|setDate|setFullYear|setHours|setMilliseconds|setMinutes|setMonth|setSeconds|setTime|setUTCDate|setUTCFullYear|setUTCHours|setUTCMilliseconds|setUTCMinutes|setUTCMonth|setUTCSeconds|setYear|shift|sin|slice|slice|small|sort|splice|split|sqrt|SQRT1_2|SQRT2|strike|sub|substr|substring|sup|tan|toGMTString|toLocaleString|toLowerCase|toString|toUpperCase|toUTCString|unescape|unshift|UTC|valueOf)\b/g, tmplt:".<span class=\"mbr\">$1</span>" }, // members
|
||||
];
|
||||
Wiky.rules.lang.xml = [
|
||||
{ rex:/<script([^>]*)>(.*?)<\/script>/g, tmplt:function($0,$1,$2){return "<script"+$1+">"+Wiky.store(Wiky.apply($2, Wiky.rules.lang.js))+"</script>";} }, // script blocks ..
|
||||
{ rex:/<!\[CDATA\[(.*?)\]\]>/g, tmplt:function($0,$1){return Wiky.store("<![CDATA["+$1+"]]>");} }, // CDATA sections, ..
|
||||
{ rex:/<!(.*?)>/g, tmplt:function($0,$1){return Wiky.store("<span class=\"cmt\"><!"+$1+"></span>");} }, // inline xml comments, doctypes, ..
|
||||
{ rex:/</g, tmplt:"\xAB"}, // replace '<' by '«'
|
||||
{ rex:/>/g, tmplt:"\xBB"}, // replace '>' by '»'
|
||||
{ rex:/([-A-Za-z0-9_:]+)[ ]*=[ ]*\"(.*?)\"/g, tmplt:"<span class=\"xnam\">$1</span>=<span class=\"xval\">"$2"</span>"}, // "xml attribute value strings ..
|
||||
{ rex:/(\xAB[\/]?)([-A-Za-z0-9_:]+)/g, tmplt:"$1<span class=\"xtag\">$2</span>"}, // "xml tag ..
|
||||
{ rex:/\xAB/g, tmplt:"<"}, // replace '«' by '<'
|
||||
{ rex:/\xBB/g, tmplt:">"}, // replace '»' by '>'
|
||||
];
|
||||
Wiky.inverse.lang.js = [
|
||||
{ rex:/<span class=\"?(cmt|kwd|mbr|obj|str)\"?>|<\/span>/mgi, tmplt:"" },
|
||||
{ rex:/<strong>(.*?)<\/strong>/mgi, tmplt:"[*$1*]" },
|
||||
"Wiky.inverse.code"
|
||||
];
|
||||
Wiky.inverse.lang.xml = [
|
||||
{ rex:/<span class=\"?(cmt|xtag|xnam|xval)\"?>|<\/span>/mgi, tmplt:"" },
|
||||
"Wiky.inverse.lang.js"
|
||||
];
|
||||
@@ -0,0 +1,374 @@
|
||||
/* This work is licensed under Creative Commons GNU LGPL License.
|
||||
|
||||
License: http://creativecommons.org/licenses/LGPL/2.1/
|
||||
|
||||
Author: Stefan Goessner/2005-06
|
||||
Web: http://goessner.net/
|
||||
inspired by: http://xml-maiden.com/
|
||||
*/
|
||||
Wiky.rules.math = {
|
||||
version: 0.95,
|
||||
preshortcuts: [
|
||||
// { rex:/[ ]/g, tmplt:"`"}, // omit due to charset support ie6
|
||||
{ rex:/\+\-/g, tmplt:"±"},
|
||||
{ rex:/\/O|\\Oslash/g, tmplt:"Ø"},
|
||||
{ rex:/\/o|\\oslash/g, tmplt:"ø"},
|
||||
{ rex:/<->|\\harr/g, tmplt:"↔"},
|
||||
{ rex:/<-|\\larr/g, tmplt:"←"},
|
||||
{ rex:/->|\\rarr/g, tmplt:"→"},
|
||||
{ rex:/<=>|\\hArr/g, tmplt:"⇔"},
|
||||
{ rex:/=>|\\rArr/g, tmplt:"⇒"},
|
||||
{ rex:/-=|\\equiv/g, tmplt:"≡"},
|
||||
{ rex:/<=|\\le/g, tmplt:"≤"},
|
||||
{ rex:/>=|\\ge/g, tmplt:"≥"},
|
||||
{ rex:/</g, tmplt:"<"},
|
||||
{ rex:/>/g, tmplt:">"}
|
||||
],
|
||||
postshortcuts: [
|
||||
{ rex:/\*|\\middot/g, tmplt:"·"},
|
||||
{ rex:/\\x|\\times/g, tmplt:"×"},
|
||||
{ rex:/~=|\\cong/g, tmplt:"≅"},
|
||||
{ rex:/~~|\\asymp/g, tmplt:"≈"},
|
||||
{ rex:/~|\\sim/g, tmplt:"∼"},
|
||||
{ rex:/!=|\\neq|\\ne/g, tmplt:"≠"},
|
||||
{ rex:/\.\.\.|\\ldots/g, tmplt:"…"},
|
||||
{ rex:/\\in|\\isin/g, tmplt:"∈"},
|
||||
{ rex:/([0-9])x([0-9])/g, tmplt:"$1×$2"},
|
||||
{ rex:/([A-Za-z]) x ([A-Za-z])/g, tmplt:"$1×$2"},
|
||||
// { rex:/[`]{4}/g, tmplt:" "}, // omit due to charset support ie6
|
||||
// { rex:/[`]{3}/g, tmplt:" "},
|
||||
// { rex:/[`]{2}/g, tmplt:" "},
|
||||
// { rex:/[`]/g, tmplt:" "},
|
||||
{ rex:/\{/g, tmplt:"‎"}, // unvisible left-to-right mark,
|
||||
{ rex:/\}/g, tmplt:"‏"} // unvisible right-to-left mark,
|
||||
],
|
||||
expr: [
|
||||
{ rex:/\^\^/g, tmplt:"^^"}, // ^ overindex
|
||||
{ rex:/(\\sum|\\prod|\\int)_([-]?[a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})\^([-]?[a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})/g, tmplt:"<span class=\"o\"><span class=\"x\">$3</span>$1<span class=\"x\">$2</span></span>"}, // over-/underscript (\sum, \prod, \int)
|
||||
{ rex:/(\\sum|\\prod|\\int)\^([-]?[a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})/g, tmplt:"<span class=\"o\"><span class=\"x\">$2</span>$1<span> </span></span>"},
|
||||
{ rex:/(\\sum|\\prod|\\int)_([-]?[a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})/g, tmplt:"<span class=\"o\"><span> </span>$1<span class=\"x\">$2</span></span>"},
|
||||
{ rex:/_([-]?[a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})\^([-]?[a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})/g, tmplt:"<span class=\"s\"><span class=\"i\">$2</span><span class=\"i\">$1</span></span>"}, // over-/underindex
|
||||
{ rex:/\^([-]?[a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})/g, tmplt:"<sup class=\"i\">$1</sup>"}, // overindex
|
||||
{ rex:/_([-]?[a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})/g, tmplt:"<sub class=\"i\">$1</sub>"}, // underindex
|
||||
{ rex:/-/g, tmplt:"−"},
|
||||
{ rex:/([a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})\/([a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})/g, tmplt:"<span class=\"f\"><span class=\"n\">$1</span><span class=\"d\">$2</span></span>"}, // fraction
|
||||
{ rex:/([a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})\/\/([a-zA-Z0-9\.&;#\\]+|\{@[0-9]+@\})/g, tmplt:"<sup>$1</sup>⁄<sub>$2</sub>"}, // fraction
|
||||
{ rex:/\[((\[(([^,\]]+[,]){1,}[^\]]+)\][ \n]*){1,})\]/g, tmplt:function($0,$1){var m=Wiky.math.transpose($1.replace(/(^\[|\]$)/g,"").replace(/(\][ \n]*\[)/g,"|").split("|")),sz=" style=\"font-size:"+(m.len)+"00%;\"";/*alert("{("+m.mat.join(")}\n{(").split(",").join(")(")+")}");*/ return "<span class=\"lb\""+sz+">"+Wiky.math.fence()+"</span><span class=\"m\"><span class=\"e\">"+m.mat.join("</span></span>\n<span class=\"m\"><span class=\"e\">").split(",").join("</span><span class=\"e\">")+"</span></span><span class=\"rb\""+sz+">"+Wiky.math.fence()+"</span>";}}, // matrix
|
||||
{ rex:/\[((?:[^,\]]){1,}[^\]]+)\]/g, tmplt:function($0,$1){var v=$1.split(","),sz=" style=\"font-size:"+v.length+"00%;\""; return "<span class=\"lb\""+sz+">"+Wiky.math.fence()+"</span><span class=\"v\"><span class=\"e\">"+v.join("</span><span class=\"e\">")+"</span></span><span class=\"rb\""+sz+">"+Wiky.math.fence()+"</span>";}}, // vector
|
||||
{ rex:/!([a-zA-Z0-9\.&;]+)/g, tmplt:"<span class=\"b\">$1</span>" }, // bold vector symbol ..
|
||||
{ rex:/\\prod/g, tmplt:"<span class=\"h\">∏</span>"},
|
||||
{ rex:/\\sum/g, tmplt:"<span class=\"h\">∑</span>"},
|
||||
{ rex:/\\int/g, tmplt:"<span class=\"h\">∫</span>"},
|
||||
"Wiky.rules.math.postshortcuts"
|
||||
],
|
||||
symbols: [
|
||||
{ rex:/\\Alpha/g, tmplt:"Α"},
|
||||
{ rex:/\\Beta/g, tmplt:"Β"},
|
||||
{ rex:/\\Gamma/g, tmplt:"Γ"},
|
||||
{ rex:/\\Delta/g, tmplt:"Δ"},
|
||||
{ rex:/\\Epsilon/g, tmplt:"Ε"},
|
||||
{ rex:/\\Zeta/g, tmplt:"Ζ"},
|
||||
{ rex:/\\Eta/g, tmplt:"Η"},
|
||||
{ rex:/\\Theta/g, tmplt:"Θ"},
|
||||
{ rex:/\\Iota/g, tmplt:"Ι"},
|
||||
{ rex:/\\Kappa/g, tmplt:"Κ"},
|
||||
{ rex:/\\Lambda/g, tmplt:"Λ"},
|
||||
{ rex:/\\Mu/g, tmplt:"Μ"},
|
||||
{ rex:/\\Nu/g, tmplt:"Ν"},
|
||||
{ rex:/\\Xi/g, tmplt:"Ξ"},
|
||||
{ rex:/\\Omicron/g, tmplt:"Ο"},
|
||||
{ rex:/\\Pi/g, tmplt:"Π"},
|
||||
{ rex:/\\Rho/g, tmplt:"Ρ"},
|
||||
{ rex:/\\Sigma/g, tmplt:"Σ"},
|
||||
{ rex:/\\Tau/g, tmplt:"Τ"},
|
||||
{ rex:/\\Upsilon/g, tmplt:"Υ"},
|
||||
{ rex:/\\Phi/g, tmplt:"Φ"},
|
||||
{ rex:/\\Chi/g, tmplt:"Χ"},
|
||||
{ rex:/\\Psi/g, tmplt:"Ψ"},
|
||||
{ rex:/\\Omega/g, tmplt:"Ω"},
|
||||
{ rex:/\\alpha/g, tmplt:"α"},
|
||||
{ rex:/\\beta/g, tmplt:"β"},
|
||||
{ rex:/\\gamma/g, tmplt:"γ"},
|
||||
{ rex:/\\delta/g, tmplt:"δ"},
|
||||
{ rex:/\\epsilon/g, tmplt:"ε"},
|
||||
{ rex:/\\zeta/g, tmplt:"ζ"},
|
||||
{ rex:/\\eta/g, tmplt:"η"},
|
||||
{ rex:/\\thetasym/g, tmplt:"ϑ"},
|
||||
{ rex:/\\theta/g, tmplt:"θ"},
|
||||
{ rex:/\\iota/g, tmplt:"ι"},
|
||||
{ rex:/\\kappa/g, tmplt:"κ"},
|
||||
{ rex:/\\lambda/g, tmplt:"λ"},
|
||||
{ rex:/\\mu/g, tmplt:"μ"},
|
||||
{ rex:/\\nu/g, tmplt:"ν"},
|
||||
{ rex:/\\xi/g, tmplt:"ξ"},
|
||||
{ rex:/\\omicron/g, tmplt:"ο"},
|
||||
{ rex:/\\piv/g, tmplt:"ϖ"},
|
||||
{ rex:/\\pi/g, tmplt:"π"},
|
||||
{ rex:/\\rho/g, tmplt:"ρ"},
|
||||
{ rex:/\\sigmaf/g, tmplt:"ς"},
|
||||
{ rex:/\\sigma/g, tmplt:"σ"},
|
||||
{ rex:/\\tau/g, tmplt:"τ"},
|
||||
{ rex:/\\upsilon/g, tmplt:"υ"},
|
||||
{ rex:/\\phi/g, tmplt:"φ"},
|
||||
{ rex:/\\chi/g, tmplt:"χ"},
|
||||
{ rex:/\\psi/g, tmplt:"ψ"},
|
||||
{ rex:/\\omega/g, tmplt:"ω"},
|
||||
{ rex:/\\upsih/g, tmplt:"ϒ"},
|
||||
// miscellaneous symbols
|
||||
{ rex:/\\bull/g, tmplt:"•"},
|
||||
{ rex:/\\uarr/g, tmplt:"↑"},
|
||||
{ rex:/\\darr/g, tmplt:"↓"},
|
||||
{ rex:/\\crarr/g, tmplt:"↵"},
|
||||
{ rex:/\\lArr/g, tmplt:"⇐"},
|
||||
{ rex:/\\uArr/g, tmplt:"⇑"},
|
||||
{ rex:/\\dArr/g, tmplt:"⇓"},
|
||||
{ rex:/\\forall/g, tmplt:"∀"},
|
||||
{ rex:/\\part/g, tmplt:"∂"},
|
||||
{ rex:/\\exist/g, tmplt:"∃"},
|
||||
{ rex:/\\empty/g, tmplt:"∅"},
|
||||
{ rex:/\\nabla/g, tmplt:"∇"},
|
||||
{ rex:/\\notin/g, tmplt:"∉"},
|
||||
{ rex:/\\ni/g, tmplt:"∋"},
|
||||
{ rex:/\\minus/g, tmplt:"−"},
|
||||
{ rex:/\\lowast/g, tmplt:"∗"},
|
||||
{ rex:/\\sqrt|\\radic/g, tmplt:"√"},
|
||||
{ rex:/\\prop/g, tmplt:"∝"},
|
||||
{ rex:/\\infin/g, tmplt:"∞"},
|
||||
{ rex:/\\ang/g, tmplt:"∠"},
|
||||
{ rex:/\\and/g, tmplt:"∧"},
|
||||
{ rex:/\\or/g, tmplt:"∨"},
|
||||
{ rex:/\\cap/g, tmplt:"∩"},
|
||||
{ rex:/\\cup/g, tmplt:"∪"},
|
||||
{ rex:/\\there4/g, tmplt:"∴"},
|
||||
{ rex:/\\sub/g, tmplt:"⊂"},
|
||||
{ rex:/\\sup/g, tmplt:"⊃"},
|
||||
{ rex:/\\nsub/g, tmplt:"⊄"},
|
||||
{ rex:/\\sube/g, tmplt:"⊆"},
|
||||
{ rex:/\\supe/g, tmplt:"⊇"},
|
||||
{ rex:/\\oplus/g, tmplt:"⊕"},
|
||||
{ rex:/\\otimes/g, tmplt:"⊗"},
|
||||
{ rex:/\\perp/g, tmplt:"⊥"},
|
||||
{ rex:/\\sdot/g, tmplt:"⋅"}
|
||||
]
|
||||
};
|
||||
|
||||
Wiky.inverse.math = {
|
||||
pre: [
|
||||
{ rex:/−|\u2212/g, tmplt:"-"},
|
||||
{ rex:/ |\u2009/g, tmplt:" "},
|
||||
{ rex:/‎|\u200E/g, tmplt:"{"},
|
||||
{ rex:/‏|\u200F/g, tmplt:"}"}
|
||||
],
|
||||
post: [
|
||||
// { rex:/([$])/g, tmplt:"\\$1" },
|
||||
{ rex:/^|\x5E/g, tmplt:"^"},
|
||||
{ rex:/</g, tmplt:"<"},
|
||||
{ rex:/>/g, tmplt:">"}
|
||||
],
|
||||
shortcuts: [
|
||||
// { rex:/ |\u2003/g, tmplt:" "}, // omit due to charset support ie6
|
||||
// { rex:/ |\u2002/g, tmplt:" "},
|
||||
// { rex:/ |\u2009/g, tmplt:" "},
|
||||
{ rex:/±|\xB1/g, tmplt:"+-"},
|
||||
{ rex:/·|\xB7/g, tmplt:"*"},
|
||||
{ rex:/×|\xD7/g, tmplt:"\\x"},
|
||||
{ rex:/Ø|\xD8/g, tmplt:"/O"},
|
||||
{ rex:/ø|\xF8/g, tmplt:"/o"},
|
||||
{ rex:/←|\u2190/g, tmplt:"<-"},
|
||||
{ rex:/→|\u2192/g, tmplt:"->"},
|
||||
{ rex:/↔|\u2194/g, tmplt:"<->"},
|
||||
{ rex:/⇒|\u21D2/g, tmplt:"=>"},
|
||||
{ rex:/⇔|\u21D4/g, tmplt:"<=>"},
|
||||
{ rex:/∼|\u223C/g, tmplt:"~"},
|
||||
{ rex:/≅|\u2245/g, tmplt:"~="},
|
||||
{ rex:/≈|\u2248/g, tmplt:"~~"},
|
||||
{ rex:/≠|\u2260/g, tmplt:"!="},
|
||||
{ rex:/…/g, tmplt:"..."},
|
||||
{ rex:/≡|\u2261/g, tmplt:"-="},
|
||||
{ rex:/≤|\u2264/g, tmplt:"<="},
|
||||
{ rex:/≥|\u2265/g, tmplt:">="}
|
||||
],
|
||||
expr: [
|
||||
{ rex:/<span class=\"s\"><span class=\"i\">(\{?@[0-9]+@\}?)<\/span><span class="i">(\{?@[0-9]+@\}?)<\/span><\/span>/g, tmplt:"_$2^$1"}, // superscript + subscript
|
||||
{ rex:/<span class=\"o\"><span class=\"x\">(\{?@[0-9]+@\}?)<\/span>(\\prod|\\sum|\\int)<span class=\"x\">(\{?@[0-9]+@\}?)<\/span><\/span>/g, tmplt:"$2_$3^$1"}, // overscript + underscript
|
||||
{ rex:/<span class=\"o\"><span>@[0-9]+@<\/span>(\\prod|\\sum|\\int)<span class=\"x\">(\{?@[0-9]+@\}?)<\/span><\/span>/mgi, tmplt:"$1_$2", dbg:true}, // underscript
|
||||
{ rex:/<span class=\"o\"><span class=\"x\">(\{?@[0-9]+@\}?)<\/span>(\\prod|\\sum|\\int)<span>@[0-9]+@<\/span><\/span>/mgi, tmplt:"$2^$1"}, // overscript
|
||||
{ rex:/<span class=\"f\"><span class=\"n\">(\{?@[0-9]+@\}?)<\/span><span class="d">(\{?@[0-9]+@\}?)<\/span><\/span>/mgi, tmplt:"$1/$2"}, // fraction
|
||||
{ rex:/<span class=\"lb\"[^>]*>&[^;]+;<\/span><span class=\"v\">((?:<span class=\"e\">[^>]*<\/span>){2,})<\/span><span class=\"rb\"[^>]*>&[^;]+;<\/span>/mgi, tmplt:function($0,$1){return "["+$1.replace(/(?:^<span class=\"e\">|<\/span>$)/g,"").replace(/<\/span><span class=\"e\">/g,",")+"]";}}, // vector ..
|
||||
{ rex:/<span class=\"lb\"[^>]*>&[^;]+;<\/span>((?:<span class=\"m\">(?:(?:<span class=\"e\">[^>]*<\/span>){2,})<\/span>[^>]*){2,})<span class=\"rb\"[^>]*>&[^;]+;<\/span>/mgi, tmplt:function($0,$1){return "[["+Wiky.math.transpose($1.replace(/(?:^<span class=\"m\"><span class=\"e\">|<\/span><\/span>$)/g,"").replace(/<\/span><span class=\"e\">/g,",").replace(/<\/span><\/span>[^>]*<span class=\"m\"><span class=\"e\">/g,"|").split("|")).mat.join("][")+"]]";}}, // matrix ..
|
||||
{ rex:/<span class=\"b\">(@[0-9]+@)<\/span>/mgi, tmplt:"!$1"}, // bold vector ..
|
||||
{ rex:/<sup>(\{?@[0-9]+@\}?)<\/sup>⁄<sub>(\{?@[0-9]+@\}?)<\/sub>/mgi, tmplt:"$1//$2"},
|
||||
{ rex:/<sup class=\"i\">(\{?@[0-9]+@\}?)<\/sup>/mgi, tmplt:"^$1" },
|
||||
{ rex:/<sub class=\"i\">(\{?@[0-9]+@\}?)<\/sub>/mgi, tmplt:"_$1" }
|
||||
],
|
||||
symbols: [
|
||||
// greek symbols
|
||||
{ rex:/Α|\u391/g, tmplt:"\\Alpha"},
|
||||
{ rex:/Β|\u392/g, tmplt:"\\Beta"},
|
||||
{ rex:/Γ|\u393/g, tmplt:"\\Gamma"},
|
||||
{ rex:/Δ|\u394/g, tmplt:"\\Delta"},
|
||||
{ rex:/Ε|\u395/g, tmplt:"\\Epsilon"},
|
||||
{ rex:/Ζ|\u396/g, tmplt:"\\Zeta"},
|
||||
{ rex:/Η|\u397/g, tmplt:"\\Eta"},
|
||||
{ rex:/Θ|\u398/g, tmplt:"\\Theta"},
|
||||
{ rex:/Ι|\u399/g, tmplt:"\\Iota"},
|
||||
{ rex:/Κ|\u39A/g, tmplt:"\\Kappa"},
|
||||
{ rex:/Λ|\u39B/g, tmplt:"\\Lambda"},
|
||||
{ rex:/Μ|\u39C/g, tmplt:"\\Mu"},
|
||||
{ rex:/Ν|\u39D/g, tmplt:"\\Nu"},
|
||||
{ rex:/Ξ|\u39E/g, tmplt:"\\Xi"},
|
||||
{ rex:/Ο|\u39F/g, tmplt:"\\Omicron"},
|
||||
{ rex:/Π|\u3A0/g, tmplt:"\\Pi"},
|
||||
{ rex:/Ρ|\u3A1/g, tmplt:"\\Rho"},
|
||||
{ rex:/Σ|\u3A3/g, tmplt:"\\Sigma"},
|
||||
{ rex:/Τ|\u3A4/g, tmplt:"\\Tau"},
|
||||
{ rex:/Υ|\u3A5/g, tmplt:"\\Upsilon"},
|
||||
{ rex:/Φ|\u3A6/g, tmplt:"\\Phi"},
|
||||
{ rex:/Χ|\u3A7/g, tmplt:"\\Chi"},
|
||||
{ rex:/Ψ|\u3A8/g, tmplt:"\\Psi"},
|
||||
{ rex:/Ω|\u3A9/g, tmplt:"\\Omega"},
|
||||
{ rex:/α|\u3B1/g, tmplt:"\\alpha"},
|
||||
{ rex:/β|\u3B2/g, tmplt:"\\beta"},
|
||||
{ rex:/γ|\u3B3/g, tmplt:"\\gamma"},
|
||||
{ rex:/δ|\u3B4/g, tmplt:"\\delta"},
|
||||
{ rex:/ε|\u3B5/g, tmplt:"\\epsilon"},
|
||||
{ rex:/ζ|\u3B6/g, tmplt:"\\zeta"},
|
||||
{ rex:/η|\u3B7/g, tmplt:"\\eta"},
|
||||
{ rex:/ϑ|\u3D1/g, tmplt:"\\thetasym"},
|
||||
{ rex:/θ|\u3B8/g, tmplt:"\\theta"},
|
||||
{ rex:/ι|\u3B9/g, tmplt:"\\iota"},
|
||||
{ rex:/κ|\u3BA/g, tmplt:"\\kappa"},
|
||||
{ rex:/λ|\u3BB/g, tmplt:"\\lambda"},
|
||||
{ rex:/μ|\u3BC/g, tmplt:"\\mu"},
|
||||
{ rex:/ν|\u3BD/g, tmplt:"\\nu"},
|
||||
{ rex:/ξ|\u3BE/g, tmplt:"\\xi"},
|
||||
{ rex:/ο|\u3BF/g, tmplt:"\\omicron"},
|
||||
{ rex:/π|\u3C0/g, tmplt:"\\pi"},
|
||||
{ rex:/ρ|\u3C1/g, tmplt:"\\rho"},
|
||||
{ rex:/ς|\u3C2/g, tmplt:"\\sigmaf"},
|
||||
{ rex:/σ|\u3C3/g, tmplt:"\\sigma"},
|
||||
{ rex:/τ|\u3C4/g, tmplt:"\\tau"},
|
||||
{ rex:/υ|\u3C5/g, tmplt:"\\upsilon"},
|
||||
{ rex:/φ|\u3C6/g, tmplt:"\\phi"},
|
||||
{ rex:/χ|\u3C7/g, tmplt:"\\chi"},
|
||||
{ rex:/ψ|\u3C8/g, tmplt:"\\psi"},
|
||||
{ rex:/ω|\u3C9/g, tmplt:"\\omega"},
|
||||
// miscellaneous symbols
|
||||
{ rex:/ϒ|\u3D2/g, tmplt:"\\upsih"},
|
||||
{ rex:/ϖ|\u3D6/g, tmplt:"\\piv"},
|
||||
{ rex:/•|\u2022/g, tmplt:"\\bull"},
|
||||
{ rex:/↑|\u2191/g, tmplt:"\\uarr"},
|
||||
{ rex:/↓|\u2193/g, tmplt:"\\darr"},
|
||||
{ rex:/↵|\u21B5/g, tmplt:"\\crarr"},
|
||||
{ rex:/⇐|\u21D0/g, tmplt:"\\lArr"},
|
||||
{ rex:/⇑|\u21D1/g, tmplt:"\\uArr"},
|
||||
{ rex:/⇓|\u21D3/g, tmplt:"\\dArr"},
|
||||
{ rex:/∀|\u2200/g, tmplt:"\\forall"},
|
||||
{ rex:/∂|\u2202/g, tmplt:"\\part"},
|
||||
{ rex:/∃|\u2203/g, tmplt:"\\exist"},
|
||||
{ rex:/∅|\u2205/g, tmplt:"\\empty"},
|
||||
{ rex:/∇|\u2207/g, tmplt:"\\nabla"},
|
||||
{ rex:/∈|\u2208/g, tmplt:"\\isin"},
|
||||
{ rex:/∉|\u2209/g, tmplt:"\\notin"},
|
||||
{ rex:/∋|\u220B/g, tmplt:"\\ni"},
|
||||
{ rex:/<span class=\"h\">(∏|\u220F)<\/span>/g, tmplt:"\\prod"},
|
||||
{ rex:/<span class=\"h\">(∑|\u2211)<\/span>/g, tmplt:"\\sum"},
|
||||
{ rex:/∗|\u2217/g, tmplt:"\\lowast"},
|
||||
{ rex:/√|\u221A/g, tmplt:"\\sqrt"},
|
||||
{ rex:/∝|\u221D/g, tmplt:"\\prop"},
|
||||
{ rex:/∞|\u221E/g, tmplt:"\\infin"},
|
||||
{ rex:/∠|\u2220/g, tmplt:"\\ang"},
|
||||
{ rex:/∧|\u2227/g, tmplt:"\\and"},
|
||||
{ rex:/∨|\u2228/g, tmplt:"\\or"},
|
||||
{ rex:/∩|\u2229/g, tmplt:"\\cap"},
|
||||
{ rex:/∪|\u222A/g, tmplt:"\\cup"},
|
||||
{ rex:/<span class=\"h\">(?:∫|\u222B)<\/span>/g, tmplt:"\\int"},
|
||||
{ rex:/∴|\u2234/g, tmplt:"\\there4"},
|
||||
{ rex:/⊂|\u2282/g, tmplt:"\\sub"},
|
||||
{ rex:/⊃|\u2283/g, tmplt:"\\sup"},
|
||||
{ rex:/⊄|\u2284/g, tmplt:"\\nsub"},
|
||||
{ rex:/⊆|\u2286/g, tmplt:"\\sube"},
|
||||
{ rex:/⊇|\u2287/g, tmplt:"\\supe"},
|
||||
{ rex:/⊕|\u2295/g, tmplt:"\\oplus"},
|
||||
{ rex:/⊗|\u2297/g, tmplt:"\\otimes"},
|
||||
{ rex:/⊥|\u22A5/g, tmplt:"\\perp"},
|
||||
{ rex:/⋅|\u22C5/g, tmplt:"\\sdot"}
|
||||
]
|
||||
};
|
||||
|
||||
Wiky.math = {
|
||||
toHtml: function(str) {
|
||||
var expr = function(itr) { // region from "{" to "}", nesting allowed ..
|
||||
var s = "";
|
||||
for (var c = itr.str.charAt(itr.pos++); itr.pos <= itr.str.length && c != "}"; c = itr.str.charAt(itr.pos++))
|
||||
s += (c == "{") ? ("{"+expr(itr)+"}") : c;
|
||||
return Wiky.store(Wiky.apply(s, Wiky.rules.math.expr));
|
||||
};
|
||||
str = Wiky.apply(str, Wiky.rules.math.preshortcuts);
|
||||
str = Wiky.apply(str, Wiky.rules.math.symbols);
|
||||
str = expr({str:str,pos:0});
|
||||
return str;
|
||||
},
|
||||
toWiki: function(str) {
|
||||
var parseTree = function(itr, endtag) {
|
||||
var c, s="",gt,nam,idxof=function(s,c,p){var i=s.indexOf(c,p);return i>=0?i:s.length;}
|
||||
for (itr.buf=itr.str.substr(itr.pos,endtag.length);
|
||||
itr.pos<itr.str.length && (!endtag || itr.buf!=endtag);
|
||||
itr.buf=itr.str.substr(++itr.pos,endtag.length)) {
|
||||
if ((c=itr.str.charAt(itr.pos))=="<" && (gt=idxof(itr.str,">",itr.pos)) < idxof(itr.str,"/",itr.pos)) { // start tags .. no empty elements or endtags ..
|
||||
nam = itr.str.substring(itr.pos+1,Math.min(idxof(itr.str," ",itr.pos),gt));
|
||||
s += itr.str.substring(itr.pos,itr.pos=gt+1) + parseTree(itr, "</" + nam + ">") + "</" + nam + ">";
|
||||
itr.pos += nam.length+3;
|
||||
}
|
||||
else
|
||||
s += c;
|
||||
}
|
||||
itr.pos--;
|
||||
return Wiky.store(s, true);
|
||||
};
|
||||
str = Wiky.apply(str, Wiky.inverse.math.pre);
|
||||
str = Wiky.apply(str, Wiky.inverse.math.symbols);
|
||||
str = parseTree({str:str,pos:0,buf:null}, "");
|
||||
while (str.match(/@[0-9]+@/g) != null)
|
||||
str = Wiky.apply(str.replace(/@([0-9]+)@/g, function($0,$1){return Wiky.restore($1);}), Wiky.inverse.math.expr);
|
||||
str = Wiky.apply(str, Wiky.inverse.math.shortcuts);
|
||||
str = Wiky.apply(str, Wiky.inverse.math.post);
|
||||
return str;
|
||||
},
|
||||
fence: function(str) {
|
||||
return window && window.ActiveXObject ? " " : " ";
|
||||
},
|
||||
transpose: function (m) {
|
||||
var t=[];
|
||||
for (var i in m) {
|
||||
m[i] = m[i].split(",");
|
||||
for (var j in m[i]) {
|
||||
if (!t[j]) t[j]=[];
|
||||
t[j][i] = m[i][j];
|
||||
}
|
||||
}
|
||||
for (var i in t)
|
||||
t[i] = t[i].join(",");
|
||||
return {mat:t, len:m.length};
|
||||
}
|
||||
};
|
||||
|
||||
Wiky.rules.pre = Wiky.rules.pre.concat({ rex:/\\([$])/g, tmplt:function($0,$1){return Wiky.store($1);} });
|
||||
Wiky.rules.nonwikiblocks = Wiky.rules.nonwikiblocks.concat(
|
||||
[
|
||||
{ rex:/\[\(([a-zA-Z0-9\.-]+)\)\$([^$]*)\$\]/g, tmplt:function($0,$1,$2){return ":p]<div class=\"eq\"><a name=\"eq"+$1+"\">("+$1+")</a>" + Wiky.math.toHtml($2) + "</div>[p:";} }, // numbered equation
|
||||
{ rex:/\[\$([^$]*)\$\]/g, tmplt:function($0,$1){return ":p]<div class=\"eq\">" + Wiky.math.toHtml($1) + "</div>[p:";} }, // equation
|
||||
]);
|
||||
Wiky.rules.nonwikiinlines = Wiky.rules.nonwikiinlines.concat(
|
||||
{ rex:/\$([^$]*)\$/g, tmplt:function($0,$1){return "<dfn>" + Wiky.math.toHtml($1) + "</dfn>";} } // inline equation
|
||||
);
|
||||
|
||||
Wiky.inverse.pre = Wiky.inverse.pre.concat({ rex:/([\$])/g, tmplt:"\\$1" });
|
||||
Wiky.inverse.nonwikiblocks = Wiky.inverse.nonwikiblocks.concat(
|
||||
[
|
||||
{ rex:/<div class=\"eq\"><a name=\"eq([0-9]+)\">(?:.*?)<\/a>(.*?)<\/div>/g, tmplt:function($0,$1,$2){return Wiky.store("[("+$1+")$"+Wiky.math.toWiki($2)+"$]");} }, // numbered equation
|
||||
{ rex:/<div class=\"eq\">(.*?)<\/div>/g, tmplt:function($0,$1){return Wiky.store("[$"+Wiky.math.toWiki($1)+"$]");} }, // equation
|
||||
]);
|
||||
Wiky.inverse.nonwikiinlines = Wiky.inverse.nonwikiinlines.concat(
|
||||
{ rex:/<dfn>(.*?)<\/dfn>/g, tmplt:function($0,$1){return Wiky.store("$"+Wiky.math.toWiki($1)+"$");} } // inline equation
|
||||
);
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Extension rules for S3AjaxWiki
|
||||
*/
|
||||
|
||||
Wiky.rules.wikiinlines = Wiky.rules.wikiinlines.concat(
|
||||
{
|
||||
rex: /([A-Z][a-z0-9]+(?:[A-Z][a-z0-9]*)+)/g,
|
||||
tmplt: '<a class="wikiword" href="$1">$1</a>'
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Wiky.inverse.wikiinlines = Wiky.inverse.wikiinlines.concat(
|
||||
{
|
||||
rex: /<a class="?wikiword"? [^>]*?>(.*?)<\/a>/mgi,
|
||||
tmplt:"$1"
|
||||
},
|
||||
{
|
||||
rex: /<a class="?newword"? [^>]*?>(.*?)<\/a>/mgi,
|
||||
tmplt:"$1"
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user