Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
/*{{{*/
// may be required for mikes comments plugi
//window.saveChanges = function(){};
setStylesheet(
"label {width:8em; float:left; text-align:right; width:9em; font-size:1.1em; padding:3px; height:1.5em: top:-20px; margin: 0px -2px 0 0;}"+
// "div.wizardFooter {padding-left:0em}"+
"div.wizardStep > input {display:fixed; padding:3px; margin-bottom:5px; margin-top:0px; margin-right:0px}",
'labelStyles');
config.backstageTasks.remove("upgrade");
config.backstageTasks.remove("save");
config.backstageTasks.remove("sync");
// ccAutoSave config//
config.options.chkAutoSave = true;
if(!config.extensions) { config.extensions = {}; } //# obsolete from v2.4.2
config.extensions.ServerSideSavingPlugin = {
adaptor: config.adaptors.cctiddly
};
window.ccTiddlyVersion = '1.8.2';
window.workspacePermission= {};
window.url = "http://www.andreanis.de/_tiddly";
window.url= 'http://www.andreanis.de/_tiddly/';
window.workspace = "";
window.fullUrl = window.url;
window.useModRewrite = 1;
//if (config.options.txtTheme == "")
//config.options.txtTheme = 'purpleTheme';
workspacePermission.upload = 1;workspacePermission.anonC = 1 ;
workspacePermission.anonR = 1;
workspacePermission.anonU = 1;
workspacePermission.anonD = 1;
workspacePermission.userC = 1 ;
workspacePermission.userR = 1;
workspacePermission.userU = 1;
workspacePermission.userD = 1;
workspacePermission.canCreateWorkspace = 1;
window.workspace_delete = "A";
window.workspace_udate = "A";
var serverside={
url:"http://www.andreanis.de/_tiddly", //server url, for use in local TW or TW hosted elsewhere
workspace:"",
queryString:"",
debug:0, //debug mode, display alert box for each action
passwordTime:0, //defines how long password variable store in cookie. 0 = indefinite
messageDuration:5000, //displayMessage autoclose duration (in milliseconds), 0=leave open
loggedIn:0,
can_create_account:"1",
openId:"1"
};
config.defaultCustomFields = {"server.host":window.url, "server.type":"cctiddly", "server.workspace":window.workspace};
config.shadowTiddlers.OptionsPanel = "[[help|Help]] <br />[[settings|AdvancedOptions]]<br /><<ccOptions>>";
readOnly =false;
config.options.chkHttpReadOnly = false; //make it HTTP writable by default
config.options.chkSaveBackups = false; //disable save backup
//config.options.chkAutoSave = true; //disable autosave
config.options.chkUsePreForStorage = false;
/*}}}*/
powerpapepowerpape
Please see the TiddlyWiki community wiki documentation : http://tiddlywiki.org/wiki/TiddlyWiki_Markup
!!!{{{<<today>>}}}
Shows current date.
!!!{{{<<version>>}}}
This macro shows the version number of the current TiddlyWiki document.
!!!{{{<<Alltags>>}}}
Lists all tags. Clicking on a tag lists all the tiddlers assigned that tag.
!!!{{{<<List [type]>>}}}
Parameters : (all (default), missing, orphans, shadowed, touched, filter)
!!!{{{<<Timeline [date] [length] [format]>>}}}
The timeline macro creates a list of tiddlers sorted by a date specified.
Example :
{{{<<timeline "modified" "0" "ddd, YYYY-0MM-0DD">>}}}
Produces :
<<timeline "modified" "0" "ddd, YYYY-0MM-0DD">>
!!!{{{<<Slider cookie tiddler label tooltip>>}}}
The slider macro allows embedding tiddlers within another tiddler, with the option to toggle the visibility of the transcluded contents.
* cookie: variable to save the state of the slider
* tiddler: name of the tiddler to include in the slider
* label: title text of the slider
* tooltip: tooltip text of the slider
Example
{{{<<slider chkTestSlider [[OptionsPanel]] "Options" "Open advanced options">>}}}
Produces :
<<slider chkTestSlider [[OptionsPanel]] "Options" "Open advanced options">>
!!!{{{<<Tabs>>}}}
The tabs macro creates an area where it displays one of several tiddlers alternately, as the user clicks on the tab labels at the top.
It is used like this:
{{{<<tabs ID Label1 Tip1 Tiddler1 Label2 Tip2 Tiddler2 [Label3 ...]>>}}}
produces :
<<tabs ID Label1 Tip1 Tiddler1 Label2 Tip2 Tiddler2 [Label3 ...]>>
* ID: specifies the name of a cookie used to save the information about which tab was displayed last.
* Label1, Label2, ... define the labels that are displayed at the top of the area for each tab
* Tip1, Tip2, ... define tooltips that explain, somewhat more verbosely than the labels, what you can expect to find on each tab.
* Tiddler1, Tiddler2, ... name the tiddlers that are displayed on each tab.
Obviously, there must be exactly three strings for each tab.
The syntax for the tabs macro looks like this:
{{{<<tabs txt[cookieName]
"[label]" "[title]" [[tiddler]]
"[label]" "[title]" [[tiddler]]
...
>>}}}
produces :
<<tabs txt[cookieName]
"[label]" "[title]" [[tiddler]]
"[label]" "[title]" [[tiddler]]
...
>>
!!!{{{<<Tagging [tag]>>}}}
This macro generates a list of tiddlers that carry the specified tag.
<<tagging [tag]>>
If the tag parameter is not specified, the current tiddler's name will be used instead.
!!!{{{<<Tagchooser>>}}}
!!!{{{<<NewJournal>>}}}
This macro generates a button to create a journal tiddler, using the current time and date as title.
It is otherwise identical to the NewTiddler macro.
Example :
{{{<<newJournal [date format]>>}}}
Produces :
<<newJournal [date format]>>
The optional parameter can be used to specify a custom date format.
In addition, all of the NewTiddler macro's parameters are valid.
!!!{{{<<NewTiddler>>}}}
Usage
<<newTiddler [parameters]>>
Parameters
This macro uses named parameters. All parameters are optional.
|Parameter|Description|
|label |button label|
|prompt|button tooltip|
|title|title for the new tiddler (defaults to "New Tiddler")|
|text|contents for the new tiddler|
|tag|tag to be applied to the new tiddler (parameter can be used repeatedly to specify multiple tags)|
|accessKey|single letter to use as access key to trigger the button|
|focus|which of the editable fields to default the focus to (e.g. "title", "text", "tags")|
|template|template tiddler to use to display the new tiddler (defaults to EditTemplate)|
|fields|custom fields to be assigned to the new tiddler, in name:value;name:value; format|
Only fields contained as input fields in the specified template can be primed with an initial value.
[edit] Example
<<newTiddler
label:"New Tiddler"
text:"Hello world."
tag:"test"
tag:"an example"
accessKey:"1"
focus:"tags"
>>
!!!{{{<<Savechanges>>}}}
!!!{{{<<Search>>}}}
This macro creates an input field to perform full-text searches on a TiddlyWiki document's tiddler contents.
[edit] Usage
Example :
{{{<<search [value]>>}}}
Produces :
<<search [value]>>
By specifiying the value parameter, the search form can be "preloaded" with the desired term.
[edit] Options
This section is still incomplete. You can help by contributing to its expansion.
Please improve the article, or discuss the issue on the talk page.
* case-sensitive
* regular expressions
!!!{{{<<Gradient>>}}}
The Gradient macro allows simple horizontal and vertical coloured gradients. They are constructed from coloured HTML elements, and don't require any images to work.
The Gradient macro is an extended macro that processes the text after it up until the next '
>>
' sequence. It looks like this:
Example :
{{{<<gradient vert #ffffff #ffdddd #ff8888>>gradient fill>>}}}
Produces :
<<gradient vert #ffffff #ffdddd #ff8888>>gradient fill>>
The first parameter can be vert or horiz to indicate the direction of the gradient. The following parameters are two or more colours (CSS RGB(r,g,b) format is also acceptable). The macro constructs a smooth linear gradient between each of the colours in turn.
Inline CSS definitions can be added to gradient fills like this:
Example :
{{{<<gradient vert #000000 #660000 #aa2222>>color:#ffffff;font-size:12pt;Darkness>>}}}
Produces :
<<gradient vert #000000 #660000 #aa2222>>color:#ffffff;font-size:12pt;Darkness>>
!!!{{{<<Closeall>>}}}
!!!{{{<<Permaview>>}}}
Changes the browser address bar to a permalink to the current Tiddler or the set of open tiddlers. It is used with the ToolbarMacro like this:
Example :
{{{<<toolbar permalink>>}}}
Produces :
<<toolbar permalink>>
!!!{{{<<Toolbar>>}}}
The ToolbarMacro is used in the TemplateMechanism to define the toolbar that appearthat appear either in EditMode or in ViewMode. The arguments to the ToolbarMacro is a list of command names, as discussed in the CommandMechanism..
You can precede a command name with a "+" to specify a default command that is automatically chosen when a tiddler is double-clicked, or the ctrl-Enter key combination pressed. Similarly, precede it with "-" to specify a command to be chosen when the Escape key is pressed.
!!!{{{<<Annotations>>}}}
!!!{{{<<Edit>>}}}
The command <<edit>> switches from ViewMode to EditMode. The EditMacro is either a double mouse click inside the tiddler or the entry 'edit' in the tiddler's Toolbar. It is used in ViewTemplate as ToolbarMacro like this:
Example :
{{{<<toolbar +editTiddler>>}}}
Produces :
<<toolbar +editTiddler>>
!!!{{{<<Message>>}}}
!!!{{{<<Refreshdisplay>>}}}
!!!{{{<<View fieldname how...>>}}}
Retrieves a specified field (given by fieldname) from the tiddler to be displayed and outputs its value in one of the following ways (the optional //how// parameter):
* (unspecified): render as is (without formatting)
* link: format as a link (using createTiddlyLink)
* wikified: format using all the normal rendering rules
* date: expects a value of the form YYYYMMDDHHMM and outputs it using either a specified format (...) or config.views.wikified.dateFormat
The standard field names are:
* title - the tiddler title
* tiddler - the tiddler title (as well)
* text - the text of the tiddler
* modifier - the person who last modified it
* modified - date&time of last modification
* created - when it was created
* tags - the tiddler tags
If your tiddlers contain custom fields, they could be specified as well.
The view macro is used extensively in the standard tiddler rendering templates (ViewTemplate and EditTemplate).
(this content is a work in progress)
!!!ccTiddly Tiddlers
[[AnonDefaultTiddlers]]
Allows you to specify a different set of tiddlers to be loaded for anonymous users. Logged in users will be shown the [[DefaultTiddlers]].
[[ccAssignments]]
!!! Predefined ccTiddly Tags
!!!!wizard
Displays the tiddler without showing the date editor tags or title.
!!!!private
Only administrators of a workspace can read tiddlers tagged private.
!!! Working Offline :
To take a copy of a ccTiddly workspace offline add &standalone=1 to the end of the URI and you will be prompted to download an offline file.
!!!{{{<<ccUpload>>}}}
If enabled on the server users can upload files to the ccTiddly server
!!!{{{<<ccLogin>>}}}
Displays the login box if the users is not logged in, if the user is logged in they are shown a logout button
!!!{{{<<ccLoginStatus>>}}}
As with {{{<<ccLogin>>}}} except this displays a link to the login tiddler so can be used where space is tight.
!!!{{{<<ccCreateWorkspace>>}}}
Allows users with permission to create a workspace and define its permissions.
!!!{{{<<ccEditWorkspace>>}}}
Allows admin users to change the permission of a workspace.
!!!{{{<<ccAdmin>>}}}
Allows admin users to add and remove admin users for a workspace.
!!!{{{<<ccVersion>>}}}
Allows users to confirm which version of ccTiddly they are using.
~TiddlyWiki is a single html file containing all the characteristics of a wiki - all the content, all the functionality (including editing, saving, tagging and searching) and the style sheet. Because it's a single file, it's very portable - you can email it, put it on a web server or share it via a USB stick. ccTiddly provides a serverside backend to ~TiddlyWiki so you can store your content on the web and access it from anywhere.
Together the two provide a powerful combination which allows you to collaborate with your colleages online, you can then tear a copy of all the work to take on a plane or train journey. When you have found an internet connection again you can sync your changes with the online copy and you will be notified of any conflicts.
Some things you could do with ccTiddly workspace include:
* A team/public Website
* A Blog
* A personal notebook
* A GTD ("Getting Things Done") productivity tool
* A collaboration/communication tool
* A TeamTasks implementation
* For building websites (this site is a TiddlyWiki file!)
* For rapid prototyping
* ...and much more!
You can import and export data to and from all sorts of places. Check out the backstage > import options. There's a more detailed list of features here.
<<slider cctHelpIntro [[ccTiddly Introduction]] "ccTiddly Introduction »" "A introduction to the basics of TiddlyWiki.">>
<<slider cctHelpFormatting [[TiddlyWiki Formatting Guide]] "Tiddly Wiki Formatting Guide »" "A basic guide to TiddlyWiki formatting.">>
<<slider cctHelpccTiddlyMacros [[ccTiddly Macros]] "ccTiddly Macros »" "A Guide to all the ccTiddly Macros">>
<<slider cctHelpTiddlyWikiMacros [[TiddlyWiki Macros]] "TiddlyWiki Macros »" "A Guide to all the TiddlyWiki Macros">>
More info on Osmosoft can be found at [[osmosoft.com|http://osmosoft.com/]]
powerpape
|''Description:''|MonkeyPirate|
|''Type:''|tiddlywiki|
|''URL:''|http://mptw.tiddlyspot.com/empty.html|
|''Workspace:''|Main|
|''Description:''|TeamTasks |
|''Type:''|tiddlywiki|
|''URL:''|http://getteamtasks.com/teamtasks.html|
|''image:''|http://127.0.0.1/teamtasks.jpg|
|''Workspace:''|Main|
|''Description:''|TiddlyThemes |
|''Type:''|tiddlywiki|
|''URL:''|http://tiddlythemes.com|
|''Workspace:''|Main|
|''Description:''|TiddlyTools |
|''Type:''|TiddlyWiki|
|''URL:''|http://tiddlytools.com|
|''Workspace:''|Main|
|''Description:''|TiddlyVault |
|''Type:''|TiddlyWiki|
|''URL:''|http://tiddlyvault.tiddlyspot.com/|
|''Workspace:''|Main|
|''Description:''|Visual TW |
|''Type:''|tiddlywiki|
|''URL:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Workspace:''|Main|
|''Description:''|LocalccTiddly|
|''Type:''|cctiddly|
|''URL:''|http://127.0.0.1/Trunk/|
|''Workspace:''|martin|
|''Description:''|ROOT|
|''Type:''|tiddlywiki|
|''URL:''|http://www.andreanis.de/_tiddly/uploads/export.xml|
|''Workspace:''|Main|
|''Description:''|Life Stream |
|''Type:''|tiddlywiki|
|''URL:''|http://simonmcmanus.com|
|''image:''|http://127.0.0.1/simonmcmanustheme.jpg|
|''Workspace:''|Main|
|''Description:''|tiddlydocs|
|''Type:''|tiddlywiki|
|''URL:''|http://www.tiddlydocs.com/|
|''Workspace:'XXXX'|Main|
powerpape
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
major: 1, minor: 1, revision: 0,
date: new Date("mar 17, 2007"),
source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};
if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};
bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){
url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
}
return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
/***
|''Name''|ServerSideSavingPlugin|
|''Description''|server-side saving|
|''Author''|FND|
|''Version''|0.3.2|
|''Status''|@@experimental@@|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/ServerSideSavingPlugin.js|
|''License''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''Requires''|[[ServerConfig]]|
|''Keywords''|serverSide|
!Notes
This plugin relies on a dedicated configuration plugin to be present.
The specific nature of this plugins depends on the respective server.
!Revision History
!!v0.1 (2008-11-24)
* initial release
!!v0.2 (2008-12-01)
* added support for local saving
!!v0.3 (2008-12-03)
* added Save to Web macro for manual synchronization
!To Do
* conflict detection/resolution
* rename to ServerLinkPlugin?
* attempt to determine default adaptor (and defaultCustomFields) from systemServer tiddlers
* handle deleting/renaming (e.g. by hijacking the respective commands and creating a log)
!Code
***/
//{{{
if(!version.extensions.ServerSideSavingPlugin) { //# ensure that the plugin is only installed once
version.extensions.ServerSideSavingPlugin = { installed: true };
if(!config.extensions) { config.extensions = {}; } //# obsolete from v2.4.2
(function(plugin) { //# set up alias
if(!plugin || !plugin.adaptor) {
throw "Missing dependency: ServerConfig";
}
plugin = {
adaptor: plugin.adaptor, //# N.B.: expects config.extensions.ServerSideSavingPlugin.adaptor to be set
locale: {
saved: "%0 saved successfully",
saveError: "Error saving %0: %1",
deleted: "Removed %0",
deleteError: "Error removing %0: %1",
deleteLocalError: "Error removing %0 locally",
removedNotice: "This tiddler has been deleted."
},
sync: function() {
store.forEachTiddler(function(title, tiddler) {
if(tiddler.fields.deleted) {
plugin.removeTiddler(tiddler);
} else if(tiddler.isTouched() && tiddler.getServerType() && tiddler.fields["server.host"]) {
plugin.saveTiddler(tiddler);
}
});
},
saveTiddler: function(tiddler) {
var adaptor = new this.adaptor();
var context = {
tiddler: tiddler,
changecount: tiddler.fields.changecount
};
context.workspace = tiddler.fields["server.workspace"];
var req = adaptor.putTiddler(tiddler, context, {}, this.saveTiddlerCallback);
return req ? tiddler : false;
},
saveTiddlerCallback: function(context, userParams) {
var tiddler = context.tiddler;
if(context.status) {
if(tiddler.fields.changecount == context.changecount) { //# check for changes since save was triggered
tiddler.clearChangeCount();
} else if(tiddler.fields.changecount > 0) {
tiddler.fields.changecount -= context.changecount;
}
displayMessage(plugin.locale.saved.format([tiddler.title]));
store.setDirty(false);
} else {
displayMessage(plugin.locale.saveError.format([tiddler.title, context.statusText]));
}
},
removeTiddler: function(tiddler) {
var adaptor = new this.adaptor();
context = { tiddler: tiddler };
context.workspace = tiddler.fields["server.workspace"];
var req = adaptor.deleteTiddler(tiddler, context, {}, this.removeTiddlerCallback);
return req ? tiddler : false;
},
removeTiddlerCallback: function(context, userParams) {
var tiddler = context.tiddler;
if(context.status) {
if(tiddler.fields.deleted) {
store.deleteTiddler(tiddler.title);
} else {
displayMessage(plugin.locale.deleteError.format([tiddler.title]));
}
displayMessage(plugin.locale.deleted.format([tiddler.title]));
store.setDirty(false);
} else {
displayMessage(plugin.locale.deleteLocalError.format([tiddler.title, context.statusText]));
}
}
};
config.macros.saveToWeb = { // XXX: hijack existing sync macro?
locale: {
btnLabel: "save to web",
btnTooltip: "synchronize changes",
btnAccessKey: null
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
createTiddlyButton(place, this.locale.btnLabel, this.locale.btnTooltip,
plugin.sync, null, null, this.locale.btnAccessKey);
}
};
// hijack saveChanges to trigger remote saving
plugin.saveChanges = saveChanges;
saveChanges = function(onlyIfDirty, tiddlers) {
if(window.location.protocol == "file:") {
plugin.saveChanges.apply(this, arguments);
} else {
plugin.sync();
}
};
// override removeTiddler to flag tiddler as deleted
TiddlyWiki.prototype.removeTiddler = function(title) { // XXX: should override deleteTiddler instance method?
var tiddler = this.fetchTiddler(title);
if(tiddler) {
tiddler.tags = ["excludeLists", "excludeSearch", "excludeMissing"];
tiddler.text = plugin.locale.removedNotice;
tiddler.fields.deleted = true; // XXX: rename to removed/tiddlerRemoved?
tiddler.incChangeCount();
this.notify(title, true);
this.setDirty(true);
}
};
})(config.extensions.ServerSideSavingPlugin); //# end of alias
// override saveTiddler to fix core bug (ticket #769) -- XXX: to be fixed in TiddlyWiki v2.4.2
Story.prototype.saveTiddler = function(title,minorUpdate)
{
var tiddlerElem = this.getTiddler(title);
if(tiddlerElem) {
var fields = {};
this.gatherSaveFields(tiddlerElem,fields);
var newTitle = fields.title || title;
if(!store.tiddlerExists(newTitle))
newTitle = newTitle.trim();
if(store.tiddlerExists(newTitle) && newTitle != title) {
if(!confirm(config.messages.overwriteWarning.format([newTitle.toString()])))
return null;
}
if(newTitle != title)
this.closeTiddler(newTitle,false);
tiddlerElem.id = this.tiddlerId(newTitle);
tiddlerElem.setAttribute("tiddler",newTitle);
tiddlerElem.setAttribute("template",DEFAULT_VIEW_TEMPLATE);
tiddlerElem.setAttribute("dirty","false");
if(config.options.chkForceMinorUpdate)
minorUpdate = !minorUpdate;
if(!store.tiddlerExists(newTitle))
minorUpdate = false;
var newDate = new Date();
var extendedFields = store.tiddlerExists(newTitle) ? store.fetchTiddler(newTitle).fields : (newTitle!=title && store.tiddlerExists(title) ? store.fetchTiddler(title).fields : merge({},config.defaultCustomFields));
for(var n in fields) {
if(!TiddlyWiki.isStandardField(n))
extendedFields[n] = fields[n];
}
var tiddler = store.saveTiddler(title,newTitle,fields.text,minorUpdate ? undefined : config.options.txtUserName,minorUpdate ? undefined : newDate,fields.tags,extendedFields);
autoSaveChanges(null,[tiddler]);
return newTitle;
}
return null;
};
} //# end of "install only once"
//}}}
/***
|Name|TaggedTemplateTweak|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Documentation|http://www.TiddlyTools.com/#TaggedTemplateTweakInfo|
|Version|1.4.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.chooseTemplateForTiddler()|
|Description|use alternative ViewTemplate/EditTemplate for tiddler's tagged with specific tag values|
This tweak extends story.chooseTemplateForTiddler() so that ''whenever a tiddler is marked with a specific tag value, it can be viewed and/or edited using alternatives to the standard tiddler templates.''
!!!!!Documentation
>see [[TaggedTemplateTweakInfo]]
!!!!!Revisions
<<<
2008.08.29 [1.4.1] corrected handling for tiddlers with no matching tagged template when non-default theme is in effect (e.g., use "MyTheme##ViewTemplate").
| please see [[TaggedTemplateTweakInfo]] for previous revision details |
2007.06.11 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TaggedTemplateTweak= {major: 1, minor: 4, revision: 1, date: new Date(2008,8,29)};
Story.prototype.taggedTemplate_chooseTemplateForTiddler = Story.prototype.chooseTemplateForTiddler
Story.prototype.chooseTemplateForTiddler = function(title,template)
{
// get default template from core
var coreTemplate=this.taggedTemplate_chooseTemplateForTiddler.apply(this,arguments);
// if the tiddler doesn't exist yet or is untagged, return core result
var tiddler=store.getTiddler(title);
if (!tiddler || !tiddler.tags.length)
return coreTemplate;
// split core template into theme prefix and template name
var theme="";
var template=coreTemplate;
var parts=template.split(config.textPrimitives.sectionSeparator);
if (parts[1]) { theme=parts[0]; template=parts[1]; }
else theme=config.options.txtTheme||""; // fallback if theme is not specified
theme+=config.textPrimitives.sectionSeparator;
// look for template whose prefix matches a tag on this tiddler (if any)
for (i=0; i<tiddler.tags.length; i++) {
var t=tiddler.tags[i]+template; // add tag prefix to template
var c=t.substr(0,1).toUpperCase()+t.substr(1); // capitalized for WikiWord title
if (store.getTiddlerText(theme+t)) { return theme+t; } // theme##tagTemplate
if (store.getTiddlerText(theme+c)) { return theme+c; } // theme##TagTemplate
if (store.getTiddlerText(t)) { return t; } // tagTemplate
if (store.getTiddlerText(c)) { return c; } // TagTemplate
}
return coreTemplate; // no matching tag, return core result
}
//}}}
config.macros.taggedTabs={};
config.macros.taggedTabs.handler=function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
var params = paramString.parseParams("taggedTabset",null,true,false,false);
var tagged = store.getTaggedTiddlers(params[1].value,"title").reverse();
var cookie = "taggedTabs";
var wrapper = createTiddlyElement(null,"div",null,"tabsetWrapper taggedTabset" + cookie);
var tabset = createTiddlyElement(wrapper,"div",null,"tabset");
var validTab = false;
tabset.setAttribute("cookie",cookie);
for(var t=0; t<tagged.length; t++) {
var label = tagged[t].title;
if(label=='ccLogin')
tabLabel = config.macros.ccLogin.buttonLogin;
else
tabLabel = label;
var prompt = tagged[t].title;
var tab = createTiddlyButton(tabset,tabLabel,prompt,config.macros.tabs.onClickTab,"tab tabUnselected");
tab.setAttribute("tab",label);
tab.setAttribute("content",label);
if(config.options[cookie] == label)
validTab = true;
}
if(!validTab)
config.options[cookie] = tagged[0].title;
place.appendChild(wrapper);
config.macros.tabs.switchTab(tabset, config.options[cookie]);
setStylesheet("div.tiddler .tab {font-size:1.2em; font-weight:bold;padding-left:2em; padding-right:2em; margin-left:0px; margin-right:1em; padding-bottom:2px}"+
"div.tiddler .wizard { margin:0px; }"+
" div.tabContents .wizard { margin:0px; }"+
".tabsetWrapper .wizard h1 {display:none}"+
".tabsetWrapper .wizard h2 {padding:0.5em}"+
".viewer {float:right; width:90%;}"+
"div.viewer div.tabsetWrapper{width:90%}"+
"a.tabSelected{ filter:'alpha(opacity:60)'; }"+
"div.tabset {padding:0px}"+
"div.tabContents {padding:0px; background:transparent}",
"taggedTabs");
};
//}}}
/***
|Name|TaggedTemplateTweak|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Documentation|http://www.TiddlyTools.com/#TaggedTemplateTweakInfo|
|Version|1.4.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.chooseTemplateForTiddler()|
|Description|use alternative ViewTemplate/EditTemplate for tiddler's tagged with specific tag values|
This tweak extends story.chooseTemplateForTiddler() so that ''whenever a tiddler is marked with a specific tag value, it can be viewed and/or edited using alternatives to the standard tiddler templates.''
!!!!!Documentation
>see [[TaggedTemplateTweakInfo]]
!!!!!Revisions
<<<
2008.08.29 [1.4.1] corrected handling for tiddlers with no matching tagged template when non-default theme is in effect (e.g., use "MyTheme##ViewTemplate").
| please see [[TaggedTemplateTweakInfo]] for previous revision details |
2007.06.11 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TaggedTemplateTweak= {major: 1, minor: 4, revision: 1, date: new Date(2008,8,29)};
Story.prototype.taggedTemplate_chooseTemplateForTiddler = Story.prototype.chooseTemplateForTiddler
Story.prototype.chooseTemplateForTiddler = function(title,template)
{
// get default template from core
var coreTemplate=this.taggedTemplate_chooseTemplateForTiddler.apply(this,arguments);
// if the tiddler doesn't exist yet or is untagged, return core result
var tiddler=store.getTiddler(title);
if (!tiddler || !tiddler.tags.length)
return coreTemplate;
// split core template into theme prefix and template name
var theme="";
var template=coreTemplate;
var parts=template.split(config.textPrimitives.sectionSeparator);
if (parts[1]) { theme=parts[0]; template=parts[1]; }
else theme=config.options.txtTheme||""; // fallback if theme is not specified
theme+=config.textPrimitives.sectionSeparator;
// look for template whose prefix matches a tag on this tiddler (if any)
for (i=0; i<tiddler.tags.length; i++) {
var t=tiddler.tags[i]+template; // add tag prefix to template
var c=t.substr(0,1).toUpperCase()+t.substr(1); // capitalized for WikiWord title
if (store.getTiddlerText(theme+t)) { return theme+t; } // theme##tagTemplate
if (store.getTiddlerText(theme+c)) { return theme+c; } // theme##TagTemplate
if (store.getTiddlerText(t)) { return t; } // tagTemplate
if (store.getTiddlerText(c)) { return c; } // TagTemplate
}
return coreTemplate; // no matching tag, return core result
}
powerpape
|~ViewToolbar|closeTiddler closeOthers +newChild newParent +editTiddler > fields -syncing permalink -revisions references jump|
|~EditToolbar|+saveTiddler copyTiddler -cancelTiddler deleteTiddlerHosted|
<div class='toolbar' macro='toolbar closeTiddler closeOthers'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
powerpape
// ccAdaptorCommandsPlugin //
function ccTiddlyAdaptor(){}
merge(ccTiddlyAdaptor,{
errorTitleNotSaved:"<h1>Your changes were NOT saved.</h1>",
errorTextSessionExpired:"Your Session has expired. <br /> You will need to log into the new window and then copy your changes from this window into the new window. ",
errorTextConfig:"There was a conflict when saving. <br /> Please open the page in a new window to see the changes.",
errorTextUnknown:"An unknown error occured.",
errorClose:"close",
buttonOpenNewWindow:"Open a Window where I can save my changes .... ",
buttonHideThisMessage:"Hide this message",
msgErrorCode:"Error Code : "
});
if(!config.extensions) { config.extensions = {}; } //# obsolete from v2.4.2
config.extensions.ServerSideSavingPlugin = {
adaptor: config.adaptors.cctiddly
};
//{{{
config.commands.revisions = {};
merge(config.commands.revisions,{
text: "revisions",
tooltip: "View another revision of this tiddler",
loading: "loading...",
done: "Revision downloaded",
revisionTooltip: "View this revision",
popupNone: "No revisions",
revisionTemplate: "%0 r:%1 m:%2",
dateFormat:"YYYY mmm 0DD 0hh:0mm"
});
config.commands.deleteTiddlerHosted = {};
merge(config.commands.deleteTiddlerHosted,{
text: "delete",
tooltip: "Delete this tiddler",
warning: "Are you sure you want to delete '%0'?",
hideReadOnly: true,
done: "Deleted "
});
// Ensure that the plugin is only installed once.
if(!version.extensions.AdaptorCommandsPlugin) {
version.extensions.AdaptorCommandsPlugin = {installed:true};
// implementing closeTiddler without the clearMessage();
Story.prototype.closeTiddler = function(title,animate,unused)
{
var tiddlerElem = this.getTiddler(title);
if(tiddlerElem) {
this.scrubTiddler(tiddlerElem);
if(config.options.chkAnimate && animate && anim && typeof Slider == "function")
anim.startAnimating(new Slider(tiddlerElem,false,null,"all"));
else {
removeNode(tiddlerElem);
forceReflow();
}
}
};
function getServerType(fields)
{
if(!fields)
return null;
var serverType = fields['server.type'];
if(!serverType)
serverType = fields['wikiformat'];
if(!serverType)
serverType = config.defaultCustomFields['server.type'];
if(!serverType && typeof RevisionAdaptor != 'undefined' && fields.uuid)
serverType = RevisionAdaptor.serverType;
return serverType;
}
function invokeAdaptor(fnName,param1,param2,context,userParams,callback,fields)
{
var serverType = getServerType(fields);
if(!serverType)
return null;
var adaptor = new config.adaptors[serverType];
if(!adaptor)
return false;
if(!config.adaptors[serverType].prototype[fnName])
return false;
adaptor.openHost(fields['server.host']);
adaptor.openWorkspace(fields['server.workspace']);
var ret = false;
if(param1)
ret = param2 ? adaptor[fnName](param1,param2,context,userParams,callback) : adaptor[fnName](param1,context,userParams,callback);
else
ret = adaptor[fnName](context,userParams,callback);
return ret;
}
//# Returns true if function fnName is available for the serverType specified in fields
//# Used by (eg): config.commands.download.isEnabled
function isAdaptorFunctionSupported(fnName,fields)
{
var serverType = getServerType(fields);
if(!serverType || !config.adaptors[serverType])
return false;
if(!config.adaptors[serverType].isLocal && !fields['server.host'])
return false;
var fn = config.adaptors[serverType].prototype[fnName];
return fn ? true : false;
}
config.commands.revisions.isEnabled = function(tiddler)
{
return isAdaptorFunctionSupported('getTiddlerRevisionList',tiddler.fields);
};
config.commands.revisions.handler = function(event,src,title)
{
var tiddler = store.fetchTiddler(title);
userParams = {};
userParams.tiddler = tiddler;
userParams.src = src;
userParams.dateFormat = config.commands.revisions.dateFormat;
var revisionLimit = 10;
if(!invokeAdaptor('getTiddlerRevisionList',title,revisionLimit,null,userParams,config.commands.revisions.callback,tiddler.fields))
return false;
event.cancelBubble = true;
if(event.stopPropagation)
event.stopPropagation();
return true;
};
config.commands.revisions.callback = function(context,userParams)
// The revisions are returned as tiddlers in the context.revisions array
{
var revisions = context.revisions;
popup = Popup.create(userParams.src);
Popup.show(popup,false);
if(revisions.length==0) {
createTiddlyText(createTiddlyElement(popup,'li',null,'disabled'),config.commands.revisions.popupNone);
} else {
revisions.sort(function(a,b) {return a.modified < b.modified ? +1 : -1;});
for(var i=0; i<revisions.length; i++) {
var tiddler = revisions[i];
var modified = tiddler.modified.formatString(context.dateFormat||config.commands.revisions.dateFormat);
var revision = tiddler.fields['server.page.revision'];
var btn = createTiddlyButton(createTiddlyElement(popup,'li'),
config.commands.revisions.revisionTemplate.format([modified,revision,tiddler.modifier]),
tiddler.text||config.commands.revisions.revisionTooltip,
function() {
config.commands.revisions.getTiddlerRevision(this.getAttribute('tiddlerTitle'),this.getAttribute('tiddlerModified'),this.getAttribute('tiddlerRevision'),this);
return false;
},
'tiddlyLinkExisting tiddlyLink');
btn.setAttribute('tiddlerTitle',userParams.tiddler.title);
btn.setAttribute('tiddlerRevision',revision);
btn.setAttribute('tiddlerModified',tiddler.modified.convertToYYYYMMDDHHMM());
if(userParams.tiddler.fields['server.page.revision'] == revision || (!userParams.tiddler.fields['server.page.revision'] && i==0))
btn.className = 'revisionCurrent';
}
}
};
config.commands.revisions.getTiddlerRevision = function(title,modified,revision)
{
var tiddler = store.fetchTiddler(title);
var context = {modified:modified};
return invokeAdaptor('getTiddlerRevision',title,revision,context,null,config.commands.revisions.getTiddlerRevisionCallback,tiddler.fields);
};
config.commands.revisions.getTiddlerRevisionCallback = function(context,userParams)
{
if(context.status) {
var tiddler = context.tiddler;
store.addTiddler(tiddler);
store.notify(tiddler.title, true);
story.refreshTiddler(tiddler.title,1,true);
} else {
displayMessage(context.statusText);
}
};
config.commands.deleteTiddlerHosted.handler = function(event,src,title)
{
var tiddler = store.fetchTiddler(title);
if(!tiddler)
return false;
var deleteIt = true;
if(config.options.chkConfirmDelete)
deleteIt = confirm(this.warning.format([title]));
if(deleteIt) {
var ret = invokeAdaptor('deleteTiddler',title,null,null,null,config.commands.deleteTiddlerHosted.callback,tiddler.fields);
if(ret){
store.removeTiddler(title);
story.closeTiddler(title,true);
}
}
return false;
};
config.commands.deleteTiddlerHosted.callback = function(context,userParams)
{
if(context.status) {
displayMessage(config.commands.deleteTiddlerHosted.done + context.title);
} else {
if (context.statusText.indexOf("Not Found") == -1)
displayMessage(context.statusText);
}
};
}//# end of 'install only once'
//}}}
// ccAdaptor //
//{{{
window.isLoggedIn = function(){
return (window.loggedIn == '1')
}
ccTiddlyAdaptor.prototype = new AdaptorBase();
ccTiddlyAdaptor.mimeType = 'application/json';
ccTiddlyAdaptor.serverType = 'cctiddly'; // MUST BE LOWER CASE
ccTiddlyAdaptor.serverParsingErrorMessage = "Error parsing result from server";
ccTiddlyAdaptor.errorInFunctionMessage = "Error in function ccTiddlyAdaptor.%0";
ccTiddlyAdaptor.minHostName = function(host){
return host ? host.replace(/^http:\/\//,'').replace(/\/$/,'') : '';
};
// Convert a page title to the normalized form used in uris
ccTiddlyAdaptor.normalizedTitle = function(title){
return title;
};
// Convert a date in YYYY-MM-DD hh:mm format into a JavaScript Date object
ccTiddlyAdaptor.dateFromEditTime = function(editTime){
var dt = editTime;
return new Date(Date.UTC(dt.substr(0,4),dt.substr(5,2)-1,dt.substr(8,2),dt.substr(11,2),dt.substr(14,2)));
};
ccTiddlyAdaptor.prototype.login = function(context,userParams,callback){
if(window.location.search.substring(1))
var uriParams = window.location.search.substring(1);
else
var uriParams = "";
context = this.setContext(context,userParams,callback);
var uriTemplate = '%0/handle/loginFile.php?cctuser=%1&cctpass=%2&'+uriParams;
var uri = uriTemplate.format([context.host,context.username,context.password]);
var req = httpReq('GET',uri,ccTiddlyAdaptor.loginCallback,context);
return typeof req == 'string' ? req : true;
};
ccTiddlyAdaptor.loginCallback = function(status,context,responseText,uri,xhr){
if(xhr.status==401){
context.status = false;
}else{
context.status = true;
var c='sessionToken'+"="+responseText;
c+="; expires=Fri, 1 Jan 2811 12:00:00 UTC; host=*";
document.cookie=c;
}
if(context.callback)
context.callback(context,context.userParams);
};
ccTiddlyAdaptor.prototype.register = function(context,userParams,callback){
context = this.setContext(context,userParams,callback);
var uriTemplate = '%0/handle/register.php';
var uri = uriTemplate.format([context.host,context.username,Crypto.hexSha1Str(context.password)]);
var dataTemplate = 'username=&0®_mail=%1&password=%2&password2=%3';
var data = dataTemplate.format([context.username,context.password1,context.password2]);
var req = httpReq('POST', uri,ccTiddlyAdaptor.registerCallback,context,null,data);
return typeof req == 'string' ? req : true;
};
ccTiddlyAdaptor.prototype.rename = function(context, userParams, callback){
if(window.location.search.substring(1))
var postParams = "&"+window.location.search.substring(1);
else
var postParams = "";
context = this.setContext(context,userParams,callback);
var uri = window.url+"handle/renameTiddler.php?otitle="+context.title+"&ntitle="+context.newTitle+"&workspace="+window.workspace+postParams;;
httpReq('POST', uri,ccTiddlyAdaptor.renameCallback,context,null,null);
};
ccTiddlyAdaptor.renameCallback = function(status,context,responseText,uri,xhr){
if(context.callback)
context.callback(context,context.userParams);
};
ccTiddlyAdaptor.registerCallback = function(status,context,responseText,uri,xhr){
if(status){
context.status = true;
}else{
context.status = false;
}
if(context.callback)
context.callback(context,context.userParams);
};
ccTiddlyAdaptor.prototype.getWorkspaceList = function(context,userParams,callback){
context = this.setContext(context,userParams,callback);
var uriTemplate = '%0/handle/listWorkspaces.php';
var uri = uriTemplate.format([context.host]);
var req = httpReq('GET', uri,ccTiddlyAdaptor.getWorkspaceListCallback,context,{'accept':'application/json'});
return typeof req == 'string' ? req : true;
};
ccTiddlyAdaptor.getWorkspaceListCallback = function(status,context,responseText,uri,xhr){
context.status = false;
context.workspaces = [];
context.statusText = ccTiddlyAdaptor.errorInFunctionMessage.format(['getWorkspaceListCallback']);
if(status){
try{
eval('var workspaces=' + responseText);
}catch (ex){
context.statusText = exceptionText(ex,ccTiddlyAdaptor.serverParsingErrorMessage);
if(context.callback)
context.callback(context,context.userParams);
return;
}
for (var i=0; i < workspaces.length; i++){
context.workspaces.push({title:workspaces[i]})
}
context.status = true;
}else{
context.statusText = xhr.statusText;
}
if(context.callback)
context.callback(context,context.userParams);
};
ccTiddlyAdaptor.prototype.getTiddlerList = function(context,userParams,callback){
context = this.setContext(context,userParams,callback);
var uriTemplate = '%0/handle/listTiddlers.php?workspace=%1';
var uri = uriTemplate.format([context.host,context.workspace]);
var req = httpReq('GET', uri,ccTiddlyAdaptor.getTiddlerListCallback,context,{'accept':'application/json'});
return typeof req == 'string' ? req : true;
};
ccTiddlyAdaptor.getTiddlerListCallback = function(status,context,responseText,uri,xhr){
context.status = false;
context.statusText = ccTiddlyAdaptor.errorInFunctionMessage.format(['getTiddlerListCallback']);
if(status){
try{
eval('var tiddlers=' + responseText);
}catch (ex){
context.statusText = exceptionText(ex,ccTiddlyAdaptor.serverParsingErrorMessage);
if(context.callback)
context.callback(context,context.userParams);
return;
}
var list = [];
for(var i=0; i < tiddlers.length; i++){
var tiddler = new Tiddler(tiddlers[i]['title']);
tiddler.fields['server.page.revision'] = tiddlers[i]['revision'];
list.push(tiddler);
}
context.tiddlers = list;
context.status = true;
}else{
context.statusText = xhr.statusText;
}
if(context.callback)
context.callback(context,context.userParams);
};
ccTiddlyAdaptor.prototype.generateTiddlerInfo = function(tiddler){
var info ={};
var host = this && this.host ? this.host : this.fullHostName(tiddler.fields['server.host']);
var bag = tiddler.fields['server.bag']
var workspace = tiddler.fields['server.workspace']
var uriTemplate = '%0/%1/#%2';
info.uri = uriTemplate.format([host,workspace,tiddler.title]);
return info;
};
ccTiddlyAdaptor.prototype.getTiddlerRevision = function(title,revision,context,userParams,callback){
context = this.setContext(context,userParams,callback);
if(revision)
context.revision = revision;
return this.getTiddler(title,context,userParams,callback);
};
ccTiddlyAdaptor.prototype.getTiddler = function(title,context,userParams,callback){
context = this.setContext(context,userParams,callback);
if(title)
context.title = title;
if(context.revision){
var uriTemplate = '%0/handle/revisionDisplay.php?title=%2&workspace=%1&revision=%3';
}else{
var uriTemplate = '%0/handle/getTiddler.php?title=%2&workspace=%1';
}
uri = uriTemplate.format([context.host,context.workspace,ccTiddlyAdaptor.normalizedTitle(title),context.revision]);
context.tiddler = new Tiddler(title);
context.tiddler.fields['server.type'] = ccTiddlyAdaptor.serverType;
context.tiddler.fields['server.host'] = ccTiddlyAdaptor.minHostName(context.host);
context.tiddler.fields['server.workspace'] = context.workspace;
var req = httpReq('GET', uri,ccTiddlyAdaptor.getTiddlerCallback,context,{'accept':'application/json'});
return typeof req == 'string' ? req : true;
};
ccTiddlyAdaptor.getTiddlerCallback = function(status,context,responseText,uri,xhr){
context.status = false;
context.statusText = ccTiddlyAdaptor.errorInFunctionMessage.format(['getTiddlerCallback']);
if(status){
var info=[]
try{
eval('info=' + responseText);
}catch (ex){
context.statusText = exceptionText(ex,ccTiddlyAdaptor.serverParsingErrorMessage);
if(context.callback)
context.callback(context,context.userParams);
return;
}
context.tiddler.text = info['text'];
context.tiddler.tags = info['tags'].split(" ");
context.tiddler.fields['server.page.revision'] = info['server.page.revision'];
context.tiddler.fields['server.id'] = info['id'];
context.tiddler.fields = merge(info['fields'], context.tiddler.fields);
context.tiddler.modifier = info['modifier'];
context.tiddler.modified = Date.convertFromYYYYMMDDHHMM(info['modified']);
context.tiddler.created = Date.convertFromYYYYMMDDHHMM(info['created']);
context.status = true;
}else{
context.statusText = xhr.statusText;
if(context.callback)
context.callback(context,context.userParams);
return;
}
if(context.callback)
context.callback(context,context.userParams);
};
ccTiddlyAdaptor.prototype.getTiddlerRevisionList = function(title,limit,context,userParams,callback){
context = this.setContext(context,userParams,callback);
context.title = title;
context.revisions = [];
var tiddler = store.fetchTiddler(title);
var encodedTitle = encodeURIComponent(title);
var uriTemplate = '%0/handle/revisionList.php?workspace=%1&title=%2';
var host = this.fullHostName(this.host);
var workspace = context.workspace ? context.workspace : tiddler.fields['server.workspace'];
var uri = uriTemplate.format([host,workspace,encodedTitle]);
var req = httpReq('GET', uri,ccTiddlyAdaptor.getTiddlerRevisionListCallback,context);
};
ccTiddlyAdaptor.getTiddlerRevisionListCallback = function(status,context,responseText,uri,xhr){
if(responseText.indexOf('<!DOCTYPE html')==1)
status = false;
if(xhr.status=="204")
status = false;
context.status = false;
if(status){
var r = responseText;
if(r != '-' && r.trim() != 'revision not found'){
var revs = r.split('\n');
for(var i=0; i<revs.length; i++){
var parts = revs[i].split(' ');
if(parts.length>1){
var tiddler = new Tiddler(context.title);
tiddler.modified = Date.convertFromYYYYMMDDHHMM(parts[0]);
tiddler.fields['server.page.revision'] = String(parts[1]);
tiddler.modifier = String(parts[2]);
tiddler.fields['server.host'] = ccTiddlyAdaptor.minHostName(context.host);
tiddler.fields['server.type'] = ccTiddlyAdaptor.serverType;
context.revisions.push(tiddler);
}
}
}
context.revisions.sort(function(a,b){return a.modified<b.modified?+1:-1;});
context.status = true;
}else{
context.statusText = xhr.statusText;
}
if(context.callback)
context.callback(context,context.userParams);
};
ccTiddlyAdaptor.prototype.putTiddler = function(tiddler,context,userParams,callback){
context = this.setContext(context,userParams,callback);
context.title = tiddler.title;
if(window.location.search.substring(1))
var postParams = window.location.search.substring(1);
else
var postParams = "";
var recipeuriTemplate = '%0/handle/save.php';
var host = context.host ? context.host : this.fullHostName(tiddler.fields['server.host']);
var uri = recipeuriTemplate.format([host,context.workspace,tiddler.title]);
var d = new Date();
d.setTime(Date.parse(tiddler['modified']));
d = d.convertToYYYYMMDDHHMM();
// SEO Code
if(workspace)
var breaker = "/";
else
var breaker = "";
var el = createTiddlyElement(document.body, "div", "ccTiddlyTMP", null, null, { "style.display": "none" });
el.style.display = "none"; // Just in case the above command is ignored
var formatter = new Formatter(config.formatters);
var wikifier = new Wikifier(tiddler.text,formatter,null,tiddler);
wikifier.isStatic = true;
wikifier.subWikify(el);
delete formatter;
var links = el.getElementsByTagName("a");
for(var i = 0; i < links.length; i++) {
var tiddlyLink = links[i].getAttribute("tiddlyLink");
if(tiddlyLink) {
if(hasClass(links[i], "tiddlyLinkNonExisting")) { // target tiddler does not exist
links[i].href = "#";
} else {
links[i].href = url+ workspace + breaker +tiddlyLink + ".html";
}
}
}
// End SEO Code
var fieldString = "";
for (var name in tiddler.fields){
if (String(tiddler.fields[name]) && name != "server.page.revision" && name != "changecount")
fieldString += name +"='"+tiddler.fields[name]+"' ";
}
if(!tiddler.fields['server.page.revision'])
tiddler.fields['server.page.revision'] = 0;
else
tiddler.fields['server.page.revision'] = parseInt(tiddler.fields['server.page.revision'],10);
context.revision = tiddler.fields['server.page.revision'];
if(!context.otitle)
var otitle = tiddler.title;
else
var otitle = context.otitle;
var payload = "workspace="+window.workspace+"&otitle="+encodeURIComponent(otitle)+"&title="+encodeURIComponent(tiddler.title) + "&modified="+tiddler.modified.convertToYYYYMMDDHHMM()+"&modifier="+tiddler.modifier + "&tags="+encodeURIComponent(tiddler.getTags())+"&revision="+encodeURIComponent(tiddler.fields['server.page.revision']) + "&fields="+encodeURIComponent(fieldString)+
"&body="+encodeURIComponent(tiddler.text)+"&wikifiedBody="+encodeURIComponent(el.innerHTML)+"&id="+tiddler.fields['server.id']+"&"+postParams;
var req = httpReq('POST', uri,ccTiddlyAdaptor.putTiddlerCallback,context,{'Content-type':'application/x-www-form-urlencoded', "Content-length": payload.length},payload,"application/x-www-form-urlencoded");
return typeof req == 'string' ? req : true;
};
ccTiddlyAdaptor.putTiddlerCallback = function(status,context,responseText,uri,xhr){
if(xhr.status != 201){
ccTiddlyAdaptor.handleError(xhr.status);
}else{
context.status = true;
if(responseText!="") {
context.tiddler.fields['server.id'] = responseText;
}
context.tiddler.fields['server.page.revision'] = context.revision + 1;
}
if(context.callback){
context.callback(context,context.userParams);
}
};
ccTiddlyAdaptor.center = function(el){
var size = this.getsize(el);
el.style.left = (Math.round(findWindowWidth()/2) - (size.width /2) + findScrollX())+'px';
el.style.top = (Math.round(findWindowHeight()/2) - (size.height /2) + findScrollY())+'px';
}
ccTiddlyAdaptor.getsize = function (el){
var x ={};
x.width = el.offsetWidth || el.style.pixelWidth;
x.height = el.offsetHeight || el.style.pixelHeight;
return x;
}
ccTiddlyAdaptor.showCloak = function(){
var cloak = document.getElementById('backstageCloak');
if (config.browser.isIE){
cloak.style.height = Math.max(document.documentElement.scrollHeight,document.documentElement.offsetHeight);
cloak.style.width = document.documentElement.scrollWidth;
}
cloak.style.display = "block";
}
ccTiddlyAdaptor.hideError = function(){
var box = document.getElementById('errorBox');
box.parentNode.removeChild(box);
document.getElementById('backstageCloak').style.display = "";
}
ccTiddlyAdaptor.handleError = function(error_code){
setStylesheet(
"#errorBox .button{padding:0.5em 1em; border:1px solid #222; background-color:#ccc; color:black; margin-right:1em;}\n"+
"html > body > #backstageCloak{height:100%;}"+
"#errorBox{border:1px solid #ccc;background-color: #eee; color:#111;padding:1em 2em; z-index:9999;}",'errorBoxStyles');
var box = document.getElementById('errorBox') || createTiddlyElement(document.body,'div','errorBox');
var error = ccTiddlyAdaptor.errorTitleNotSaved;
switch(error_code){
case 401:
error += ccTiddlyAdaptor.errorTextSessionExpired;
break;
case 409:
error += "\n\n"+ccTiddlyAdaptor.errorTextConfig+"\n \n error code : "+error_code+" \n";
break;
default:
error += ccTiddlyAdaptor.errorTextUnknown+"<br />"+error_code;
}
box.innerHTML = " <a style='float:right' href='javascript:onclick=ccTiddlyAdaptor.hideError()'>"+ccTiddlyAdaptor.errorClose+"</a><p>"+error+"</p><br/><br/>";
createTiddlyButton(box,ccTiddlyAdaptor.buttonOpenNewWindow,null,function(e){ window.open (window.location,"mywindow"); return false;});
createTiddlyElement(box,"br");
createTiddlyElement(box,"br");
createTiddlyButton(box,ccTiddlyAdaptor.buttonHideThisMessage,null,function(){ccTiddlyAdaptor.hideError();});
box.style.position = 'absolute';
ccTiddlyAdaptor.center(box);
ccTiddlyAdaptor.showCloak();
}
ccTiddlyAdaptor.prototype.deleteTiddler = function(title,context,userParams,callback){
context = this.setContext(context,userParams,callback);
context.title = title;
title = encodeURIComponent(title);
var uri = tiddler.fields['server.host']+'/handle/delete.php'
var data = "workspace="+workspace+"&title="+title;
var req = httpReq('POST', uri,ccTiddlyAdaptor.deleteTiddlerCallback,context, null, data);
return typeof req == 'string' ? req : true;
};
ccTiddlyAdaptor.deleteTiddlerCallback = function(status,context,responseText,uri,xhr){
if(status){
context.status = true;
}else{
context.status = false;
context.statusText = xhr.statusText;
}
if(context.callback)
context.callback(context,context.userParams);
};
config.adaptors[ccTiddlyAdaptor.serverType] = ccTiddlyAdaptor;
//}}}
//}}}
//{{{
// ccAbout //
config.macros.ccAbout={};
config.macros.ccAbout.handler=function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
var w = new Wizard();
var me = config.macros.ccAbout;
w.createWizard(place,me.stepAboutTitle);
w.addStep(null, me.stepAboutTextStart + window.ccTiddlyVersion + "<br /><br />" + me.stepAboutTextEnd);
};
//}}}
// ccAdmin //
//{{{
config.macros.ccAdmin = {}
config.macros.ccAdmin.handler = function(place,macroName,params,wikifier,paramString,tiddler, errorMsg){
var w = new Wizard();
w.createWizard(place,config.macros.ccAdmin.WizardTitleText);
config.macros.ccAdmin.refresh(w);
};
config.macros.ccAdmin.refresh= function(w){
params = {};
params.w = w;
params.e = this;
me = config.macros.ccAdmin;
doHttp('POST',url+'/handle/workspaceAdmin.php','action=LISTALL&workspace='+workspace,null,null,null,config.macros.ccAdmin.listAllCallback,params);
w.setButtons([
{caption: me.buttonDeleteText, tooltip: me.buttonDeleteTooltip, onClick: function(w){
config.macros.ccAdmin.delAdminSubmit(null, params);
return false;
}},
{caption: me.buttonAddText, tooltip: me.buttonAddTooltip, onClick: function(w){
config.macros.ccAdmin.addAdminDisplay(null, params); return false } }]);
};
config.macros.ccAdmin.delAdminSubmit = function(e, params){
var listView = params.w.getValue("listView");
var rowNames = ListView.getSelectedRows(listView);
var delUsers = "";
for(var e=0; e < rowNames.length; e++)
delUsers += rowNames[e]+",";
doHttp('POST',url+'/handle/workspaceAdmin.php','action=DELETEADMIN&username='+delUsers+'&workspace='+workspace,null,null,null,config.macros.ccAdmin.addAdminCallback,params);
return false;
};
config.macros.ccAdmin.addAdminDisplay = function(e, params){
doHttp('POST',url+'/handle/workspaceAdmin.php','action=LISTWORKSPACES',null,null,null,config.macros.ccAdmin.listWorkspaces,params);
};
config.macros.ccAdmin.listWorkspaces = function(status,params,responseText,uri,xhr){
var frm = createTiddlyElement(null,'form',null,null);
var me = config.macros.ccAdmin;
frm.onsubmit = config.macros.ccAdmin.addAdminSubmit;
params.w.addStep(me.stepAddTitle,"<input type='hidden' name='admin_placeholder'/>"+me.labelUsername+"<input name=adminUsername><br />"+me.labelWorkspace+"<select name=workspaceName />");
var workspaces = eval('[ '+responseText+' ]');
for(var t=0; t<workspaces.length; t++) {
var o = createTiddlyElement(params.w.formElem.workspaceName, "option", null, null, workspaces[t]);
o.value=workspaces[t];
if(workspaces[t] == workspace)
o.selected = true;
}
params.w.formElem.admin_placeholder.parentNode.appendChild(frm);
params.w.setButtons([
{caption: me.buttonCancelText, tooltip: me.buttonCancelTooltip, onClick: function(w){ config.macros.ccAdmin.refresh(params.w) } },
{caption: me.buttonCreateText, tooltip: me.buttonCreateTooltip, onClick: function(){config.macros.ccAdmin.addAdminSubmit(null, params); } }
]);
};
config.macros.ccAdmin.addAdminSubmit = function(e, params){
doHttp('POST',url+'/handle/workspaceAdmin.php','&add_username='+params.w.formElem.adminUsername.value+'&action=addNew&workspace='+params.w.formElem.workspaceName[params.w.formElem.workspaceName.selectedIndex].value,null,null,null,config.macros.ccAdmin.addAdminCallback,params);
return false;
};
config.macros.ccAdmin.listAllCallback = function(status,params,responseText,uri,xhr) {
var me = config.macros.ccAdmin;
var out = "";
var adminUsers = [];
if(xhr.status == 403){
var html ='';
params.w.addStep(me.stepErrorText+workspace, me.stepErrorTitle);
params.w.setButtons([]);
return false;
}
try{
var a = eval(responseText);
for(var e=0; e < a.length; e++){
out += a[e].username;
adminUsers.push({
name: a[e].username,
lastVisit:a[e].lastVisit});
}
}catch(ex){
params.w.addStep(" "+workspace, me.stepNoAdminTitle);
params.w.setButtons([
{caption: me.buttonCreateText, tooltip: me.buttonCreateTooltip, onClick: function(){ config.macros.ccAdmin.addAdminDisplay(null, params)}}]);
return false;
}
var html ='<input type="hidden" name="markList"></input>';
params.w.addStep(me.stepManageWorkspaceTitle+workspace, html);
var markList = params.w.getElement("markList");
var listWrapper = document.createElement("div");
markList.parentNode.insertBefore(listWrapper,markList);
var listView = ListView.create(listWrapper,adminUsers,config.macros.ccAdmin.listAdminTemplate);
params.w.setValue("listView",listView);
};
config.macros.ccAdmin.addAdminCallback = function(status,params,responseText,uri,xhr) {
config.macros.ccAdmin.refresh(params.w);
};
// ccChangePassword //
// {{{
config.macros.ccChangePassword={};
config.macros.ccChangePassword.handler=function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
var w = new Wizard();
var me = config.macros.ccChangePassword;
w.createWizard(place,me.title);
w.addStep(me.subTitle+cookieString(document.cookie).txtUserName,me.step1Html);
w.setButtons([
{caption: me.buttonChangeText, tooltip: me.buttonChangeToolTip, onClick: function(){config.macros.ccChangePassword.doPost(w); } }
]);
};
config.macros.ccChangePassword.doPost = function (w) {
me = config.macros.ccChangePassword;
if(!w.formElem.new1.value || !w.formElem.new2.value || !w.formElem.old.value) {
displayMessage(me.noticePasswordUpdateFailed);
return false;
}
if(w.formElem.new1.value != w.formElem.new2.value){
displayMessage(me.noticePasswordsNoMatch);
return false;
}
doHttp("POST", url+"handle/changePassword.php", "&new1="+Crypto.hexSha1Str(w.formElem.new1.value)+"&new2="+Crypto.hexSha1Str(w.formElem.new2.value)+"&old1="+Crypto.hexSha1Str(w.formElem.old.value),null,null,null,config.macros.ccChangePassword.callback);
}
config.macros.ccChangePassword.callback = function(status,context,responseText,uri,xhr) {
if(xhr.status == 304)
displayMessage(me.noticePasswordUpdateFailed);
else
displayMessage(me.noticePasswordUpdated);
}
//}}}
//{{{
config.macros.ccCreateWorkspace = {};
config.macros.ccCreateWorkspace.setStatus=function(w,element,text){
var label_var = w.getElement(element);
removeChildren(label_var.previousSibling);
var label = document.createTextNode(text);
label_var.previousSibling.insertBefore(label,null);
}
config.macros.ccCreateWorkspace.workspaceNameKeyPress=function(w){
params={};
params.w = w;
doHttp('POST',url+'/handle/lookupWorkspaceName.php',"ccWorkspaceLookup="+w.formElem["workspace_name"].value+"&free=1",null,null,null,config.macros.ccCreateWorkspace.workspaceNameCallback,params);
return false;
};
config.macros.ccCreateWorkspace.workspaceNameCallback=function(status,params,responseText,uri,xhr){
var me = config.macros.ccCreateWorkspace;
if(responseText > 0){{
config.macros.register.setStatus(params.w, "workspace_error", me.errorWorkspaceNameInUse);
config.macros.register.setStatus(params.w, "workspace_url", "");
}}else{
config.macros.register.setStatus(params.w, "workspace_error", me.msgWorkspaceAvailable);
if (window.useModRewrite == 1)
config.macros.register.setStatus(params.w, "workspace_url", url+''+params.w.formElem["workspace_name"].value);
else
config.macros.register.setStatus(params.w, "workspace_url", url+'?workspace='+params.w.formElem["workspace_name"].value);
}
};
config.macros.ccCreateWorkspace.handler = function(place,macroName,params,wikifier,paramString,tiddler, errorMsg){
if (window.workspacePermission.canCreateWorkspace!=1) {
createTiddlyElement(place,'div', null, "annotation", config.macros.ccCreateWorkspace.errorPermissions);
return null;
}
var me = config.macros.ccCreateWorkspace;
var w = new Wizard();
w.createWizard(place,me.wizardTitle);
if(config.macros.ccCreateWorkspace.createWorkspaceAdvanced)
me.stepCreateHtml += config.macros.ccCreateWorkspace.createWorkspaceAdvanced();
w.addStep(me.stepTitle, me.stepCreateHtml);
w.formElem["workspace_name"].onkeyup=function() {me.workspaceNameKeyPress(w);};
w.formElem.onsubmit = function() { config.macros.ccCreateWorkspace.createWorkspaceOnSubmit(w); return false;};
w.setButtons([
{caption: me.buttonCreateWorkspaceText, tooltip: me.buttonCreateWorkspaceTooltip, onClick:function(){config.macros.ccCreateWorkspace.createWorkspaceOnSubmit(w);}
}]);
};
config.macros.ccCreateWorkspace.createWorkspaceOnSubmit = function(w){
var params = {};
params.w = w;
if(window.useModRewrite == 1)
params.url = url+w.formElem["workspace_name"].value;
else
params.url = url+'?workspace='+w.formElem["workspace_name"].value;
var loginResp = doHttp('POST',url+'?&workspace='+w.formElem["workspace_name"].value+"/",'&ccCreateWorkspace=' + encodeURIComponent(w.formElem["workspace_name"].value)+'&ccAnonPerm='+encodeURIComponent("AADD"),null,null,null,config.macros.ccCreateWorkspace.createWorkspaceCallback,params);
return false;
};
config.macros.ccCreateWorkspace.createWorkspaceCallback = function(status,params,responseText,uri,xhr) {
if(xhr.status==201){
params.w.addStep("Please wait", "This could take afew minutes depending on your internet connection.<img src='http://www.ajaxload.info/cache/FF/FF/FF/00/00/00/37-0.gif'/>"+"<br/><br/><input width='300' name='statusMarker'/>");
params.w.setButtons([]);
if(params.selectedPackage) {
var url = store.getTiddlerSlice(params.selectedPackage,'URL');
loadRemoteFile(url,config.macros.ccCreateWorkspace.fetchFileCallback ,params);
} else {
window.location = params.url;
}
}else if(xhr.status == 200){
displayMessage(config.macros.ccCreateWorkspace.errorWorkspaceNameInUse);
}else if(xhr.status == 403){
displayMessage(config.macros.ccCreateWorkspace.errorPermissions);
}else{
displayMessage("sd"+responseText);
}
};
//}}}
// ccEditWorkspace //
//{{{
config.macros.ccEditWorkspace={};
config.macros.ccEditWorkspace.handler = function(place, macroName, params, wikifier, paramString, tiddler){
var me = config.macros.ccEditWorkspace;
if(workspacePermission.owner !=1){
createTiddlyElement(place,'div', null, "annotation", me.errorTextPermissionDenied);
return null;
}
var w = new Wizard();
w.createWizard(place, this.WizardTitleText);
var booAdmin = false;
var booUser = false;
var booAnon = false;
// Check which colums to display
for(i = 0; i <= params.length - 1; i++){
switch (params[i].toLowerCase()) {
case 'admin':
booAdmin = true;
break;
case 'user':
booUser = true;
break;
case 'anon':
booAnon = true;
break;
}
}
// if nothing passed show all
if(!booAdmin && !booUser && !booAnon){
booAdmin = true;
booUser = true;
booAnon = true;
}
var tableBodyBuffer = new Array();
tableBodyBuffer.push('<table border=0px class="listView twtable">');
tableBodyBuffer.push('<tr">');
tableBodyBuffer.push('<th>' + this.stepLabelPermission + '</th>');
if(booAnon){
tableBodyBuffer.push('<th>' + this.stepLabelAnon + '</th>');
}
if(booUser){
tableBodyBuffer.push('<th>' + this.stepLabelUser + '</th>');
}
if(booAdmin){
tableBodyBuffer.push('<th>' + this.stepLabelAdmin + '</th>');
}
tableBodyBuffer.push('</tr>');
tableBodyBuffer.push('<tr>')
tableBodyBuffer.push('<th align="right">'+this.stepLabelRead+'</th>');
if(booAnon){
tableBodyBuffer.push('<td><input name="anR" class="checkInput" type="checkbox" ');
tableBodyBuffer.push(workspacePermission.anonR == 1 ? 'checked' : '');
tableBodyBuffer.push(' ></input></td>');
}
if(booUser){
tableBodyBuffer.push('<td><input name="usR" class="checkInput" type="checkbox" ');
tableBodyBuffer.push(workspacePermission.userR == 1 ? 'checked' : '');
tableBodyBuffer.push('></input></td>');
}
if(booAdmin){
tableBodyBuffer.push('<td><input name="adR" class="checkInput" type="checkbox" checked disabled></input></td>');
}
tableBodyBuffer.push('</tr>');
tableBodyBuffer.push('<tr>');
tableBodyBuffer.push('<th align="right">' + this.stepLabelCreate + '</th>');
if(booAnon){
tableBodyBuffer.push('<td><input name="anC" class="checkInput" type="checkbox" ');
tableBodyBuffer.push(workspacePermission.anonC == 1 ? 'checked' : '');
tableBodyBuffer.push(' ></input></td>');
}
if(booUser){
tableBodyBuffer.push('<td><input name="usC" class="checkInput" type="checkbox" ');
tableBodyBuffer.push(workspacePermission.userC == 1 ? 'checked' : '');
tableBodyBuffer.push(' ></input></td>');
}
if(booAdmin){
tableBodyBuffer.push('<td><input name="adC" class="checkInput" type="checkbox" checked disabled></input></td>');
}
tableBodyBuffer.push('</tr>');
tableBodyBuffer.push('<tr>');
tableBodyBuffer.push('<th align="right">' + this.stepLabelUpdate + '</th>');
if(booAnon){
tableBodyBuffer.push('<td><input name="anU" class="checkInput" type="checkbox" ');
tableBodyBuffer.push(workspacePermission.anonU == 1 ? 'checked' : '');
tableBodyBuffer.push(' ></input></td>');
}
if(booUser){
tableBodyBuffer.push('<td><input name="usU" class="checkInput" type="checkbox" ');
tableBodyBuffer.push(workspacePermission.userU == 1 ? 'checked' : '');
tableBodyBuffer.push(' ></input></td>');
}
if(booAdmin){
tableBodyBuffer.push('<td><input name="adU" class="checkInput" type="checkbox" checked disabled></input></td>');
}
tableBodyBuffer.push('</tr>');
tableBodyBuffer.push('<tr>');
tableBodyBuffer.push('<th align="right">' + this.stepLabelDelete + '</th>');
if(booAnon){
tableBodyBuffer.push('<td><input name="anD" class="checkInput" type="checkbox" ');
tableBodyBuffer.push(workspacePermission.anonD == 1 ? 'checked' : '');
tableBodyBuffer.push(' ></input></td>');
}
if(booUser){
tableBodyBuffer.push('<td><input name="usD" class="checkInput" type="checkbox" ');
tableBodyBuffer.push(workspacePermission.userD == 1 ? 'checked' : '');
tableBodyBuffer.push(' ></input></td>');
}
if(booAdmin){
tableBodyBuffer.push('<td><input name="adD" class="checkInput" type="checkbox" checked disabled></input></td>');
}
tableBodyBuffer.push('</tr>');
tableBodyBuffer.push('</table>');
var stepHTML = tableBodyBuffer.join('');
w.addStep(this.stepEditTitle,stepHTML);
w.setButtons([
{caption: this.buttonSubmitCaption, tooltip: this.buttonSubmitToolTip, onClick: function() {me.ewSubmit(place, macroName, params, wikifier, paramString, tiddler,w,booAnon,booUser);}
}]);
};
config.macros.ccEditWorkspace.ewSubmit = function(place, macroName, params2, wikifier, paramString, tiddler,w, booAnon, booUser){
var trueStr = "A";
var falseStr = "U";
var anon = '';
var user = '';
if(booAnon){
var anonBuffer = new Array();
anonBuffer.push(w.formElem['anR'].checked ? trueStr : falseStr);
anonBuffer.push(w.formElem['anC'].checked ? trueStr : falseStr);
anonBuffer.push(w.formElem['anU'].checked ? trueStr : falseStr);
anonBuffer.push(w.formElem['anD'].checked ? trueStr : falseStr);
anon = anonBuffer.join('');
}
if(booUser){
var userBuffer = new Array();
userBuffer.push(w.formElem['usR'].checked ? trueStr : falseStr);
userBuffer.push(w.formElem['usC'].checked ? trueStr : falseStr);
userBuffer.push(w.formElem['usU'].checked ? trueStr : falseStr);
userBuffer.push(w.formElem['usD'].checked ? trueStr : falseStr);
user = userBuffer.join('');
}
var params = new Array();
params.w = w;
params.u = user;
params.a = anon;
params.p = place;
params.m = macroName;
params.pr = params2;
params.wi = wikifier;
params.ps = paramString;
params.t = tiddler;
doHttp('POST', url + '/handle/updateWorkspace.php', 'ccCreateWorkspace=' + encodeURIComponent(workspace) + '&ccAnonPerm=' + encodeURIComponent(anon) + '&ccUserPerm=' + encodeURIComponent(user), null, null, null, config.macros.ccEditWorkspace.editWorkspaceCallback, params);
return false;
}
config.macros.ccEditWorkspace.editWorkspaceCallback = function(status,params,responseText,uri,xhr){
var w = params.w;
var me = config.macros.ccEditWorkspace;
if(xhr.status == 200){
// use the incoming parameters to set the workspace permission variables.
if (params.a != ''){
workspacePermission.anonR = (params.a.substr(0,1)=='A'?1:0);
workspacePermission.anonC = (params.a.substr(1,1)=='A'?1:0);
workspacePermission.anonU = (params.a.substr(2,1)=='A'?1:0);
workspacePermission.anonD = (params.a.substr(3,1)=='A'?1:0);
}
if (params.u != ''){
workspacePermission.userR = (params.u.substr(0,1)=='A'?1:0);
workspacePermission.userC = (params.u.substr(1,1)=='A'?1:0);
workspacePermission.userU = (params.u.substr(2,1)=='A'?1:0);
workspacePermission.userD = (params.u.substr(3,1)=='A'?1:0);
}
w.addStep('',responseText);
// want to set a back button here
w.setButtons([
{caption: me.button1SubmitCaption, tooltip: me.button1SubmitToolTip, onClick: function() {config.macros.ccEditWorkspace.refresh(params.p, params.m, params.pr, params.wi, params.ps, params.t);}}
]);
}else{
w.addStep(me.step2Error+': ' + xhr.status,config.macros.ccEditWorkspace.errorUpdateFailed);
}
return false;
};
config.macros.ccEditWorkspace.refresh = function(place, macroName, params, wikifier, paramString, tiddler){
removeChildren(place);
config.macros.ccEditWorkspace.handler(place, macroName, params, wikifier, paramString, tiddler);
}
//}}}
// ccFile //
//{{{
config.macros.ccFile = {};
var iFrameLoad=function(w){
var uploadIframe = document.getElementById('uploadIframe');
var a = createTiddlyElement(null, "div");
a.innerHTML = uploadIframe.contentDocument.body.innerHTML;
removeChildren(w.formElem.placeholder);
w.formElem.placeholder.parentNode.appendChild(a);
var statusArea = w.formElem.placeholder;
document.getElementById("ccfile").value="";
};
config.macros.ccFile.handler=function(place,macroName,params,wikifier,paramString,tiddler, errorMsg){
var w = new Wizard();
w.createWizard(place,config.macros.ccFile.wizardTitleText);
config.macros.ccFile.refresh(w);
};
config.macros.ccFile.refresh=function(w){
params = {};
params.w = w;
params.e = this;
var me = config.macros.ccFile;
doHttp('GET',url+'/handle/listFiles.php?workspace='+workspace,'',null,null,null,config.macros.ccFile.listAllCallback,params);
w.setButtons([
{caption: me.buttonDeleteText, tooltip: me.buttonDeleteTooltip, onClick: function(w){
config.macros.ccFile.delFileSubmit(null, params);
return false;
}},
{caption: me.buttonUploadText, tooltip: me.buttonUploadTooltip, onClick: function(e){
config.macros.ccFile.addFileDisplay(null, params); return false
} }
]);
};
config.macros.ccFile.delFileSubmit=function(e, params) {
var listView = params.w.getValue("listView");
var rowNames = ListView.getSelectedRows(listView);
for(var e=0; e < rowNames.length; e++)
doHttp('POST',url+'/handle/listFiles.php','action=DELETEFILE&file='+rowNames[e]+'&workspace='+workspace,null,null,null,config.macros.ccFile.delFileCallback,params);
return false;
};
config.macros.ccFile.delFileCallback=function(status,params,responseText,uri,xhr){
config.macros.ccFile.refresh(params.w);
};
config.macros.ccFile.addFileDisplay = function(e, params){
var frm = params.w.formElem;
if(navigator.appName=="Microsoft Internet Explorer"){
encType = frm.getAttributeNode("enctype");
encType.value = "multipart/form-data";
}
frm.setAttribute("enctype","multipart/form-data");
frm.setAttribute("method","POST");
frm.action=window.url+"/handle/upload.php";
frm.id="ccUpload";
frm.target="uploadIframe";
frm.name = "uploadForm";
frm.parentNode.appendChild(frm);
params.w.addStep("ss", "<input id='ccfile' class='input' type='file' name='userFile'/>"+"<input type='hidden' name='placeholder'/>");
var workspaceName=createTiddlyElement(null,'input','workspaceName','workspaceName');
workspaceName .setAttribute('name','workspace');
workspaceName.type="HIDDEN";
workspaceName.value=workspace;
frm.appendChild(workspaceName);
createTiddlyElement(frm,'br');
var saveTo=createTiddlyElement(null,"input","saveTo","saveTo");
var iframe=document.createElement("iframe");
iframe.style.display="none";
iframe.id='uploadIframe';
iframe.name='uploadIframe';
iframe.onload = function() {
iFrameLoad(params.w);
}
frm.appendChild(iframe);
createTiddlyElement(frm,"div",'uploadStatus');
params.w.setButtons([
{caption: config.macros.ccFile.buttonCancelText, tooltip: config.macros.ccFile.buttonCancelTooltip, onClick: function(){config.macros.ccFile.refresh(params.w);}
},
{caption: config.macros.ccFile.buttonUploadText, tooltip: config.macros.ccFile.buttonUploadTooltip, onClick: function(){params.w.formElem.submit();}
}]);
};
function addOption(selectbox,text,value ){
var optn = document.createElement("OPTION");
optn.text = text;
optn.value = value;
selectbox.options.add(optn);
}
config.macros.ccFileImageBox = function(image){
var full = image.src;
setStylesheet(
"#errorBox .button {padding:0.5em 1em; border:1px solid #222; background-color:#ccc; color:black; margin-right:1em;}\n"+
"html > body > #backstageCloak {height:"+window.innerHeight*2+"px;}"+
"#errorBox {border:1px solid #ccc;background-color: #fff; color:#111;padding:1em 2em; z-index:9999;}",'errorBoxStyles');
var box = document.getElementById('errorBox') || createTiddlyElement(document.body,'div','errorBox');
box.innerHTML = "<a style='float:right' href='javascript:onclick=ccTiddlyAdaptor.hideError()'>"+ccTiddlyAdaptor.errorClose+"</a><h3>"+image.src+"</h3><br />";
box.style.position = 'absolute';
box.style.width= "800px";
var img = createTiddlyElement(box, "img");
img.src = full;
ccTiddlyAdaptor.center(box);
ccTiddlyAdaptor.showCloak();
}
config.macros.ccFile.listAllCallback = function(status,params,responseText,uri,xhr){
var me = config.macros.ccFile;
var out = "";
var adminUsers = [];
if(xhr.status!=200){
params.w.addStep(me.errorPermissionDeniedTitle, me.errorPermissionDeniedView);
return true;
}
try{
var a = eval(responseText);
for(var e=0; e < a.length; e++){
out += a[e].username;
adminUsers.push({
htmlName: "<html><a href='"+a[e].url+"' target='new'>"+a[e].filename+"</a></html>",
name: a[e].filename,
wikiText:'<html><img onclick="config.macros.ccFileImageBox(this)"; src="'+a[e].url+'" style="width: 70px; "/></html>',
URI:a[e].url,
lastVisit:a[e].lastVisit,
fileSize:a[e].fileSize
});
}
}catch (ex){
params.w.setButtons([
{caption: me.buttonUploadText, tooltip: me.buttonUploadTooltip, onClick: function(w){
config.macros.ccFile.addFileDisplay(e, params);
} }]);
}
params.w.addStep(me.wizardStepText+workspace, "<input type='hidden' name='markList'></input>");
var markList = params.w.getElement("markList");
var listWrapper = document.createElement("div");
markList.parentNode.insertBefore(listWrapper,markList);
var listView = ListView.create(listWrapper,adminUsers,config.macros.ccFile.listAdminTemplate);
//params.w.setValue("listAdminView",listAdminView);
params.w.setValue("listView",listView);
};
config.macros.ccFile.addFileCallback = function(status,params,responseText,uri,xhr){
config.macros.ccFile.refresh(params.w);
};
//}}}
// ccLogin //
//{{{
config.macros.ccLogin={sha1:true};
function isLoggedIn() {
if(window.loggedIn)
return true;
else
return false;
}
config.macros.saveChanges.handler=function(place,macroName,params,wikifier,paramString,tiddler){
if(isLoggedIn()){
createTiddlyButton(place, config.macros.ccLogin.buttonLogout, config.macros.ccLogin.buttonLogoutToolTip, function(){
if (window.fullUrl.indexOf("?") >0)
window.location = window.fullUrl+"&logout=1";
else
window.location = window.fullUrl+"?logout=1";
return false;
},null,null,this.accessKey);
}else{
createTiddlyButton(place,config.macros.ccLogin.buttonlogin, config.macros.ccLogin.buttonLoginToolTip, function() {
story.displayTiddler(null, "Login");
},null,null,this.accessKey);
}
};
var loginState=null;
var registerState=null;
config.macros.ccLogin.handler=function(place,macroName,params,wikifier,paramString,tiddler){
var params = paramString.parseParams('reload',null,true);
config.macros.ccLogin.refresh(place, params[0].reload);
};
config.macros.ccLogin.refresh=function(place, reload, error){
removeChildren(place);
var w = new Wizard();
if (isLoggedIn()){
w.createWizard(place,this.stepLogoutTitle);
w.addStep(null, this.stepLogoutText+decodeURIComponent(cookieString(document.cookie).txtUserName)+"<br /><br />");
w.setButtons([
{caption: this.buttonLogout, tooltip: this.buttonLogoutToolTip, onClick: function() {window.location=fullUrl+"?&logout=1"}
}]);
return true;
}
w.createWizard(place,this.WizardTitleText);
w.setValue('reload', reload);
var me=config.macros.ccLogin;
var oldForm = w.formElem.innerHTML;
var form = w.formElem;
if (error!==undefined)
this.stepLoginTitle=error;
w.addStep(this.stepLoginTitle,me.stepLoginIntroTextHtml);
txtPassword = w.formElem.txtPassword;
w.formElem.password.style.display="none";
txtPassword.onkeyup = function() {
if(me.sha1 == true){
w.formElem.password.value = Crypto.hexSha1Str(w.formElem.txtPassword.value);
} else {
w.formElem.password.value = w.formElem.txtPassword.value;
}
};
txtPassword.onchange = txtPassword.onkeyup;
w.formElem.method ="POST";
w.formElem.onsubmit = function() {config.macros.ccLogin.doLogin(w.formElem["username"].value, w.formElem["password"].value, this, place); return false;};
var submit = createTiddlyElement(null, "input");
submit.type="submit";
submit.style.display="none";
w.formElem.appendChild(submit);
var cookieValues=findToken(document.cookie);
if (cookieValues.txtUserName!==undefined){
w.formElem["username"].value=decodeURIComponent(cookieValues.txtUserName) ;
}
var footer = findRelated(form,"wizardFooter","className");
createTiddlyButton(w.footer,this.buttonLogin,this.buttonLoginToolTip,function() {
if (w.formElem["username"].value==""){
displayMessage(me.msgNoUsername);
return false;
}
if (w.formElem["password"].value==""){
displayMessage(me.msgNoPassword);
return false;
}
config.macros.ccLogin.doLogin(w.formElem["username"].value, w.formElem["password"].value, this, place);
});
createTiddlyButton(w.footElem,this.buttonLogin,this.buttonLoginToolTip,function() {
config.macros.ccLogin.doLogin(w.formElem["username"].value, w.formElem["password"].value, this, place);
},null, null, null, {tabindex:'3'});
if(config.macros.register!==undefined){
var li_register = createTiddlyElement(w.footElem, "li");
createTiddlyButton(li_register,config.macros.register.buttonRegister,config.macros.register.buttonRegisterToolTip,function() {
config.macros.register.displayRegister(place, w, this);
},"nobox", null, null, {tabindex:4});
}
var li_forgotten = createTiddlyElement(w.footElem, "li");
createTiddlyButton(li_forgotten,this.buttonForgottenPassword,this.buttonForgottenPasswordToolTip,function() {
config.macros.ccLogin.displayForgottenPassword(this, place);
},"nobox", null, null, {tabindex:5});
};
config.macros.ccLogin.doLogin=function(username, password, item, place){
var w = new Wizard(item);
var me = config.macros.ccLogin;
var userParams = {};
userParams.place = place;
var adaptor = new config.adaptors[config.defaultCustomFields['server.type']];
var context = {};
context.reload = w.getValue("reload");
context.host = window.url;
context.username = username;
context.password = password;
adaptor.login(context,userParams,config.macros.ccLogin.loginCallback)
var html = me.stepDoLoginIntroText;
w.addStep(me.stepDoLoginTitle,html);
w.setButtons([
{caption: this.buttonCancel, tooltip: this.buttonCancelToolTip, onClick: function() {config.macros.ccLogin.refresh(place);}
}]);
}
config.macros.ccLogin.loginCallback=function(context,userParams){
if(!context.status)
{
config.macros.ccLogin.refresh(userParams.place, config.macros.ccLogin.msgLoginFailed);
}else{
if(context.reload=="false"){
window.loggedIn = true;
var $ = jQuery;
story.refreshTiddler(story.findContainingTiddler(userParams.place).id.replace("tiddler", ""), null, true);
}else{
window.location.reload();
}
}
};
config.macros.ccLogin.displayForgottenPassword=function(item, place){
var w = new Wizard(item);
var me = config.macros.ccLogin;
w.addStep(me.stepForgotPasswordTitle,me.stepForgotPasswordIntroText);
w.setButtons([
{caption: this.buttonCancel, tooltip: this.buttonCancelToolTip, onClick: function() {me.refresh(place);}}
]);
};
//config.macros.ccLogin.sendForgottenPassword=function(item, place){
// var w = new Wizard(item);
// var me = config.macros.ccLogin;
//}
config.macros.toolbar.isCommandEnabled=function(command,tiddler){
var title=tiddler.title;
if (workspace_delete=="D"){
// REMOVE OPTION TO DELETE TIDDLERS
if (command.text=='delete')
return false;
}
if (workspace_udate=="D"){
// REMOVE EDIT LINK FROM TIDDLERS
if (command.text=='edit')
return false;
}
var ro=tiddler.isReadOnly();
var shadow=store.isShadowTiddler(title) && !store.tiddlerExists(title);
return (!ro || (ro && !command.hideReadOnly)) && !(shadow && command.hideShadow);
};
// Returns output var with output.txtUsername and output.sessionToken
function findToken(cookieStash){
var output={};
if (!cookieStash)
return false;
// THIS IS VERY HACKY AND SHOULD BE REFACTORED WHEN TESTS ARE IN PLACE
var cookies=cookieStash.split('path=/');
for(var c=0; c < cookies.length ; c++){
var cl =cookies[c].split(";");
for(var e=0; e < cl.length; e++){
var p=cl[e].indexOf("=");
if(p!=-1){
var name=cl[e].substr(0,p).trim();
var value=cl[e].substr(p+1).trim();
if (name=='txtUserName'){
output.txtUserName=value;
}
if (name=='sessionToken'){
output.sessionToken=value;
}
}
}
}
return output;
};
function cookieString(str){
var cookies = str.split(";");
var output = {};
for(var c=0; c < cookies.length; c++){
var p = cookies[c].indexOf("=");
if(p != -1) {
var name = cookies[c].substr(0,p).trim();
var value = cookies[c].substr(p+1).trim();
if (name=='txtUserName'){
output.txtUserName=value;
}
if (name=='sessionToken'){
output.sessionToken=value;
}
}
}
return output;
}
//}}}
// ccLoginStatus //
//{{{
config.macros.ccLoginStatus={};
config.macros.ccLoginStatus.handler=function(place,macroName,params,wikifier,paramString,tiddler){
var loginDiv=createTiddlyElement(place,"div",null,"loginDiv",null);
this.refresh(loginDiv);
};
config.macros.ccLoginStatus.refresh=function(place,errorMsg){
var me = config.macros.ccLoginStatus;
var loginDivRef=document.getElementById ("LoginDiv");
removeChildren(loginDivRef);
var wrapper=createTiddlyElement(place,"div");
var str = (workspace == "" ? me.textDefaultWorkspaceLoggedIn :(me.textViewingWorkspace+workspace))+"\r\n\r\n";
if (isLoggedIn()){
name = cookieString(document.cookie).txtUserName;
str += me.textLoggedInAs+decodeURIComponent(name)+".\r\n\r\n";
if (workspacePermission.owner==1){
str += me.textAdmin;
}
}else{
str += me.textNotLoggedIn;
}
wikify(str,wrapper);
};
//}}}
// ccOptions //
//{{{
config.macros.ccOptions={};
config.macros.ccOptions.handler=function(place,macroName,params,wikifier,paramString,tiddler){
var me = config.macros.ccOptions;
if(workspacePermission.owner==1)
wikify("[["+me.linkManageUsers+"|Manage Users]]<br />[["+me.linkPermissions+"|Permissions]]<br />[["+me.linkStats+"|Statistics]]<br />", place);
if (isLoggedIn())
wikify("[["+me.linkFiles+"|files]]<br />", place);
if (isLoggedIn()){
if (workspacePermission.canCreateWorkspace==1)
wikify("[["+me.linkCreate+"|CreateWorkspace]]<br />", place);
// append url function required
wikify("[["+me.linkPassword+"|Password]]<br />", place);
if (window.fullUrl.indexOf("?") >0)
wikify("[["+me.linkOffline+"|"+fullUrl+"&standalone=1]]<br />", place);
else
wikify("[["+me.linkOffline+"|"+fullUrl+"?standalone=1]]<br />", place);
}
};
//}}}
// ccRegister //
//{{{
config.macros.register={};
config.macros.register.handler=function(place,macroName,params,wikifier,paramString,tiddler){
//config.macros.login.refresh(place);
};
config.macros.register.displayRegister=function(place, w, item){
var me = config.macros.register;
var w = new Wizard(item);
w.addStep(me.stepRegisterTitle, me.stepRegisterHtml);
w.formElem["reg_username"].onkeyup=function() {me.isUsernameAvailable(w);};
w.setButtons([
{caption: me.buttonRegister, tooltip: me.buttonRegisterToolTip, onClick:function() { me.doRegister(place, w)}},
{caption: me.buttonCancel, tooltip: me.buttonCancelToolTip, onClick: function() { config.macros.ccLogin.refresh(place)}}
]);
var h1 = createTiddlyElement(null, "h1", null, null, "hahahaha");
// w.footElem.appendChild(h1, w.footElem);
w.footElem.firstChild.parentNode.appendChild(h1, w.footElem);
//w.footElem.firstChild.insertBefore(h1, w.footElem);
}
config.macros.register.setStatus=function(w, element, text){
var label_var = w.getElement(element);
removeChildren(label_var.previousSibling);
var label = document.createTextNode(text);
label_var.previousSibling.insertBefore(label,null);
}
config.macros.register.doRegister=function(place, w){
var me = config.macros.register;
if(w.formElem["reg_username"].value==''){
me.setStatus(w, "username_error", me.msgNoUsername);
}else {
me.setStatus(w, "username_error", "");
}
if(me.emailValid(w.formElem["reg_mail"].value)){
me.setStatus(w, "mail_error", me.msgEmailOk);
}else{
me.setStatus(w, "mail_error", "invalid email address");
return false;
}
if(w.formElem["reg_password1"].value==''){
me.setStatus(w, "pass1_error", me.msgNoPassword);
return false;
}else{
me.setStatus(w, "pass1_error", "");
}
if(w.formElem["reg_password2"].value==''){
me.setStatus(w, "pass2_error", me.msgNoPassword);
return false;
}
if(w.formElem["reg_password1"].value != w.formElem["reg_password2"].value ){
me.setStatus(w, "pass1_error", me.msgDifferentPasswords);
me.setStatus(w, "pass2_error", me.msgDifferentPasswords);
return false;
}
var params ={};
params.p = Crypto.hexSha1Str(w.formElem['reg_password1'].value);
params.u = w.formElem['reg_username'].value;
params.place = place;
params.w = w;
var loginResp=doHttp('POST',url+'/handle/register.php',"username="+w.formElem['reg_username'].value+"®_mail="+w.formElem['reg_mail'].value+"&password="+Crypto.hexSha1Str(w.formElem['reg_password1'].value)+"&password2="+Crypto.hexSha1Str(w.formElem['reg_password2'].value),null,null,null,config.macros.register.registerCallback,params);
w.addStep(me.step2Title, me.msgCreatingAccount);
w.setButtons([
{caption: me.buttonCancel, tooltip: me.buttonCancelToolTip, onClick: function() {config.macros.ccLogin.refresh(place);}
}]);
}
config.macros.register.emailValid=function(str){
if((str.indexOf(".") > 0) && (str.indexOf("@") > 0))
return true;
else
return false;
};
config.macros.register.usernameValid=function(str){
if((str.indexOf("_") > 0) && (str.indexOf("@") > 0))
return false;
else
return true;
};
config.macros.register.registerCallback=function(status,params,responseText,uri,xhr){
var userParams = {};
userParams.place = params.place;
if (xhr.status==304){
params.w.addStep(config.macros.register.errorRegisterTitle, config.macros.register.errorRegister);
return false;
}
var adaptor = new config.adaptors[config.defaultCustomFields['server.type']];
var context = {};
context.host = window.url;
context.username = params.u;
context.password = params.p;
adaptor.login(context,userParams,config.macros.ccLogin.loginCallback);
return true;
}
config.macros.register.isUsernameAvailable=function(w){
var params = {};
params.w = w;
doHttp('POST',url+'/handle/register.php',"username="+w.formElem["reg_username"].value+"&free=1",null,null,null,config.macros.register.isUsernameAvailabeCallback,params);
return false;
};
config.macros.register.isUsernameAvailabeCallback=function(status,params,responseText,uri,xhr){
var me = config.macros.register;
var resp = (responseText > 0) ? me.msgUsernameTaken : me.msgUsernameAvailable;
config.macros.register.setStatus(params.w, "username_error", resp);
};
//}}}
// ccStats //
//{{{
config.macros.ccStats={};
config.macros.ccStats.handler = function(place,macroName,params,wikifier,paramString,tiddler){
var params;
params.place = place;
doHttp('POST',url+'/handle/workspaceAdmin.php','action=LISTWORKSPACES',null,null,null,config.macros.ccStats.listWorkspaces,params);
}
config.macros.ccStats.simpleEncode = function(valueArray,maxValue){
var simpleEncoding = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var chartData = ['s:'];
for (var i = 0; i < valueArray.length; i++){
var currentValue = valueArray[i];
if (!isNaN(currentValue) && currentValue >= 0){
chartData.push(simpleEncoding.charAt(Math.round((simpleEncoding.length-1) * currentValue / maxValue)));
}else{
chartData.push('_');
}
}
return chartData.join('');
}
config.macros.ccStats.max = function(array){
return Math.max.apply(Math, array);
}
config.macros.ccStats.dataCallback = function(status,params,responseText,uri,xhr){
me = config.macros.ccStats;
if(xhr.status==401){
createTiddlyElement(params.container, "h4", null, null, me.errorPermissionDenied.format([params.title], [workspace]));
return false;
}
var res = eval("[" + responseText + "]");
var d=[];
var l="";
for(var c=0; c<res.length; c++){
d[c]= res[c].hits;
l+=res[c].date+"|";
}
var maxValue = config.macros.ccStats.max(d);
params.gData = config.macros.ccStats.simpleEncode(d,maxValue);
params.XLabel = l.substring(0, l.length -1);
params.YLabel = "0|"+maxValue+"|";
var image = 'http://chart.apis.google.com/chart?cht=lc&chs=100x75&chd='+params.gData+'&chxt=x,y&chxl=0:||1:|';
var div = createTiddlyElement(params.container, "div", null, "div_button");
setStylesheet(".div_button:hover{opacity:0.7; cursor: pointer} .div_button{ width:100%; padding:5px;color:#555;background-color:white;} ", "DivButton");
div.onclick = function(){
var full = "http://chart.apis.google.com/chart?cht=lc&chs=800x375&chd="+params.gData+"&chxt=x,y&chxl=1:|"+params.YLabel+"0:|"+params.XLabel+"&chf=c,lg,90,EEEEEE,0.5,ffffff,20|bg,s,FFFFFF&&chg=10.0,10.0&";
setStylesheet(
"#errorBox .button{padding:0.5em 1em; border:1px solid #222; background-color:#ccc; color:black; margin-right:1em;}\n"+
"html > body > #backstageCloak{height:"+window.innerHeight*2+"px;}"+
"#errorBox{border:1px solid #ccc;background-color: #fff; color:#111;padding:1em 2em; z-index:9999;}",'errorBoxStyles');
var box = document.getElementById('errorBox') || createTiddlyElement(document.body,'div','errorBox');
box.innerHTML = "<a style='float:right' href='javascript:onclick=ccTiddlyAdaptor.hideError()'>"+ccTiddlyAdaptor.errorClose+"</a><h3>"+params.title+"</h3><br />";
box.style.position = 'absolute';
box.style.height= "460px";
box.style.width= "800px";
var img = createTiddlyElement(box, "img");
img.src = full;
ccTiddlyAdaptor.center(box);
ccTiddlyAdaptor.showCloak();
}
var img = createTiddlyElement(div, "h2", null, null, params.title);
var img = createTiddlyElement(div, "img");
img.src = image;
var span = createTiddlyElement(div, "div", null, "graph_label", params.desc);
setStylesheet(".graph_label{ position:relative; width:300px; top:-80px; left:130px;}");
}
config.macros.ccStats.switchWorkspace = function(params){
removeChildren(params.container);
config.macros.ccStats.refresh(params);
}
config.macros.ccStats.refresh = function(params){
var me = config.macros.ccStats;
var select = params.w.formElem.workspaces;
if(select[select.selectedIndex].value!="")
workspace = select[select.selectedIndex].value;
params ={ container: params.container, url: window.url+"/handle/stats.php?graph=minute&workspace="+workspace,title:me.graph20MinsTitle, desc:me.graph20MinsDesc};
doHttp('GET',params.url,null, null, null, null, config.macros.ccStats.dataCallback,params);
params ={ container:params.container, url: window.url+"/handle/stats.php?graph=hour&workspace="+workspace,title:me.graph24HourTitle, desc:me.graph24HourDesc};
doHttp('GET',params.url,null, null, null, null, config.macros.ccStats.dataCallback,params);
params ={ container: params.container, url: window.url+"/handle/stats.php?graph=day&workspace="+workspace,title:me.graph7DaysTitle, desc:me.graph7DaysDesc};
doHttp('GET',params.url,null, null, null, null, config.macros.ccStats.dataCallback,params);
params ={ container: params.container, url: window.url+"/handle/stats.php?graph=month&workspace="+workspace,title:me.graph5MonthsTitle, desc:me.graph5MonthsDesc};
doHttp('GET',params.url,null, null, null, null, config.macros.ccStats.dataCallback,params);
}
config.macros.ccStats.listWorkspaces = function(status,params,responseText,uri,xhr){
params.container=createTiddlyElement(null, "div", "container");
var me = config.macros.ccStats;
var w = new Wizard();
w.createWizard(params.place,me.stepTitle);
w.addStep(null, "<select name='workspaces'></select><input name='stats_hol' type='hidden'></input>");
var s = w.formElem.workspaces;
s.onchange = function(){config.macros.ccStats.switchWorkspace(params) ;};
var workspaces = eval('[ '+responseText+' ]');
for(var d=0; d < workspaces.length; d++){
var i = createTiddlyElement(s,"option",null,null,workspaces[d]);
i.value = workspaces[d];
if (workspace == workspaces[d]){
i.selected = true;
}
}
params.w = w;
w.formElem.stats_hol.parentNode.appendChild(params.container);
config.macros.ccStats.refresh(params);
}
//}}}
config.backstageTasks.push("about");
merge(config.tasks,{about:{text: config.macros.ccAbout.buttonBackstageText,tooltip: config.macros.ccAbout.buttonBackstageTooltip,content: '<<ccAbout>>'}});
if (isLoggedIn()){
config.backstageTasks.push("logout");
merge(config.tasks,{logout:{text: config.macros.ccLogin.buttonLogout,tooltip: config.macros.ccLogin.buttonLogoutToolTip,content: '<<ccLogin>>'}});
// config.backstageTasks.push("create");
// merge(config.tasks,{create: {text: config.macros.ccCreateWorkspace.buttonCreateText, tooltip: config.macros.ccCreateWorkspace.buttonCreateTooltip, content:'<<ccCreateWorkspace>>'}});
}else{
config.backstageTasks.push("login");
merge(config.tasks,{login:{text: config.macros.ccLogin.buttonlogin,tooltip: config.macros.ccLogin.buttonLoginToolTip,content: '\r\n\r\n<<tiddler Login>>'}});
}
// Allows users to change the default tiddlers for anonymous users by setting the AnonDefaultTiddlers tiddler.
// also requires overide of restart.
Story.prototype.displayDefaultTiddlers = function(){
var tiddlers="";
if(isLoggedIn()){
var url = window.location;
url = url.toString();
var bits = url.split('#');
if(bits.length == 1){
tiddlers = store.filterTiddlers(store.getTiddlerText("DefaultTiddlers"));
story.displayTiddlers(null, tiddlers);
}
}else{
tiddlers=store.filterTiddlers(store.getTiddlerText("AnonDefaultTiddlers"));
story.displayTiddlers(null, tiddlers);
}
};
// Import Override - ensures imported tiddlers have cctiddly server type.
config.macros.importTiddlers.onGetTiddler = function(context,wizard)
{
if(!context.status)
displayMessage("Error in importTiddlers.onGetTiddler: " + context.statusText);
var tiddler = context.tiddler;
if(store.tiddlerExists(tiddler.title)) {
var t = store.getTiddler(tiddler.title);
tiddler.fields = t.fields;
}
store.suspendNotifications();
tiddler.fields['server.type'] = 'cctiddly';
tiddler.fields['server.host'] = window.url;
tiddler.fields['workspace']= window.workspace;
store.saveTiddler(tiddler.title, tiddler.title, tiddler.text, tiddler.modifier, tiddler.modified, tiddler.tags, tiddler.fields, false, tiddler.created);// local
// config.extensions.ServerSideSavingPlugin.saveTiddler(tiddler); // remote save.
if(!wizard.getValue("sync")) {
store.setValue(tiddler.title,'server',null);
}
store.resumeNotifications();
if(!context.isSynchronous)
store.notify(tiddler.title,true);
var remainingImports = wizard.getValue("remainingImports")-1;
wizard.setValue("remainingImports",remainingImports);
if(remainingImports == 0) {
if(context.isSynchronous) {
store.notifyAll();
refreshDisplay();
}
wizard.setButtons([
{caption: config.macros.importTiddlers.doneLabel, tooltip: config.macros.importTiddlers.donePrompt, onClick: config.macros.importTiddlers.onClose}
],config.macros.importTiddlers.statusDoneImport);
autoSaveChanges();
}
};
/*
// Displays the default tiddlers alongside the login box when users are not logged in.
window.restart = function(){
story.displayDefaultTiddlers();
invokeParamifier(params,"onstart");
window.scrollTo(0,0);
});
};
*/
/*!
* jQuery JavaScript Library v1.4a1
* http://jquery.com/
*
* Copyright (c) 2009 John Resig
* Dual licensed under the MIT and GPL licenses.
* http://docs.jquery.com/License
*
* Date: Fri Dec 4 12:51:47 2009 -0500
*/
(function(window, undefined){
// Define a local copy of jQuery
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return arguments.length === 0 ?
rootjQuery :
new jQuery.fn.init( selector, context );
},
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$,
// Use the correct document accordingly with window argument (sandbox)
document = window.document,
// A central reference to the root jQuery(document)
rootjQuery,
// A simple way to check for HTML strings or ID strings
// (both of which we optimize for)
quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,
// Is it a simple selector
isSimple = /^.[^:#\[\.,]*$/,
// Check if a string has a non-whitespace character in it
rnotwhite = /\S/,
// Used for trimming whitespace
rtrim = /(\s|\u00A0)+|(\s|\u00A0)+$/g,
// Match a standalone tag
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
// Keep a UserAgent string for use with jQuery.browser
userAgent = navigator.userAgent.toLowerCase(),
// Save a reference to some core methods
toString = Object.prototype.toString,
hasOwnProperty = Object.prototype.hasOwnProperty,
push = Array.prototype.push,
slice = Array.prototype.slice,
indexOf = Array.prototype.indexOf;
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
var match, elem, ret, doc;
// Handle $(""), $(null), or $(undefined)
if ( !selector ) {
return this;
}
// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
// Handle HTML strings
if ( typeof selector === "string" ) {
// Are we dealing with HTML string or an ID?
match = quickExpr.exec( selector );
// Verify a match, and that no context was specified for #id
if ( match && (match[1] || !context) ) {
// HANDLE: $(html) -> $(array)
if ( match[1] ) {
doc = (context ? context.ownerDocument || context : document);
// If a single string is passed in and it's a single tag
// just do a createElement and skip the rest
ret = rsingleTag.exec( selector );
if ( ret ) {
selector = [ doc.createElement( ret[1] ) ];
} else {
ret = buildFragment( [ match[1] ], [ doc ] );
selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
}
// HANDLE: $("#id")
} else {
elem = document.getElementById( match[2] );
if ( elem ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}
// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// HANDLE: $("TAG")
} else if ( !context && /^\w+$/.test( selector ) ) {
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName( selector );
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return (context || rootjQuery).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return jQuery( context ).find( selector );
}
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
if (selector.selector !== undefined) {
this.selector = selector.selector;
this.context = selector.context;
}
return jQuery.isArray( selector ) ?
this.setArray( selector ) :
jQuery.makeArray( selector, this );
},
// Start with an empty selector
selector: "",
// The current version of jQuery being used
jquery: "1.4a1",
// The default length of a jQuery object is 0
length: 0,
// The number of elements contained in the matched element set
size: function() {
return this.length;
},
toArray: function(){
return slice.call( this, 0 );
},
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function( num ) {
return num == null ?
// Return a 'clean' array
this.toArray() :
// Return just the object
( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );
},
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems, name, selector ) {
// Build a new jQuery matched element set
var ret = jQuery( elems || null );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
if ( name === "find" ) {
ret.selector = this.selector + (this.selector ? " " : "") + selector;
} else if ( name ) {
ret.selector = this.selector + "." + name + "(" + selector + ")";
}
// Return the newly-formed element set
return ret;
},
// Force the current matched set of elements to become
// the specified array of elements (destroying the stack in the process)
// You should use pushStack() in order to do this, but maintain the stack
setArray: function( elems ) {
// Resetting the length to 0, then using the native Array push
// is a super-fast way to populate an object with array-like properties
this.length = 0;
push.apply( this, elems );
return this;
},
// Execute a callback for every element in the matched set.
// (You can seed the arguments with an array of args, but this is
// only used internally.)
each: function( callback, args ) {
return jQuery.each( this, callback, args );
},
// Determine the position of an element within
// the matched set of elements
index: function( elem ) {
if ( !elem || typeof elem === "string" ) {
return jQuery.inArray( this[0],
// If it receives a string, the selector is used
// If it receives nothing, the siblings are used
elem ? jQuery( elem ) : this.parent().children() );
}
// Locate the position of the desired element
return jQuery.inArray(
// If it receives a jQuery object, the first element is used
elem.jquery ? elem[0] : elem, this );
},
is: function( selector ) {
return !!selector && jQuery.filter( selector, this ).length > 0;
},
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: push,
sort: [].sort,
splice: [].splice
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function() {
// copy reference to target object
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
if ( length === i ) {
target = this;
--i;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging object literal values
if ( deep && copy && jQuery.isObjectLiteral(copy) ) {
// Don't extend not object literals
var clone = src && jQuery.isObjectLiteral(src) ? src : {};
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
jQuery.extend({
noConflict: function( deep ) {
window.$ = _$;
if ( deep ) {
window.jQuery = _jQuery;
}
return jQuery;
},
// See test/unit/core.js for details concerning isFunction.
// Since version 1.3, DOM methods and functions like alert
// aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
return toString.call(obj) === "[object Function]";
},
isArray: function( obj ) {
return toString.call(obj) === "[object Array]";
},
isObjectLiteral: function( obj ) {
if ( toString.call(obj) !== "[object Object]" || typeof obj.nodeType === "number" ) {
return false;
}
// not own constructor property must be Object
if ( obj.constructor
&& !hasOwnProperty.call(obj, "constructor")
&& !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
//own properties are iterated firstly,
//so to speed up, we can test last one if it is own or not
var key;
for ( key in obj ) {}
return key === undefined || hasOwnProperty.call( obj, key );
},
isEmptyObject: function( obj ) {
for ( var name in obj ) {
return false;
}
return true;
},
// check if an element is in a (or is an) XML document
isXMLDoc: function( elem ) {
// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
},
// Evalulates a script in a global context
globalEval: function( data ) {
if ( data && rnotwhite.test(data) ) {
// Inspired by code by Andrea Giammarchi
// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
var head = document.getElementsByTagName("head")[0] || document.documentElement,
script = document.createElement("script");
script.type = "text/javascript";
if ( jQuery.support.scriptEval ) {
script.appendChild( document.createTextNode( data ) );
} else {
script.text = data;
}
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709).
head.insertBefore( script, head.firstChild );
head.removeChild( script );
}
},
nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
},
// args is for internal usage only
each: function( object, callback, args ) {
var name, i = 0,
length = object.length,
isObj = length === undefined || jQuery.isFunction(object);
if ( args ) {
if ( isObj ) {
for ( name in object ) {
if ( callback.apply( object[ name ], args ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.apply( object[ i++ ], args ) === false ) {
break;
}
}
}
// A special, fast, case for the most common use of each
} else {
if ( isObj ) {
for ( name in object ) {
if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
break;
}
}
} else {
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
}
}
return object;
},
trim: function( text ) {
return (text || "").replace( rtrim, "" );
},
// results is for internal usage only
makeArray: function( array, results ) {
var ret = results || [];
if ( array != null ) {
// The window, strings (and functions) also have 'length'
if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval ) {
push.call( ret, array );
} else {
jQuery.merge( ret, array );
}
}
return ret;
},
inArray: function( elem, array ) {
if ( array.indexOf ) {
return array.indexOf( elem );
}
for ( var i = 0, length = array.length; i < length; i++ ) {
if ( array[ i ] === elem ) {
return i;
}
}
return -1;
},
merge: function( first, second ) {
var pos, i = second.length;
// We have to get length this way when IE & Opera overwrite the length
// expando of getElementsByTagName
if ( i && i.nodeType ) {
for ( i = 0; second[i]; ++i ) {}
}
pos = i + first.length;
// Correct length for non Arrays
first.length = pos;
while ( i ) {
first[ --pos ] = second[ --i ];
}
return first;
},
grep: function( elems, callback, inv ) {
var ret = [];
// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
if ( !inv !== !callback( elems[ i ], i ) ) {
ret.push( elems[ i ] );
}
}
return ret;
},
// arg is for internal usage only
map: function( elems, callback, arg ) {
var ret = [], value;
// Go through the array, translating each of the items to their
// new value (or values).
for ( var i = 0, length = elems.length; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
return ret.concat.apply( [], ret );
},
// Use of jQuery.browser is deprecated.
// It's included for backwards compatibility and plugins,
// although they should work to migrate away.
browser: {
version: (/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/.exec(userAgent) || [0,'0'])[1],
safari: /webkit/.test( userAgent ),
opera: /opera/.test( userAgent ),
msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
}
});
if ( indexOf ) {
jQuery.inArray = function( elem, array ) {
return indexOf.call( array, elem );
};
}
// All jQuery objects should point back to these
rootjQuery = jQuery(document);
function evalScript( i, elem ) {
if ( elem.src ) {
jQuery.ajax({
url: elem.src,
async: false,
dataType: "script"
});
} else {
jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
}
if ( elem.parentNode ) {
elem.parentNode.removeChild( elem );
}
}
// Mutifunctional method to get and set values to a collection
// The value/s can be optionally by executed if its a function
function access( elems, key, value, exec, fn ) {
var l = elems.length;
// Setting many attributes
if ( typeof key === "object" ) {
for (var k in key) {
access(elems, k, key[k], exec, fn);
}
return elems;
}
// Setting one attribute
if (value !== undefined) {
// Optionally, function values get executed if exec is true
exec = exec && jQuery.isFunction(value);
for (var i = 0; i < l; i++) {
var elem = elems[i],
val = exec ? value.call(elem, i) : value;
fn(elem, key, val);
}
return elems;
}
// Getting an attribute
return l ? fn(elems[0], key) : null;
}
function now() {
return (new Date).getTime();
}
var expando = "jQuery" + now(), uuid = 0, windowData = {};
var emptyObject = {};
jQuery.extend({
cache: {},
expando:expando,
data: function( elem, name, data ) {
elem = elem == window ?
windowData :
elem;
var id = elem[ expando ], cache = jQuery.cache, thisCache;
// Handle the case where there's no name immediately
if ( !name && !id ) {
return null;
}
// Compute a unique ID for the element
if ( !id ) {
id = ++uuid;
}
// Avoid generating a new cache unless none exists and we
// want to manipulate it.
if ( cache[ id ] ) {
thisCache = cache[ id ];
} else if ( typeof data === "undefined" ) {
thisCache = emptyObject;
} else {
thisCache = cache[ id ] = {};
}
// Prevent overriding the named cache with undefined values
if ( data !== undefined ) {
elem[ expando ] = id;
thisCache[ name ] = data;
}
return name ? thisCache[ name ] : thisCache;
},
removeData: function( elem, name ) {
elem = elem == window ?
windowData :
elem;
var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];
// If we want to remove a specific section of the element's data
if ( name ) {
if ( thisCache ) {
// Remove the section of cache data
delete thisCache[ name ];
// If we've removed all the data, remove the element's cache
if ( jQuery.isEmptyObject(thisCache) ) {
jQuery.removeData( elem );
}
}
// Otherwise, we want to remove all of the element's data
} else {
// Clean up the element expando
try {
delete elem[ expando ];
} catch( e ) {
// IE has trouble directly removing the expando
// but it's ok with using removeAttribute
if ( elem.removeAttribute ) {
elem.removeAttribute( expando );
}
}
// Completely remove the data cache
delete cache[ id ];
}
},
queue: function( elem, type, data ) {
if ( !elem ) { return; }
type = (type || "fx") + "queue";
var q = jQuery.data( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if ( !data ) { return q || []; }
if ( !q || jQuery.isArray(data) ) {
q = jQuery.data( elem, type, jQuery.makeArray(data) );
} else {
q.push( data );
}
return q;
},
dequeue: function( elem, type ){
type = type || "fx";
var queue = jQuery.queue( elem, type ), fn = queue.shift();
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) { fn = queue.shift(); }
if ( fn ) {
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type == "fx" ) { queue.unshift("inprogress"); }
fn.call(elem, function() { jQuery.dequeue(elem, type); });
}
}
});
jQuery.fn.extend({
data: function( key, value ){
if ( typeof key === "undefined" && this.length ) {
return jQuery.data( this[0] );
}
var parts = key.split(".");
parts[1] = parts[1] ? "." + parts[1] : "";
if ( value === undefined ) {
var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
if ( data === undefined && this.length ) {
data = jQuery.data( this[0], key );
}
return data === undefined && parts[1] ?
this.data( parts[0] ) :
data;
} else {
return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
jQuery.data( this, key, value );
});
}
},
removeData: function( key ){
return this.each(function(){
jQuery.removeData( this, key );
});
},
queue: function(type, data){
if ( typeof type !== "string" ) {
data = type;
type = "fx";
}
if ( data === undefined ) {
return jQuery.queue( this[0], type );
}
return this.each(function(i, elem){
var queue = jQuery.queue( this, type, data );
if ( type == "fx" && queue[0] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
});
},
dequeue: function(type){
return this.each(function(){
jQuery.dequeue( this, type );
});
},
// Based off of the plugin by Clint Helfers, with permission.
// http://blindsignals.com/index.php/2009/07/jquery-delay/
delay: function( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
type = type || "fx";
return this.queue( type, function() {
var elem = this;
setTimeout(function() {
jQuery.dequeue( elem, type );
}, time );
});
},
clearQueue: function(type){
return this.queue( type || "fx", [] );
}
});
/*
* A number of helper functions used for managing events.
* Many of the ideas behind this code originated from
* Dean Edwards' addEvent library.
*/
jQuery.event = {
// Bind an event to an element
// Original by Dean Edwards
add: function( elem, types, handler, data ) {
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
// For whatever reason, IE has trouble passing the window object
// around, causing it to be cloned in the process
if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
elem = window;
}
// Make sure that the function being executed has a unique ID
if ( !handler.guid ) {
handler.guid = this.guid++;
}
// if data is passed, bind to handler
if ( data !== undefined ) {
// Create temporary function pointer to original handler
var fn = handler;
// Create unique handler function, wrapped around original handler
handler = this.proxy( fn );
// Store data in unique handler
handler.data = data;
}
// Init the element's event structure
var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ),
handle = jQuery.data( elem, "handle" ) || jQuery.data( elem, "handle", function() {
// Handle the second event of a trigger and when
// an event is called after a page has unloaded
return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
jQuery.event.handle.apply( arguments.callee.elem, arguments ) :
undefined;
});
// Add elem as a property of the handle function
// This is to prevent a memory leak with non-native
// event in IE.
handle.elem = elem;
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
types = types.split( /\s+/ );
var type, i=0;
while ( (type = types[ i++ ]) ) {
// Namespaced event handlers
var namespaces = type.split(".");
type = namespaces.shift();
handler.type = namespaces.slice(0).sort().join(".");
// Get the current list of functions bound to this event
var handlers = events[ type ],
special = this.special[ type ] || {};
// Init the event handler queue
if ( !handlers ) {
handlers = events[ type ] = {};
// Check for a special event handler
// Only use addEventListener/attachEvent if the special
// events handler returns false
if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
elem.addEventListener( type, handle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, handle );
}
}
}
if ( special.add ) {
var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers );
if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {
modifiedHandler.guid = modifiedHandler.guid || handler.guid;
handler = modifiedHandler;
}
}
// Add the function to the element's handler list
handlers[ handler.guid ] = handler;
// Keep track of which events have been used, for global triggering
this.global[ type ] = true;
}
// Nullify elem to prevent memory leaks in IE
elem = null;
},
guid: 1,
global: {},
// Detach an event or set of events from an element
remove: function( elem, types, handler ) {
// don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
var events = jQuery.data( elem, "events" ), ret, type, fn;
if ( events ) {
// Unbind all events for the element
if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
for ( type in events ) {
this.remove( elem, type + (types || "") );
}
} else {
// types is actually an event object here
if ( types.type ) {
handler = types.handler;
types = types.type;
}
// Handle multiple events seperated by a space
// jQuery(...).unbind("mouseover mouseout", fn);
types = types.split(/\s+/);
var i = 0;
while ( (type = types[ i++ ]) ) {
// Namespaced event handlers
var namespaces = type.split(".");
type = namespaces.shift();
var all = !namespaces.length,
cleaned = jQuery.map( namespaces.slice(0).sort() , function(nm){ return nm.replace(/[^\w\s\.\|`]/g, function(ch){return "\\"+ch }) }),
namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"),
special = this.special[ type ] || {};
if ( events[ type ] ) {
// remove the given handler for the given type
if ( handler ) {
fn = events[ type ][ handler.guid ];
delete events[ type ][ handler.guid ];
// remove all handlers for the given type
} else {
for ( var handle in events[ type ] ) {
// Handle the removal of namespaced events
if ( all || namespace.test( events[ type ][ handle ].type ) ) {
delete events[ type ][ handle ];
}
}
}
if ( special.remove ) {
special.remove.call( elem, namespaces, fn);
}
// remove generic event handler if no more handlers exist
for ( ret in events[ type ] ) {
break;
}
if ( !ret ) {
if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
if ( elem.removeEventListener ) {
elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
} else if ( elem.detachEvent ) {
elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) );
}
}
ret = null;
delete events[ type ];
}
}
}
}
// Remove the expando if it's no longer used
for ( ret in events ) {
break;
}
if ( !ret ) {
var handle = jQuery.data( elem, "handle" );
if ( handle ) {
handle.elem = null;
}
jQuery.removeData( elem, "events" );
jQuery.removeData( elem, "handle" );
}
}
},
// bubbling is internal
trigger: function( event, data, elem /*, bubbling */ ) {
// Event object or event type
var type = event.type || event,
bubbling = arguments[3];
if ( !bubbling ) {
event = typeof event === "object" ?
// jQuery.Event object
event[expando] ? event :
// Object literal
jQuery.extend( jQuery.Event(type), event ) :
// Just the event type (string)
jQuery.Event(type);
if ( type.indexOf("!") >= 0 ) {
event.type = type = type.slice(0, -1);
event.exclusive = true;
}
// Handle a global trigger
if ( !elem ) {
// Don't bubble custom events when global (to avoid too much overhead)
event.stopPropagation();
// Only trigger if we've ever bound an event for it
if ( this.global[ type ] ) {
jQuery.each( jQuery.cache, function() {
if ( this.events && this.events[type] ) {
jQuery.event.trigger( event, data, this.handle.elem );
}
});
}
}
// Handle triggering a single element
// don't do events on text and comment nodes
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
return undefined;
}
// Clean up in case it is reused
event.result = undefined;
event.target = elem;
// Clone the incoming data, if any
data = jQuery.makeArray( data );
data.unshift( event );
}
event.currentTarget = elem;
// Trigger the event, it is assumed that "handle" is a function
var handle = jQuery.data( elem, "handle" );
if ( handle ) {
handle.apply( elem, data );
}
var nativeFn, nativeHandler;
try {
nativeFn = elem[ type ];
nativeHandler = elem[ "on" + type ];
// prevent IE from throwing an error for some elements with some event types, see #3533
} catch (e) {}
// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
if ( (!nativeFn || (jQuery.nodeName(elem, 'a') && type === "click")) && nativeHandler && nativeHandler.apply( elem, data ) === false ) {
event.result = false;
}
// Trigger the native events (except for clicks on links)
if ( !bubbling && nativeFn && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type === "click") ) {
this.triggered = true;
try {
nativeFn();
// prevent IE from throwing an error for some hidden elements
} catch (e) {}
}
this.triggered = false;
if ( !event.isPropagationStopped() ) {
var parent = elem.parentNode || elem.ownerDocument;
if ( parent ) {
jQuery.event.trigger( event, data, parent, true );
}
}
},
handle: function( event ) {
// returned undefined or false
var all, handlers;
event = arguments[0] = jQuery.event.fix( event || window.event );
event.currentTarget = this;
// Namespaced event handlers
var namespaces = event.type.split(".");
event.type = namespaces.shift();
// Cache this now, all = true means, any handler
all = !namespaces.length && !event.exclusive;
var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
for ( var j in handlers ) {
var handler = handlers[ j ];
// Filter the functions by class
if ( all || namespace.test(handler.type) ) {
// Pass in a reference to the handler function itself
// So that we can later remove it
event.handler = handler;
event.data = handler.data;
var ret = handler.apply( this, arguments );
if ( ret !== undefined ) {
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
if ( event.isImmediatePropagationStopped() ) {
break;
}
}
}
},
props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix: function( event ) {
if ( event[ expando ] ) {
return event;
}
// store a copy of the original event object
// and "clone" to set read-only properties
var originalEvent = event;
event = jQuery.Event( originalEvent );
for ( var i = this.props.length, prop; i; ) {
prop = this.props[ --i ];
event[ prop ] = originalEvent[ prop ];
}
// Fix target property, if necessary
if ( !event.target ) {
event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
}
// check if target is a textnode (safari)
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
}
// Add relatedTarget, if necessary
if ( !event.relatedTarget && event.fromElement ) {
event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
}
// Calculate pageX/Y if missing and clientX/Y available
if ( event.pageX == null && event.clientX != null ) {
var doc = document.documentElement, body = document.body;
event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
}
// Add which for key events
if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
event.which = event.charCode || event.keyCode;
}
// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
if ( !event.metaKey && event.ctrlKey ) {
event.metaKey = event.ctrlKey;
}
// Add which for click: 1 == left; 2 == middle; 3 == right
// Note: button is not normalized, so don't use it
if ( !event.which && event.button !== undefined ) {
event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
}
return event;
},
proxy: function( fn, proxy, thisObject ) {
if ( proxy !== undefined && !jQuery.isFunction( proxy ) ) {
thisObject = proxy;
proxy = undefined;
}
// FIXME: Should proxy be redefined to be applied with thisObject if defined?
proxy = proxy || function() { return fn.apply( thisObject !== undefined ? thisObject : this, arguments ); };
// Set the guid of unique handler to the same of original handler, so it can be removed
proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
// So proxy can be declared as an argument
return proxy;
},
special: {
ready: {
// Make sure the ready event is setup
setup: bindReady,
teardown: function() {}
},
live: {
add: function( proxy, data, namespaces, live ) {
jQuery.extend( proxy, data || {} );
proxy.guid += data.selector + data.live;
jQuery.event.add( this, data.live, liveHandler, data );
},
remove: function( namespaces ) {
if ( namespaces.length ) {
var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
jQuery.each( (jQuery.data(this, "events").live || {}), function() {
if ( name.test(this.type) ) {
remove++;
}
});
if ( remove < 1 ) {
jQuery.event.remove( this, namespaces[0], liveHandler );
}
}
},
special: {}
}
}
};
jQuery.Event = function( src ){
// Allow instantiation without the 'new' keyword
if ( !this.preventDefault ) {
return new jQuery.Event( src );
}
// Event object
if ( src && src.type ) {
this.originalEvent = src;
this.type = src.type;
// Event type
} else {
this.type = src;
}
// timeStamp is buggy for some events on Firefox(#3843)
// So we won't rely on the native value
this.timeStamp = now();
// Mark it as fixed
this[ expando ] = true;
};
function returnFalse() {
return false;
}
function returnTrue() {
return true;
}
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
preventDefault: function() {
this.isDefaultPrevented = returnTrue;
var e = this.originalEvent;
if ( !e ) {
return;
}
// if preventDefault exists run it on the original event
if ( e.preventDefault ) {
e.preventDefault();
}
// otherwise set the returnValue property of the original event to false (IE)
e.returnValue = false;
},
stopPropagation: function() {
this.isPropagationStopped = returnTrue;
var e = this.originalEvent;
if ( !e ) {
return;
}
// if stopPropagation exists run it on the original event
if ( e.stopPropagation ) {
e.stopPropagation();
}
// otherwise set the cancelBubble property of the original event to true (IE)
e.cancelBubble = true;
},
stopImmediatePropagation: function(){
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
},
isDefaultPrevented: returnFalse,
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse
};
// Checks if an event happened on an element within another element
// Used in jQuery.event.special.mouseenter and mouseleave handlers
var withinElement = function( event ) {
// Check if mouse(over|out) are still within the same parent element
var parent = event.relatedTarget;
// Traverse up the tree
while ( parent && parent != this ) {
// Firefox sometimes assigns relatedTarget a XUL element
// which we cannot access the parentNode property of
try { parent = parent.parentNode; }
// assuming we've left the element since we most likely mousedover a xul element
catch(e) { break; }
}
if ( parent != this ) {
// set the correct event type
event.type = event.data;
// handle event if we actually just moused on to a non sub-element
jQuery.event.handle.apply( this, arguments );
}
},
// In case of event delegation, we only need to rename the event.type,
// liveHandler will take care of the rest.
delegate = function( event ) {
event.type = event.data;
jQuery.event.handle.apply( this, arguments );
};
// Create mouseenter and mouseleave events
jQuery.each({
mouseover: "mouseenter",
mouseout: "mouseleave"
}, function( orig, fix ) {
jQuery.event.special[ fix ] = {
setup: function(data){
jQuery.event.add( this, orig, data && data.selector ? delegate : withinElement, fix );
},
teardown: function(data){
jQuery.event.remove( this, orig, data && data.selector ? delegate : withinElement );
}
};
});
// submit delegation
jQuery.event.special.submit = {
setup: function( data, namespaces, fn ) {
if ( !jQuery.support.submitBubbles && this.nodeName.toLowerCase() !== "form" ) {
jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
var elem = e.target, type = elem.type;
if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
return trigger( "submit", this, arguments );
}
});
jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
var elem = e.target, type = elem.type;
if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
return trigger( "submit", this, arguments );
}
});
}
return false;
},
remove: function( namespaces, fn ) {
jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
}
};
// change delegation, happens here so we have bind.
jQuery.event.special.change = {
filters: {
click: function( e ) {
var elem = e.target;
if ( elem.nodeName.toLowerCase() === "input" && elem.type === "checkbox" ) {
return trigger( "change", this, arguments );
}
return changeFilters.keyup.call( this, e );
},
keyup: function( e ) {
var elem = e.target, data, index = elem.selectedIndex + "";
if ( elem.nodeName.toLowerCase() === "select" ) {
data = jQuery.data( elem, "_change_data" );
jQuery.data( elem, "_change_data", index );
if ( (elem.type === "select-multiple" || data != null) && data !== index ) {
return trigger( "change", this, arguments );
}
}
},
beforeactivate: function( e ) {
var elem = e.target;
if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" && !elem.checked ) {
return trigger( "change", this, arguments );
}
},
blur: function( e ) {
var elem = e.target, nodeName = elem.nodeName.toLowerCase();
if ( (nodeName === "textarea" || (nodeName === "input" && (elem.type === "text" || elem.type === "password")))
&& jQuery.data(elem, "_change_data") !== elem.value ) {
return trigger( "change", this, arguments );
}
},
focus: function( e ) {
var elem = e.target, nodeName = elem.nodeName.toLowerCase();
if ( nodeName === "textarea" || (nodeName === "input" && (elem.type === "text" || elem.type === "password" ) ) ) {
jQuery.data( elem, "_change_data", elem.value );
}
}
},
setup: function( data, namespaces, fn ) {
// return false if we bubble
if ( !jQuery.support.changeBubbles ) {
for ( var type in changeFilters ) {
jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
}
}
// always want to listen for change for trigger
return false;
},
remove: function( namespaces, fn ) {
if ( !jQuery.support.changeBubbles ) {
for ( var type in changeFilters ) {
jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
}
}
}
};
var changeFilters = jQuery.event.special.change.filters;
function trigger( type, elem, args ) {
args[0].type = type;
return jQuery.event.handle.apply( elem, args );
}
// Create "bubbling" focus and blur events
jQuery.each({
focus: "focusin",
blur: "focusout"
}, function( orig, fix ){
var event = jQuery.event,
handle = event.handle;
function ieHandler() {
arguments[0].type = orig;
return handle.apply(this, arguments);
}
event.special[orig] = {
setup:function() {
if ( this.addEventListener ) {
this.addEventListener( orig, handle, true );
} else {
event.add( this, fix, ieHandler );
}
},
teardown:function() {
if ( this.removeEventListener ) {
this.removeEventListener( orig, handle, true );
} else {
event.remove( this, fix, ieHandler );
}
}
};
});
jQuery.fn.extend({
// TODO: make bind(), unbind() and one() DRY!
bind: function( type, data, fn, thisObject ) {
// Handle object literals
if ( typeof type === "object" ) {
for ( var key in type ) {
this.bind(key, data, type[key], fn);
}
return this;
}
if ( jQuery.isFunction( data ) ) {
thisObject = fn;
fn = data;
data = undefined;
}
fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
return type === "unload" ? this.one(type, data, fn, thisObject) : this.each(function() {
jQuery.event.add( this, type, fn, data );
});
},
one: function( type, data, fn, thisObject ) {
// Handle object literals
if ( typeof type === "object" ) {
for ( var key in type ) {
this.one(key, data, type[key], fn);
}
return this;
}
if ( jQuery.isFunction( data ) ) {
thisObject = fn;
fn = data;
data = undefined;
}
fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
var one = jQuery.event.proxy( fn, function( event ) {
jQuery( this ).unbind( event, one );
return fn.apply( this, arguments );
});
return this.each(function() {
jQuery.event.add( this, type, one, data );
});
},
unbind: function( type, fn ) {
// Handle object literals
if ( typeof type === "object" && !type.preventDefault ) {
for ( var key in type ) {
this.unbind(key, type[key]);
}
return this;
}
return this.each(function() {
jQuery.event.remove( this, type, fn );
});
},
trigger: function( type, data ) {
return this.each(function() {
jQuery.event.trigger( type, data, this );
});
},
triggerHandler: function( type, data ) {
if ( this[0] ) {
var event = jQuery.Event( type );
event.preventDefault();
event.stopPropagation();
jQuery.event.trigger( event, data, this[0] );
return event.result;
}
},
toggle: function( fn ) {
// Save reference to arguments for access in closure
var args = arguments, i = 1;
// link all the functions, so any of them can unbind this click handler
while( i < args.length ) {
jQuery.event.proxy( fn, args[ i++ ] );
}
return this.click( jQuery.event.proxy( fn, function( event ) {
// Figure out which function to execute
var lastToggle = ( jQuery.data( this, 'lastToggle' + fn.guid ) || 0 ) % i;
jQuery.data( this, 'lastToggle' + fn.guid, lastToggle + 1 );
// Make sure that clicks stop
event.preventDefault();
// and execute the function
return args[ lastToggle ].apply( this, arguments ) || false;
}));
},
hover: function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
},
ready: function( fn ) {
// Attach the listeners
bindReady();
// If the DOM is already ready
if ( jQuery.isReady ) {
// Execute the function immediately
fn.call( document, jQuery );
// Otherwise, remember the function for later
} else {
// Add the function to the wait list
jQuery.readyList.push( fn );
}
return this;
},
live: function( type, data, fn, thisObject ) {
if ( jQuery.isFunction( data ) ) {
if ( fn !== undefined ) {
thisObject = fn;
}
fn = data;
data = undefined;
}
jQuery( this.context ).bind( liveConvert( type, this.selector ), {
data: data, selector: this.selector, live: type
}, fn, thisObject );
return this;
},
die: function( type, fn ) {
jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
return this;
}
});
function liveHandler( event ) {
var stop = true, elems = [], selectors = [], args = arguments,
related, match, fn, elem, j, i, data,
live = jQuery.extend({}, jQuery.data( this, "events" ).live);
for ( j in live ) {
fn = live[j];
if ( fn.live === event.type ||
fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {
data = fn.data;
if ( !(data.beforeFilter && data.beforeFilter[event.type] &&
!data.beforeFilter[event.type](event)) ) {
selectors.push( fn.selector );
}
} else {
delete live[j];
}
}
match = jQuery( event.target ).closest( selectors, event.currentTarget );
for ( i = 0, l = match.length; i < l; i++ ) {
for ( j in live ) {
fn = live[j];
elem = match[i].elem;
related = null;
if ( match[i].selector === fn.selector ) {
// Those two events require additional checking
if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
}
if ( !related || related !== elem ) {
elems.push({ elem: elem, fn: fn });
}
}
}
}
for ( i = 0, l = elems.length; i < l; i++ ) {
match = elems[i];
event.currentTarget = match.elem;
event.data = match.fn.data;
if ( match.fn.apply( match.elem, args ) === false ) {
stop = false;
break;
}
}
return stop;
}
function liveConvert( type, selector ) {
return ["live", type, selector//.replace(/[^\w\s\.]/g, function(ch){ return "\\"+ch})
.replace(/\./g, "`")
.replace(/ /g, "|")].join(".");
}
jQuery.extend({
isReady: false,
readyList: [],
// Handle when the DOM is ready
ready: function() {
// Make sure that the DOM is not already loaded
if ( !jQuery.isReady ) {
if ( !document.body ) {
return setTimeout( jQuery.ready, 13 );
}
// Remember that the DOM is ready
jQuery.isReady = true;
// If there are functions bound, to execute
if ( jQuery.readyList ) {
// Execute all of them
var fn, i = 0;
while ( (fn = jQuery.readyList[ i++ ]) ) {
fn.call( document, jQuery );
}
// Reset the list of functions
jQuery.readyList = null;
}
// Trigger any bound ready events
jQuery( document ).triggerHandler( "ready" );
}
}
});
var readyBound = false;
function bindReady() {
if ( readyBound ) { return; }
readyBound = true;
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
return jQuery.ready();
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", function() {
document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
jQuery.ready();
}, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", function() {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", arguments.callee );
jQuery.ready();
}
});
// If IE and not a frame
// continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e){}
if ( document.documentElement.doScroll && toplevel ) {
(function() {
if ( jQuery.isReady ) {
return;
}
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch( error ) {
setTimeout( arguments.callee, 0 );
return;
}
// and execute any waiting functions
jQuery.ready();
})();
}
}
// A fallback to window.onload, that will always work
jQuery.event.add( window, "load", jQuery.ready );
}
jQuery.each( ("blur focus load resize scroll unload click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup error").split(" "), function( i, name ) {
// Handle event binding
jQuery.fn[ name ] = function( fn ) {
return fn ? this.bind( name, fn ) : this.trigger( name );
};
});
// Prevent memory leaks in IE
// Window isn't included so as not to unbind existing unload events
// More info:
// - http://isaacschlueter.com/2006/10/msie-memory-leaks/
/*@cc_on
jQuery( window ).bind( 'unload', function() {
for ( var id in jQuery.cache ) {
// Skip the window
if ( id != 1 && jQuery.cache[ id ].handle ) {
jQuery.event.remove( jQuery.cache[ id ].handle.elem );
}
}
});
@*/
(function(){
jQuery.support = {};
var root = document.documentElement,
script = document.createElement("script"),
div = document.createElement("div"),
id = "script" + now();
div.style.display = "none";
div.innerHTML = ' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.55;">a</a><select><option>text</option></select>';
var all = div.getElementsByTagName("*"),
a = div.getElementsByTagName("a")[0];
// Can't get basic test support
if ( !all || !all.length || !a ) {
return;
}
jQuery.support = {
// IE strips leading whitespace when .innerHTML is used
leadingWhitespace: div.firstChild.nodeType == 3,
// Make sure that tbody elements aren't automatically inserted
// IE will insert them into empty tables
tbody: !div.getElementsByTagName("tbody").length,
// Make sure that link elements get serialized correctly by innerHTML
// This requires a wrapper element in IE
htmlSerialize: !!div.getElementsByTagName("link").length,
// Get the style information from getAttribute
// (IE uses .cssText insted)
style: /red/.test( a.getAttribute("style") ),
// Make sure that URLs aren't manipulated
// (IE normalizes it by default)
hrefNormalized: a.getAttribute("href") === "/a",
// Make sure that element opacity exists
// (IE uses filter instead)
opacity: a.style.opacity === "0.55",
// Verify style float existence
// (IE uses styleFloat instead of cssFloat)
cssFloat: !!a.style.cssFloat,
// Will be defined later
scriptEval: false,
noCloneEvent: true,
boxModel: null
};
script.type = "text/javascript";
try {
script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
} catch(e){}
root.insertBefore( script, root.firstChild );
// Make sure that the execution of code works by injecting a script
// tag with appendChild/createTextNode
// (IE doesn't support this, fails, and uses .text instead)
if ( window[ id ] ) {
jQuery.support.scriptEval = true;
delete window[ id ];
}
root.removeChild( script );
if ( div.attachEvent && div.fireEvent ) {
div.attachEvent("onclick", function click(){
// Cloning a node shouldn't copy over any
// bound event handlers (IE does this)
jQuery.support.noCloneEvent = false;
div.detachEvent("onclick", click);
});
div.cloneNode(true).fireEvent("onclick");
}
// Figure out if the W3C box model works as expected
// document.body must exist before we can do this
jQuery(function(){
var div = document.createElement("div");
div.style.width = div.style.paddingLeft = "1px";
document.body.appendChild( div );
jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
document.body.removeChild( div ).style.display = 'none';
div = null;
});
// Technique from Juriy Zaytsev
// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
var eventSupported = function( eventName ) {
var el = document.createElement("div");
eventName = "on" + eventName;
var isSupported = (eventName in el);
if ( !isSupported ) {
el.setAttribute(eventName, "return;");
isSupported = typeof el[eventName] === "function";
}
el = null;
return isSupported;
};
jQuery.support.submitBubbles = eventSupported("submit");
jQuery.support.changeBubbles = eventSupported("change");
// release memory in IE
root = script = div = all = a = null;
})();
jQuery.props = {
"for": "htmlFor",
"class": "className",
readonly: "readOnly",
maxlength: "maxLength",
cellspacing: "cellSpacing",
rowspan: "rowSpan",
colspan: "colSpan",
tabindex: "tabIndex",
usemap: "useMap",
frameborder: "frameBorder"
};
/*!
* Sizzle CSS Selector Engine - v1.0
* Copyright 2009, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
* More information: http://sizzlejs.com/
*/
(function(){
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
done = 0,
toString = Object.prototype.toString,
hasDuplicate = false,
baseHasDuplicate = true;
// Here we check if the JavaScript engine is using some sort of
// optimization where it does not always call our comparision
// function. If that is the case, discard the hasDuplicate value.
// Thus far that includes Google Chrome.
[0, 0].sort(function(){
baseHasDuplicate = false;
return 0;
});
var Sizzle = function(selector, context, results, seed) {
results = results || [];
var origContext = context = context || document;
if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
return [];
}
if ( !selector || typeof selector !== "string" ) {
return results;
}
var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),
soFar = selector;
// Reset the position of the chunker regexp (start from head)
while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
soFar = m[3];
parts.push( m[1] );
if ( m[2] ) {
extra = m[3];
break;
}
}
if ( parts.length > 1 && origPOS.exec( selector ) ) {
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
set = posProcess( parts[0] + parts[1], context );
} else {
set = Expr.relative[ parts[0] ] ?
[ context ] :
Sizzle( parts.shift(), context );
while ( parts.length ) {
selector = parts.shift();
if ( Expr.relative[ selector ] )
selector += parts.shift();
set = posProcess( selector, set );
}
}
} else {
// Take a shortcut and set the context if the root selector is an ID
// (but not if it'll be faster if the inner selector is an ID)
if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
var ret = Sizzle.find( parts.shift(), context, contextXML );
context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
}
if ( context ) {
var ret = seed ?
{ expr: parts.pop(), set: makeArray(seed) } :
Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
if ( parts.length > 0 ) {
checkSet = makeArray(set);
} else {
prune = false;
}
while ( parts.length ) {
var cur = parts.pop(), pop = cur;
if ( !Expr.relative[ cur ] ) {
cur = "";
} else {
pop = parts.pop();
}
if ( pop == null ) {
pop = context;
}
Expr.relative[ cur ]( checkSet, pop, contextXML );
}
} else {
checkSet = parts = [];
}
}
if ( !checkSet ) {
checkSet = set;
}
if ( !checkSet ) {
throw "Syntax error, unrecognized expression: " + (cur || selector);
}
if ( toString.call(checkSet) === "[object Array]" ) {
if ( !prune ) {
results.push.apply( results, checkSet );
} else if ( context && context.nodeType === 1 ) {
for ( var i = 0; checkSet[i] != null; i++ ) {
if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
results.push( set[i] );
}
}
} else {
for ( var i = 0; checkSet[i] != null; i++ ) {
if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
results.push( set[i] );
}
}
}
} else {
makeArray( checkSet, results );
}
if ( extra ) {
Sizzle( extra, origContext, results, seed );
Sizzle.uniqueSort( results );
}
return results;
};
Sizzle.uniqueSort = function(results){
if ( sortOrder ) {
hasDuplicate = baseHasDuplicate;
results.sort(sortOrder);
if ( hasDuplicate ) {
for ( var i = 1; i < results.length; i++ ) {
if ( results[i] === results[i-1] ) {
results.splice(i--, 1);
}
}
}
}
return results;
};
Sizzle.matches = function(expr, set){
return Sizzle(expr, null, null, set);
};
Sizzle.find = function(expr, context, isXML){
var set, match;
if ( !expr ) {
return [];
}
for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
var type = Expr.order[i], match;
if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
var left = match[1];
match.splice(1,1);
if ( left.substr( left.length - 1 ) !== "\\" ) {
match[1] = (match[1] || "").replace(/\\/g, "");
set = Expr.find[ type ]( match, context, isXML );
if ( set != null ) {
expr = expr.replace( Expr.match[ type ], "" );
break;
}
}
}
}
if ( !set ) {
set = context.getElementsByTagName("*");
}
return {set: set, expr: expr};
};
Sizzle.filter = function(expr, set, inplace, not){
var old = expr, result = [], curLoop = set, match, anyFound,
isXMLFilter = set && set[0] && isXML(set[0]);
while ( expr && set.length ) {
for ( var type in Expr.filter ) {
if ( (match = Expr.match[ type ].exec( expr )) != null ) {
var filter = Expr.filter[ type ], found, item;
anyFound = false;
if ( curLoop == result ) {
result = [];
}
if ( Expr.preFilter[ type ] ) {
match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
if ( !match ) {
anyFound = found = true;
} else if ( match === true ) {
continue;
}
}
if ( match ) {
for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
if ( item ) {
found = filter( item, match, i, curLoop );
var pass = not ^ !!found;
if ( inplace && found != null ) {
if ( pass ) {
anyFound = true;
} else {
curLoop[i] = false;
}
} else if ( pass ) {
result.push( item );
anyFound = true;
}
}
}
}
if ( found !== undefined ) {
if ( !inplace ) {
curLoop = result;
}
expr = expr.replace( Expr.match[ type ], "" );
if ( !anyFound ) {
return [];
}
break;
}
}
}
// Improper expression
if ( expr == old ) {
if ( anyFound == null ) {
throw "Syntax error, unrecognized expression: " + expr;
} else {
break;
}
}
old = expr;
}
return curLoop;
};
var Expr = Sizzle.selectors = {
order: [ "ID", "NAME", "TAG" ],
match: {
ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
},
leftMatch: {},
attrMap: {
"class": "className",
"for": "htmlFor"
},
attrHandle: {
href: function(elem){
return elem.getAttribute("href");
}
},
relative: {
"+": function(checkSet, part, isXML){
var isPartStr = typeof part === "string",
isTag = isPartStr && !/\W/.test(part),
isPartStrNotTag = isPartStr && !isTag;
if ( isTag && !isXML ) {
part = part.toUpperCase();
}
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
if ( (elem = checkSet[i]) ) {
while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
elem || false :
elem === part;
}
}
if ( isPartStrNotTag ) {
Sizzle.filter( part, checkSet, true );
}
},
">": function(checkSet, part, isXML){
var isPartStr = typeof part === "string";
if ( isPartStr && !/\W/.test(part) ) {
part = isXML ? part : part.toUpperCase();
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
var parent = elem.parentNode;
checkSet[i] = parent.nodeName === part ? parent : false;
}
}
} else {
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
checkSet[i] = isPartStr ?
elem.parentNode :
elem.parentNode === part;
}
}
if ( isPartStr ) {
Sizzle.filter( part, checkSet, true );
}
}
},
"": function(checkSet, part, isXML){
var doneName = done++, checkFn = dirCheck;
if ( !/\W/.test(part) ) {
var nodeCheck = part = isXML ? part : part.toUpperCase();
checkFn = dirNodeCheck;
}
checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
},
"~": function(checkSet, part, isXML){
var doneName = done++, checkFn = dirCheck;
if ( typeof part === "string" && !/\W/.test(part) ) {
var nodeCheck = part = isXML ? part : part.toUpperCase();
checkFn = dirNodeCheck;
}
checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
}
},
find: {
ID: function(match, context, isXML){
if ( typeof context.getElementById !== "undefined" && !isXML ) {
var m = context.getElementById(match[1]);
return m ? [m] : [];
}
},
NAME: function(match, context, isXML){
if ( typeof context.getElementsByName !== "undefined" ) {
var ret = [], results = context.getElementsByName(match[1]);
for ( var i = 0, l = results.length; i < l; i++ ) {
if ( results[i].getAttribute("name") === match[1] ) {
ret.push( results[i] );
}
}
return ret.length === 0 ? null : ret;
}
},
TAG: function(match, context){
return context.getElementsByTagName(match[1]);
}
},
preFilter: {
CLASS: function(match, curLoop, inplace, result, not, isXML){
match = " " + match[1].replace(/\\/g, "") + " ";
if ( isXML ) {
return match;
}
for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
if ( elem ) {
if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
if ( !inplace )
result.push( elem );
} else if ( inplace ) {
curLoop[i] = false;
}
}
}
return false;
},
ID: function(match){
return match[1].replace(/\\/g, "");
},
TAG: function(match, curLoop){
for ( var i = 0; curLoop[i] === false; i++ ){}
return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
},
CHILD: function(match){
if ( match[1] == "nth" ) {
// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
// calculate the numbers (first)n+(last) including if they are negative
match[2] = (test[1] + (test[2] || 1)) - 0;
match[3] = test[3] - 0;
}
// TODO: Move to normal caching system
match[0] = done++;
return match;
},
ATTR: function(match, curLoop, inplace, result, not, isXML){
var name = match[1].replace(/\\/g, "");
if ( !isXML && Expr.attrMap[name] ) {
match[1] = Expr.attrMap[name];
}
if ( match[2] === "~=" ) {
match[4] = " " + match[4] + " ";
}
return match;
},
PSEUDO: function(match, curLoop, inplace, result, not){
if ( match[1] === "not" ) {
// If we're dealing with a complex expression, or a simple one
if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
match[3] = Sizzle(match[3], null, null, curLoop);
} else {
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
if ( !inplace ) {
result.push.apply( result, ret );
}
return false;
}
} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
return true;
}
return match;
},
POS: function(match){
match.unshift( true );
return match;
}
},
filters: {
enabled: function(elem){
return elem.disabled === false && elem.type !== "hidden";
},
disabled: function(elem){
return elem.disabled === true;
},
checked: function(elem){
return elem.checked === true;
},
selected: function(elem){
// Accessing this property makes selected-by-default
// options in Safari work properly
elem.parentNode.selectedIndex;
return elem.selected === true;
},
parent: function(elem){
return !!elem.firstChild;
},
empty: function(elem){
return !elem.firstChild;
},
has: function(elem, i, match){
return !!Sizzle( match[3], elem ).length;
},
header: function(elem){
return /h\d/i.test( elem.nodeName );
},
text: function(elem){
return "text" === elem.type;
},
radio: function(elem){
return "radio" === elem.type;
},
checkbox: function(elem){
return "checkbox" === elem.type;
},
file: function(elem){
return "file" === elem.type;
},
password: function(elem){
return "password" === elem.type;
},
submit: function(elem){
return "submit" === elem.type;
},
image: function(elem){
return "image" === elem.type;
},
reset: function(elem){
return "reset" === elem.type;
},
button: function(elem){
return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
},
input: function(elem){
return /input|select|textarea|button/i.test(elem.nodeName);
}
},
setFilters: {
first: function(elem, i){
return i === 0;
},
last: function(elem, i, match, array){
return i === array.length - 1;
},
even: function(elem, i){
return i % 2 === 0;
},
odd: function(elem, i){
return i % 2 === 1;
},
lt: function(elem, i, match){
return i < match[3] - 0;
},
gt: function(elem, i, match){
return i > match[3] - 0;
},
nth: function(elem, i, match){
return match[3] - 0 == i;
},
eq: function(elem, i, match){
return match[3] - 0 == i;
}
},
filter: {
PSEUDO: function(elem, match, i, array){
var name = match[1], filter = Expr.filters[ name ];
if ( filter ) {
return filter( elem, i, match, array );
} else if ( name === "contains" ) {
return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
} else if ( name === "not" ) {
var not = match[3];
for ( var i = 0, l = not.length; i < l; i++ ) {
if ( not[i] === elem ) {
return false;
}
}
return true;
}
},
CHILD: function(elem, match){
var type = match[1], node = elem;
switch (type) {
case 'only':
case 'first':
while ( (node = node.previousSibling) ) {
if ( node.nodeType === 1 ) return false;
}
if ( type == 'first') return true;
node = elem;
case 'last':
while ( (node = node.nextSibling) ) {
if ( node.nodeType === 1 ) return false;
}
return true;
case 'nth':
var first = match[2], last = match[3];
if ( first == 1 && last == 0 ) {
return true;
}
var doneName = match[0],
parent = elem.parentNode;
if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
var count = 0;
for ( node = parent.firstChild; node; node = node.nextSibling ) {
if ( node.nodeType === 1 ) {
node.nodeIndex = ++count;
}
}
parent.sizcache = doneName;
}
var diff = elem.nodeIndex - last;
if ( first == 0 ) {
return diff == 0;
} else {
return ( diff % first == 0 && diff / first >= 0 );
}
}
},
ID: function(elem, match){
return elem.nodeType === 1 && elem.getAttribute("id") === match;
},
TAG: function(elem, match){
return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
},
CLASS: function(elem, match){
return (" " + (elem.className || elem.getAttribute("class")) + " ")
.indexOf( match ) > -1;
},
ATTR: function(elem, match){
var name = match[1],
result = Expr.attrHandle[ name ] ?
Expr.attrHandle[ name ]( elem ) :
elem[ name ] != null ?
elem[ name ] :
elem.getAttribute( name ),
value = result + "",
type = match[2],
check = match[4];
return result == null ?
type === "!=" :
type === "=" ?
value === check :
type === "*=" ?
value.indexOf(check) >= 0 :
type === "~=" ?
(" " + value + " ").indexOf(check) >= 0 :
!check ?
value && result !== false :
type === "!=" ?
value != check :
type === "^=" ?
value.indexOf(check) === 0 :
type === "$=" ?
value.substr(value.length - check.length) === check :
type === "|=" ?
value === check || value.substr(0, check.length + 1) === check + "-" :
false;
},
POS: function(elem, match, i, array){
var name = match[2], filter = Expr.setFilters[ name ];
if ( filter ) {
return filter( elem, i, match, array );
}
}
}
};
var origPOS = Expr.match.POS;
for ( var type in Expr.match ) {
Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source );
}
var makeArray = function(array, results) {
array = Array.prototype.slice.call( array, 0 );
if ( results ) {
results.push.apply( results, array );
return results;
}
return array;
};
// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
try {
Array.prototype.slice.call( document.documentElement.childNodes, 0 );
// Provide a fallback method if it does not work
} catch(e){
makeArray = function(array, results) {
var ret = results || [];
if ( toString.call(array) === "[object Array]" ) {
Array.prototype.push.apply( ret, array );
} else {
if ( typeof array.length === "number" ) {
for ( var i = 0, l = array.length; i < l; i++ ) {
ret.push( array[i] );
}
} else {
for ( var i = 0; array[i]; i++ ) {
ret.push( array[i] );
}
}
}
return ret;
};
}
var sortOrder;
if ( document.documentElement.compareDocumentPosition ) {
sortOrder = function( a, b ) {
if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
if ( a == b ) {
hasDuplicate = true;
}
return a.compareDocumentPosition ? -1 : 1;
}
var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
if ( ret === 0 ) {
hasDuplicate = true;
}
return ret;
};
} else if ( "sourceIndex" in document.documentElement ) {
sortOrder = function( a, b ) {
if ( !a.sourceIndex || !b.sourceIndex ) {
if ( a == b ) {
hasDuplicate = true;
}
return a.sourceIndex ? -1 : 1;
}
var ret = a.sourceIndex - b.sourceIndex;
if ( ret === 0 ) {
hasDuplicate = true;
}
return ret;
};
} else if ( document.createRange ) {
sortOrder = function( a, b ) {
if ( !a.ownerDocument || !b.ownerDocument ) {
if ( a == b ) {
hasDuplicate = true;
}
return a.ownerDocument ? -1 : 1;
}
var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
aRange.setStart(a, 0);
aRange.setEnd(a, 0);
bRange.setStart(b, 0);
bRange.setEnd(b, 0);
var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
if ( ret === 0 ) {
hasDuplicate = true;
}
return ret;
};
}
// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
// We're going to inject a fake input element with a specified name
var form = document.createElement("div"),
id = "script" + (new Date).getTime();
form.innerHTML = "<a name='" + id + "'/>";
// Inject it into the root element, check its status, and remove it quickly
var root = document.documentElement;
root.insertBefore( form, root.firstChild );
// The workaround has to do additional checks after a getElementById
// Which slows things down for other browsers (hence the branching)
if ( document.getElementById( id ) ) {
Expr.find.ID = function(match, context, isXML){
if ( typeof context.getElementById !== "undefined" && !isXML ) {
var m = context.getElementById(match[1]);
return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
}
};
Expr.filter.ID = function(elem, match){
var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
return elem.nodeType === 1 && node && node.nodeValue === match;
};
}
root.removeChild( form );
root = form = null; // release memory in IE
})();
(function(){
// Check to see if the browser returns only elements
// when doing getElementsByTagName("*")
// Create a fake element
var div = document.createElement("div");
div.appendChild( document.createComment("") );
// Make sure no comments are found
if ( div.getElementsByTagName("*").length > 0 ) {
Expr.find.TAG = function(match, context){
var results = context.getElementsByTagName(match[1]);
// Filter out possible comments
if ( match[1] === "*" ) {
var tmp = [];
for ( var i = 0; results[i]; i++ ) {
if ( results[i].nodeType === 1 ) {
tmp.push( results[i] );
}
}
results = tmp;
}
return results;
};
}
// Check to see if an attribute returns normalized href attributes
div.innerHTML = "<a href='#'></a>";
if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
div.firstChild.getAttribute("href") !== "#" ) {
Expr.attrHandle.href = function(elem){
return elem.getAttribute("href", 2);
};
}
div = null; // release memory in IE
})();
if ( document.querySelectorAll ) (function(){
var oldSizzle = Sizzle, div = document.createElement("div");
div.innerHTML = "<p class='TEST'></p>";
// Safari can't handle uppercase or unicode characters when
// in quirks mode.
if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
return;
}
Sizzle = function(query, context, extra, seed){
context = context || document;
// Only use querySelectorAll on non-XML documents
// (ID selectors don't work in non-HTML documents)
if ( !seed && context.nodeType === 9 && !isXML(context) ) {
try {
return makeArray( context.querySelectorAll(query), extra );
} catch(e){}
}
return oldSizzle(query, context, extra, seed);
};
for ( var prop in oldSizzle ) {
Sizzle[ prop ] = oldSizzle[ prop ];
}
div = null; // release memory in IE
})();
if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
var div = document.createElement("div");
div.innerHTML = "<div class='test e'></div><div class='test'></div>";
// Opera can't find a second classname (in 9.6)
if ( div.getElementsByClassName("e").length === 0 )
return;
// Safari caches class attributes, doesn't catch changes (in 3.2)
div.lastChild.className = "e";
if ( div.getElementsByClassName("e").length === 1 )
return;
Expr.order.splice(1, 0, "CLASS");
Expr.find.CLASS = function(match, context, isXML) {
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
return context.getElementsByClassName(match[1]);
}
};
div = null; // release memory in IE
})();
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
var sibDir = dir == "previousSibling" && !isXML;
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
if ( sibDir && elem.nodeType === 1 ){
elem.sizcache = doneName;
elem.sizset = i;
}
elem = elem[dir];
var match = false;
while ( elem ) {
if ( elem.sizcache === doneName ) {
match = checkSet[elem.sizset];
break;
}
if ( elem.nodeType === 1 && !isXML ){
elem.sizcache = doneName;
elem.sizset = i;
}
if ( elem.nodeName === cur ) {
match = elem;
break;
}
elem = elem[dir];
}
checkSet[i] = match;
}
}
}
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
var sibDir = dir == "previousSibling" && !isXML;
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
if ( sibDir && elem.nodeType === 1 ) {
elem.sizcache = doneName;
elem.sizset = i;
}
elem = elem[dir];
var match = false;
while ( elem ) {
if ( elem.sizcache === doneName ) {
match = checkSet[elem.sizset];
break;
}
if ( elem.nodeType === 1 ) {
if ( !isXML ) {
elem.sizcache = doneName;
elem.sizset = i;
}
if ( typeof cur !== "string" ) {
if ( elem === cur ) {
match = true;
break;
}
} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
match = elem;
break;
}
}
elem = elem[dir];
}
checkSet[i] = match;
}
}
}
var contains = document.compareDocumentPosition ? function(a, b){
return a.compareDocumentPosition(b) & 16;
} : function(a, b){
return a !== b && (a.contains ? a.contains(b) : true);
};
var isXML = function(elem){
return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
!!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
};
var posProcess = function(selector, context){
var tmpSet = [], later = "", match,
root = context.nodeType ? [context] : context;
// Position selectors must be done after the filter
// And so must :not(positional) so we move all PSEUDOs to the end
while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
later += match[0];
selector = selector.replace( Expr.match.PSEUDO, "" );
}
selector = Expr.relative[selector] ? selector + "*" : selector;
for ( var i = 0, l = root.length; i < l; i++ ) {
Sizzle( selector, root[i], tmpSet );
}
return Sizzle.filter( later, tmpSet );
};
// EXPOSE
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
jQuery.unique = Sizzle.uniqueSort;
return;
window.Sizzle = Sizzle;
})();
var runtil = /Until$/,
rparentsprev = /^(?:parents|prevUntil|prevAll)/,
// Note: This RegExp should be improved, or likely pulled from Sizzle
rmultiselector = /,/,
slice = Array.prototype.slice;
// Implement the identical functionality for filter and not
var winnow = function( elements, qualifier, keep ) {
if ( jQuery.isFunction( qualifier ) ) {
return jQuery.grep(elements, function(elem, i) {
return !!qualifier.call( elem, i ) === keep;
});
} else if ( qualifier.nodeType ) {
return jQuery.grep(elements, function(elem, i) {
return (elem === qualifier) === keep;
});
} else if ( typeof qualifier === "string" ) {
var filtered = jQuery.grep(elements, function(elem) {
return elem.nodeType === 1;
});
if ( isSimple.test( qualifier ) ) {
return jQuery.filter(qualifier, filtered, !keep);
} else {
qualifier = jQuery.filter( qualifier, elements );
}
}
return jQuery.grep(elements, function(elem, i) {
return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
});
};
jQuery.fn.extend({
find: function( selector ) {
var ret = this.pushStack( "", "find", selector ), length = 0;
for ( var i = 0, l = this.length; i < l; i++ ) {
length = ret.length;
jQuery.find( selector, this[i], ret );
if ( i > 0 ) {
// Make sure that the results are unique
for ( var n = length; n < ret.length; n++ ) {
for ( var r = 0; r < length; r++ ) {
if ( ret[r] === ret[n] ) {
ret.splice(n--, 1);
break;
}
}
}
}
}
return ret;
},
not: function( selector ) {
return this.pushStack( winnow(this, selector, false), "not", selector);
},
filter: function( selector ) {
return this.pushStack( winnow(this, selector, true), "filter", selector );
},
closest: function( selectors, context ) {
if ( jQuery.isArray( selectors ) ) {
var ret = [], cur = this[0], match, matches = {}, selector;
if ( cur && selectors.length ) {
for ( var i = 0, l = selectors.length; i < l; i++ ) {
selector = selectors[i];
if ( !matches[selector] ) {
matches[selector] = jQuery.expr.match.POS.test( selector ) ?
jQuery( selector, context || this.context ) :
selector;
}
}
while ( cur && cur.ownerDocument && cur !== context ) {
for ( selector in matches ) {
match = matches[selector];
if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
ret.push({ selector: selector, elem: cur });
delete matches[selector];
}
}
cur = cur.parentNode;
}
}
return ret;
}
var pos = jQuery.expr.match.POS.test( selectors ) ?
jQuery( selectors, context || this.context ) : null;
return this.map(function(i, cur){
while ( cur && cur.ownerDocument && cur !== context ) {
if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {
return cur;
}
cur = cur.parentNode;
}
return null;
});
},
add: function( selector, context ) {
var set = typeof selector === "string" ?
jQuery( selector, context || this.context ) :
jQuery.makeArray( selector ),
all = jQuery.merge( this.get(), set );
return this.pushStack( set[0] && (set[0].setInterval || set[0].nodeType === 9 || (set[0].parentNode && set[0].parentNode.nodeType !== 11)) ?
jQuery.unique( all ) :
all );
},
eq: function( i ) {
return i === -1 ?
this.slice( i ) :
this.slice( i, +i + 1 );
},
first: function() {
return this.eq( 0 );
},
last: function() {
return this.eq( -1 );
},
slice: function() {
return this.pushStack( slice.apply( this, arguments ),
"slice", slice.call(arguments).join(",") );
},
map: function( callback ) {
return this.pushStack( jQuery.map(this, function(elem, i){
return callback.call( elem, i, elem );
}));
},
andSelf: function() {
return this.add( this.prevObject );
},
end: function() {
return this.prevObject || jQuery(null);
}
});
jQuery.each({
parent: function(elem){return elem.parentNode;},
parents: function(elem){return jQuery.dir(elem,"parentNode");},
parentsUntil: function(elem,i,until){return jQuery.dir(elem,"parentNode",until);},
next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
nextUntil: function(elem,i,until){return jQuery.dir(elem,"nextSibling",until);},
prevUntil: function(elem,i,until){return jQuery.dir(elem,"previousSibling",until);},
siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
children: function(elem){return jQuery.sibling(elem.firstChild);},
contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
}, function(name, fn){
jQuery.fn[ name ] = function( until, selector ) {
var ret = jQuery.map( this, fn, until );
if ( !runtil.test( name ) ) {
selector = until;
}
if ( selector && typeof selector === "string" ) {
ret = jQuery.filter( selector, ret );
}
ret = this.length > 1 ? jQuery.unique( ret ) : ret;
if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
ret = ret.reverse();
}
return this.pushStack( ret, name, slice.call(arguments).join(",") );
};
});
jQuery.extend({
filter: function( expr, elems, not ) {
if ( not ) {
expr = ":not(" + expr + ")";
}
return jQuery.find.matches(expr, elems);
},
dir: function( elem, dir, until ) {
var matched = [], cur = elem[dir];
while ( cur && cur.nodeType !== 9 && (until === undefined || !jQuery( cur ).is( until )) ) {
if ( cur.nodeType === 1 ) {
matched.push( cur );
}
cur = cur[dir];
}
return matched;
},
nth: function( cur, result, dir, elem ) {
result = result || 1;
var num = 0;
for ( ; cur; cur = cur[dir] ) {
if ( cur.nodeType === 1 && ++num === result ) {
break;
}
}
return cur;
},
sibling: function( n, elem ) {
var r = [];
for ( ; n; n = n.nextSibling ) {
if ( n.nodeType === 1 && n !== elem ) {
r.push( n );
}
}
return r;
}
});
jQuery.fn.extend({
attr: function( name, value ) {
return access(this, name, value, true, jQuery.attr);
},
addClass: function( value ) {
if ( value && typeof value === "string" ) {
var classNames = (value || "").split(/\s+/);
for ( var i = 0, l = this.length; i < l; i++ ) {
var elem = this[i];
if ( elem.nodeType === 1 ) {
if ( !elem.className ) {
elem.className = value;
} else {
var className = " " + elem.className + " ";
for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
elem.className += " " + classNames[c];
}
}
}
}
}
}
return this;
},
removeClass: function( value ) {
if ( (value && typeof value === "string") || value === undefined ) {
var classNames = (value || "").split(/\s+/);
for ( var i = 0, l = this.length; i < l; i++ ) {
var elem = this[i];
if ( elem.nodeType === 1 && elem.className ) {
if ( value ) {
var className = " " + elem.className + " ";
for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
className = className.replace(" " + classNames[c] + " ", " ");
}
elem.className = className.substring(1, className.length - 1);
} else {
elem.className = "";
}
}
}
}
return this;
},
hasClass: function( selector ) {
var className = " " + selector + " ";
for ( var i = 0, l = this.length; i < l; i++ ) {
if ( (" " + this[i].className + " ").indexOf( className ) > -1 ) {
return true;
}
}
return false;
},
val: function( value ) {
if ( value === undefined ) {
var elem = this[0];
if ( elem ) {
if( jQuery.nodeName( elem, 'option' ) ) {
return (elem.attributes.value || {}).specified ? elem.value : elem.text;
}
// We need to handle select boxes special
if ( jQuery.nodeName( elem, "select" ) ) {
var index = elem.selectedIndex,
values = [],
options = elem.options,
one = elem.type == "select-one";
// Nothing was selected
if ( index < 0 ) {
return null;
}
// Loop through all the selected options
for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
var option = options[ i ];
if ( option.selected ) {
// Get the specifc value for the option
value = jQuery(option).val();
// We don't need an array for one selects
if ( one ) {
return value;
}
// Multi-Selects return an array
values.push( value );
}
}
return values;
}
// Everything else, we just grab the value
return (elem.value || "").replace(/\r/g, "");
}
return undefined;
}
// Typecast once if the value is a number
if ( typeof value === "number" ) {
value += '';
}
var val = value;
return this.each(function(){
if(jQuery.isFunction(value)) {
val = value.call(this);
// Typecast each time if the value is a Function and the appended
// value is therefore different each time.
if( typeof val === "number" ) {
val += '';
}
}
if ( this.nodeType != 1 ) {
return;
}
if ( jQuery.isArray(val) && /radio|checkbox/.test( this.type ) ) {
this.checked = jQuery.inArray(this.value || this.name, val) >= 0;
}
else if ( jQuery.nodeName( this, "select" ) ) {
var values = jQuery.makeArray(val);
jQuery( "option", this ).each(function(){
this.selected = jQuery.inArray( this.value || this.text, values ) >= 0;
});
if ( !values.length ) {
this.selectedIndex = -1;
}
} else {
this.value = val;
}
});
}
});
jQuery.each({
removeAttr: function( name ) {
jQuery.attr( this, name, "" );
if (this.nodeType == 1) {
this.removeAttribute( name );
}
},
toggleClass: function( classNames, state ) {
var type = typeof classNames;
if ( type === "string" ) {
// toggle individual class names
var isBool = typeof state === "boolean", className, i = 0,
classNames = classNames.split( /\s+/ );
while ( (className = classNames[ i++ ]) ) {
// check each className given, space seperated list
state = isBool ? state : !jQuery(this).hasClass( className );
jQuery(this)[ state ? "addClass" : "removeClass" ]( className );
}
} else if ( type === "undefined" || type === "boolean" ) {
if ( this.className ) {
// store className if set
jQuery.data( this, "__className__", this.className );
}
// toggle whole className
this.className = this.className || classNames === false ? "" : jQuery.data( this, "__className__" ) || "";
}
}
}, function(name, fn){
jQuery.fn[ name ] = function(){
return this.each( fn, arguments );
};
});
jQuery.extend({
attr: function( elem, name, value ) {
// don't set attributes on text and comment nodes
if (!elem || elem.nodeType == 3 || elem.nodeType == 8) {
return undefined;
}
if ( name in jQuery.fn && name !== "attr" ) {
return jQuery(elem)[name](value);
}
var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
// Whether we are setting (or getting)
set = value !== undefined;
// Try to normalize/fix the name
name = notxml && jQuery.props[ name ] || name;
// Only do all the following if this is a node (faster for style)
if ( elem.nodeType === 1 ) {
// These attributes require special treatment
var special = /href|src|style/.test( name );
// Safari mis-reports the default selected property of a hidden option
// Accessing the parent's selectedIndex property fixes it
if ( name == "selected" && elem.parentNode ) {
elem.parentNode.selectedIndex;
}
// If applicable, access the attribute via the DOM 0 way
if ( name in elem && notxml && !special ) {
if ( set ) {
// We can't allow the type property to be changed (since it causes problems in IE)
if ( name == "type" && /(button|input)/i.test(elem.nodeName) && elem.parentNode ) {
throw "type property can't be changed";
}
elem[ name ] = value;
}
// browsers index elements by id/name on forms, give priority to attributes.
if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
return elem.getAttributeNode( name ).nodeValue;
}
// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
if ( name == "tabIndex" ) {
var attributeNode = elem.getAttributeNode( "tabIndex" );
return attributeNode && attributeNode.specified
? attributeNode.value
: /(button|input|object|select|textarea)/i.test(elem.nodeName)
? 0
: /^(a|area)$/i.test(elem.nodeName) && elem.href
? 0
: undefined;
}
return elem[ name ];
}
if ( !jQuery.support.style && notxml && name == "style" ) {
if ( set ) {
elem.style.cssText = "" + value;
}
return elem.style.cssText;
}
if ( set ) {
// convert the value to a string (all browsers do this but IE) see #1070
elem.setAttribute( name, "" + value );
}
var attr = !jQuery.support.hrefNormalized && notxml && special
// Some attributes require a special call on IE
? elem.getAttribute( name, 2 )
: elem.getAttribute( name );
// Non-existent attributes return null, we normalize to undefined
return attr === null ? undefined : attr;
}
// elem is actually elem.style ... set the style
// Using attr for specific style information is now deprecated. Use style insead.
return jQuery.style(elem, name, value);
}
});
var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
rleadingWhitespace = /^\s+/,
rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g,
rselfClosing = /^(?:abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i,
rtagName = /<([\w:]+)/,
rtbody = /<tbody/i,
rhtml = /<|&\w+;/,
fcloseTag = function(all, front, tag){
return rselfClosing.test(tag) ?
all :
front + "></" + tag + ">";
},
wrapMap = {
option: [ 1, "<select multiple='multiple'>", "</select>" ],
legend: [ 1, "<fieldset>", "</fieldset>" ],
thead: [ 1, "<table>", "</table>" ],
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
_default: [ 0, "", "" ]
};
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
// IE can't serialize <link> and <script> tags normally
if ( !jQuery.support.htmlSerialize ) {
wrapMap._default = [ 1, "div<div>", "</div>" ];
}
jQuery.fn.extend({
text: function( text ) {
if ( typeof text !== "object" && text !== undefined ) {
return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
}
var ret = "";
jQuery.each( this, function() {
// Get the text from text nodes and CDATA nodes
if ( this.nodeType === 3 || this.nodeType === 4 ) {
ret += this.nodeValue;
// Traverse everything else, except comment nodes
} else if ( this.nodeType !== 8 ) {
ret += jQuery.fn.text.call( this.childNodes );
}
});
return ret;
},
wrapAll: function( html ) {
if ( jQuery.isFunction( html ) ) {
return this.each(function() {
jQuery(this).wrapAll( html.apply(this, arguments) );
});
}
if ( this[0] ) {
// The elements to wrap the target around
var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone();
if ( this[0].parentNode ) {
wrap.insertBefore( this[0] );
}
wrap.map(function(){
var elem = this;
while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
elem = elem.firstChild;
}
return elem;
}).append(this);
}
return this;
},
wrapInner: function( html ) {
return this.each(function(){
jQuery( this ).contents().wrapAll( html );
});
},
wrap: function( html ) {
return this.each(function(){
jQuery( this ).wrapAll( html );
});
},
unwrap: function() {
return this.parent().each(function(){
if ( !jQuery.nodeName( this, "body" ) ) {
jQuery( this ).replaceWith( this.childNodes );
}
}).end();
},
append: function() {
return this.domManip(arguments, true, function(elem){
if ( this.nodeType === 1 ) {
this.appendChild( elem );
}
});
},
prepend: function() {
return this.domManip(arguments, true, function(elem){
if ( this.nodeType === 1 ) {
this.insertBefore( elem, this.firstChild );
}
});
},
before: function() {
if ( this[0] && this[0].parentNode ) {
return this.domManip(arguments, false, function(elem){
this.parentNode.insertBefore( elem, this );
});
} else if ( arguments.length ) {
var set = jQuery(arguments[0]);
set.push.apply( set, this.toArray() );
return this.pushStack( set, "before", arguments );
}
},
after: function() {
if ( this[0] && this[0].parentNode ) {
return this.domManip(arguments, false, function(elem){
this.parentNode.insertBefore( elem, this.nextSibling );
});
} else if ( arguments.length ) {
var set = this.pushStack( this, "after", arguments );
set.push.apply( set, jQuery(arguments[0]).toArray() );
return set;
}
},
clone: function( events ) {
// Do the clone
var ret = this.map(function(){
if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
// IE copies events bound via attachEvent when
// using cloneNode. Calling detachEvent on the
// clone will also remove the events from the orignal
// In order to get around this, we use innerHTML.
// Unfortunately, this means some modifications to
// attributes in IE that are actually only stored
// as properties will not be copied (such as the
// the name attribute on an input).
var html = this.outerHTML, ownerDocument = this.ownerDocument;
if ( !html ) {
var div = ownerDocument.createElement("div");
div.appendChild( this.cloneNode(true) );
html = div.innerHTML;
}
return jQuery.clean([html.replace(rinlinejQuery, "")
.replace(rleadingWhitespace, "")], ownerDocument)[0];
} else {
return this.cloneNode(true);
}
});
// Copy the events from the original to the clone
if ( events === true ) {
cloneCopyEvent( this, ret );
cloneCopyEvent( this.find("*"), ret.find("*") );
}
// Return the cloned set
return ret;
},
html: function( value ) {
if ( value === undefined ) {
return this[0] ?
this[0].innerHTML.replace(rinlinejQuery, "") :
null;
// See if we can take a shortcut and just use innerHTML
} else if ( typeof value === "string" && !/<script/i.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
} else {
this.empty().append( value );
}
return this;
},
replaceWith: function( value ) {
if ( this[0] && this[0].parentNode ) {
return this.after( value ).remove();
} else {
return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value );
}
},
detach: function( selector ) {
return this.remove( selector, true );
},
domManip: function( args, table, callback ) {
var results, first, value = args[0], scripts = [];
if ( jQuery.isFunction(value) ) {
return this.each(function() {
args[0] = value.call(this);
return jQuery(this).domManip( args, table, callback );
});
}
if ( this[0] ) {
// If we're in a fragment, just use that instead of building a new one
if ( args[0] && args[0].parentNode && args[0].parentNode.nodeType === 11 ) {
results = { fragment: args[0].parentNode };
} else {
results = buildFragment( args, this, scripts );
}
first = results.fragment.firstChild;
if ( first ) {
table = table && jQuery.nodeName( first, "tr" );
for ( var i = 0, l = this.length; i < l; i++ ) {
callback.call(
table ?
root(this[i], first) :
this[i],
results.cacheable || this.length > 1 || i > 0 ?
results.fragment.cloneNode(true) :
results.fragment
);
}
}
if ( scripts ) {
jQuery.each( scripts, evalScript );
}
}
return this;
function root( elem, cur ) {
return jQuery.nodeName(elem, "table") ?
(elem.getElementsByTagName("tbody")[0] ||
elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
elem;
}
}
});
function cloneCopyEvent(orig, ret) {
var i = 0;
ret.each(function(){
if ( this.nodeName !== orig[i].nodeName ) {
return;
}
var events = jQuery.data( orig[i], "events" );
for ( var type in events ) {
for ( var handler in events[ type ] ) {
jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
}
}
});
}
function buildFragment(args, nodes, scripts){
var fragment, cacheable, cached, cacheresults, doc;
if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && args[0].indexOf("<option") < 0 ) {
cacheable = true;
cacheresults = jQuery.fragments[ args[0] ];
if ( cacheresults ) {
if ( cacheresults !== 1 ) {
fragment = cacheresults;
}
cached = true;
}
}
if ( !fragment ) {
doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
fragment = doc.createDocumentFragment();
jQuery.clean( args, doc, fragment, scripts );
}
if ( cacheable ) {
jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
}
return { fragment: fragment, cacheable: cacheable };
}
jQuery.fragments = {};
jQuery.each({
appendTo: "append",
prependTo: "prepend",
insertBefore: "before",
insertAfter: "after",
replaceAll: "replaceWith"
}, function(name, original){
jQuery.fn[ name ] = function( selector ) {
var ret = [], insert = jQuery( selector );
for ( var i = 0, l = insert.length; i < l; i++ ) {
var elems = (i > 0 ? this.clone(true) : this).get();
jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
ret = ret.concat( elems );
}
return this.pushStack( ret, name, insert.selector );
};
});
jQuery.each({
// keepData is for internal use only--do not document
remove: function( selector, keepData ) {
if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
if ( !keepData && this.nodeType === 1 ) {
cleanData( this.getElementsByTagName("*") );
cleanData( [ this ] );
}
if ( this.parentNode ) {
this.parentNode.removeChild( this );
}
}
},
empty: function() {
// Remove element nodes and prevent memory leaks
if ( this.nodeType === 1 ) {
cleanData( this.getElementsByTagName("*") );
}
// Remove any remaining nodes
while ( this.firstChild ) {
this.removeChild( this.firstChild );
}
}
}, function(name, fn){
jQuery.fn[ name ] = function(){
return this.each( fn, arguments );
};
});
jQuery.extend({
clean: function( elems, context, fragment, scripts ) {
context = context || document;
// !context.createElement fails in IE with an error but returns typeof 'object'
if ( typeof context.createElement === "undefined" ) {
context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
}
var ret = [], div = context.createElement("div");
jQuery.each(elems, function(i, elem){
if ( typeof elem === "number" ) {
elem += '';
}
if ( !elem ) { return; }
// Convert html string into DOM nodes
if ( typeof elem === "string" && !rhtml.test( elem ) ) {
elem = context.createTextNode( elem );
} else if ( typeof elem === "string" ) {
// Fix "XHTML"-style tags in all browsers
elem = elem.replace(rxhtmlTag, fcloseTag);
// Trim whitespace, otherwise indexOf won't work as expected
var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
wrap = wrapMap[ tag ] || wrapMap._default,
depth = wrap[0];
// Go to html and back, then peel off extra wrappers
div.innerHTML = wrap[1] + elem + wrap[2];
// Move to the right depth
while ( depth-- ) {
div = div.lastChild;
}
// Remove IE's autoinserted <tbody> from table fragments
if ( !jQuery.support.tbody ) {
// String was a <table>, *may* have spurious <tbody>
var hasBody = rtbody.test(elem),
tbody = tag === "table" && !hasBody ?
div.firstChild && div.firstChild.childNodes :
// String was a bare <thead> or <tfoot>
wrap[1] == "<table>" && !hasBody ?
div.childNodes :
[];
for ( var j = tbody.length - 1; j >= 0 ; --j ) {
if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
tbody[ j ].parentNode.removeChild( tbody[ j ] );
}
}
}
// IE completely kills leading whitespace when innerHTML is used
if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
}
elem = jQuery.makeArray( div.childNodes );
}
if ( elem.nodeType ) {
ret.push( elem );
} else {
ret = jQuery.merge( ret, elem );
}
});
if ( fragment ) {
for ( var i = 0; ret[i]; i++ ) {
if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
} else {
if ( ret[i].nodeType === 1 ) {
ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
}
fragment.appendChild( ret[i] );
}
}
}
return ret;
}
});
function cleanData( elems ) {
for ( var i = 0, elem, id; (elem = elems[i]) != null; i++ ) {
if ( (id = elem[expando]) ) {
delete jQuery.cache[ id ];
}
}
}
// exclude the following css properties to add px
var rexclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
ralpha = /alpha\([^)]*\)/,
ropacity = /opacity=([^)]*)/,
rfloat = /float/i,
rdashAlpha = /-([a-z])/ig,
rupper = /([A-Z])/g,
rnumpx = /^\d+(?:px)?$/i,
rnum = /^\d/,
// cache check for defaultView.getComputedStyle
getComputedStyle = document.defaultView && document.defaultView.getComputedStyle,
// normalize float css property
styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat",
fcamelCase = function(all, letter){
return letter.toUpperCase();
};
jQuery.fn.css = function( name, value ) {
return access( this, name, value, true, function( elem, name, value ) {
if (value === undefined) {
return jQuery.css( elem, name );
}
if ( typeof value === "number" && !rexclude.test(name) ) {
value += "px";
}
jQuery.style( elem, name, value );
});
};
jQuery.extend({
style: function( elem, name, value ) {
// don't set styles on text and comment nodes
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
return undefined;
}
// ignore negative width and height values #1599
if ( (name === "width" || name === "height") && parseFloat(value) < 0 ) {
value = undefined;
}
var style = elem.style || elem, set = value !== undefined;
// IE uses filters for opacity
if ( !jQuery.support.opacity && name === "opacity" ) {
if ( set ) {
// IE has trouble with opacity if it does not have layout
// Force it by setting the zoom level
style.zoom = 1;
// Set the alpha filter to set the opacity
var opacity = parseInt( value, 10 ) + '' === "NaN" ? "" : "alpha(opacity=" + value * 100 + ")";
filter = style.filter || jQuery.curCSS( elem, 'filter' ) || ""
style.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : opacity;
}
return style.filter && style.filter.indexOf("opacity=") >= 0 ?
(parseFloat( ropacity.exec(style.filter)[1] ) / 100) + '':
"";
}
// Make sure we're using the right name for getting the float value
if ( rfloat.test( name ) ) {
name = styleFloat;
}
name = name.replace(rdashAlpha, fcamelCase);
if ( set ) {
style[ name ] = value;
}
return style[ name ];
},
css: function( elem, name, force, extra ) {
if ( name === "width" || name === "height" ) {
var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name === "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
function getWH() {
val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
if ( extra === "border" ) { return; }
jQuery.each( which, function() {
if ( !extra ) {
val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
}
if ( extra === "margin" ) {
val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
} else {
val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
}
});
}
if ( elem.offsetWidth !== 0 ) {
getWH();
} else {
jQuery.swap( elem, props, getWH );
}
return Math.max(0, Math.round(val));
}
return jQuery.curCSS( elem, name, force );
},
curCSS: function( elem, name, force ) {
var ret, style = elem.style, filter;
// IE uses filters for opacity
if ( !jQuery.support.opacity && name === "opacity" && elem.currentStyle ) {
ret = ropacity.test(elem.currentStyle.filter || "") ?
(parseFloat(RegExp.$1) / 100) + "" :
"";
return ret === "" ?
"1" :
ret;
}
// Make sure we're using the right name for getting the float value
if ( rfloat.test( name ) ) {
name = styleFloat;
}
if ( !force && style && style[ name ] ) {
ret = style[ name ];
} else if ( getComputedStyle ) {
// Only "float" is needed here
if ( rfloat.test( name ) ) {
name = "float";
}
name = name.replace( rupper, "-$1" ).toLowerCase();
var computedStyle = elem.ownerDocument.defaultView.getComputedStyle( elem, null );
if ( computedStyle ) {
ret = computedStyle.getPropertyValue( name );
}
// We should always get a number back from opacity
if ( name === "opacity" && ret === "" ) {
ret = "1";
}
} else if ( elem.currentStyle ) {
var camelCase = name.replace(rdashAlpha, fcamelCase);
ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
// From the awesome hack by Dean Edwards
// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
// If we're not dealing with a regular pixel number
// but a number that has a weird ending, we need to convert it to pixels
if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
// Remember the original values
var left = style.left, rsLeft = elem.runtimeStyle.left;
// Put in the new values to get a computed value out
elem.runtimeStyle.left = elem.currentStyle.left;
style.left = camelCase === "fontSize" ? "1em" : (ret || 0);
ret = style.pixelLeft + "px";
// Revert the changed values
style.left = left;
elem.runtimeStyle.left = rsLeft;
}
}
return ret;
},
// A method for quickly swapping in/out CSS properties to get correct calculations
swap: function( elem, options, callback ) {
var old = {};
// Remember the old values, and insert the new ones
for ( var name in options ) {
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
callback.call( elem );
// Revert the old values
for ( var name in options ) {
elem.style[ name ] = old[ name ];
}
}
});
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.hidden = function(elem){
var width = elem.offsetWidth, height = elem.offsetHeight,
force = /^tr$/i.test( elem.nodeName ); // ticket #4512
return width === 0 && height === 0 && !force ?
true :
width !== 0 && height !== 0 && !force ?
false :
jQuery.curCSS(elem, "display") === "none";
};
jQuery.expr.filters.visible = function(elem){
return !jQuery.expr.filters.hidden(elem);
};
}
var jsc = now(),
rscript = /<script(.|\s)*?\/script>/g,
rselectTextarea = /select|textarea/i,
rinput = /text|hidden|password|search/i,
jsre = /=\?(&|$)/,
rquery = /\?/,
rts = /(\?|&)_=.*?(&|$)/,
rurl = /^(\w+:)?\/\/([^\/?#]+)/,
r20 = /%20/g;
jQuery.fn.extend({
// Keep a copy of the old load
_load: jQuery.fn.load,
load: function( url, params, callback ) {
if ( typeof url !== "string" ) {
return this._load( url );
// Don't do a request if no elements are being requested
} else if ( !this.length ) {
return this;
}
var off = url.indexOf(" ");
if ( off >= 0 ) {
var selector = url.slice(off, url.length);
url = url.slice(0, off);
}
// Default to a GET request
var type = "GET";
// If the second parameter was provided
if ( params ) {
// If it's a function
if ( jQuery.isFunction( params ) ) {
// We assume that it's the callback
callback = params;
params = null;
// Otherwise, build a param string
} else if ( typeof params === "object" ) {
params = jQuery.param( params );
type = "POST";
}
}
// Request the remote document
jQuery.ajax({
url: url,
type: type,
dataType: "html",
data: params,
context:this,
complete: function(res, status){
// If successful, inject the HTML into all the matched elements
if ( status === "success" || status === "notmodified" ) {
// See if a selector was specified
this.html( selector ?
// Create a dummy div to hold the results
jQuery("<div />")
// inject the contents of the document in, removing the scripts
// to avoid any 'Permission Denied' errors in IE
.append(res.responseText.replace(rscript, ""))
// Locate the specified elements
.find(selector) :
// If not, just inject the full result
res.responseText );
}
if ( callback ) {
this.each( callback, [res.responseText, status, res] );
}
}
});
return this;
},
serialize: function() {
return jQuery.param(this.serializeArray());
},
serializeArray: function() {
return this.map(function(){
return this.elements ? jQuery.makeArray(this.elements) : this;
})
.filter(function(){
return this.name && !this.disabled &&
(this.checked || rselectTextarea.test(this.nodeName) ||
rinput.test(this.type));
})
.map(function(i, elem){
var val = jQuery(this).val();
return val == null ?
null :
jQuery.isArray(val) ?
jQuery.map( val, function(val, i){
return {name: elem.name, value: val};
}) :
{name: elem.name, value: val};
}).get();
}
});
// Attach a bunch of functions for handling common AJAX events
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function(i,o){
jQuery.fn[o] = function(f){
return this.bind(o, f);
};
});
jQuery.extend({
get: function( url, data, callback, type ) {
// shift arguments if data argument was omited
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = null;
}
return jQuery.ajax({
type: "GET",
url: url,
data: data,
success: callback,
dataType: type
});
},
getScript: function( url, callback ) {
return jQuery.get(url, null, callback, "script");
},
getJSON: function( url, data, callback ) {
return jQuery.get(url, data, callback, "json");
},
post: function( url, data, callback, type ) {
// shift arguments if data argument was omited
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = {};
}
return jQuery.ajax({
type: "POST",
url: url,
data: data,
success: callback,
dataType: type
});
},
ajaxSetup: function( settings ) {
jQuery.extend( jQuery.ajaxSettings, settings );
},
ajaxSettings: {
url: location.href,
global: true,
type: "GET",
contentType: "application/x-www-form-urlencoded",
processData: true,
async: true,
/*
timeout: 0,
data: null,
username: null,
password: null,
*/
// Create the request object; Microsoft failed to properly
// implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
// This function can be overriden by calling jQuery.ajaxSetup
xhr: function(){
return window.ActiveXObject ?
new ActiveXObject("Microsoft.XMLHTTP") :
new XMLHttpRequest();
},
accepts: {
xml: "application/xml, text/xml",
html: "text/html",
script: "text/javascript, application/javascript",
json: "application/json, text/javascript",
text: "text/plain",
_default: "*/*"
}
},
// Last-Modified header cache for next request
lastModified: {},
etag: {},
ajax: function( s ) {
// Extend the settings, but re-extend 's' so that it can be
// checked again later (in the test suite, specifically)
s = jQuery.extend(true, {}, jQuery.ajaxSettings, s);
var jsonp, status, data,
callbackContext = s.context || window,
type = s.type.toUpperCase();
// convert data if not already a string
if ( s.data && s.processData && typeof s.data !== "string" ) {
s.data = jQuery.param(s.data);
}
// Handle JSONP Parameter Callbacks
if ( s.dataType === "jsonp" ) {
if ( type === "GET" ) {
if ( !jsre.test( s.url ) ) {
s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";
}
} else if ( !s.data || !jsre.test(s.data) ) {
s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
}
s.dataType = "json";
}
// Build temporary JSONP function
if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
jsonp = "jsonp" + jsc++;
// Replace the =? sequence both in the query string and the data
if ( s.data ) {
s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
}
s.url = s.url.replace(jsre, "=" + jsonp + "$1");
// We need to make sure
// that a JSONP style response is executed properly
s.dataType = "script";
// Handle JSONP-style loading
window[ jsonp ] = function(tmp){
data = tmp;
success();
complete();
// Garbage collect
window[ jsonp ] = undefined;
try{ delete window[ jsonp ]; } catch(e){}
if ( head ) {
head.removeChild( script );
}
};
}
if ( s.dataType === "script" && s.cache === null ) {
s.cache = false;
}
if ( s.cache === false && type === "GET" ) {
var ts = now();
// try replacing _= if it is there
var ret = s.url.replace(rts, "$1_=" + ts + "$2");
// if nothing was replaced, add timestamp to the end
s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
}
// If data is available, append data to url for get requests
if ( s.data && type === "GET" ) {
s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
}
// Watch for a new set of requests
if ( s.global && ! jQuery.active++ ) {
jQuery.event.trigger( "ajaxStart" );
}
// Matches an absolute URL, and saves the domain
var parts = rurl.exec( s.url ),
remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
// If we're requesting a remote document
// and trying to load JSON or Script with a GET
if ( s.dataType === "script" && type === "GET" && remote ) {
var head = document.getElementsByTagName("head")[0] || document.documentElement;
var script = document.createElement("script");
script.src = s.url;
if ( s.scriptCharset ) {
script.charset = s.scriptCharset;
}
// Handle Script loading
if ( !jsonp ) {
var done = false;
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function(){
if ( !done && (!this.readyState ||
this.readyState === "loaded" || this.readyState === "complete") ) {
done = true;
success();
complete();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
if ( head && script.parentNode ) {
head.removeChild( script );
}
}
};
}
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709 and #4378).
head.insertBefore( script, head.firstChild );
// We handle everything using the script element injection
return undefined;
}
var requestDone = false;
// Create the request object
var xhr = s.xhr();
// Open the socket
// Passing null username, generates a login popup on Opera (#2865)
if ( s.username ) {
xhr.open(type, s.url, s.async, s.username, s.password);
} else {
xhr.open(type, s.url, s.async);
}
// Need an extra try/catch for cross domain requests in Firefox 3
try {
// Set the correct header, if data is being sent
if ( s.data ) {
xhr.setRequestHeader("Content-Type", s.contentType);
}
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
if ( jQuery.lastModified[s.url] ) {
xhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);
}
if ( jQuery.etag[s.url] ) {
xhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);
}
}
// Set header so the called script knows that it's an XMLHttpRequest
// Only send the header if it's not a remote XHR
if ( !remote ) {
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
}
// Set the Accepts header for the server, depending on the dataType
xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
s.accepts[ s.dataType ] + ", */*" :
s.accepts._default );
} catch(e){}
// Allow custom headers/mimetypes and early abort
if ( s.beforeSend && s.beforeSend.call(callbackContext, xhr, s) === false ) {
// Handle the global AJAX counter
if ( s.global && ! --jQuery.active ) {
jQuery.event.trigger( "ajaxStop" );
}
// close opended socket
xhr.abort();
return false;
}
if ( s.global ) {
trigger("ajaxSend", [xhr, s]);
}
// Wait for a response to come back
var onreadystatechange = function(isTimeout){
// The request was aborted, clear the interval and decrement jQuery.active
if ( !xhr || xhr.readyState === 0 ) {
if ( ival ) {
// clear poll interval
clearInterval( ival );
ival = null;
// Handle the global AJAX counter
if ( s.global && ! --jQuery.active ) {
jQuery.event.trigger( "ajaxStop" );
}
}
// The transfer is complete and the data is available, or the request timed out
} else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {
requestDone = true;
// clear poll interval
if (ival) {
clearInterval(ival);
ival = null;
}
status = isTimeout === "timeout" ?
"timeout" :
!jQuery.httpSuccess( xhr ) ?
"error" :
s.ifModified && jQuery.httpNotModified( xhr, s.url ) ?
"notmodified" :
"success";
if ( status === "success" ) {
// Watch for, and catch, XML document parse errors
try {
// process the data (runs the xml through httpData regardless of callback)
data = jQuery.httpData( xhr, s.dataType, s );
} catch(e) {
status = "parsererror";
}
}
// Make sure that the request was successful or notmodified
if ( status === "success" || status === "notmodified" ) {
// JSONP handles its own success callback
if ( !jsonp ) {
success();
}
} else {
jQuery.handleError(s, xhr, status);
}
// Fire the complete handlers
complete();
if ( isTimeout ) {
xhr.abort();
}
// Stop memory leaks
if ( s.async ) {
xhr = null;
}
}
};
if ( s.async ) {
// don't attach the handler to the request, just poll it instead
var ival = setInterval(onreadystatechange, 13);
// Timeout checker
if ( s.timeout > 0 ) {
setTimeout(function(){
// Check to see if the request is still happening
if ( xhr && !requestDone ) {
onreadystatechange( "timeout" );
}
}, s.timeout);
}
}
// Send the data
try {
xhr.send( type === "POST" || type === "PUT" ? s.data : null );
} catch(e) {
jQuery.handleError(s, xhr, null, e);
// Fire the complete handlers
complete();
}
// firefox 1.5 doesn't fire statechange for sync requests
if ( !s.async ) {
onreadystatechange();
}
function success(){
// If a local callback was specified, fire it and pass it the data
if ( s.success ) {
s.success.call( callbackContext, data, status, xhr );
}
// Fire the global callback
if ( s.global ) {
trigger( "ajaxSuccess", [xhr, s] );
}
}
function complete(){
// Process result
if ( s.complete ) {
s.complete.call( callbackContext, xhr, status);
}
// The request was completed
if ( s.global ) {
trigger( "ajaxComplete", [xhr, s] );
}
// Handle the global AJAX counter
if ( s.global && ! --jQuery.active ) {
jQuery.event.trigger( "ajaxStop" );
}
}
function trigger(type, args){
(s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
}
// return XMLHttpRequest to allow aborting the request etc.
return xhr;
},
handleError: function( s, xhr, status, e ) {
// If a local callback was specified, fire it
if ( s.error ) {
s.error.call( s.context || window, xhr, status, e );
}
// Fire the global callback
if ( s.global ) {
(s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] );
}
},
// Counter for holding the number of active queries
active: 0,
// Determines if an XMLHttpRequest was successful or not
httpSuccess: function( xhr ) {
try {
// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
return !xhr.status && location.protocol === "file:" ||
// Opera returns 0 when status is 304
( xhr.status >= 200 && xhr.status < 300 ) ||
xhr.status === 304 || xhr.status === 1223 || xhr.status === 0;
} catch(e){}
return false;
},
// Determines if an XMLHttpRequest returns NotModified
httpNotModified: function( xhr, url ) {
var lastModified = xhr.getResponseHeader("Last-Modified"),
etag = xhr.getResponseHeader("Etag");
if ( lastModified ) {
jQuery.lastModified[url] = lastModified;
}
if ( etag ) {
jQuery.etag[url] = etag;
}
// Opera returns 0 when status is 304
return xhr.status === 304 || xhr.status === 0;
},
httpData: function( xhr, type, s ) {
var ct = xhr.getResponseHeader("content-type"),
xml = type === "xml" || !type && ct && ct.indexOf("xml") >= 0,
data = xml ? xhr.responseXML : xhr.responseText;
if ( xml && data.documentElement.nodeName === "parsererror" ) {
throw "parsererror";
}
// Allow a pre-filtering function to sanitize the response
// s is checked to keep backwards compatibility
if ( s && s.dataFilter ) {
data = s.dataFilter( data, type );
}
// The filter can actually parse the response
if ( typeof data === "string" ) {
// If the type is "script", eval it in global context
if ( type === "script" ) {
jQuery.globalEval( data );
}
// Get the JavaScript object, if JSON is used.
if ( type === "json" ) {
if ( typeof JSON === "object" && JSON.parse ) {
data = JSON.parse( data );
} else {
data = (new Function("return " + data))();
}
}
}
return data;
},
// Serialize an array of form elements or a set of
// key/values into a query string
param: function( a ) {
var s = [],
param_traditional = jQuery.param.traditional;
function add( key, value ){
// If value is a function, invoke it and return its value
value = jQuery.isFunction(value) ? value() : value;
s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
}
// If an array was passed in, assume that it is an array
// of form elements
if ( jQuery.isArray(a) || a.jquery ) {
// Serialize the form elements
jQuery.each( a, function() {
add( this.name, this.value );
});
} else {
// Encode parameters from object, recursively. If
// jQuery.param.traditional is set, encode the "old" way
// (the way 1.3.2 or older did it)
jQuery.each( a, function buildParams( prefix, obj ) {
if ( jQuery.isArray(obj) ) {
jQuery.each( obj, function(i,v){
// Due to rails' limited request param syntax, numeric array
// indices are not supported. To avoid serialization ambiguity
// issues, serialized arrays can only contain scalar values. php
// does not have this issue, but we should go with the lowest
// common denominator
add( prefix + ( param_traditional ? "" : "[]" ), v );
});
} else if ( typeof obj == "object" ) {
if ( param_traditional ) {
add( prefix, obj );
} else {
jQuery.each( obj, function(k,v){
buildParams( prefix ? prefix + "[" + k + "]" : k, v );
});
}
} else {
add( prefix, obj );
}
});
}
// Return the resulting serialization
return s.join("&").replace(r20, "+");
}
});
var elemdisplay = {},
timerId,
fxAttrs = [
// height animations
[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
// width animations
[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
// opacity animations
[ "opacity" ]
];
function genFx( type, num ){
var obj = {};
jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function(){
obj[ this ] = type;
});
return obj;
}
jQuery.fn.extend({
show: function( speed, callback ) {
if ( speed != null ) {
return this.animate( genFx("show", 3), speed, callback);
} else {
for ( var i = 0, l = this.length; i < l; i++ ){
var old = jQuery.data(this[i], "olddisplay");
this[i].style.display = old || "";
if ( jQuery.css(this[i], "display") === "none" ) {
var nodeName = this[i].nodeName, display;
if ( elemdisplay[ nodeName ] ) {
display = elemdisplay[ nodeName ];
} else {
var elem = jQuery("<" + nodeName + " />").appendTo("body");
display = elem.css("display");
if ( display === "none" ) {
display = "block";
}
elem.remove();
elemdisplay[ nodeName ] = display;
}
jQuery.data(this[i], "olddisplay", display);
}
}
// Set the display of the elements in a second loop
// to avoid the constant reflow
for ( var i = 0, l = this.length; i < l; i++ ){
this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
}
return this;
}
},
hide: function( speed, callback ) {
if ( speed != null ) {
return this.animate( genFx("hide", 3), speed, callback);
} else {
for ( var i = 0, l = this.length; i < l; i++ ){
var old = jQuery.data(this[i], "olddisplay");
if ( !old && old !== "none" ){
jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
}
}
// Set the display of the elements in a second loop
// to avoid the constant reflow
for ( var i = 0, l = this.length; i < l; i++ ){
this[i].style.display = "none";
}
return this;
}
},
// Save the old toggle function
_toggle: jQuery.fn.toggle,
toggle: function( fn, fn2 ){
var bool = typeof fn === "boolean";
return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
this._toggle.apply( this, arguments ) :
fn == null || bool ?
this.each(function(){
var state = bool ? fn : jQuery(this).is(":hidden");
jQuery(this)[ state ? "show" : "hide" ]();
}) :
this.animate(genFx("toggle", 3), fn, fn2);
},
fadeTo: function(speed,to,callback){
return this.filter(":hidden").css('opacity', 0).show().end()
.animate({opacity: to}, speed, callback);
},
animate: function( prop, speed, easing, callback ) {
var optall = jQuery.speed(speed, easing, callback);
return this[ optall.queue === false ? "each" : "queue" ](function(){
var opt = jQuery.extend({}, optall), p,
hidden = this.nodeType == 1 && jQuery(this).is(":hidden"),
self = this;
for ( p in prop ) {
var name = p.replace(rdashAlpha, fcamelCase);
if ( p !== name ) {
prop[ name ] = prop[ p ];
delete prop[ p ];
p = name;
}
if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden ) {
return opt.complete.call(this);
}
if ( ( p == "height" || p == "width" ) && this.style ) {
// Store display property
opt.display = jQuery.css(this, "display");
// Make sure that nothing sneaks out
opt.overflow = this.style.overflow;
}
}
if ( opt.overflow != null ) {
this.style.overflow = "hidden";
}
opt.curAnim = jQuery.extend({}, prop);
jQuery.each( prop, function(name, val){
var e = new jQuery.fx( self, opt, name );
if ( /toggle|show|hide/.test(val) ) {
e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
} else {
var parts = /^([+-]=)?([\d+-.]+)(.*)$/.exec(val),
start = e.cur(true) || 0;
if ( parts ) {
var end = parseFloat(parts[2]),
unit = parts[3] || "px";
// We need to compute starting value
if ( unit != "px" ) {
self.style[ name ] = (end || 1) + unit;
start = ((end || 1) / e.cur(true)) * start;
self.style[ name ] = start + unit;
}
// If a +=/-= token was provided, we're doing a relative animation
if ( parts[1] ) {
end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
}
e.custom( start, end, unit );
} else {
e.custom( start, val, "" );
}
}
});
if ( jQuery.isEmptyObject( prop ) ) {
return optall.complete.call(this);
}
// For JS strict compliance
return true;
});
},
stop: function(clearQueue, gotoEnd){
var timers = jQuery.timers;
if (clearQueue) {
this.queue([]);
}
this.each(function(){
// go in reverse order so anything added to the queue during the loop is ignored
for ( var i = timers.length - 1; i >= 0; i-- ) {
if ( timers[i].elem == this ) {
if (gotoEnd) {
// force the next step to be the last
timers[i](true);
}
timers.splice(i, 1);
}
}
});
// start the next in the queue if the last step wasn't forced
if (!gotoEnd) {
this.dequeue();
}
return this;
}
});
// Generate shortcuts for custom animations
jQuery.each({
slideDown: genFx("show", 1),
slideUp: genFx("hide", 1),
slideToggle: genFx("toggle", 1),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" }
}, function( name, props ){
jQuery.fn[ name ] = function( speed, callback ){
return this.animate( props, speed, callback );
};
});
jQuery.extend({
speed: function(speed, easing, fn) {
var opt = typeof speed === "object" ? speed : {
complete: fn || !fn && easing ||
jQuery.isFunction( speed ) && speed,
duration: speed,
easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
};
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
// Queueing
opt.old = opt.complete;
opt.complete = function(){
if ( opt.queue !== false ) {
jQuery(this).dequeue();
}
if ( jQuery.isFunction( opt.old ) ) {
opt.old.call( this );
}
};
return opt;
},
easing: {
linear: function( p, n, firstNum, diff ) {
return firstNum + diff * p;
},
swing: function( p, n, firstNum, diff ) {
return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
}
},
timers: [],
fx: function( elem, options, prop ){
this.options = options;
this.elem = elem;
this.prop = prop;
if ( !options.orig ) {
options.orig = {};
}
}
});
jQuery.fx.prototype = {
// Simple function for setting a style value
update: function(){
if ( this.options.step ) {
this.options.step.call( this.elem, this.now, this );
}
(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
// Set display property to block for height/width animations
if ( ( this.prop == "height" || this.prop == "width" ) && this.elem.style ) {
this.elem.style.display = "block";
}
},
// Get the current size
cur: function(force){
if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
return this.elem[ this.prop ];
}
var r = parseFloat(jQuery.css(this.elem, this.prop, force));
return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
},
// Start an animation from one number to another
custom: function(from, to, unit){
this.startTime = now();
this.start = from;
this.end = to;
this.unit = unit || this.unit || "px";
this.now = this.start;
this.pos = this.state = 0;
var self = this;
function t(gotoEnd){
return self.step(gotoEnd);
}
t.elem = this.elem;
if ( t() && jQuery.timers.push(t) && !timerId ) {
timerId = setInterval(jQuery.fx.tick, 13);
}
},
// Simple 'show' function
show: function(){
// Remember where we started, so that we can go back to it later
this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
this.options.show = true;
// Begin the animation
// Make sure that we start at a small width/height to avoid any
// flash of content
this.custom(this.prop == "width" || this.prop == "height" ? 1 : 0, this.cur());
// Start by showing the element
jQuery(this.elem).show();
},
// Simple 'hide' function
hide: function(){
// Remember where we started, so that we can go back to it later
this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
this.options.hide = true;
// Begin the animation
this.custom(this.cur(), 0);
},
// Each step of an animation
step: function(gotoEnd){
var t = now();
if ( gotoEnd || t >= this.options.duration + this.startTime ) {
this.now = this.end;
this.pos = this.state = 1;
this.update();
this.options.curAnim[ this.prop ] = true;
var done = true;
for ( var i in this.options.curAnim ) {
if ( this.options.curAnim[i] !== true ) {
done = false;
}
}
if ( done ) {
if ( this.options.display != null ) {
// Reset the overflow
this.elem.style.overflow = this.options.overflow;
// Reset the display
this.elem.style.display = this.options.display;
if ( jQuery.css(this.elem, "display") == "none" ) {
this.elem.style.display = "block";
}
}
// Hide the element if the "hide" operation was done
if ( this.options.hide ) {
jQuery(this.elem).hide();
}
// Reset the properties, if the item has been hidden or shown
if ( this.options.hide || this.options.show ){
for ( var p in this.options.curAnim ) {
jQuery.style(this.elem, p, this.options.orig[p]);
}
}
// Execute the complete function
this.options.complete.call( this.elem );
}
return false;
} else {
var n = t - this.startTime;
this.state = n / this.options.duration;
// Perform the easing function, defaults to swing
this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
this.now = this.start + ((this.end - this.start) * this.pos);
// Perform the next step of the animation
this.update();
}
return true;
}
};
jQuery.extend( jQuery.fx, {
tick:function(){
var timers = jQuery.timers;
for ( var i = 0; i < timers.length; i++ ) {
if ( !timers[i]() ) {
timers.splice(i--, 1);
}
}
if ( !timers.length ) {
jQuery.fx.stop();
}
},
stop:function(){
clearInterval( timerId );
timerId = null;
},
speeds:{
slow: 600,
fast: 200,
// Default speed
_default: 400
},
step: {
opacity: function(fx){
jQuery.style(fx.elem, "opacity", fx.now);
},
_default: function(fx){
if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
fx.elem.style[ fx.prop ] = fx.now + fx.unit;
} else {
fx.elem[ fx.prop ] = fx.now;
}
}
}
});
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.animated = function(elem){
return jQuery.grep(jQuery.timers, function(fn){
return elem === fn.elem;
}).length;
};
}
if ( "getBoundingClientRect" in document.documentElement ) {
jQuery.fn.offset = function( options ) {
var elem = this[0];
if ( !elem || !elem.ownerDocument ) { return null; }
if ( options ) {
return this.each(function() {
jQuery.offset.setOffset( this, options );
});
}
if ( elem === elem.ownerDocument.body ) {
return jQuery.offset.bodyOffset( elem );
}
var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,
clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
top = box.top + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ) - clientTop,
left = box.left + (self.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
return { top: top, left: left };
};
} else {
jQuery.fn.offset = function( options ) {
var elem = this[0];
if ( !elem || !elem.ownerDocument ) { return null; }
if ( options ) {
return this.each(function() {
jQuery.offset.setOffset( this, options );
});
}
if ( elem === elem.ownerDocument.body ) {
return jQuery.offset.bodyOffset( elem );
}
jQuery.offset.initialize();
var offsetParent = elem.offsetParent, prevOffsetParent = elem,
doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
body = doc.body, defaultView = doc.defaultView,
prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
top = elem.offsetTop, left = elem.offsetLeft;
while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { break; }
computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
top -= elem.scrollTop;
left -= elem.scrollLeft;
if ( elem === offsetParent ) {
top += elem.offsetTop;
left += elem.offsetLeft;
if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) {
top += parseFloat( computedStyle.borderTopWidth ) || 0;
left += parseFloat( computedStyle.borderLeftWidth ) || 0;
}
prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
}
if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
top += parseFloat( computedStyle.borderTopWidth ) || 0;
left += parseFloat( computedStyle.borderLeftWidth ) || 0;
}
prevComputedStyle = computedStyle;
}
if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
top += body.offsetTop;
left += body.offsetLeft;
}
if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
top += Math.max( docElem.scrollTop, body.scrollTop );
left += Math.max( docElem.scrollLeft, body.scrollLeft );
}
return { top: top, left: left };
};
}
jQuery.offset = {
initialize: function() {
var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.curCSS(body, 'marginTop', true) ) || 0,
html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
jQuery.extend( container.style, { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' } );
container.innerHTML = html;
body.insertBefore( container, body.firstChild );
innerDiv = container.firstChild;
checkDiv = innerDiv.firstChild;
td = innerDiv.nextSibling.firstChild.firstChild;
this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
checkDiv.style.position = 'fixed', checkDiv.style.top = '20px';
// safari subtracts parent border width here which is 5px
this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
checkDiv.style.position = checkDiv.style.top = '';
innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
body.removeChild( container );
body = container = innerDiv = checkDiv = table = td = null;
jQuery.offset.initialize = function(){};
},
bodyOffset: function( body ) {
var top = body.offsetTop, left = body.offsetLeft;
jQuery.offset.initialize();
if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
top += parseFloat( jQuery.curCSS(body, 'marginTop', true) ) || 0;
left += parseFloat( jQuery.curCSS(body, 'marginLeft', true) ) || 0;
}
return { top: top, left: left };
},
setOffset: function( elem, options ) {
// set position first, in-case top/left are set even on static elem
if ( /static/.test( jQuery.curCSS( elem, 'position' ) ) ) {
elem.style.position = 'relative';
}
var curElem = jQuery( elem ),
curOffset = curElem.offset(),
curTop = parseInt( jQuery.curCSS( elem, 'top', true ), 10 ) || 0,
curLeft = parseInt( jQuery.curCSS( elem, 'left', true ), 10) || 0,
props = {
top: (options.top - curOffset.top) + curTop,
left: (options.left - curOffset.left) + curLeft
};
if ( 'using' in options ) {
options.using.call( elem, props );
} else {
curElem.css( props );
}
}
};
jQuery.fn.extend({
position: function() {
if ( !this[0] ) { return null; }
var elem = this[0],
// Get *real* offsetParent
offsetParent = this.offsetParent(),
// Get correct offsets
offset = this.offset(),
parentOffset = /^body|html$/i.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
// Subtract element margins
// note: when an element has margin: auto the offsetLeft and marginLeft
// are the same in Safari causing offset.left to incorrectly be 0
offset.top -= parseFloat( jQuery.curCSS(elem, 'marginTop', true) ) || 0;
offset.left -= parseFloat( jQuery.curCSS(elem, 'marginLeft', true) ) || 0;
// Add offsetParent borders
parentOffset.top += parseFloat( jQuery.curCSS(offsetParent[0], 'borderTopWidth', true) ) || 0;
parentOffset.left += parseFloat( jQuery.curCSS(offsetParent[0], 'borderLeftWidth', true) ) || 0;
// Subtract the two offsets
return {
top: offset.top - parentOffset.top,
left: offset.left - parentOffset.left
};
},
offsetParent: function() {
return this.map(function(){
var offsetParent = this.offsetParent || document.body;
while ( offsetParent && (!/^body|html$/i.test(offsetParent.nodeName) && jQuery.css(offsetParent, 'position') === 'static') ) {
offsetParent = offsetParent.offsetParent;
}
return offsetParent;
});
}
});
// Create scrollLeft and scrollTop methods
jQuery.each( ['Left', 'Top'], function(i, name) {
var method = 'scroll' + name;
jQuery.fn[ method ] = function(val) {
var elem = this[0], win;
if ( !elem ) { return null; }
if ( val !== undefined ) {
// Set the scroll offset
return this.each(function() {
win = getWindow( this );
win ?
win.scrollTo(
!i ? val : jQuery(win).scrollLeft(),
i ? val : jQuery(win).scrollTop()
) :
this[ method ] = val;
});
} else {
win = getWindow( elem );
// Return the scroll offset
return win ? ('pageXOffset' in win) ? win[ i ? 'pageYOffset' : 'pageXOffset' ] :
jQuery.support.boxModel && win.document.documentElement[ method ] ||
win.document.body[ method ] :
elem[ method ];
}
};
});
function getWindow( elem ) {
return ("scrollTo" in elem && elem.document) ?
elem :
elem.nodeType === 9 ?
elem.defaultView || elem.parentWindow :
false;
}
// Create innerHeight, innerWidth, outerHeight and outerWidth methods
jQuery.each([ "Height", "Width" ], function(i, name){
var type = name.toLowerCase();
// innerHeight and innerWidth
jQuery.fn["inner" + name] = function(){
return this[0] ?
jQuery.css( this[0], type, false, "padding" ) :
null;
};
// outerHeight and outerWidth
jQuery.fn["outer" + name] = function(margin) {
return this[0] ?
jQuery.css( this[0], type, false, margin ? "margin" : "border" ) :
null;
};
jQuery.fn[ type ] = function( size ) {
// Get window width or height
var elem = this[0];
if ( !elem ) { return null; }
return ("scrollTo" in elem && elem.document) ? // does it walk and quack like a window?
// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] ||
elem.document.body[ "client" + name ] :
// Get document width or height
(elem.nodeType === 9) ? // is it a document
// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
Math.max(
elem.documentElement["client" + name],
elem.body["scroll" + name], elem.documentElement["scroll" + name],
elem.body["offset" + name], elem.documentElement["offset" + name]
) :
// Get or set width or height on the element
size === undefined ?
// Get width or height on the element
jQuery.css( elem, type ) :
// Set the width or height on the element (default to pixels if value is unitless)
this.css( type, typeof size === "string" ? size : size + "px" );
};
});
// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;
})(window);
powerpape
/***
|''Name:''|purpleTheme|
|''Description:''|A theme with lots of white space and a clean and elegant purple presentation|
|''Author:''|Saq Imtiaz and Simon McManus|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]] |
|''Source''|http://svn.tiddlywiki.org/Trunk/association/serversides/cctiddly/Trunk/tiddlers/themes/purpleTheme.tiddler|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/association/serversides/cctiddly/Trunk/tiddlers/themes/purpleTheme.tiddler|
|''~CoreVersion:''|2.4.1|
|''~PageTemplate:''|##PageTemplate|
|''~tabs:''|##tabs|
|''~OptionsPanel:''|##OptionsPanel|
|''~SideBarTabs:''|##SideBarTabs|
|''~StyleSheet:''|##StyleSheet|
|''~taskViewTemplate:''|##taskViewTemplate|
|''~taskEditTemplate:''|##taskEditTemplate|
|''~EditTemplate:''|##EditTemplate|.wizzz
|''~ViewTemplate:''|##ViewTemplate|
***/
!PageTemplate
<!--{{{-->
<div id='bodywrapper'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' force='true' tiddler='purpleTheme##SideBarOptions'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<div id='contentFooter' macro='gradient vert #eee #ccc'></div>
</div>
<!--}}}-->
!EditTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
!ViewTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='tagClear'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<hr />
<!--}}}-->
!tabs
<<tabs txtMainTab "Timeline" "Timeline" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>
!SideBarOptions
<<search {{config.options.search}}>><<closeAll>><<newTiddler label:{{config.macros.newTiddler.label}} text:{{config.macros.newTiddler.text}} title:{{config.macros.newTiddler.title}} tag:"">
<<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel {{config.macros.ccOptions.options}} 'change TiddlyWiki Options'>><<slider 'chkLoginStatus' 'LoginStatus' {{config.macros.ccLoginStatus.status}} 'Login to make changes'>><<slider chkSliderTabs SideBarTabs {{config.theme.contentTitle}} {{config.theme.contentTiddlerTooltip}}>>
!StyleSheet
/***
General
***/
/*{{{*/
body, html{
background-color: #999999;
color:#333;
// background:url(http://www.thefabricdeli.com/assets/images/qud21112-purple.jpg);
// background:url(http://mr-pc.org/inc/paisleyTileSmall.png);
}
#backstageCloak {
opacity:0.8; filter:'alpha(opacity:70)';
background:black;
}
.tiddler .button {
line-height:4;
margin:5px;
padding:8px;
}
body .chkOptionInput {
width:auto;
float:right;
}
#contentWrapper .wizard .txtOptionInput {
width:7em;
}
.wizard .txtOptionInput{
text-align:right;
border:1px solid #ccc;
}
#contentWrapper .sliderPanel .tabsetWrapper .tabContents {
border:0px;
background-color:white;
}
.header {
background-color:#eee;
}
#messageArea {
border:1px solid white;
background-color:#eee;
}
#messageArea .button {
background:none;
}
h1 {
color:black;
}
#contentWrapper {
position:relative;
margin: 2.5em auto;
width:780px;
line-height: 1.6em;
border:1px solid #ccc;
font-size: 11px;
font-family: Lucida Grande, Tahoma, Arial, Helvetica, sans-serif;
height:1%;
// display:table;
background-color:#eee;
}
.clearAll{
clear:both;
}
.tagClear{
clear:none;
}
/*}}}*/
/*{{{*/
.siteTitle {
font-family: 'Trebuchet MS' sans-serif;
font-weight: bold;
position:relative;
top:20px;
left :20px;
font-size: 32px;
color:Purple;
}
.siteSubtitle {
padding-top:15px;
font-size: 1.0em;
display:block;
color: #999; margin-top:0.5em !important; margin-top:1em; margin-left:3em;
padding-top:3em;
}
#displayArea {
margin-left:1.35em;
margin-right:16.3em;
margin-top:0;
padding-top:1em;
padding-bottom:10px;
}
#sidebarOptions input {
border:1px solid #ddd;
}
div.tabset {
margin-bottom:1px;
}
.tabUnselected {
background:#ddd none repeat scroll 0%;
color:#999;
border:1px solid #ccc;
}
#sidebar {
position:inherit;
float:right;
display:inline;
}
#tiddlerDisplay .tagging, #tiddlerDisplay .tagged {
background-color:#eee;
border:none;
float:none;
}
.sliderPanel .tabsetWrapper .tabContents {
border-right:none;
border-color:#999;
background-color:#999;
}
#sidebarOptions .sliderPanel a {
padding:3px;
margin:0px;
border:2px;
background-color:#999;
}
.tabsetWrapper {
position :relative;
}
#sidebar{
padding-left:0.5em;
background-color:#eee;
padding-top:1em;
}
#sidebarOptions a {
margin:17px;
display:block;
margin:0.5em 0em;
padding:0.3em 0.6em;
}
.popup li a {
margin:0px;
padding:0px;
display:inline;
color:black;
}
.popup {
background-color:white;
border:1px solid purple;
}
.popup li a:hover {
display:inline;
margin:0px;
padding:0px;
background-color:white;
color:purple;
}
.popup li {
margin:0px;
padding:5px;
background-color:#eee;
}
.popup li:hover {
background-color:white;
}
#tiddlerDisplay .toolbar a.button, #sidebarOptions a, .toolbar .popup li a, #mainMenu a, .tiddler .button, #sidebarOptions .sliderPanel input {
border:1px solid white;
background-color:white;
color:purple;
}
#tiddlerDisplay .toolbar a.button:hover, #sidebarOptions a:hover, #mainMenu a:hover, .tiddler .button, #sidebarOptions .sliderPanel input:hover
{
border:1px solid #ccc;
}
#sidebarOptions a:hover {
border-right:1px solid white;
}
.tagged ul {
list-style: none;
}
.tagged li {
display: inline;
}
.zoomer {
background:none; color:#ddd;
border:2px solid #ddd;
}
a:active{
border:1px solid red;
background-color:#eee;
color:[[ColorPalette::smmLight1]]
}
a:hover {
background-color:#eee;
color:[[ColorPalette::smmLight1]]
}
#backstageArea,#backstageArea a {
background:transparent;
color:white;
}
#mainMenu a {
padding:8px 15px 8px 15px;
margin:10px;
line-height:40px;
border:1px solid #eee;
}
#contentWrapper #mainMenu{
position:static;
width:100%;
float:left;
text-align:left;
padding-top:20px;
}
.editor textarea, .editor input, input, body select {
border:1px solid #ccc;
background-color:white;
color:#999;
padding:3px;
margin:3px;
}
#sidebarOptions input {
width:85%;
margin-left:-0.1em;}
#sidebarTabs {
margin:0px;
padding:0px
}
#sidebarTabs .tabContents {
color:[[ColorPalette::smmLight1]];
background:#999;
}
#contentWrapper .tiddler .button {
margin:0.4em;
padding:0.4em 0.8em;
}
#sideBarOptions .searchButton{
display:none;
}
#sidebar .sliderPanel {
margin-left:5px;
border:0px;
padding:0em;
border-right:1px solid #eee;
margin-bottom:0.8em;
}
#sidebarOptions .searchButton {
display:none;
}
.title {
color:#C0C0C0;
}
.subtitle, .subtitle a {
color: #999;
font-size: 1em;margin:0.2em;
font-variant: small-caps;
}
* html .viewer pre {
margin-left: 0em;
}
* html .editor textarea, * html .editor input {
width: 98%;
}
a,#sidebarOptions .sliderPanel a, #topMenu a, #topMenu .button {
color:purple;
background-color:transparent;
}
#sidebarOptions .sliderPanel a:hover, #topMenu a, #topMenu .button:hover {
color:black;
background-color:transparent;
border:0px;
}
#topMenu a, #topMenu .button {
padding: 5px 15px;
margin:9px;
border:1px solid #999;
font-weight:bold;
line-height:40px;
top:1em;
color:[[ColorPalette::smmLight1]];
background-color:#eee;
}
#topMenu br {
display:none;
}
#topMenu a:hover, #topMenu .button:hover {
background-color:#eee;
}
.tagging, .tagged {
border: 0px dotted [[ColorPalette::smmLight1]];
}
.highlight, .marked {
background:transparent;
color:#999;
border:none;
text-decoration:underline;
}
.tagging .button:hover, .tagged .button:hover, .tagging .button:active, .tagged .button:active {
border: none;
background:transparent;
text-decoration:underline;
color:#eee;
}
.viewer th, thead td {
background: #eee;
border:none;
color: #fff;
}
.viewer table {
border:1px solid #eee;
}
table.twtable {
border-collapse:seperate;
}
.viewer pre {
background-color:white;
border: 1px dotted #999;
}
hr {
border: dotted 1px #ccc;
}
#sidebarOptions .sliderPanel .tabUnselected {
background:#eee none repeat scroll 0%;
border:0px solid #999;
color:#999;
}
.tabSelected, #sidebarOptions .sliderPanel .tabSelected {
background:white none repeat scroll 0%;
border:1px solid #ddd;
border-bottom:1px solid white;
color:#999;
}
.tabContents {
background:#f7f7f7;
border:0px;
}
.viewer code {
background:##eee none repeat scroll 0%;
color:#999;
}
h1,h2,h3,h4,h5 {
color: #555;
border-color:#333;
background: transparent;
padding-bottom:2px;
font-family: Arial, Helvetica, sans-serif;
}
h1 {
font-size:18px;
}
h2 {
font-size:16px;
border-bottom:1px solid #FFF;
}
h3 {
font-size: 14px;
border-bottom:1px solid #FFF;
}
.annotation {
background-color:purple;
border:1px solid white;
color:white;
}
#contentFooter {
background:#999;
clear: both;
padding: 0.5em 1em;
}
.button, .wizard .button:hover {
border:0px;
}
.sliderPanel input {
border:1px solid #777;
background-color:white;
color:#777;
}
#contentWrapper .tiddler .button:hover {
border:1px solid;
}
table, .viewer td, .viewer tr, .twtable td, .twtable tr {
border:0px solid #666666;
}
body .wizardFooter {
margin:0px;
padding-top:0px;
background:white;
font-weight:bold;
padding-left:10em;
}
.wizardStep {
padding:0px;
border:none;
background-color:none;
}
.wizard th{
background:white;
color:#888;
padding:3px;
margin:40px;
};
.wizard, listView twtable {
border:0px;
};
.wizard {
color:#292929;
}
.viewer .wizard, body .wizard{
background:white;
margin:2em;
border:1px solid #CCCCCC;
color:#999;
}
.wizard h1 {
color:#999;
padding-top:10px;
padding-bottom:10px;
}
.wizard h2 {
color:black;
}
body .wizardStep {
color:#999;
border:0px;
margin:0m;
background:white;
}
body select {
border:0px;
padding:3px;
margin:4px;
}
#backstageArea a:hover {
background-color:white;
}
#backstagePanel {
background:none;
width:60%;
position:fixed
padding:0px;
margin:0px;
margin-top:-36px;
}
#backstageToolbar a.backstageSelTab {
background-color:white;
border:1px solid white;
}
#sidebar .sliderPanel {
background-color:#eee;
font-size:1em;
}
.viewer .wizardStep table {
border:0px;
}
.viewer th, .viewer td, .viewer tr, .viewer caption, .twtable th, .twtable td, .twtable tr, .twtable caption {
border:0px;
padding:0px;
margin:0px;
}
.viewer .sortable td {
padding:12px;
margin:21px;
}
.title {
color:#777;
padding:0px;
}
.viewer table, table.twtable {
border-collapse:seperated;
border:0px;
}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {
border:0px;
background-color:white;
color:black;
}
.twtable th{
background-color:#eee;
padding:15px;
margin:15px;
}
table.sortable td.sortedCol {
background-color:white;
}
/*}}}*/
[[StyleSheet]]
/***
|''Name:''|smmTheme|
|''Author:''|Saq Imtiaz and Simon McManus|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/serversides/cctiddly/Trunk/tiddlers/themes/smmTheme.tiddler|
|''~CodeRepository:''|http://svn.tiddlywiki.org/Trunk/association/serversides/cctiddly/Trunk/tiddlers/themes/smmTheme.tiddler|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]] |
|''~CoreVersion:''|2.4.1|
|''~PageTemplate:''|##PageTemplate|
|''~tabs:''|##tabs|
|''~OptionsPanel:''|##OptionsPanel|
|''~StyleSheet:''|##StyleSheet|
|''~taskViewTemplate:''|##taskViewTemplate|
|''~taskEditTemplate:''|##taskEditTemplate|
|''~EditTemplate:''|##EditTemplate|
|''~ViewTemplate:''|##ViewTemplate|
***/
!PageTemplate
<!--{{{-->
<div class='header' macro='gradient vert #111 #222'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span><div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
</div>
<div id='bodywrapper'>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' force='true' tiddler='smmTheme##SideBarOptions'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<div id='contentFooter' macro='gradient vert #222 #111'></div>
</div>
<!--}}}-->
!taskViewTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'>Task : </div>
<div class='task'>
<table>
<tr>
<td class='taskbody' width=100%><div class='viewer' macro='view text wikified'></div></td>
<td class='taskControls' valign='top'><div class='taskControls' macro='tiddler TaskTiddlerControls'></td>
</tr>
</table>
</div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='tagClear'></div>
<!--}}}-->
!taskEditTemplate
<!--{{{-->
<div class="editor">
<div class='toolbar' macro='toolbar[[ToolbarCommands::EditToolbar]]'></div>
<div class='title edit' macro='edit title'></div>
<div class='task'>
<table>
<tr>
<td class='taskbody' width=100% height=100%><div class='viewer edit' macro='edit text wikified'></div></div></td>
<td class='taskControls' valign=top><div class='taskControls' macro='tiddler TaskTiddlerControls'></td>
</tr>
</table>
</div>
<div class='subtitle'>Last edited by: <span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<div class='tagClear'></div>
</div>
<!--}}}-->
!EditTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
!ViewTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='subtitle'>Last edited by: <span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='tagClear'></div>
<!--}}}-->
!wizardViewTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
!OptionsPanel
[[help|Help]] <br />[[settings|AdvancedOptions]]<br /><<ccOptions>>
!tabs
<<tabs txtMainTab "Timeline" "Timeline" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>
!SideBarOptions
<<search {{config.options.search}}>><<closeAll>><<newTiddler label:{{config.macros.newTiddler.label}} text:{{config.macros.newTiddler.text}} title:{{config.macros.newTiddler.title}} tag:"">
<<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel {{config.macros.ccOptions.options}} 'change TiddlyWiki Options'>><<slider 'chkLoginStatus' 'LoginStatus' {{config.macros.ccLoginStatus.status}} 'Login to make changes'>><<slider chkSliderTabs SideBarTabs {{config.theme.contentTiddler}} {{config.theme.contentTiddlerTooltip}}>>
!StyleSheet
/***
General
***/
/*{{{*/
.tiddler .button:hover {
background-color:#222;
}
.tiddler .button {
border:1px solid black;
line-height:2;
margin:5px;
padding:8px;
}
#contentWrapper .tiddler .button {
margin-left:20px;
}
body .chkOptionInput {
width:auto;
float:right;
}
#contentWrapper .wizard .txtOptionInput {
width:7em;
}
body{
background: #111;
color:white;
// background-image:url(http://friendster.bigoo.ws/content/layout/film-cartoon/film-cartoon_111.jpg);
// background-image:url(http://g.editingmyspace.com/shay773/halloweenbackgrounds/BG1.gif);
}
#backstageCloak {
opacity:0.9; filter:'alpha(opacity:90)';
background:#222;
}
#messageArea {
border:0px;
color:white;
background-color:#222;
}
#messageArea .button{
background:none;
}
#mainMenu br {
display:none;
}
h1 {
color:white;
}
#contentWrapper{
position:relative;
margin: 2.5em auto;
width:780px;
line-height: 1.6em;
border:1px solid #111;
font-size: 11px;
font-family: Lucida Grande, Tahoma, Arial, Helvetica, sans-serif;
height:1%;
background-color:#222;
}
.clearAll{
clear:both;
}
.tagClear{
clear:none;
}
/*}}}*/
/*{{{*/
.siteTitle {
font-family: 'Trebuchet MS' sans-serif;
font-weight: bold;
position:relative;
top:20px;
left :20px;
font-size: 32px;
color:#eee;
}
.siteSubtitle {
padding-top:15px;
font-size: 1.0em;
display:block;
color: #999; margin-top:0.5em !important; margin-top:1em; margin-left:3em;
}
#displayArea {
margin-left:1.35em;
margin-right:16.3em;
margin-top:0;
padding-top:1em;
padding-bottom:10px;
}
.tabUnselected {
background:#222 none repeat scroll 0%;
color:#999;
}
#sidebar {
position:inherit;
float:right;
display:inline;
}
#tiddlerDisplay .tagging, #tiddlerDisplay .tagged {
background-color:#222;
border:none;
float:none;
}
.sliderPanel .tabsetWrapper .tabContents {
border-right:none;
border-color:#999;
background-color:#111;
}
#sidebarOptions .sliderPanel a{
padding:3px;
margin:0px;
border:2px;
background-color:#111;
}
.tabsetWrapper {
position :relative;
}
#sidebar {
padding-left:0.5em;
background-color:#222;
padding-top:1em;
}
#sidebarOptions a {
margin:17px;
display:block;
margin:0.5em 0em;
padding:0.3em 0.6em;
}
.popup li a {
padding:12px;
}
#tiddlerDisplay .toolbar a.button, #sidebarOptions a, .toolbar .popup li a, #mainMenu a, #sidebarOptions .sliderPanel input {
background-color:#111;
color:#999;
border:1px solid #111;
}
.wizard .txtOptionInput {
text-align:right;
}
a:hover {
background-color:#222;
color:#eee
}
#tiddlerDisplay .toolbar a.button:hover, #sidebarOptions a:hover, #mainMenu a:hover, #sidebarOptions .sliderPanel input:hover {
border:1px dotted #000;
background-color:#222;
color:white;
}
#mainMenu a {
padding:8px 15px 8px 15px;
margin:10px;
line-height:40px;
border:0px solid #eee;
}
#contentWrapper #mainMenu {
position:static;
width:100%;
float:left;
text-align:left;
padding-top:20px;
}
.editor textarea, .editor input, input, body select {
border:1px solid #222;
background-color:#333;
color:#999;
padding:3px;
margin:3px;
}
#sidebarOptions input {
border:1px solid #999;
background-color:#00000;
width:10em;
}
#sidebarTabs {
margin:0px;
padding:0px
}
#sidebarTabs .tabContents {
color:#eee;
background:#111;
}
.tagged li
{
display: inline;
}
.tiddler .button {
color:white;
padding:0.4em 0.9em 0.4em 0.9em;
margin:0px 0px 0px 7px;
}
#sideBarOptions .searchButton {
display:none;
}
#sidebar .sliderPanel {
border-color:-moz-use-text-color #222 -moz-use-text-color -moz-use-text-color;
border-style:none solid none none;
border-width:0 1px 0 0;
margin-bottom:0.8em;
margin-left:5px;
padding:0;
margin-left:0px;
}
#sidebarOptions .searchButton {
display:none;
}
.title {
color:#C0C0C0;
}
.subtitle, .subtitle a {
color: #999;
font-size: 1em;margin:0.2em;
font-variant: small-caps;
}
.wizard .button:hover{
background-color:#333;
border:1px solid #444;
color:white;
}
.selected .toolbar a {
color:#999;
}
.selected .toolbar a:hover {
color:#222;
background:transparent;
border:1px solid #fff;
}
.viewer pre {
background:#111111 none repeat scroll 0 0;
border:1px solid #FFEE88;
}
* html .viewer pre {
margin-left: 0em;
}
* html .editor textarea, * html .editor input {
width: 98%;
}
a,#sidebarOptions .sliderPanel a, #topMenu a, #topMenu .button {
color:green;
background-color:transparent;
}
#sidebarOptions .sliderPanel a:hover, #topMenu a, #topMenu .button:hover {
color:white;
background-color:transparent;
border:0px;
}
#topMenu a, #topMenu .button, .wizard .button {
padding: 5px 15px;
margin:9px;
border:1px solid #999;
font-weight:bold;
line-height:40px;
top:1em;
color:#eee;
background-color:#222;
}
#topMenu br {
display:none;
}
#topMenu a:hover, #topMenu .button:hover {
background-color:#222;
}
.tagging, .tagged {
border: 1px solid #eee;
}
.highlight, .marked {
background:transparent;
color:#111;
border:none;
text-decoration:underline;
}
.tagging .button:hover, .tagged .button:hover, .tagging .button:active, .tagged .button:active {
border: none;
background:transparent;
text-decoration:underline;
color:#222;
}
.tiddler {
padding-bottom: 40px;
}
.viewer th, thead td {
background: #222;
border:none;
color: #fff;
}
.viewer table {
border:1px dotted #222;
}
table.twtable {
border-collapse:seperate;
}
.viewer pre {
border: 1px solid #999;
}
.viewer hr {
border-top: dashed 1px #999;
}
.tabSelected {
background:#111 none repeat scroll 0%;
border:1px solid #111;
border-bottom:1px solid black;
color:#999;
}
.tabContents {
background:#f7f7f7;
border:0px;
}
.viewer code {
background:##222 none repeat scroll 0%;
color:#999;
}
h1,h2,h3,h4,h5 {
color: #555; border-color:#333; background: transparent; padding-bottom:2px; font-family: Arial, Helvetica, sans-serif;
}
h1 {
font-size:18px;
}
h2 {
font-size:16px;
}
h3 {
font-size: 14px;
}
#contentFooter {
background:#999;
clear: both;
padding: 0.5em 1em;
}
.wizard input {
border:1px solid #333;
}
#sidebarOptions input {
border: 1px solid #222;
}
.annotation {
background-color:green;
border:1px solid white;
color:white;
}
.wizardFooter .button{
background:#222;
margin:3px;
padding:0.5em;
padding-left:1.5em;
padding-right:1.5em;
color:white;
border:1px solid #333;
}
table, .viewer td, .viewer tr, .twtable td, .twtable tr {
border:0px solid #666666;
}
.tagging .listTitle, .tagged .listTitle, .txtMainTab .tabContents li {
color:white;
}
body .wizardFooter {
background:none;
font-weight:bold;}
.wizardStep {
border:none;
background-color:none;
}
body .wizard {
width:80%;
padding:10px;
border:1px solid #EBE6F5;
}
.wizard th{
background:#222;
color:#888;
padding:3px;
margin:40px;
};
.wizard, listView twtable {
border:0px;
};
.wizard {
padding : 4px 14px 4px 14px;
font-weight:bold;
color:#292929;
border:solid 0px #292929;
margin-top:1px;
}
.viewer .wizard, body .wizard{
background:#111;
margin:2em;
border:0px;
border:1px solid #333;
color:#777;
}
.wizard h1{
color:#999;
}
.wizard h2{
padding:4px;
color:white;
}
body .wizardStep{
color:#999;
border:0px;
margin:0m;
background:none;
}
body select {
border:0px;
padding:3px;
margin:4px;
}
#backstagePanel {
border:0px;
background:none;
width:60%;
position:fixed
padding:0px;
margin:0px;
margin-top:-36px;
}
#sidebar .sliderPanel {
background-color:#222;
font-size:1em;
}
.viewer .wizardStep table {
border:0px;
}
.viewer th, .viewer td, .viewer tr, .viewer caption, .twtable th, .twtable td, .twtable tr, .twtable caption {
border:0px;
padding:0px;
margin:0px;
}
.viewer .sortable td {
padding:12px;
margin:21px;
}
.title {
color:#C0C0C0;
padding:10px;
}
.viewer table, table.twtable {
border-collapse:seperated;
border:0px;
}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {
border:0px;
color:white;
}
.twtable th{
background-color:#333;
padding:15px;
margin:15px;
}
table.sortable td.sortedCol {
background-color:#333;
}
#backstageArea a:hover, #backstageArea a.backstageSelTab {
background-color:#111;
color:white;
}
/*}}}*/
[[StyleSheet]]
powerpape
merge(config.options, {search:"search.."})
config.theme = {
contentTitle : ' ssss »',
contentToolTip : 'aaaa',
contentTiddler : 'Content »',
contentTiddlerTooltip : 'click to view TiddlyWiki content'
};
merge(config.macros.ccAbout,{
buttonBackstageText:"about",
buttonBackstageTooltip:"Find out more about ccTiddly ",
stepAboutTitle:"About",
stepAboutTextStart:"You are running ccTiddly ",
stepAboutTextEnd:"More info about ccTiddly can be found at <a target=new href=http://www.tiddlywiki.org/wiki/CcTiddly>http://www.tiddlywiki.org/wiki/CcTiddly</a><br/><br/> More information about TiddlyWiki can be found at <a target=new href=http://www.tiddlywiki.com>http://www.tiddlywiki.com</a><br/>"
});
merge(config.macros.ccChangePassword,{
title:"Change Password",
subTitle : "for user ",
step1Html: " <label for='old'>Old Password </label><input name='old' type='password'/><br/> <label for='new1'>New Password </label> <input name='new1' type='password' /><br /><label for='new2'>Repeat Password</label> <input name='new2' type='password' /> ",
buttonChangeText:"Change Password",
buttonChangeToolTip:"Click to change your password",
buttonCancelText:"Cancel",
buttonCancelToolTip:"Click to cancel",
noticePasswordsNoMatch : "Your new passwords do not match",
noticePasswordWrong : "Your password is incorrect.",
noticePasswordUpdated : "Your Password has been updated",
noticePasswordUpdateFailed : "Your Password was NOT updated."
});
merge(config.macros.ccAdmin,{
stepAddTitle:"Add a new Workspace Administrator",
WizardTitleText:"Workspace Administration.",
buttonDeleteText:"Delete Users",
buttonDeleteTooltip:"Click to delete users.",
buttonAddText:"Add User",
buttonAddTooltip:"Click to add user.",
buttonCancelText:"Cancel",
buttonCalcelTooltip:"Calcel adding user.",
buttonCreateText:"Make User Admin",
buttonCreateTooltip:"Click to make user admin.",
labelWorkspace:"Workspace: ",
labelUsername:"Username : ",
stepErrorTitle:"You need to be an administrator of this workspace.",
stepErrorText:"Permission Denied to edit workspace : ",
stepNoAdminTitle:"There are no admins of this workspace.",
stepManageWorkspaceTitle:"",
listAdminTemplate: {
columns: [
{name: 'Selected', field: 'Selected', rowName: 'name', type: 'Selector'},
{name: 'Name', field: 'name', title: "Username", type: 'String'},
{name: 'Last Visit', field: 'lastVisit', title: "Last Login", type: 'String'}
],
rowClasses: [
{className: 'lowlight', field: 'lowlight'}
]}
});
/*
merge(ccTiddlyAutoSave,{
msgSaved:"Saved ",
msgError:"There was an error saving "
});
*/
merge(config.macros.ccCreateWorkspace, {
wizardTitle:"Create Workspace",
buttonCreateText:"create",
buttonCreateWorkspaceText:"Create Workspace",
buttonCreateTooltip:'Create new workspace',
errorPermissions:"You do not have permissions to create a workspace. You may need to log in.",
msgPleaseWait:"Please wait, your workspace is being created.",
msgWorkspaceAvailable:"Workspace name is available.",
errorWorkspaceNameInUse:"Workspace name is already in use.",
stepTitle:"Please enter workspace name",
stepCreateHtml:"<input class='input' id='workspace_name' name='workspace_name' value='' tabindex='1' /><span></span><input type='hidden' name='workspace_error'></input><h2></h2><input type='hidden' name='workspace_url'></input>"
});
merge(config.macros.ccEditWorkspace,{
WizardTitleText:"Edit Workspace Permissions",
stepEditTitle:null,
stepLabelCreate:'Create',
stepLabelRead:'Read',
stepLabelUpdate:'Edit',
stepLabelDelete:'Delete',
stepLabelPermission:'',
stepLabelAnon:' Anonymous ',
stepLabelUser:' Authenticated ',
stepLabelAdmin:' Admin ',
buttonSubmitCaption:"Update Workspace Permissions",
buttonSubmitToolTip:"Update workspace permissions",
button1SubmitCaption:"ok",
button1SubmitToolTip:"review permissions",
step2Error:"Error",
errorTextPermissionDenied:"You do not have permissions to edit this workspace permissions. You may need to log in.",
errorUpdateFailed:"Permissions Not changed"
});
merge(config.macros.ccFile,{
wizardTitleText:"Manage Files",
wizardStepText:"Manage files in workspace ",
buttonDeleteText:"Delete Files",
buttonDeleteTooltip:"Click to Delete files.",
buttonUploadText:"Upload File",
buttonUploadTooltip:"Click to Upload files.",
buttonCancelText:"Cancel",
buttonCancelTooltip:"Click to cancel.",
labelFiles:"Existing Files ",
errorPermissionDeniedTitle:"Permission Denied",
errorPermissionDeniedUpload:"You do not have permissions to create a file on this server. ",
errorPermissionDeniedView:"You do not have permissions to view files in this workspace. ",
listAdminTemplate: {
columns: [
{name: 'wiki text', field: 'wikiText', title: "", type: 'WikiText'},
{name: 'Selected', field: 'Selected', rowName: 'name', type: 'Selector'},
{name: 'Name', field: 'name', title: "File", type: 'WikiText'},
{name: 'URI', field: 'URI', title: "URI", type: 'WikiText'},
{name: 'Size', field: 'fileSize', title: "size", type: 'String'}
],
rowClasses: [
{className: 'lowlight', field: 'lowlight'}
]}
});
merge(config.macros.ccLogin,{
WizardTitleText:null,
usernameRequest:"Username",
passwordRequest:"Password",
stepLoginTitle:null,
stepLoginIntroTextHtml:"<label>username</label><input name=username id=username tabindex='1'><br /><label>password</label><input type='password' tabindex='2' name='txtPassword' class='txtPassword'><input name='password'>",
stepDoLoginTitle:"Logging you in",
stepDoLoginIntroText:"we are currently trying to log you in.... ",
stepForgotPasswordTitle:"Password Request",
stepForgotPasswordIntroText:"Please contact your system administrator or register for a new account. <br /><input id='forgottenPassword' type='hidden' name='forgottenPassword'/>",
stepLogoutTitle:"Logout",
stepLogoutText:"You are currently logged in as ",
buttonLogout:"logout",
buttonLogoutToolTip:"Click here to logout.",
buttonLogin:"Login",
buttonlogin:"login",
buttonLoginToolTip:"Click to Login.",
buttonCancel:"Cancel",
buttonCancelToolTip:"Cancel transaction ",
buttonForgottenPassword:"Forgotten Password",
buttonSendForgottenPassword:"Mail me a New Password",
buttonSendForgottenPasswordToolTip:"Click here if you have forgotten your password",
buttonForgottenPasswordToolTip:"Click to be reminded of your password",
msgNoUsername:"Please enter a username",
msgNoPassword:"Please enter a password",
msgLoginFailed:"Login Failed, please try again. ",
configURL:window.url+"/handle/login.php",
configUsernameInputName:"cctuser",
configPasswordInputName:"cctpass",
configPasswordCookieName:"cctPass"
});
merge(config.macros.ccLoginStatus,{
textDefaultWorkspaceLoggedIn:"Viewing default workspace",
textViewingWorkspace:"Viewing Workspace : ",
textLoggedInAs:"Logged in as ",
status:"status »",
textNotLoggedIn:"You are not logged in.",
textAdmin:"You are an Administrator."
});
merge(config.macros.ccOptions, {
linkManageUsers:"users",
linkPermissions:"permissions",
linkFiles:"files",
linkPassword:"password",
linkCreate:"create",
linkOffline:"offline",
linkStats:"statistics",
options:"options »"
});
merge(config.macros.register,{
usernameRequest:"username",
passwordRequest:"password",
passwordConfirmationRequest:"confirm password",
emailRequest:"email",
stepRegisterTitle:"Register for an account.",
stepRegisterIntroText:"Hi, please register below.... ",
stepRegisterHtml:"<label> username</label><input class='input' id='reg_username' name='reg_username' tabindex='1'/><span></span><input type='hidden' name='username_error'></input><br /><label>email</label><input class='input' name=reg_mail id='reg_mail' tabindex='2'/><span> </span><input type='hidden' name='mail_error'></input><br/><label>password</label><input type='password' class='input' id='password1' name='reg_password1' tabindex='3'/><span> </span><input type='hidden' name='pass1_error'></input><br/><label>confirm password</label><input type='password' class='input' id='password2' name='reg_password2' tabindex='4'/><span> </span><input type='hidden' name='pass2_error'></input>",
buttonCancel:"Cancel",
buttonCancelToolTip:"Cancel transaction ",
buttonRegister:"Register",
buttonRegisterToolTip:"click to register",
msgCreatingAccount:"Attempting to create the account for you.",
msgNoUsername:"No username entered",
msgEmailOk:"Email address is OK.",
msgNoPassword:"no password entered.",
msgDifferentPasswords:"Your Passwords do not match.",
msgUsernameTaken:"The username requested has been taken.",
msgUsernameAvailable:"The username is available.",
step2Title:"",
step2Html:"Please wait while we create you an account...",
errorRegisterTitle:"Error",
errorRegister:"User not created, please try again with a different username."
});
merge(config.macros.ccStats,{
graph24HourTitle:"Last 24 hours",
graph24HourDesc:"The number of views of this workspace in the past 24 hours",
graph20MinsTitle:"Last 20 Minutes",
graph20MinsDesc:"The number of views of this workspace in the last 20 minutes",
graph7DaysTitle:"Last 7 days",
graph7DaysDesc:"The number of views of this workspace in the last 7 days.",
graph5MonthsTitle:"Last 5 months",
graph5MonthsDesc:"The number of views of this workspace in the past 30 days.",
errorPermissionDenied:"Permissions Denied to data for %0 You need to be an administrator on the %1 workspace.",
stepTitle:"Workspace Statistics"
});
// GENERAL NON CCT CONTENT
config.theme = {
contentTitle:"content »",
contentToolTip : "View the TiddlyWiki tabs",
help : "Help"
};
merge(config.macros.importTiddlers, {
wizardTitle: "Import tiddlers",
step1Title: "Step 1: Locate the server or TiddlyWiki file",
step1Html: "Specify the type of the server: <select name='selTypes'><option value=''>Choose...</option></select><br>Enter the URL here: <input type='text' size=50 name='txtPath'><br><input type='hidden' size=50 name='txtBrowse'><br><hr>...or select a pre-defined feed: <select name='selFeeds'><option value=''>Choose...</option></select>"
});
merge(config.optionsDesc,{
txtUserName: "",
chkRegExpSearch: "Enable regular expressions for searches",
chkCaseSensitiveSearch: "Case-sensitive searching",
chkIncrementalSearch: "Incremental key-by-key searching",
chkAnimate: "Enable animations",
chkSaveBackups: "",
chkAutoSave: "",
txtTheme: "Change the TiddlyWiki theme being used",
chkGenerateAnRssFeed: "",
chkSaveEmptyTemplate: "",
chkOpenInNewWindow: "Open external links in a new window",
chkToggleLinks: "Clicking on links to open tiddlers causes them to close",
chkHttpReadOnly: "",
chkForceMinorUpdate: "",
chkConfirmDelete: "Require confirmation before deleting tiddlers",
chkInsertTabs: "Use the tab key to insert tab characters instead of moving between fields",
txtBackupFolder: "",
txtMaxEditRows: "Maximum number of rows in edit boxes",
txtFileSystemCharSet: "Default character set for saving changes (Firefox/Mozilla only)"});
merge(config.macros.options,{
wizardTitle: "Change Settings",
step1Title: "",
step1Html: '<input type="hidden" name="markList"></input><br><input type="hidden" checked="false" name="chkUnknown"></input>These options are saved in a cookie.'
});
merge(config.macros.options,{
wizardTitle:"Advanced settings",
step1Title:null,
unknownDescription: "//(unknown)//",
listViewTemplate: {
columns: [
{name: 'Option', field: 'option', title: "", type: 'String'},
{name: 'Description', field: 'description', title: "", type: 'WikiText'}
],
rowClasses: [
{className: 'lowlight', field: 'lowlight'}
]
}
});
config.macros.OpenID={};
merge(config.macros.OpenID,{
titleOpenID:"",
buttonOpenIDText:"Login",
buttonOpenIDToolTip:"Click to use OpenID Login"
});
config.macros.OpenID.handler=function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
var w = new Wizard();
var me = config.macros.OpenID;
w.createWizard(place,me.titleOpenID);
w.addStep(null,"<!--<img width='150px' src='http://openid.net/wp-content/uploads/2007/10/openid_big_logo_text.png'/><br />--><input name='open_id_login' value='%0' size=40 style='background: rgb(255, 255, 255) url(http://www.openid.net/login-bg.gif) no-repeat scroll 0pt 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 0, 0); padding-left: 18px;'/>".format([decodeURIComponent(cookieString(document.cookie).txtUserName)]));
w.setButtons([
{caption: me.buttonOpenIDText, tooltip: me.buttonOpenIDToolTip, onClick: function(){config.macros.OpenID.login(w); } }
]);
};
config.macros.OpenID.login = function (w) {
var iframe = document.createElement("iframe");
iframe.style.display = "none";
iframe.src = url+"plugins/OpenID/files/openid/try_auth.php?action=verify&openid_identifier="+w.formElem.open_id_login.value;
document.body.appendChild(iframe);
iframe.onload = function() {
// this is not working properly.
if(iframe.src.indexOf("finish_auth.php")){
window.location = iframe.src;
}
};
document.body.appendChild(iframe);
}
//}}}
<link rel='alternate' type='application/rss+xml' title='RSS Feed for ccTiddly workspace : ' href='http://www.andreanis.de/_tiddlyindex.xml'/>
/***
|''Name:''|TagsTreePlugin|
|''Description:''|Displays tags hierachy as a tree of tagged tiddlers.<br>Can be used to create dynamic outline navigation.|
|''Version:''|1.0.1|
|''Date:''|Jan 04,2008|
|''Source:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Author:''|Pascal Collin|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0|
!Demo
On the plugin [[homepage|http://visualtw.ouvaton.org/VisualTW.html]] :
*Try to tag some <<newTiddler>> with a tag displayed in the menu and edit MainMenu.
*Look at some tags like [[Plugins]] or [[menu]].
!Installation
#import the plugin,
#save and reload,
#optionally, edit TagsTreeStyleSheet.
! Usage
{{{<<tagsTree>>}}} macro accepts the following //optional// parameters.
|!#|!parameter|!description|!by default|
|1|{{{root}}}|Uses {{{root}}} tag as tree root|- In a //tiddler// content or template : uses the tiddler as root tag.<br>- In the //page// content or template (by ex MainMenu) : displays all untagged tags.|
|2|{{{excludeTag}}}|Excludes all such tagged tiddlers from the tree|Uses default excludeLists tag|
|3|{{{level}}}|Expands nodes until level {{{level}}}.<br>Value {{{0}}} hides expand/collapse buttons.|Nodes are collapsed on first level|
|4|{{{depth}}}|Hierachy depth|6 levels depth (H1 to H6 header styles)|
|5|{{{sortField}}}|Alternate sort field. By example : "index".|Sorts tags and tiddlers alphabetically (on their title)|
|6|{{{labelField}}}|Alertnate label field. By example : "label".|Displays tiddler's title|
!Useful addons
*[[FieldsEditorPlugin]] : //create//, //edit//, //view// and //delete// commands in toolbar <<toolbar fields>>.
*[[TaggerPlugin]] : Provides a drop down listing current tiddler tags, and allowing toggling of tags.
!Advanced Users
You can change the global defaults for TagsTreePlugin, like default {{{level}}} value or level styles, by editing or overriding the first config.macros.tagsTree attributes below.
!Code
***/
//{{{
config.macros.tagsTree = {
expand : "+",
collapse : "–",
depth : 6,
level : 1,
sortField : "",
labelField : "",
styles : ["h1","h2","h3","h4","h5","h6"],
trees : {}
}
config.macros.tagsTree.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
var root = params[0] ? params[0] : (tiddler ? tiddler.title : null);
var excludeTag = params[1] ? params[1] : "excludeTagsTree";
var level = params[2] ? params[2] : config.macros.tagsTree.level;
var depth = params[3] ? params[3] : config.macros.tagsTree.depth;
var sortField = params[4] ? params[4] : config.macros.tagsTree.sortField;
var labelField = params[5] ? params[5] : config.macros.tagsTree.labelField;
var showButtons = (level>0);
var id = config.macros.tagsTree.getId(place);
if (config.macros.tagsTree.trees[id]==undefined) config.macros.tagsTree.trees[id]={};
config.macros.tagsTree.createSubTree(place,id,root,excludeTag,[],level>0 ? level : 1,depth, sortField, labelField,showButtons);
}
config.macros.tagsTree.createSubTree = function(place, id, root, excludeTag, ancestors, level, depth, sortField, labelField,showButtons){
var childNodes = root ? this.getChildNodes(root, ancestors) : this.getRootTags(excludeTag);
var isOpen = (level>0) || (!showButtons);
if (root && this.trees[id][root]!=undefined) isOpen = this.trees[id][root];
if (root && ancestors.length) {
var t = store.getTiddler(root);
if (childNodes.length && depth>0) {
var wrapper = createTiddlyElement(place , this.styles[Math.min(Math.max(ancestors.length,1),6)-1],null,"branch");
if (showButtons) {
b = createTiddlyButton(wrapper, isOpen ? config.macros.tagsTree.collapse : config.macros.tagsTree.expand, null, config.macros.tagsTree.onClick);
b.setAttribute("treeId",id);
b.setAttribute("tiddler",root);
}
createTiddlyText(createTiddlyLink(wrapper, root),t&&labelField ? t.fields[labelField] ? t.fields[labelField] : root : root);
}
else
createTiddlyText(createTiddlyLink(place, root,false,"leaf"),t&&labelField ? t.fields[labelField] ? t.fields[labelField] : root : root);
}
if (childNodes.length && depth) {
var d = createTiddlyElement(place,"div",null,"subtree");
d.style.display= isOpen ? "block" : "none";
if (sortField)
childNodes.sort(function(a, b){
var fa=a.fields[sortField];
var fb=b.fields[sortField];
return (fa==undefined && fb==undefined) ? a.title < b.title ? -1 : a.title > b.title ? 1 : 0 : (fa==undefined && fb!=undefined) ? 1 :(fa!=undefined && fb==undefined) ? -1 : fa < fb ? -1 : fa > fb ? 1 : 0;
})
for (var cpt=0; cpt<childNodes.length; cpt++)
this.createSubTree(d, id, childNodes[cpt].title, excludeTag, ancestors.concat(root), level-1, depth-1, sortField, labelField, showButtons);
}
}
config.macros.tagsTree.onClick = function(e){
var id = this.getAttribute("treeId");
var tiddler = this.getAttribute("tiddler");
var n = this.parentNode.nextSibling;
var isOpen = n.style.display != "none";
if(config.options.chkAnimate && anim && typeof Slider == "function")
anim.startAnimating(new Slider(n,!isOpen,null,"none"));
else
n.style.display = isOpen ? "none" : "block";
this.firstChild.nodeValue = isOpen ? config.macros.tagsTree.expand : config.macros.tagsTree.collapse;
config.macros.tagsTree.trees[id][tiddler]=!isOpen;
return false;
}
config.macros.tagsTree.getChildNodes = function(root ,ancestors){
var childs = store.getTaggedTiddlers(root);
var result = new Array();
for (var cpt=0; cpt<childs.length; cpt++)
if (childs[cpt].title!=root && ancestors.indexOf(childs[cpt].title)==-1) result.push(childs[cpt]);
return result;
}
config.macros.tagsTree.getRootTags = function(excludeTag){
var tags = store.getTags(excludeTag);
tags.sort(function(a,b) {return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : (a[0].toLowerCase() == b[0].toLowerCase() ? 0 : +1);});
var result = new Array();
for (var cpt=0; cpt<tags.length; cpt++) {
var t = store.getTiddler(tags[cpt][0]);
if (!t || t.tags.length==0) result.push(t ? t : {title:tags[cpt][0],fields:{}});
}
return result;
}
config.macros.tagsTree.getId = function(element){
while (!element.id && element.parentNode) element=element.parentNode;
return element.id ? element.id : "<html>";
}
config.shadowTiddlers.TagsTreeStyleSheet = "/*{{{*/\n";
config.shadowTiddlers.TagsTreeStyleSheet +=".leaf, .subtree {display:block; margin-left : 0.5em}\n";
config.shadowTiddlers.TagsTreeStyleSheet +=".subtree {margin-bottom:0.5em}\n";
config.shadowTiddlers.TagsTreeStyleSheet +="#mainMenu {text-align:left}\n";
config.shadowTiddlers.TagsTreeStyleSheet +=".branch .button {border:1px solid #DDD; color:#AAA;font-size:9px;padding:0 2px;margin-right:0.3em;vertical-align:middle;text-align:center;}\n";
config.shadowTiddlers.TagsTreeStyleSheet +="/*}}}*/";
store.addNotification("TagsTreeStyleSheet", refreshStyles);
config.shadowTiddlers.MainMenu="<<tagsTree>>"
config.shadowTiddlers.PageTemplate = config.shadowTiddlers.PageTemplate.replace(/id='mainMenu' refresh='content' /,"id='mainMenu' refresh='content' force='true' ")
//}}}
{{firstletter{ @@color:#c06;2@@}}}right{{@@color:#c06;4@@
[[jump|http://tiddlytagmindmap.tiddlyspot.com/#TiddlyTagMindMap%20]]
[[color|http://html-color-codes.info/]]
[[fine site|http://mptw2.tiddlyspot.com/#SliderSiteMap]]
/* This plugin requires the VismoLibrary */
/***
|''Name''|TiddlyTagMindMap|
|''Description''|Bring your tiddlers to life in a radial graph which displays all your tiddlywiki tiddlers and the relationships between them. (A bit like The Brain)|
|''Author''|Jon Robson|
|''Contributors''|Nicolas Garcia Belmonte|
|''Version''|1.5 in progress|
|''Date''|Nov 2008|
|''Status''|@@experimental@@;|
|''License''|BSD|
|''CoreVersion''|<...>|
|''Documentation''|<...>|
|''Keywords''|data visualisation, mindmap, The Brain, Mind Manager, FreeMind,tag relationships,graph|
!Description
Bring your TiddlyWiki to life!
!Notes
To install you will need to paste a line of text into your Theme {{{ <div id="tagmindmap"></div>}}} in the location where you would like to see the visualisation.
Currently we are unable to support this working in internet explorer.. we are working on it however.. sorry! :(
!Usage
{{{
The tagmindmap can be created from a macro call using <<tiddlytagmindmap //params//>>
alternatively paste <div id='tagmindmap'></div> into your page template.
The following macros may be useful however they can be included in the toolbar settings of the tiddlytagmindmap macro.
<<ToggleTagMindMap id>> (create button to toggle mind map with id 'id' on/off)
<<LoadMindMap id>> (create button to load all nodes into mind map with id 'id')
There are a variety of configuration options in the backstage area under tweak. They all begin with TiddlyTagMindMapPlugin:
}}}
!!Parameters
tiddlytagmindmap takes several (but all optional) parameters. Some examples can be seen below, note the order is irrelevant of these parameters.
!!!Animation
You can turn animation on/off by using animate:true or animate:false. By default it is on.
!!!Nodes and Edges
!!!!Directional edges
The directed parameter allows you to add arrowheads to your edges. usage: {{{<< tiddlytagmindmap directed:true>>}}}
!!!!Name Length
nodeNameLength:x where x is an integer will shorten the name of any node with a name longer than x. If x =0, the labels will disappear so you can rely on tooltips.
!!!!Variable node sizes (tagcloud)
notagcloud:true as a parameter will flatten the nodes to have the same size font
!!!Dimensions
{{{<<tiddlytagmindmap height:100 width:100>>}}} will set a tiddlytagmindmap with height and width 100.
!!!Zooming
A parameter zoom allows you to specify an integer representing the initial inflation of the mind map. The smaller it is - the closer the nodes will be together.
{{{<<tiddlytagmindmap zoom:1000>>}}} will give you a very inflated TagMindMap!
!!!Tiddler Pop ups
You can now preview a tiddler by using popup:true
!!!Breadcrumb trail
You can turn visited nodes red when they are clicked on by using the {{{breadcrumb:true}}} parameter by default this is false.
!!!The toolbar
A parameter toolbar is a string of 1s. These signify the buttons. The first digit sets whether the bar should appear vertically or horizontally.
The following digits turn off or on the other available buttons.
!!!!The buttons
The digits preceding the first digit represent these buttons in this order..
toggle, loadall
{{{<<tiddlytagmindmap toolbar:101>>}}} would give you a vertical toolbar with a loadall button
!!!The Start State
A parameter can be used to specify how the map looks on start up.
Currently the options are empty OR all OR a custom executable javascript function.
The first two options are simple strings eg.
{{{<<tiddlytagmindmap startState:empty>>}}} loads a blank tag mind map however {{{<<tiddlytagmindmap startState:all>>}}} loads all nodes excluding those in the exclude List.
the latter is more interesting. Have a look at [[Example 2]]!
!Revision History
1.6
* can now preview tiddlers in place using popup:true
* can turn off animations using animate:false
* double click opens a node, single click reveals any new nodes and/or performs animations
* fixed mouse panning
1.5 xx/xx
*Ability to add arrow heads to show direction
*better performance
*better control panel: replacement of macros for toggle/zoom in and out with built in toolbar to plugin
*update to new version of RGraph (JIT)
*Ability to set meta-data specific to nodes within a tiddler in optional fields see
http://TiddlyWiki.abego-software.de/#PartTiddlerPlugin (eg. colouring of children/parents/images in node label)
*definable meta data (prefix,suffix,label,color)
*can turn off click function
1.4 11/08 tag cloud integration/multiple tag mind maps/ability to call from macro
1.3 22/10/08 working with ie/packaged up code
!To Do
*bug: zoomin breaks on more than 1 mind map.. no idea why but scale resets :(
*fix ie clicking nodes
*display tiddler loads below the place it;s called from
*Ability to define your own function for relative sizing (ie. you could weight them on some meta field)
*color property should become css property
*ability to resize using %
*distinguish between tags and tiddlers (see CreateNodeJSON - tiddlers that don't exist in store are tagged in data field)
*rss hooks - specify where tags and node names come from in feed
*ability to specify what click function is
*ability to stop displayTiddler from loading into graph (*ability to turn off dynamic as you go updates)
*allow resizing
*auto spread out messy nodes (ie. zoom out if nodes are too close)
*node repositioning and saving of state
*better css support
*performance issues
*deleting edges as tiddlers are deleted
*adapt to parabolic tree mode and other visualisation types
*Self-defined click functions
*Continued code cleanup
*breadcrumbs to become encoded in the node colour (rather than label colour) define a colour of the breadcrumb trail - make it change colour each click (increment colour, so you can get an idea of path you took to get somewhere)
*add pins to locations in the mind map to jump back to (definable in meta data long term, also short term in tiddler edit menu)
!Code
***/
/***
!Layer 1: TiddlyWiki Specific
Jon Robson
***/
{{{
//set descriptions
merge(config.optionsDesc,{
txtTTMM_canvasWidth: "TiddlyTagMindMapPlugin : Width of visualisation. You will need to refresh the page to see the change."
,txtTTMM_canvasHeight: "TiddlyTagMindMapPlugin : Height of visualisation. You will need to refresh the page to see the change."
,txtTTMM_inflation: "TiddlyTagMindMapPlugin : The visualisation can be inflated and deflated to allow you to see the structure from above or close up. This value allows you to set a start inflation."
,txtTTMM_maxNodeNameLength:"TiddlyTagMindMapPlugin : maximum length of a tiddler name. Any tiddlers with names longer than this will be abbrieviated using '...'. Set to zero to make labels disappear altogether and rely completely on tooltips."
,chkTTMM_ignoreLoneNodes: "TiddlyTagMindMapPlugin : any lone tiddlers/nodes (ie. tiddlers that are not tagged with any data) will be ignored in the visualisation. This cleans up the visualisation greatly."
,txtTTMM_excludeNodeList: "TiddlyTagMindMapPlugin :Anything tagged with this will be ignored in the visualisation. Formatted in form ['tiddlername1', 'tiddlername2']"
,chkTTMM_leaveRedBreadCrumbTrail: "TiddlyTagMindMapPlugin : When you visit a node it will be coloured red leaving a breadcrumb trail of where you have been."
}
);
/*MACROS*/
config.macros.TagMindMapEdge={ /* params: node1|commit node2 */
handler: function (place,macroName,params,wikifier,paramString,tiddler) {
var id1 = params[0]; var id2 = params[1];
var ttmm = config.macros.tiddlytagmindmap.getAssociatedTiddlyTagMindMapObject(null,false);
if(!ttmm) return;
if(id1 == "commit") {
this.commit();
return;
}
var name1,name2,data1,data2;
if(id1.id){
//its a json
if(id1.name)name1 = id1.name;
if(id1.data)data1 = id1.data;
id1 = id1.id;
}
if(id2.id){
//its a json
if(id1.name)name2 = id2.name;
if(id2.data)data2 = id2.data;
id2 = id2.id;
}
if(!data1){ data1 = {};}
if(!data2){ data2 = {};}
if(!store.tiddlerExists(id1)){
if(!data1.color && ttmm.settings.emptyTiddlerColor)data1.color = ttmm.settings.emptyTiddlerColor;
data1.emptyTiddler = true;
}
if(!store.tiddlerExists(id2)){
if(!data2.color && ttmm.settings.emptyTiddlerColor)data2.color = ttmm.settings.emptyTiddlerColor;
data2.emptyTiddler = true;
}
if(ttmm){
ttmm.drawEdge(id1,id2,name1,name2,data1,data2);
}
}
,commit: function(){
var ttmm = config.macros.tiddlytagmindmap.getAssociatedTiddlyTagMindMapObject(null,false);
ttmm.computeThenPlot();
}
};
config.macros.LoadMindMap={
label: "loadall",
prompt: "load all tiddlers into the tag mind map",
handler: function (place,macroName,params,wikifier,paramString,tiddler) {
var btn =createTiddlyButton(place,this.label,this.prompt,this.onClick);
if(params[0]){
btn.wrapperID = params[0];
}
}
,onClick: function(e,id)
{
var ttmm;
if(id)
ttmm = config.macros.tiddlytagmindmap.store[id];
else
ttmm = config.macros.tiddlytagmindmap.getAssociatedTiddlyTagMindMapObject(this.wrapperID,true);
var list = store.getTiddlers();
for (var t=0; t<list.length; t++) {
ttmm.createNodeFromJSON(config.macros.tiddlytagmindmap.createJSON(list[t].title,ttmm));
}
ttmm.computeThenPlot();
}
};
config.macros.ToggleTagMindMap={
label: "toggle",
prompt: "Toggle on or off the tag mind map",
handler: function(place,macroName,params,wikifier,paramString,tiddler){
var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick);
if(params[0])btn.wrapperID = params[0];
}
,onClick: function(e){
var id = config.macros.tiddlytagmindmap.getAssociatedTiddlyTagMindMapObject(this.wrapperID,true).wrapper.id;
if(document.getElementById(id).style.display== "none"){
document.getElementById(id).style.display= "";
}
else{
document.getElementById(id).style.display= "none";
}
}
};
config.macros.tiddlytagmindmap={
store: {}, //a library of created ttmm objects
handler: function (place,macroName,params,wikifier,paramString,tiddler) {
if(!place) { //give a default place
place = document.getElementById('tagmindmap');
if(!place) throw "no place to put ttmm!"; //unable to create
paramString =place.getAttribute("parameters");
}
var settings = this.get_ttmm_settings(paramString);
var elem = this.setup_ttmm_html(place,settings);
try{
this.store[elem.id]= new Tagmindmap(elem,settings);
this.store['last'] = elem.id;
this.store['cur'] = elem.id;
if(settings.startupFunction){
settings.startupFunction(elem.id);
}
}
catch(e){console.log("exception thrown during tiddlytagmindmap creation:"+e);}
},
get_ttmm_setting_defaults: function(){
if(!config.options.txtTTMM_canvasWidth)config.options.txtTTMM_canvasWidth = 800;
if(!config.options.txtTTMM_canvasHeight)config.options.txtTTMM_canvasHeight = 200;
if(!config.options.txtTTMM_inflation)config.options.txtTTMM_inflation = 80;
if(!config.options.txtTTMM_maxNodeNameLength)config.options.txtTTMM_maxNodeNameLength = 25;
if(config.options.chkTTMM_ignoreLoneNodes == null) config.options.chkTTMM_ignoreLoneNodes = false;
if(config.options.chkTTMM_leaveRedBreadCrumbTrail == null) config.options.chkTTMM_leaveRedBreadCrumbTrail = true;
if(!config.options.txtTTMM_excludeNodeList) config.options.txtTTMM_excludeNodeList= ['excludeLists'];
var settings = {};
/*set some defaults based on tweaked preferences if none passed as parameters*/
settings.maxNodeNameLength = config.options.txtTTMM_maxNodeNameLength;
settings.ignoreLoneNodes = config.options.chkTTMM_ignoreLoneNodes;
settings.tagcloud = {off:false};
settings.width = config.options.txtTTMM_canvasWidth;
settings.height =config.options.txtTTMM_canvasHeight;
settings.toolbar = "000";
settings.zoomLevel = parseInt(config.options.txtTTMM_inflation);
settings.breadcrumbs = config.options.chkTTMM_leaveRedBreadCrumbTrail;
settings.animate = true;
var clickfunction = function(node,id,e){
//var tiddlerElem = story.findContainingTiddler(resolveTarget(e));
story.displayTiddler(null, node.id,null,null,null,null,null,id);
};
settings.clickFunction = clickfunction;
return settings;
},
get_ttmm_settings: function(paramString){
var settings = this.get_ttmm_setting_defaults();
var exList = null;
var that = this;
var startupFunction = function(id){};
settings.dynamicUpdateFunction = this.createJSON;
if(paramString){
var prms = paramString.parseParams(null, null, true);
settings.breadcrumbs = eval(getParam(prms, "breadcrumbs"));
settings.ignoreLoneNodes = eval(getParam(prms, "ignoreLoneNodes"));
settings.arrowheads = eval(getParam(prms, "directed"));
settings.tagcloud.off = eval(getParam(prms, "notagcloud"));
if(getParam(prms,"animate")) settings.animate = eval(getParam(prms,"animate"));
if(getParam(prms, "id")) settings.id = getParam(prms, "id");
if(getParam(prms, "width")) settings.width = getParam(prms, "width");
if(getParam(prms, "height"))settings.height = getParam(prms, "height");
if(getParam(prms, "toolbar")) settings.toolbar= getParam(prms, "toolbar");
if(getParam(prms,"zoom")) settings.zoomLevel = parseInt(getParam(prms,"zoom"));
if(getParam(prms,"maxNodeNameLength"))settings.maxNodeNameLength = getParam(prms,"maxNodeNameLength");
if(getParam(prms, "exclude")) exList = getParam(prms, "exclude");
if(getParam(prms,"displayemptytiddlers"))settings.displayemptytiddlers = getParam(prms,"displayemptytiddlers");
if(getParam(prms,"emptyTiddlerColor")){
settings.emptyTiddlerColor =getParam(prms,"emptyTiddlerColor");
}
var clickfunction;
if(!getParam(prms, "click")){
clickfunction = function(node,id,e){
var tiddlerElem = story.findContainingTiddler(resolveTarget(e));
story.displayTiddler(tiddlerElem, node.id,null,null,null,null,null,id);
return;
};
}
else if(getParam(prms, "click") == "existing") {
clickfunction = function(node,id,e){
if(!node.data.emptyTiddler){
var tiddlerElem = story.findContainingTiddler(resolveTarget(e));
story.displayTiddler(tiddlerElem, node.id,null,null,null,null,null,id);
}
return;
};
}
else if(getParam(prms,"click") == "none"){
clickfunction = function(node,id,e){};
}
settings.clickFunction = clickfunction;
if(getParam(prms,"popup")) {
settings.globalSuffix = function(node){
var place = document.createElement("div");
var tiddler = store.getTiddler(node.id);
if(!tiddler) tiddler = config.shadowTiddlers[node.id];
if(tiddler)createTiddlyPopup(place,"",node.id,tiddler);
return place;
};
}
var startState = getParam(prms, "startState");
if(startState){
if(startState == 'all')
startupFunction = function(id){
config.macros.LoadMindMap.onClick(null,id);
}
else if(startState == 'empty'){
startupFunction = function(id){
};
}
/*else if(startState == 'default'){
startupFunction = function(id){
con
var startState = store.filterTiddlers(store.getTiddlerText("DefaultTiddlers"));
that.loadTiddlersIntoTTMM(startState,id);
}
}*/
else{//parse as a list of tiddler names
if(startState){
startupFunction = function(id){
if(startState.length == 0) return;
that.loadTiddlersIntoTTMM(startState,id);
}
}
}
settings.startupFunction = startupFunction;
}
}
if(!exList){
exList = [];
if(config.options.txtTTMM_excludeNodeList)exList = config.options.txtTTMM_excludeNodeList;
}
/*set the excluded nodes */
var l = eval(exList);
settings.excludeNodeList = [];
for(var i=0; i < l.length; i++){
settings.excludeNodeList.push(l[i]);
settings.excludeNodeList = settings.excludeNodeList.concat(getChildren(l[i]));
}
return settings;
}
,setup_ttmm_html: function(place,settings){
if(place.id == 'tagmindmap')settings.id = 'default';
if(place.style.width) settings.width = place.style.width;
if(place.style.height) settings.height = place.style.height;
/*setup tag mind map */
var newTTMM = document.createElement("div");
if(!settings.id) settings.id="ttmm_" +Math.random();
newTTMM.id = settings.id;
newTTMM.style.width = settings.width +"px";
newTTMM.style.height= settings.height +"px";
newTTMM.setAttribute("class","ttmm");
/*setup toolbar */
var toolbar = document.createElement("div");
toolbar.setAttribute("class","ttmm_toolbar");
var html="", divider = " ";
if(settings.toolbar[0] == 1){//MAKE VERTICAL
toolbar.style.height = "1px";
toolbar.style.position = "relative";
var temp = parseInt(settings.width) +10;
toolbar.style.top = "0px";
toolbar.style.left = temp+"px";
divider = "\n";
}
if(settings.toolbar[1] == 1) html += "<<ToggleTagMindMap " + newTTMM.id+">>" + divider;
if(settings.toolbar[2] == 1) html += "<<LoadMindMap " + newTTMM.id+">>"+ divider;
place.appendChild(toolbar);
wikify(html,toolbar);
place.appendChild(newTTMM);
if(!document.getElementById(this.store['first']))this.store['first'] = newTTMM.id; //no primary ttmm exists
if(!newTTMM.style.width) newTTMM.style.width = settings.width;
if(!newTTMM.style.height) newTTMM.style.height = settings.height;
return newTTMM;
}
,loadTiddlersIntoTTMM: function(tiddlerList,visualisationID){
var viz;
if(!visualisationID)
viz = this.store[this.store['first']];
else
viz = this.store[visualisationID];
var nodesLoaded = false;
var title ="";var firstTitle="";
for(var i =0; i < tiddlerList.length; i++){
if(tiddlerList[i].title) title = tiddlerList[i].title;
else title = tiddlerList[i];
if(i==0) firstTitle = title;
nodesLoaded = viz.createNodeFromJSON(this.createJSON(title,viz)) | nodesLoaded;
}
if(viz.rgraph){
if(nodesLoaded !=0){
viz.rgraph.compute();
viz.rgraph.plot();
}
viz.centerOnNode(title);
}
}
,getAssociatedTiddlyTagMindMapObject: function(id,getFirstCreatedTTMM){
if(id) return this.store[id];
else {
if(getFirstCreatedTTMM)
return this.store[this.store['first']];
else
return this.store[this.store['last']];
}
}
,_createJSONTagMindMapNodes: function(mylist,storeElement) {
var res=[];
for (var t=0; t<mylist.length; t++){
var node =mylist[t];
res.push(config.macros.tiddlytagmindmap._createJSONTagMindMapNode(node,storeElement));
}
return res;
}
,_createJSONTagMindMapNode: function(id,storeElement){
var json = {};
json.id = id;
json.name = id;
nodeData = {};
var parents = getParents(id);
for(var i=0; i < parents.length; i++){
var nodeid = parents[i];
if(store.tiddlerExists(nodeid)){
var tiddler = store.getTiddler(nodeid);
if(tiddler.fields.childrencolor) nodeData.color = tiddler.fields.childrencolor;
}
}
var children = getChildren(id);
for(var i=0; i < children.length; i++){
var nodeid = children[i];
if(store.tiddlerExists(nodeid)){
var tiddler = store.getTiddler(nodeid);
if(tiddler.fields.parentcolor) nodeData.color = tiddler.fields.parentcolor;
}
}
if(store.tiddlerExists(id)){
var tiddler = store.getTiddler(id);
if(tiddler.fields.nodecolor) nodeData.color = tiddler.fields.nodecolor;
if(tiddler.fields.nodeprefix) {
var place =createTiddlyElement(null,"div");
wikify(tiddler.fields.nodeprefix,place);
nodeData.nodeLabelPrefix = place;
}
if(tiddler.fields.nodesuffix) {
var place =createTiddlyElement(null,"div");
wikify(tiddler.fields.nodesuffix,place);
nodeData.nodeLabelSuffix = place;
}
if(tiddler.fields.nodelabel) {
var place =createTiddlyElement(null,"div");
wikify(tiddler.fields.nodelabel,place);
nodeData.label = place;
}
if(tiddler.fields.nodetooltip) {nodeData.title = tiddler.fields.nodetooltip;}
}
if(!nodeData.color){
var empty = false;
if(!store.tiddlerExists(id) && !store.isShadowTiddler(id)){
empty = true;
}
if(store.tiddlerExists(id)){
var tiddler = store.getTiddler(id);
if(tiddler.text == null || tiddler.text == "") empty =true;
}
if(empty){
nodeData.emptyTiddler = true;
//nodeData.color = "#cccccc";
//console.log(storeElement.settings);
if(storeElement && storeElement.settings.emptyTiddlerColor) nodeData.color= storeElement.settings.emptyTiddlerColor;
//storeElement
}
}
if(nodeData){
json.data =nodeData;
}
return json;
}
,createJSON: function(nodeid,storeElement){
if(!nodeid) return "{}";
var myjson = {};
var children = getChildren(nodeid);
var parents = getParents(nodeid);
myjson.children = config.macros.tiddlytagmindmap._createJSONTagMindMapNodes(children,storeElement);
myjson.parents = config.macros.tiddlytagmindmap._createJSONTagMindMapNodes(parents,storeElement);
myjson.node = config.macros.tiddlytagmindmap._createJSONTagMindMapNode(nodeid,storeElement);
return myjson;
}
};
function getParents(a){
if(store.getTiddler(a)){
return store.getTiddler(a).tags;
}
else
return [];
}
function getChildren(a){
if(store.getTaggedTiddlers(a)){
var tags = store.getTaggedTiddlers(a);
if(tags.length == 0) return [];
var a = new Array();
for (var t=0; t<tags.length; t++) {
a.push(tags[t].title);
}
return a;
}
else
return [];
}
story.beforettmm_displayTiddler = story.displayTiddler;
story.displayTiddler = function(srcElement,tiddler,template,animate,unused,customFields,toggle,visualisationID)
{
try{
if(!document.getElementById(config.macros.tiddlytagmindmap.store['first'])) {
config.macros.tiddlytagmindmap.handler(); //try and setup a default one
}
}
catch(e){
};
var title = (tiddler instanceof Tiddler)? tiddler.title : tiddler;
if(config.macros.tiddlytagmindmap.store){
try{
if(!visualisationID && config.macros.tiddlytagmindmap.store['first']) { //call came from outside tagmindmap
visualisationID =config.macros.tiddlytagmindmap.store['first'];
}
if(visualisationID){
res = config.macros.tiddlytagmindmap.loadTiddlersIntoTTMM([title],visualisationID);
}
}
catch(e){
//console.log("exception in display tiddler for "+title+" in visualisation" + visualisationID +": " + e);
}
}
story.beforettmm_displayTiddler(srcElement,tiddler,template,animate,unused,customFields,toggle);
};
}}}
/***
296.56
58 * 151.46
246.56
!Layer 2: DynamicInteract: Extension of RGraph
***/
{{{
Array.prototype.contains = function(item)
{
return this.indexOf(item) != -1;
};
if(!Array.indexOf) {
Array.prototype.indexOf = function(item,from)
{
if(!from)
from = 0;
for(var i=from; i<this.length; i++) {
if(this[i] === item)
return i;
}
return -1;
};
}
var Tagmindmap = function(wrapper,settings){
if(settings.clickFunction)
this.callWhenClickOnNode = settings.clickFunction;
else
this.callWhenClickOnNode = function(node,id){return};
if(settings.dynamicUpdateFunction)
this.dynamicUpdateFunction = settings.dynamicUpdateFunction;
else
this.dynamicUpdateFunction = function(node,id){return {};};
this.wrapper = wrapper;
this._setup(settings);
//this._init_html_elements(wrapper.id);
this._init_html_elements();
this.controlpanel =new VismoController(this,wrapper,["pan","zoom","mousepanning"]);
this.ready = false;
this.children = {};
this.parents = {};
this.ready = true;
this.controlpanel.setTransformation({translate:{x:0,y:0}, scale:{x: this.settings.zoomLevel,y: this.settings.zoomLevel}});
};
Tagmindmap.prototype = {
transform: function(t){
var compute = false;
if(this.settings.zoomLevel != t.scale.x) {
t.translate.x = 0; t.translate.y = 0;
if(this.lastclickednode) this.rgraph.root = this.lastclickednode;
if(t.scale.x > 0){
this.settings.zoomLevel = parseFloat(t.scale.x);
}
compute = true;
}
if(this.rgraph){
var c= {x:t.translate.x * t.scale.x, y:t.translate.y* t.scale.y};
this.rgraph.offsetCenter(c.x,c.y);
if(compute) this.rgraph.compute();
this.rgraph.plot();
}
},
_setup: function(settings){
this.settings = {'animate':true,'arrowheads':false,'maxNodeNameLength':99999,'breadcrumbs': true,'lineColor':'#ccddee','nodeColor':'#ccddee','zoomLevel':100, 'ignoreLoneNodes':false,'excludeNodeList': ['excludeLists']}; //put all default settings here
this.settings.tagcloud = {'smallest': 0.8, 'largest': 1.4, 'upper':0, 'off': false}; //upper is the maximum sized node
this.graph_showCirclesFlag = false; //shows circles in the mind map
this.maxNodeNameLength = 0;
this.displacement = {'x':0, 'y':0};
this.maxChildrenOnSingleNode = 0;
this.thehiddenbridge = "RGRAPHTREEBRIDGE"; //a hidden node which bridges all dislocated nodes.
this.settings.breadcrumb_startcolor = "red"; //rgb(0,0,0)
/*above defaults below read in */
for(var i in settings){
this.settings[i] = settings[i];
}
this.settings.arrowheads = settings.arrowheads;
this.settings.breadcrumbs = settings.breadcrumbs;
this.settings.tagcloud.off = settings.tagcloud.off;
this.settings.excludeNodeList = settings.excludeNodeList;
this.settings.ignoreLoneNodes = settings.ignoreLoneNodes;
this.maxNodeNameLength = settings.maxNodeNameLength;
this.settings.zoomLevel = settings.zoomLevel;
var ttmm = this;
},
_init_html_elements: function(){
var wrapperID = this.wrapper.id;
if(!document.getElementById(wrapperID)){ throw (wrapperID + " html element doesn't exist");}
var canvasID = wrapperID + "_canvas"; //the canvas object ID
this.labelContainer = wrapperID + "_label_container";
this.nodeLabelPrefix = canvasID +"_";
/*setup the divs */
var wrapper = this.wrapper;
wrapper.style.position = "relative";
if(!wrapper.style.height){wrapper.style.height = "200px";}
if(!wrapper.style.width){wrapper.style.width = "200px";}
var labelContainer = document.createElement("div");
labelContainer.id=this.labelContainer;
labelContainer.style.position= 'relative';
var canvas = document.createElement("canvas");
canvas.id = canvasID;
canvas.width = parseInt(wrapper.style.width);
canvas.height =parseInt(wrapper.style.height);
wrapper.appendChild(labelContainer);
wrapper.appendChild(canvas);
this.canvas = canvas;
if(config.browser.isIE && G_vmlCanvasManager) {G_vmlCanvasManager.init_(document);} //ie hack - needs changing to work outside tw
},
createNodeFromJSON: function(json){
if(json == {}) return;
var temp = false;
var res = false;
var node1= json['node'];
if(json['parents']){
for(var i=0; i < json['parents'].length; i++){
var parent = json['parents'][i];
temp = this.drawEdge(parent['id'],node1['id'],parent['name'],node1['name'],parent['data'],node1['data']);
res = temp | res;
}
}
if(json['children']){
for(var i=0; i < json['children'].length; i++){
var child = json['children'][i];
temp = this.drawEdge(node1['id'],child['id'],node1['name'],child['name'],node1['data'],child['data']);
res = temp | res;
}
}
if(json['children'] && json['parents']){
if(!this.settings.ignoreLoneNodes && json['children'].length ==0 && json['parents'].length == 0)
temp = this.drawEdge(this.thehiddenbridge, node1['id'],null,node1['name'],null,node1['data']);
res = temp | res;
}
return res;
},
centerOnNode:function(id){
//var cur =this.getCurrentNodeID();
//if(cur == id) return;
this.rgraph.onClick(id);
},
getCurrentNodeID: function(){
if(!this.rgraph.graph.root) return false;
if(this.rgraph.graph.root.id == this.thehiddenbridge) return false;
else return this.rgraph.graph.root.id;
},
setNodeName: function(nodeid,newName){
var node = this.controller.getNode(nodeid);
if(node.name != newName){
node.name = newName;
if(this.thehiddenbridge != nodeid && this.graph_index) this.graph_index[newName] = nodeid;
}
},
mergeNodeData: function(id,data){
var node = this.controller.getNode(id);
if(!node) return;
for (var key in data){
if(typeof node.data[key] == 'array')
node.data[key] = node.data[key].concat(data[key]);
else
node.data[key] = data[key];
}
if(node.data.weight > this.settings.tagcloud.upper) {
this.settings.tagcloud.upper = node.data.weight;
}
},
setNodeData: function(id,data,newvalue){
var node = this.controller.getNode(id);
if(!node) return;
if(!newvalue){
node.data = data;
}
else{
node.data[data] = newvalue;
}
if(node.data.weight > this.settings.tagcloud.upper) {
this.settings.tagcloud.upper = node.data.weight;
}
},
_nodeInExcludeList: function(id){
return this.settings.excludeNodeList.contains(id);
},
drawEdge: function(id_a,id_b,name_a,name_b,data_a,data_b){
if(this._nodeInExcludeList(id_a) || this._nodeInExcludeList(id_b)) return false;
plotNeeded=false;
if(id_a != "" && id_b != ""){
plotNeeded = this._make_connection(id_a,id_b);
if(name_a){this.setNodeName(id_a,name_a);}
if(name_b){this.setNodeName(id_b,name_b);}
if(data_a) {this.mergeNodeData(id_a,data_a); }
if(data_b) {this.mergeNodeData(id_b,data_b);}
}
return plotNeeded;
},
_make_connection: function(a,b){
var drawn = this._setupMapIfNeeded(a);
var node1, node2;
node1 = this.controller.getNode(a);
node2 = this.controller.getNode(b);
if(node1 && node2){
if(node1.adjacentTo(node2)) {return false;}
}
else if(!node1 && !node2) {//neither in graph yet
drawn = this._make_connection(this.thehiddenbridge,a); //if neither node is currently in tree, then we need to create a "bridge" to connect the trees
}
if(!node1) {node1= new Graph.Node(a,a,{});drawn= true; }//create this node
if(!node2) {node2= new Graph.Node(b,b,{});drawn= true; }//create that node
if(node1){
if(!node1.adjacentTo(node2)){
this.controller.addAdjacence(node1,node2);
node1 = this.controller.getNode(a);
node2 = this.controller.getNode(b);
if(!this.children[a]) this.children[a] = [];
if(!this.parents[b]) this.parents[b] = [];
this.children[a].push(b);
this.parents[b].push(a);
return true;
}
}
},
deleteNode: function(id){
var node = this.rgraph.controller.getNode(id);
//console.log("start",node,"end");
var parents = node.data.parents;
var children = node.data.children;
//console.log(id,parents,children);
if(children){
//sort out children
for(var i=0; i < children.length; i++){
var childNode = this.rgraph.controller.getNode(children[i]);
var oldparents = childNode.data.parents;
var newparents = [];
for(var j=0; j < oldparents.length; j++){
if(oldparents[j] != id)newparents.push(oldparents[j]);
}
this.setNodeData(children[i],"parents",newparents);
if(newparents.length == 0) { //connect it up to the bridge
this.drawEdge(this.thehiddenbridge,children[i]);
}
}
}
//sort out parents
if(parents){
for(var i=0; i < parents.length; i++){
if(parents[i] != this.thehiddenbridge){
var parentNode = this.rgraph.controller.getNode(parents[i]);
var oldchildren = parentNode.data.children;
var newchildren = [];
for(var j=0; j < oldchildren.length; j++){
if(oldchildren[j] != id)newchildren.push(oldchildren[j]);
}
this.setNodeData(parents[i],"children",newchildren);
}
}
}
this.rgraph.controller.removeNode(id);
},
computeThenPlot: function(){
try{
this.rgraph.compute();
this.rgraph.plot();
}
catch(e){
console.log(e+"in computeThenPlot");
}
},
_trimNodeName: function(node_name){
if(this.maxNodeNameLength ==0) return "<span> </span>";
if(this.maxNodeNameLength){
var nlength = this.maxNodeNameLength;
if(node_name.length > nlength)
return node_name.substr(0,nlength/2) + "..." + node_name.substr(node_name.length-nlength/2,node_name.length);
else
return node_name;
}
return node_name;
},
_getController: function(){
var ttmm = this;
var effectHash = {};
var controller = {
removeNode: function(id){
var el = document.getElementById(this.getNodeLabelPrefix()+id);
el.parentNode.removeChild(el);
var graph = ttmm.rgraph.graph;
if(graph) graph.removeNode(id);
},
getNode: function(id){
var n = GraphUtil.getNode(ttmm.rgraph.graph,id);
return n;
},
addAdjacence: function(node1,node2){
ttmm.rgraph.graph.addAdjacence(node1,node2);
},
/*some custom defined controller operations (search in RGraph source)*/
getZoomLevel: function(){
return parseFloat(ttmm.settings.zoomLevel);
},
setOffset: function(d){ttmm.displacement = d;},
getOffset: function(){return ttmm.displacement;},
getNodeLabelContainer: function(){
return ttmm.labelContainer;
},
getNodeLabelPrefix: function(){return ttmm.nodeLabelPrefix;},
onBeforeCompute: function(node) {
ttmm.createNodeFromJSON(ttmm.dynamicUpdateFunction(node.id));
if(ttmm.settings.breadcrumbs) {
ttmm.setNodeData(node.id,"color",ttmm.settings.breadcrumb_startcolor);
}
},
getName: function(node1, node2) {
for(var i=0; i<node1.data.length; i++) {
var dataset = node1.data[i];
if(dataset.key == node2.name) return dataset.value;
}
for(var i=0; i<node2.data.length; i++) {
var dataset = node2.data[i];
if(dataset.key == node1.name) return dataset.value;
}
},
onCreateLabel: function(domElement, node) {
}
,attachClickFunction: function(domElement,node){
if(node.id == this.thehiddenbridge) return;
var dblclickfunction = function(event){
//alert("!");
ttmm.callWhenClickOnNode(node,ttmm.wrapper.id,event);
};
var clickfunction = function(event){
ttmm.createNodeFromJSON(ttmm.dynamicUpdateFunction(node.id));
if(ttmm.settings.animate){
ttmm.centerOnNode(node.id);
}
else{
ttmm.lastclickednode = node.id;
//ttmm.computeThenPlot();
}
};
if(domElement.addEvent){ //for ie
//domElement.addEvent('click',clickfunction);
//domElement.addEvent('dblclick',dblclickfunction);
}
else {
//domElement.onclick = clickfunction;
}
domElement.onmousedown = clickfunction;
domElement.ondblclick = dblclickfunction;
}
,getMaxChildren: function(){
var max =0,num;
for(var i in ttmm.children){
if(ttmm.children[i])
num = ttmm.children[i].length;
else
num =0;
if(num > max) max = num;
}
return max;
},
calculateNodeWeight: function(node){
var weight=0, u=0;
if(node.data.weight) { //user has defined some sort of weight
weight = parseFloat(node.data.weight);
u =parseFloat(ttmm.settings.tagcloud.upper);
}
else{ //just take number of children
if(ttmm.children[node.id]){
weight = ttmm.children[node.id].length;
}
u = this.getMaxChildren();
}
var s,l;
if(ttmm.settings.tagcloud.smallest){
s = parseFloat(ttmm.settings.tagcloud.smallest);
}
else{
s = 0.5;
}
if(ttmm.settings.tagcloud.largest) {
l =parseFloat(ttmm.settings.tagcloud.largest);
}
else{
l = 2;
}
var fontsize = s + ((l - s) * parseFloat(weight / u));
//console.log(s,l,weight,u,fontsize);
return fontsize;
},
onPlaceLabel: function(domElement, node) {
domElement.innerHTML = ""; //quick and dirty flush
if(node.id != ttmm.thehiddenbridge){
if(node.data.color) domElement.style.color = node.data.color;
if(node.data.title){
domElement.title = node.data.title;
}
else{
domElement.title = node.name;
}
var prefix, nodeLabel,suffix;
if(node.data.nodeLabelPrefix) prefix =node.data.nodeLabelPrefix;
if(prefix){
prefix.setAttribute("class","nodeLabelPrefix");
domElement.appendChild(prefix);
}
if(!node.data.label){
nodeLabel = document.createElement("span");
var labelText = ttmm._trimNodeName(node.name);
nodeLabel.appendChild(document.createTextNode(labelText));
}
else{
nodeLabel = node.data.label;
}
if(!ttmm.settings.tagcloud.off){
var fontsize = this.calculateNodeWeight(node);
nodeLabel.style.fontSize = fontsize + "em";
}
nodeLabel.setAttribute("class","nodeLabel");
this.attachClickFunction(nodeLabel,node);
domElement.appendChild(nodeLabel);
if(ttmm.settings.globalSuffix){
suffix =ttmm.settings.globalSuffix(node);
suffix.setAttribute("class","nodeLabelSuffix");
domElement.appendChild(suffix);
}
if(node.data.nodeLabelSuffix) {
suffix =node.data.nodeLabelSuffix;
suffix.setAttribute("class","nodeLabelSuffix");
domElement.appendChild(suffix);
}
}
else domElement.style.display = "none";
var left = parseInt(domElement.style.left);
domElement.style.width = '';
domElement.style.height = '';
var w = domElement.offsetWidth;
domElement.style.left = (left - w /2) + 'px';
},
onAfterCompute: function() {
if(ttmm._afterComputeFunction){
ttmm._afterComputeFunction();
ttmm._afterComputeFunction = false;
}
},
onBeforePlotLine: function(adj){
lineW = ttmm.canvas.getContext().lineWidth;
nodeid = adj.nodeFrom.id;
nodeid2 = adj.nodeTo.id;
if(nodeid == ttmm.thehiddenbridge || nodeid2 == ttmm.thehiddenbridge){
ttmm.canvas.getContext().lineWidth = "0";
}
else ttmm.canvas.getContext().lineWidth = "1";
},
onAfterPlotLine: function(adj){
var l =this.getNodeLabelContainer();
//document.getElementById(l).innerHTML = "";
var context = ttmm.canvas.getContext();
var canvas = ttmm.canvas;
var node = adj.nodeFrom, child = adj.nodeTo;
var pos = node.pos.toComplex();
var posChild = child.pos.toComplex();
var d = this.getOffset();//jon
//draw arrowhead.. (angle needs to be calculated)
if(ttmm.settings.arrowheads){
if(node.id == ttmm.thehiddenbridge)return;
//console.log("arrowhead from",node.id, "to",child.id)
canvas.path('stroke', function(context) {
var r = 20;
var ctx = context;
ctx.save();
//ctx.beginPath();
ctx.translate(posChild.x +d.x,posChild.y+d.y);
var o = parseFloat(posChild.y-pos.y);
var a = parseFloat(posChild.x -pos.x);
if(a !=0){
var rad = Math.atan2(o,a);
ctx.rotate(rad);
ctx.moveTo(2,0);
ctx.lineTo(-r,-4);
ctx.lineTo(-r,4);
ctx.lineTo(2,0);
ctx.fill();
}
ctx.restore();
});
}
ttmm.canvas.getContext().lineWidth = "1";
}
};
return controller;
},
_setupMapIfNeeded: function(lastOpenNode){
if(!this.canvas){
this._init_html_elements();
}
var ctx = this.canvas.getContext;
if(!ctx) {console.log("no context available! Please install ExplorerCanvas");}
if(this.graphloaded) return false;
this.graphloaded = true;
//this._firstnode =lastOpenNode;
var json = {"id":this.thehiddenbridge,"children":[{"id":lastOpenNode,"name":lastOpenNode, "data":{"parents":[this.thehiddenbridge], "children":[]}, "children":[]}], 'data':{"parents":[], "children":[lastOpenNode]}};
json.data = {};
json.data.nodraw=true;
this.canvas= new Canvas(this.canvas.id, this.settings.nodeColor, this.settings.lineColor);
controller = this._getController();
this.rgraph= new RGraph(this.canvas, controller,this.labelContainer);
Config['drawConcentricCircles'] = this.graph_showCirclesFlag;
this.rgraph.loadTreeFromJSON(json);
this.controller = controller;
this.rgraph.compute();
this.centerOnNode(lastOpenNode);
//this.rgraph.graph.root = this.controller.getNode(lastOpenNode);
//if(!this.rgraph.graph.root) this.rgraph.graph.root =this.controller.getNode(this._firstNode);
return true;
}
};
}}}
/*
* File: RGraph.js
*
* Author: Nicolas Garcia Belmonte
*
* Copyright: Copyright 2008 by Nicolas Garcia Belmonte.
*
* Homepage: <http://thejit.org>
*
* Version: 1.0.7a
*
* License: BSD License
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the organization nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Nicolas Garcia Belmonte ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Nicolas Garcia Belmonte BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
Object: $_
Provides some common utility functions.
*/
var $_ = {
fn: function() { return function() {}; },
merge: function(){
var mix = {};
for (var i = 0, l = arguments.length; i < l; i++){
var object = arguments[i];
if (typeof object != 'object') continue;
for (var key in object){
var op = object[key], mp = mix[key];
mix[key] = (mp && typeof op == 'object' && typeof mp == 'object') ? this.merge(mp, op) : this.unlink(op);
}
}
return mix;
},
unlink: function (object){
var unlinked = null;
if(this.isArray(object)) {
unlinked = [];
for (var i = 0, l = object.length; i < l; i++) unlinked[i] = this.unlink(object[i]);
} else if(this.isObject(object)) {
unlinked = {};
for (var p in object) unlinked[p] = this.unlink(object[p]);
} else return object;
return unlinked;
},
isArray: function(obj) {
return obj.constructor.toString().match(/array/i);
},
isString: function(obj) {
return obj.constructor.toString().match(/string/i);
},
isObject: function(obj) {
return obj.constructor.toString().match(/object/i);
}
} ;
/*
Class: Canvas
A multi-purpose Canvas object decorator.
*/
/*
Constructor: Canvas
Canvas initializer.
Parameters:
canvasId - The canvas tag id.
fillStyle - (optional) fill color style. Default's to black
strokeStyle - (optional) stroke color style. Default's to black
Returns:
A new Canvas instance.
*/
var Canvas= function (canvasId, fillStyle, strokeStyle) {
//browser supports canvas element
this.canvasId= canvasId;
this.fillStyle = fillStyle;
this.strokeStyle = strokeStyle;
//canvas element exists
if((this.canvas= document.getElementById(this.canvasId))
&& this.canvas.getContext) {
this.ctx = this.canvas.getContext('2d');
this.ctx.fillStyle = fillStyle || 'black';
this.ctx.strokeStyle = strokeStyle || 'white';
this.setPosition();
this.translateToCenter();
} else {
throw "Canvas object could not initialize.";
}
};
Canvas.prototype= {
/*
Method: getContext
Returns:
Canvas context handler.
*/
getContext: function () {
return this.ctx;
},
/*
Method: setPosition
Calculates canvas absolute position on HTML document.
*/
setPosition: function() {
var obj= this.canvas;
var curleft = curtop = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft
curtop = obj.offsetTop
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft
curtop += obj.offsetTop
}
}
this.position= { x: curleft, y: curtop };
},
/*
Method: getPosition
Returns:
Canvas absolute position to the HTML document.
*/
getPosition: function() {
return this.position;
},
/*
Method: clear
Clears the canvas object.
*/
clear: function () {
this.ctx.clearRect(-this.getSize().x / 2, -this.getSize().x / 2, this.getSize().x, this.getSize().x);
},
/*
Method: drawConcentricCircles
Draws concentric circles. Receives an integer specifying the number of concentric circles.
*/
drawConcentricCircles: function (elem) {
var config = Config;
var times = elem || 6;
var c = this.ctx;
c.strokeStyle = config.concentricCirclesColor;
var pi2 = Math.PI*2;
for(var i=1; i<=times; i++) {
c.beginPath();
c.arc(0, 0, (i*config.levelDistance), 0, pi2, true);
c.stroke();
c.closePath();
}
c.strokeStyle = this.strokeStyle;
},
/*
Method: translateToCenter
Translates canvas coordinates system to the center of the canvas object.
*/
translateToCenter: function() {
this.ctx.translate(this.canvas.width / 2, this.canvas.height / 2);
},
/*
Method: getSize
Returns:
An object that contains the canvas width and height.
i.e. { x: canvasWidth, y: canvasHeight }
*/
getSize: function () {
var width = this.canvas.width;
var height = this.canvas.height;
return { x: width, y: height };
},
/*
Method: path
Performs a _beginPath_ executes _action_ doing then a _type_ ('fill' or 'stroke') and closing the path with closePath.
*/
path: function(type, action) {
this.ctx.beginPath();
action(this.ctx);
this.ctx[type]();
this.ctx.closePath();
}
};
/*
Class: Complex
A multi-purpose Complex Class with common methods.
*/
/*
Constructor: Complex
Complex constructor.
Parameters:
re - A real number.
im - An real number representing the imaginary part.
Returns:
A new Complex instance.
*/
var Complex= function() {
if (arguments.length > 1) {
this.x= arguments[0];
this.y= arguments[1];
} else {
this.x= null;
this.y= null;
}
};
Complex.prototype= {
/*
Method: clone
Returns a copy of the current object.
Returns:
A copy of the real object.
*/
clone: function() {
return new Complex(this.x, this.y);
},
/*
Method: toPolar
Transforms cartesian to polar coordinates.
Returns:
A new <Polar> instance.
*/
toPolar: function() {
var rho = this.norm();
var atan = Math.atan2(this.y, this.x);
if(atan < 0) atan += Math.PI * 2;
return new Polar(atan, rho);
},
/*
Method: norm
Calculates the complex norm.
Returns:
A real number representing the complex norm.
*/
norm: function () {
return Math.sqrt(this.squaredNorm());
},
/*
Method: squaredNorm
Calculates the complex squared norm.
Returns:
A real number representing the complex squared norm.
*/
squaredNorm: function () {
return this.x*this.x + this.y*this.y;
},
/*
Method: add
Returns the result of adding two complex numbers.
Does not alter the original object.
Parameters:
pos - A Complex initialized instance.
Returns:
The result of adding two complex numbers.
*/
add: function(pos) {
return new Complex(this.x + pos.x, this.y + pos.y);
},
/*
Method: prod
Returns the result of multiplying two complex numbers.
Does not alter the original object.
Parameters:
pos - A Complex initialized instance.
Returns:
The result of multiplying two complex numbers.
*/
prod: function(pos) {
return new Complex(this.x*pos.x - this.y*pos.y, this.y*pos.x + this.x*pos.y);
},
/*
Method: conjugate
Returns the conjugate por this complex.
Returns:
The conjugate por this complex.
*/
conjugate: function() {
return new Complex(this.x, -this.y);
},
/*
Method: scale
Returns the result of scaling a Complex instance.
Does not alter the original object.
Parameters:
factor - A scale factor.
Returns:
The result of scaling this complex to a factor.
*/
scale: function(factor) {
return new Complex(this.x * factor, this.y * factor);
},
/*
Method: equals
Comparison method.
*/
equals: function(c) {
return this.x == c.x && this.y == c.y;
},
/*
Method: $add
Returns the result of adding two complex numbers.
Alters the original object.
Parameters:
pos - A Complex initialized instance.
Returns:
The result of adding two complex numbers.
*/
$add: function(pos) {
this.x += pos.x; this.y += pos.y;
return this;
},
/*
Method: $prod
Returns the result of multiplying two complex numbers.
Alters the original object.
Parameters:
pos - A Complex initialized instance.
Returns:
The result of multiplying two complex numbers.
*/
$prod:function(pos) {
var x = this.x, y = this.y
this.x = x*pos.x - y*pos.y;
this.y = y*pos.x + x*pos.y;
return this;
},
/*
Method: $conjugate
Returns the conjugate for this complex.
Alters the original object.
Returns:
The conjugate for this complex.
*/
$conjugate: function() {
this.y = -this.y;
return this;
},
/*
Method: $scale
Returns the result of scaling a Complex instance.
Alters the original object.
Parameters:
factor - A scale factor.
Returns:
The result of scaling this complex to a factor.
*/
$scale: function(factor) {
this.x *= factor; this.y *= factor;
return this;
},
/*
Method: $div
Returns the division of two complex numbers.
Alters the original object.
Parameters:
pos - A Complex number.
Returns:
The result of scaling this complex to a factor.
*/
$div: function(pos) {
var x = this.x, y = this.y;
var sq = pos.squaredNorm();
this.x = x * pos.x + y * pos.y; this.y = y * pos.x - x * pos.y;
return this.$scale(1 / sq);
}
};
Complex.KER = new Complex(0, 0);
/*
Class: Polar
A multi purpose polar representation.
*/
/*
Constructor: Polar
Polar constructor.
Parameters:
theta - An angle.
rho - The norm.
Returns:
A new Polar instance.
*/
var Polar = function(theta, rho) {
this.theta = theta;
this.rho = rho;
};
Polar.prototype = {
/*
Method: clone
Returns a copy of the current object.
Returns:
A copy of the real object.
*/
clone: function() {
return new Polar(this.theta, this.rho);
},
/*
Method: toComplex
Translates from polar to cartesian coordinates and returns a new <Complex> instance.
Returns:
A new Complex instance.
*/
toComplex: function() {
return new Complex(Math.cos(this.theta), Math.sin(this.theta)).$scale(this.rho);
},
/*
Method: add
Adds two <Polar> instances.
Returns:
A new Polar instance.
*/
add: function(polar) {
return new Polar(this.theta + polar.theta, this.rho + polar.rho);
},
/*
Method: scale
Scales a polar norm.
Returns:
A new Polar instance.
*/
scale: function(number) {
return new Polar(this.theta, this.rho * number);
},
/*
Method: equals
Comparison method.
*/
equals: function(c) {
return this.theta == c.theta && this.rho == c.rho;
},
/*
Method: $add
Adds two <Polar> instances affecting the current object.
Returns:
The changed object.
*/
$add: function(polar) {
this.theta = this.theta + polar.theta; this.rho += polar.rho;
return this;
},
/*
Method: $madd
Adds two <Polar> instances affecting the current object. The resulting theta angle is modulo 2pi.
Returns:
The changed object.
*/
$madd: function(polar) {
this.theta = (this.theta + polar.theta) % (Math.PI * 2); this.rho += polar.rho;
return this;
},
/*
Method: $scale
Scales a polar instance affecting the object.
Returns:
The changed object.
*/
$scale: function(number) {
this.rho *= number;
return this;
},
/*
Method: interpolate
Calculates a polar interpolation between two points at a given delta moment.
Returns:
A new Polar instance representing an interpolation between _this_ and _elem_
*/
interpolate: function(elem, delta) {
var pi2 = Math.PI * 2;
var ch = function(t) {
return (t < 0)? (t % pi2) + pi2 : t % pi2;
};
var tt = ch(this.theta) , et = ch(elem.theta);
var sum;
if(Math.abs(tt - et) > Math.PI) {
if(tt - et > 0) {
sum =ch((et + ((tt - pi2) - et)* delta)) ;
} else {
sum =ch((et - pi2 + (tt - (et - pi2))* delta));
}
} else {
sum =ch((et + (tt - et)* delta)) ;
}
var t = (sum);
var r = (this.rho - elem.rho) * delta + elem.rho;
return new Polar(t, r);
}
};
Polar.KER = new Polar(0, 0);
/*
Object: Config
<RGraph> global configuration object. Contains important properties to enable customization and proper behavior for the <RGraph>.
*/
var Config= {
//Property: labelContainer
//Id for label container. The label container is a div dom element that must be explicitly added to your page in order to enable the RGraph.
labelContainer: 'label_container',
//Property: drawConcentricCircles
//show/hide concentricCircles
drawConcentricCircles: 4,
//Property: concentricCirclesColor
//The color of the concentric circles
concentricCirclesColor: '#444',
//Property: levelDistance
//The actual distance between levels
levelDistance: 100,
//Property: nodeRadius
//The radius of the nodes displayed
nodeRadius: 4,
//Property: allowVariableNodeDiameters
//Set this to true if you want your node diameters to be proportional to you first dataset object value property (i.e _data[0].value_).
//This will allow you to represent weighted tree/graph nodes.
allowVariableNodeDiameters: false,
//Property: nodeRangeDiameters
//Diameters range. For variable node weights.
nodeRangeDiameters: {
min: 10,
max: 35
},
//Property: nodeRangeValues
// The interval of the values of the first object of your dataSet.
// A superset of the values can also be specified.
nodeRangeValues: {
min: 1,
max: 35
},
//Property: fps
//animation frames per second
fps:40,
//Property: animationTime
animationTime: 2500,
//Property: interpolation
interpolation: 'linear'
};
/*
Object: GraphUtil
A multi purpose object to do graph traversal and processing.
*/
var GraphUtil = {
/*
Method: filter
For internal use only. Provides a filtering function based on flags.
*/
filter: function(param) {
if(!param || !$_.isString(param)) return function() { return true; };
var props = param.split(" ");
return function(elem) {
for(var i=0; i<props.length; i++) if(elem[props[i]]) return false;
return true;
};
},
/*
Method: getNode
Returns a graph's node with a specified _id_.
*/
getNode: function(graph, id) {
return graph.getNode(id);
},
/*
Method: eachNode
Iterates over graph nodes performing an action.
*/
eachNode: function(graph, action, flags) {
var filter = this.filter(flags);
for(var i in graph.nodes) if(filter(graph.nodes[i])) action(graph.nodes[i]);
},
/*
Method: eachAdjacency
Iterates over a _node_ adjacencies applying the _action_ function.
*/
eachAdjacency: function(node, action, flags) {
var adj = node.adjacencies, filter = this.filter(flags);
for(var id in adj) if(filter(adj[id])) action(adj[id], id);
},
/*
Method: computeLevels
Performs a BFS traversal setting correct level for nodes.
*/
computeLevels: function(graph, id, flags) {
var filter = this.filter(flags);
this.eachNode(graph, function(elem) {
elem._flag = false;
elem._depth = -1;
}, flags);
var root = graph.getNode(id);
root._depth = 0;
var queue = [root];
while(queue.length != 0) {
var node = queue.pop();
node._flag = true;
this.eachAdjacency(node, function(adj) {
var n = adj.nodeTo;
if(n._flag == false && filter(n)) {
if(n._depth < 0) n._depth = node._depth + 1;
queue.unshift(n);
}
}, flags);
}
},
/*
Method: eachBFS
Performs a BFS traversal of a graph beginning by the node of id _id_ and performing _action_ on each node.
This traversal ignores nodes or edges having the property _ignore_ setted to _true_.
*/
eachBFS: function(graph, id, action, flags) {
var filter = this.filter(flags);
this.clean(graph);
var queue = [graph.getNode(id)];
while(queue.length != 0) {
var node = queue.pop();
node._flag = true;
action(node, node._depth);
this.eachAdjacency(node, function(adj) {
var n = adj.nodeTo;
if(n._flag == false && filter(n)) {
n._flag = true;
queue.unshift(n);
}
}, flags);
}
},
/*
Method: eachSubnode
After a BFS traversal the _depth_ property of each node has been modified. Now the graph can be traversed as a tree. This method iterates for each subnode that has depth larger than the specified node.
*/
eachSubnode: function(graph, node, action, flags) {
var d = node._depth, filter = this.filter(flags);
this.eachAdjacency(node, function(adj) {
var n = adj.nodeTo;
if(n._depth > d && filter(n)) action(n);
}, flags);
},
/*
Method: getSubnodes
Collects all subnodes for a specified node. The _level_ parameter filters nodes having relative depth of _level_ from the root node.
*/
getSubnodes: function(graph, id, level, flags) {
var ans = new Array(), that = this, node = graph.getNode(id);
(function(graph, node) {
var fn = arguments.callee;
if(!level || level <= node._depth) ans.push(node);
that.eachSubnode(graph, node, function(elem) {
fn(graph, elem);
}, flags);
})(graph, node);
return ans;
},
/*
Method: getParents
Returns all nodes having a depth that is less than the node's depth property.
*/
getParents: function(graph, node) {
var adj = node.adjacencies;
var ans = new Array();
this.eachAdjacency(node, function(adj) {
var n = adj.nodeTo;
if(n._depth < node._depth) ans.push(n);
});
return ans;
},
/*
Method: clean
Cleans flags from nodes (by setting the _flag_ property to false).
*/
clean: function(graph) { this.eachNode(graph, function(elem) { elem._flag = false; }); }
};
/*
Object: GraphOp
An object holding unary and binary graph operations such as removingNodes, removingEdges, adding two graphs and morphing.
*/
var GraphOp = {
options: {
type: 'nothing',
duration: 2000,
fps:30
},
/*
Method: removeNode
Removes one or more nodes from the visualization. It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.
Parameters:
viz - The visualization object (an RGraph instance in this case).
node - The node's id. Can also be an array having many ids.
opt - Animation options. It's an object with two properties: _type_, which can be _nothing_, _replot_, _fade:seq_, _fade:con_ or _iter_. The other property is the _duration_ in milliseconds.
*/
removeNode: function(viz, node, opt) {
var options = $_.merge(viz.controller, this.options, opt);
var n = $_.isString(node)? [node] : node;
switch(options.type) {
case 'nothing':
for(var i=0; i<n.length; i++) viz.graph.removeNode(n[i]);
break;
case 'replot':
this.removeNode(viz, n, { type: 'nothing' });
GraphPlot.clearLabels(viz);
viz.refresh();
break;
case 'fade:seq': case 'fade':
var GPlot = GraphPlot, that = this;
//set alpha to 0 for nodes to remove.
for(var i=0; i<n.length; i++) {
var nodeObj = viz.graph.getNode(n[i]);
nodeObj.endAlpha = 0;
}
GPlot.animate(viz, $_.merge(options, {
modes: ['fade:nodes'],
onComplete: function() {
that.removeNode(viz, n, { type: 'nothing' });
GPlot.clearLabels(viz);
viz.compute('endPos');
GPlot.animate(viz, $_.merge(options, {
modes: ['linear']
}));
}
}));
break;
case 'fade:con':
var GPlot = GraphPlot, that = this;
//set alpha to 0 for nodes to remove. Tag them for being ignored on computing positions.
for(var i=0; i<n.length; i++) {
var nodeObj = viz.graph.getNode(n[i]);
nodeObj.endAlpha = 0;
nodeObj.ignore = true;
}
viz.compute('endPos');
GPlot.animate(viz, $_.merge(options, {
modes: ['fade:nodes', 'linear'],
onComplete: function() {
that.removeNode(viz, n, { type: 'nothing' });
}
}));
break;
case 'iter':
var that = this, GPlot = GraphPlot;
GPlot.sequence(viz, {
condition: function() { return n.length != 0; },
step: function() { that.removeNode(viz, n.shift(), { type: 'nothing' }); GPlot.clearLabels(viz); },
onComplete: function() { options.onComplete(); },
duration: Math.ceil(options.duration / n.length)
});
break;
default: this.doError();
}
},
/*
Method: removeEdge
Removes one or more edges from the visualization. It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.
Parameters:
viz - The visualization object (an RGraph instance in this case).
vertex - An array having two strings which are the ids of the nodes connected by this edge: ['id1', 'id2']. Can also be a two dimensional array holding many edges: [['id1', 'id2'], ['id3', 'id4'], ...].
opt - Animation options. It's an object with two properties: _type_, which can be _nothing_, _replot_, _fade:seq_, _fade:con_ or _iter_. The other property is the _duration_ in milliseconds.
*/
removeEdge: function(viz, vertex, opt) {
var options = $_.merge(viz.controller, this.options, opt);
var v = $_.isString(vertex[0])? [vertex] : vertex;
switch(options.type) {
case 'nothing':
for(var i=0; i<v.length; i++) viz.graph.removeAdjacence(v[i][0], v[i][1]);
break;
case 'replot':
this.removeEdge(viz, v, { type: 'nothing' });
viz.refresh();
break;
case 'fade:seq': case 'fade':
var GPlot = GraphPlot, that = this;
//set alpha to 0 for nodes to remove.
for(var i=0; i<v.length; i++) {
var adjs = viz.graph.getAdjacence(v[i][0], v[i][1]);
if(adjs) {
adjs[0].endAlpha = 0;
adjs[1].endAlpha = 0;
}
}
GPlot.animate(viz, $_.merge(options, {
modes: ['fade:vertex'],
onComplete: function() {
that.removeEdge(viz, v, { type: 'nothing' });
viz.compute('endPos');
GPlot.animate(viz, $_.merge(options, {
modes: ['linear']
}));
}
}));
break;
case 'fade:con':
var GPlot = GraphPlot, that = this;
//set alpha to 0 for nodes to remove. Tag them for being ignored when computing positions.
for(var i=0; i<v.length; i++) {
var adjs = viz.graph.getAdjacence(v[i][0], v[i][1]);
if(adjs) {
adjs[0].endAlpha = 0;
adjs[0].ignore = true;
adjs[1].endAlpha = 0;
adjs[1].ignore = true;
}
}
viz.compute('endPos');
GPlot.animate(viz, $_.merge(options, {
modes: ['fade:vertex', 'linear'],
onComplete: function() {
that.removeEdge(viz, v, { type: 'nothing' });
}
}));
break;
case 'iter':
var that = this, GPlot = GraphPlot;
GPlot.sequence(viz, {
condition: function() { return v.length != 0; },
step: function() { that.removeEdge(viz, v.shift(), { type: 'nothing' }); GPlot.clearLabels(viz); },
onComplete: function() { options.onComplete(); },
duration: Math.ceil(options.duration / v.length)
});
break;
default: this.doError();
}
},
/*
Method: sum
Adds a new graph to the visualization. The json graph (or tree) must at least have a common node with the current graph plotted by the visualization. The resulting graph can be defined as follows: <http://mathworld.wolfram.com/GraphSum.html>
Parameters:
viz - The visualization object (an RGraph instance in this case).
json - A json tree <http://blog.thejit.org/2008/04/27/feeding-json-tree-structures-to-the-jit/>, a json graph <http://blog.thejit.org/2008/07/02/feeding-json-graph-structures-to-the-jit/> or an extended json graph <http://blog.thejit.org/2008/08/05/weighted-nodes-weighted-edges/>.
opt - Animation options. It's an object with two properties: _type_, which can be _nothing_, _replot_, _fade:seq_, or _fade:con_. The other property is the _duration_ in milliseconds.
*/
sum: function(viz, json, opt) {
var options = $_.merge(viz.controller, this.options, opt), root = viz.root;
viz.root = opt.id || viz.root;
switch(options.type) {
case 'nothing':
var graph = viz.construct(json), GUtil = GraphUtil;
GUtil.eachNode(graph, function(elem) {
GUtil.eachAdjacency(elem, function(adj) {
viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
});
});
break;
case 'replot':
this.sum(viz, json, { type: 'nothing' });
viz.refresh();
break;
case 'fade:seq': case 'fade': case 'fade:con':
var GUtil = GraphUtil, GPlot = GraphPlot, that = this, graph = viz.construct(json);
//set alpha to 0 for nodes to add.
var fadeEdges = this.preprocessSum(viz, graph);
var modes = !fadeEdges? ['fade:nodes'] : ['fade:nodes', 'fade:vertex'];
viz.compute('endPos');
if(options.type != 'fade:con') {
GPlot.animate(viz, $_.merge(options, {
modes: ['linear'],
onComplete: function() {
GPlot.animate(viz, $_.merge(options, {
modes: modes,
onComplete: function() {
options.onComplete();
}
}));
}
}));
} else {
GUtil.eachNode(viz.graph, function(elem) {
if(elem.id != root && elem.pos.equals(Polar.KER)) elem.pos = elem.startPos = elem.endPos;
});
GPlot.animate(viz, $_.merge(options, {
modes: ['linear'].concat(modes),
onComplete: function() {
options.onComplete();
}
}));
}
break;
default: this.doError();
}
},
/*
Method: morph
This method will _morph_ the current visualized graph into the new _json_ representation passed in the method. Can also perform multiple animations. The _json_ object must at least have the root node in common with the current visualized graph.
Parameters:
viz - The visualization object (an RGraph instance in this case).
json - A json tree <http://blog.thejit.org/2008/04/27/feeding-json-tree-structures-to-the-jit/>, a json graph <http://blog.thejit.org/2008/07/02/feeding-json-graph-structures-to-the-jit/> or an extended json graph <http://blog.thejit.org/2008/08/05/weighted-nodes-weighted-edges/>.
opt - Animation options. It's an object with two properties: _type_, which can be _nothing_, _replot_, or _fade_. The other property is the _duration_ in milliseconds.
*/
morph: function(viz, json, opt) {
var options = $_.merge(viz.controller, this.options, opt), root = viz.root;
viz.root = opt.id || viz.root;
switch(options.type) {
case 'nothing':
var graph = viz.construct(json), GUtil = GraphUtil;
GUtil.eachNode(graph, function(elem) {
GUtil.eachAdjacency(elem, function(adj) {
viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
});
});
GUtil.eachNode(viz.graph, function(elem) {
GUtil.eachAdjacency(elem, function(adj) {
if(!graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id)) {
viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
}
if(!viz.graph.hasNode(elem.id)) viz.graph.removeNode(elem.id);
});
});
break;
case 'replot':
this.morph(viz, json, { type: 'nothing' });
viz.refresh();
break;
case 'fade:seq': case 'fade': case 'fade:con':
var GUtil = GraphUtil, GPlot = GraphPlot, that = this, graph = viz.construct(json);
//preprocessing for adding nodes.
var fadeEdges = this.preprocessSum(viz, graph);
//preprocessing for nodes to delete.
GUtil.eachNode(viz.graph, function(elem) {
if(!graph.hasNode(elem.id)) {
elem.alpha = 1; elem.startAlpha = 1; elem.endAlpha = 0; elem.ignore = true;
}
});
GUtil.eachNode(viz.graph, function(elem) {
if(elem.ignore) return;
GUtil.eachAdjacency(elem, function(adj) {
if(adj.nodeFrom.ignore || adj.nodeTo.ignore) return;
var nodeFrom = graph.getNode(adj.nodeFrom.id);
var nodeTo = graph.getNode(adj.nodeTo.id);
if(!nodeFrom.adjacentTo(nodeTo)) {
var adjs = viz.graph.getAdjacence(nodeFrom.id, nodeTo.id);
fadeEdges = true;
adjs[0].alpha = 1; adjs[0].startAlpha = 1; adjs[0].endAlpha = 0; adjs[0].ignore = true;
adjs[1].alpha = 1; adjs[1].startAlpha = 1; adjs[1].endAlpha = 0; adjs[1].ignore = true;
}
});
});
var modes = !fadeEdges? ['fade:nodes'] : ['fade:nodes', 'fade:vertex'];
viz.compute('endPos');
GUtil.eachNode(viz.graph, function(elem) {
if(elem.id != root && elem.pos.equals(Polar.KER)) elem.pos = elem.startPos = elem.endPos;
});
GPlot.animate(viz, $_.merge(options, {
modes: ['polar'].concat(modes),
onComplete: function() {
GUtil.eachNode(viz.graph, function(elem) {
if(elem.ignore) viz.graph.removeNode(elem.id);
});
GUtil.eachNode(viz.graph, function(elem) {
GUtil.eachAdjacency(elem, function(adj) {
if(adj.ignore) viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
});
});
options.onComplete();
}
}));
break;
default: this.doError();
}
},
preprocessSum: function(viz, graph) {
var GUtil = GraphUtil;
GUtil.eachNode(graph, function(elem) {
if(!viz.graph.hasNode(elem.id)) {
viz.graph.addNode(elem);
var n = viz.graph.getNode(elem.id);
n.alpha = 0; n.startAlpha = 0; n.endAlpha = 1;
}
});
var fadeEdges = false;
GUtil.eachNode(graph, function(elem) {
GUtil.eachAdjacency(elem, function(adj) {
var nodeFrom = viz.graph.getNode(adj.nodeFrom.id);
var nodeTo = viz.graph.getNode(adj.nodeTo.id);
if(!nodeFrom.adjacentTo(nodeTo)) {
var adjs = viz.graph.addAdjacence(nodeFrom, nodeTo, adj.data);
if(nodeFrom.startAlpha == nodeFrom.endAlpha
&& nodeTo.startAlpha == nodeTo.endAlpha) {
fadeEdges = true;
adjs[0].alpha = 0; adjs[0].startAlpha = 0; adjs[0].endAlpha = 1;
adjs[1].alpha = 0; adjs[1].startAlpha = 0; adjs[1].endAlpha = 1;
}
}
});
});
return fadeEdges;
}
};
/*
Object: GraphPlot
An object that performs specific radial layouts for a generic graph structure.
*/
var GraphPlot = {
Interpolator: {
'polar': function(elem, delta) {
var from = elem.startPos;
var to = elem.endPos;
elem.pos = to.interpolate(from, delta);
},
'linear': function(elem, delta) {
var from = elem.startPos.toComplex();
var to = elem.endPos.toComplex();
elem.pos = ((to.$add(from.scale(-1))).$scale(delta).$add(from)).toPolar();
},
'fade:nodes': function(elem, delta) {
if(elem.endAlpha != elem.alpha) {
var from = elem.startAlpha;
var to = elem.endAlpha;
elem.alpha = from + (to - from) * delta;
}
},
'fade:vertex': function(elem, delta) {
var adjs = elem.adjacencies;
for(var id in adjs) this['fade:nodes'](adjs[id], delta);
}
},
//Property: labelsHidden
//A flag value indicating if node labels are being displayed or not.
labelsHidden: false,
//Property: labelContainer
//Label DOM element
labelContainer: false,
//Property: labels
//Label DOM elements hash.
labels: {},
/*
Method: getLabelContainer
Lazy fetcher for the label container.
*/
getLabelContainer: function() {
return this.labelContainer? this.labelContainer : this.labelContainer = document.getElementById(Config.labelContainer);
},
/*
Method: getLabel
Lazy fetcher for the label DOM element.
*/
getLabel: function(id) {
return (id in this.labels && this.labels[id] != null)? this.labels[id] : this.labels[id] = document.getElementById(id);
},
/*
Method: hideLabels
Hides all labels.
*/
hideLabels: function (hide) {
var container = this.getLabelContainer();
if(hide) container.style.display = 'none';
else container.style.display = '';
this.labelsHidden = hide;
},
/*
Method: clearLabels
Clears the label container.
*/
clearLabels: function(viz) {
for(var id in this.labels)
if(!viz.graph.hasNode(id)) {
this.disposeLabel(id);
delete this.labels[id];
}
},
/*
Method: disposeLabel
Removes a label.
*/
disposeLabel: function(id) {
var elem = this.getLabel(id);
if(elem && elem.parentNode) {
elem.parentNode.removeChild(elem);
}
},
/*
Method: animate
Animates the graph mantaining a radial layout.
*/
animate: function(viz, opt) {
var that = this, GUtil = GraphUtil, Anim = Animation, duration = opt.duration || Anim.duration, fps = opt.fps || Anim.fps;
//Should be changed eventually, when Animation becomes a class.
var prevDuration = Anim.duration, prevFps = Anim.fps;
Anim.duration = duration;
Anim.fps = fps;
if(opt.hideLabels) this.hideLabels(true);
var animationController = {
compute: function(delta) {
GUtil.eachNode(viz.graph, function(node) {
for(var i=0; i<opt.modes.length; i++) {
that.Interpolator[opt.modes[i]](node, delta);
}
});
that.plot(viz, opt);
},
complete: function() {
GUtil.eachNode(viz.graph, function(node) {
node.startPos = node.pos;
node.startAlpha = node.alpha;
});
if(opt.hideLabels) that.hideLabels(false);
that.plot(viz, opt);
Anim.duration = prevDuration;
Anim.fps = prevFps;
opt.onComplete();
opt.onAfterCompute();
}
};
Anim.controller = animationController;
Anim.start();
},
/*
Method: sequence
Iteratively performs an action while refreshing the state of the visualization.
*/
sequence: function(viz, options) {
options = $_.merge({
condition: function() { return false; },
step: $_.fn(),
onComplete: $_.fn(),
duration: 200
}, options);
var interval = setInterval(function() {
if(options.condition()) {
options.step();
} else {
clearInterval(interval);
options.onComplete();
}
viz.refresh();
}, options.duration);
},
/*
Method: plot
Plots a Graph.
*/
plot: function(viz, opt) {
var aGraph = viz.graph, canvas = viz.canvas, id = viz.root;
var that = this, ctx = canvas.getContext(), GUtil = GraphUtil;
canvas.clear();
if(Config.drawConcentricCircles) canvas.drawConcentricCircles(Config.drawConcentricCircles);
var T = !!aGraph.getNode(id).visited;
GUtil.eachNode(aGraph, function(node) {
GUtil.eachAdjacency(node, function(adj) {
if(!!adj.nodeTo.visited === T) {
opt.onBeforePlotLine(adj);
ctx.save();
ctx.globalAlpha = Math.min(Math.min(node.alpha, adj.nodeTo.alpha), adj.alpha);
that.plotLine(adj, canvas);
ctx.restore();
opt.onAfterPlotLine(adj);
}
});
ctx.save();
ctx.globalAlpha = node.alpha;
that.plotNode(node, canvas);
if(!that.labelsHidden && ctx.globalAlpha >= .95) that.plotLabel(canvas, node, opt);
else if(!that.labelsHidden && ctx.globalAlpha < .95) that.hideLabel(node);
ctx.restore();
node.visited = !T;
});
},
/*
Method: plotNode
Plots a graph node.
*/
plotNode: function(node, canvas) {
var pos = node.pos.toComplex();
canvas.path('fill', function(context) {
context.arc(pos.x, pos.y, node._radius, 0, Math.PI*2, true);
});
},
/*
Method: plotLine
Plots a line connecting _node_ and _child_ nodes.
*/
plotLine: function(adj, canvas) {
var node = adj.nodeFrom, child = adj.nodeTo;
var pos = node.pos.toComplex();
var posChild = child.pos.toComplex();
canvas.path('stroke', function(context) {
context.moveTo(pos.x, pos.y);
context.lineTo(posChild.x, posChild.y);
});
},
/*
Method: hideLabel
Hides a label having _node.id_ as id.
*/
hideLabel: function(node) {
var n; if(n = document.getElementById(node.id)) n.style.display = "none";
},
/*
Method: plotLabel
Plots a label for a given node.
*/
plotLabel: function(canvas, node, controller) {
var size = node._radius, id = node.id, tag = this.getLabel(id);
if(!tag && !(tag = document.getElementById(id))) {
tag = document.createElement('div');
var container = this.getLabelContainer();
container.appendChild(tag);
tag.id = id;
tag.className = 'node';
tag.style.position = 'absolute';
controller.onCreateLabel(tag, node);
}
var pos = node.pos.toComplex();
var radius= canvas.getSize();
var cpos = canvas.getPosition();
var labelPos= {
x: Math.round(pos.x + cpos.x + radius.x/2 - size /2),
y: Math.round(pos.y + cpos.y + radius.y/2 - size /2)
};
tag.style.width = size + 'px';
tag.style.height = size + 'px';
tag.style.left = labelPos.x + 'px';
tag.style.top = labelPos.y + 'px';
tag.style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none';
controller.onPlaceLabel(tag, node);
},
/*
Method: fitsInCanvas
Returns _true_ or _false_ if the label for the node is contained on the canvas dom element or not.
*/
fitsInCanvas: function(pos, canvas) {
var size = canvas.getSize();
if(pos.x >= size.x + canvas.position.x || pos.x < canvas.position.x
|| pos.y >= size.y + canvas.position.y || pos.y < canvas.position.y) return false;
return true;
}
};
/*
Class: RGraph
An animated Graph with radial layout.
Go to <http://blog.thejit.org> to know what kind of JSON structure feeds this object.
Go to <http://blog.thejit.org/?p=8> to know what kind of controller this class accepts.
Refer to the <Config> object to know what properties can be modified in order to customize this object.
The simplest way to create and layout a RGraph is:
(start code)
var canvas= new Canvas('infovis', '#ccddee', '#772277');
var rgraph= new RGraph(canvas, controller);
rgraph.loadTreeFromJSON(json);
rgraph.compute();
rgraph.plot();
(end code)
A user should only interact with the Canvas, RGraph and Config objects/classes.
By implementing RGraph controllers you can also customize the RGraph behavior.
*/
/*
Constructor: RGraph
Creates a new RGraph instance.
Parameters:
canvas - A <Canvas> instance.
controller - _optional_ a RGraph controller <http://blog.thejit.org/?p=8>
*/
var RGraph = function(canvas, controller) {
var innerController = {
onBeforeCompute: $_.fn(),
onAfterCompute: $_.fn(),
onCreateLabel: $_.fn(),
onPlaceLabel: $_.fn(),
onCreateElement: $_.fn(),
onComplete: $_.fn(),
onBeforePlotLine: $_.fn(),
onAfterPlotLine: $_.fn(),
request: false
};
this.controller = $_.merge(innerController, controller);
this.graph = new Graph();
this.json = null;
this.canvas = canvas;
this.root = null;
this.busy = false;
Animation.duration = Config.animationTime;
Animation.fps = Config.fps;
};
RGraph.prototype = {
construct: function(json) {
var isGraph = $_.isArray(json);
var ans = new Graph();
if(!isGraph)
//make tree
(function (ans, json) {
ans.addNode(json);
for(var i=0, ch = json.children; i<ch.length; i++) {
ans.addAdjacence(json, ch[i]);
arguments.callee(ans, ch[i]);
}
})(ans, json);
else
//make graph
(function (ans, json) {
var getNode = function(id) {
for(var w=0; w<json.length; w++) if(json[w].id == id) return json[w];
};
for(var i=0; i<json.length; i++) {
ans.addNode(json[i]);
for(var j=0, adj = json[i].adjacencies; j<adj.length; j++) {
var node = adj[j], data;
if(typeof adj[j] != 'string') {
data = node.data;
node = node.nodeTo;
}
ans.addAdjacence(json[i], getNode(node), data);
}
}
})(ans, json);
return ans;
},
/*
Method: loadTree
Loads a Graph from a json tree object <http://blog.thejit.org>
*/
loadTree: function(json) {
this.graph = this.construct(json);
},
/*
Method: loadGraph
Loads a Graph from a json graph object <http://blog.thejit.org>
*/
loadGraph: function(json) {
this.graph = this.construct(json);
},
/*
Method: refresh
Computes positions and then plots.
*/
refresh: function() {
this.compute();
this.plot();
},
/*
Method: flagRoot
Flags a node specified by _id_ as root.
*/
flagRoot: function(id) {
this.unflagRoot();
this.graph.nodes[id]._root = true;
},
/*
Method: unflagRoot
Unflags all nodes.
*/
unflagRoot: function() {
GraphUtil.eachNode(this.graph, function(elem) {elem._root = false;});
},
/*
Method: getRoot
Returns the node flagged as root.
*/
getRoot: function() {
var root = false;
GraphUtil.eachNode(this.graph, function(elem){ if(elem._root) root = elem; });
return root;
},
/*
Method: loadTreeFromJSON
Loads a RGraph from a _json_ object <http://blog.thejit.org>
*/
loadTreeFromJSON: function(json) {
this.json = json;
this.loadTree(json);
this.root = json.id;
},
/*
Method: loadGraphFromJSON
Loads a RGraph from a _json_ object <http://blog.thejit.org>
*/
loadGraphFromJSON: function(json, i) {
this.json = json;
this.loadGraph(json);
this.root = json[i? i : 0].id;
},
/*
Method: plot
Plots the RGraph
*/
plot: function() {
GraphPlot.plot(this, this.controller);
},
/*
Method: compute
Computes the graph nodes positions and stores this positions on _property_.
*/
compute: function(property) {
var prop = property || ['pos', 'startPos', 'endPos'];
var node = this.graph.getNode(this.root);
node._depth = 0;
this.flagRoot(this.root);
GraphUtil.computeLevels(this.graph, this.root, "ignore");
this.computeAngularWidths();
this.computePositions(prop);
},
/*
Method: computePositions
Performs the main algorithm for computing node positions.
*/
computePositions: function(property) {
var propArray = (typeof property == 'array' || typeof property == 'object')? property : [property];
var aGraph = this.graph;
var GUtil = GraphUtil;
var root = this.graph.getNode(this.root);
for(var i=0; i<propArray.length; i++)
root[propArray[i]] = new Polar(0, 0);
root.angleSpan = {
begin: 0,
end: 2 * Math.PI
};
root._rel = 1;
GUtil.eachBFS(this.graph, this.root, function (elem) {
var angleSpan = elem.angleSpan.end - elem.angleSpan.begin;
var rho = (elem._depth + 1) * Config.levelDistance;
var angleInit = elem.angleSpan.begin;
var totalAngularWidths = (function (element){
var total = 0;
GUtil.eachSubnode(aGraph, element, function(sib) {
total += sib._treeAngularWidth;
}, "ignore");
return total;
})(elem);
GUtil.eachSubnode(aGraph, elem, function(child) {
if(!child._flag) {
child._rel = child._treeAngularWidth / totalAngularWidths;
var angleProportion = child._rel * angleSpan;
var theta = angleInit + angleProportion / 2;
for(var i=0; i<propArray.length; i++)
child[propArray[i]] = new Polar(theta, rho);
child.angleSpan = {
begin: angleInit,
end: angleInit + angleProportion
};
angleInit += angleProportion;
}
}, "ignore");
}, "ignore");
},
/*
Method: setAngularWidthForNodes
Sets nodes angular widths.
*/
setAngularWidthForNodes: function() {
var rVal = Config.nodeRangeValues, rDiam = Config.nodeRangeDiameters, nr = Config.nodeRadius, allow = Config.allowVariableNodeDiameters;
var diam = function(value) { return (((rDiam.max - rDiam.min)/(rVal.max - rVal.min)) * (value - rVal.min) + rDiam.min) };
GraphUtil.eachBFS(this.graph, this.root, function(elem, i) {
var dataValue = (allow && elem.data && elem.data.length > 0)? elem.data[0].value : nr;
var diamValue = diam(dataValue);
var rho = Config.levelDistance * i;
elem._angularWidth = diamValue / rho;
elem._radius = allow? diamValue / 2 : nr;
}, "ignore");
},
/*
Method: setSubtreesAngularWidths
Sets subtrees angular widths.
*/
setSubtreesAngularWidth: function() {
var that = this;
GraphUtil.eachNode(this.graph, function(elem) {
that.setSubtreeAngularWidth(elem);
}, "ignore");
},
/*
Method: setSubtreeAngularWidth
Sets the angular width for a subtree.
*/
setSubtreeAngularWidth: function(elem) {
var that = this, nodeAW = elem._angularWidth, sumAW = 0;
GraphUtil.eachSubnode(this.graph, elem, function(child) {
that.setSubtreeAngularWidth(child);
sumAW += child._treeAngularWidth;
}, "ignore");
elem._treeAngularWidth = Math.max(nodeAW, sumAW);
},
/*
Method: computeAngularWidths
Computes nodes and subtrees angular widths.
*/
computeAngularWidths: function () {
this.setAngularWidthForNodes();
this.setSubtreesAngularWidth();
},
/*
Method: getNodeAndParentAngle
Returns the _parent_ of the given node, also calculating its angle span.
*/
getNodeAndParentAngle: function(id) {
var theta = false;
var n = this.graph.getNode(id);
var ps = GraphUtil.getParents(this.graph, n);
var p = (ps.length > 0)? ps[0] : false;
if(p) {
var posParent = p.pos.toComplex(), posChild = n.pos.toComplex();
var newPos = posParent.add(posChild.scale(-1));
theta = (function(pos) {
var t = Math.atan2(pos.y, pos.x);
if(t < 0) t = 2 * Math.PI + t;
return t;
})(newPos);
}
return {_parent: p, theta: theta};
},
/*
Method: onClick
Performs all calculations and animation when clicking on a label specified by _id_. The label id is the same id as its homologue node.
*/
onClick: function(id) {
if(this.root != id && !this.busy) {
this.busy = true;
//we apply first constraint to the algorithm
var obj = this.getNodeAndParentAngle(id);
this.root = id, that = this;
this.controller.onBeforeCompute(this.graph.getNode(id));
var thetaDiff = obj.theta - obj._parent.endPos.theta;
GraphUtil.eachNode(this.graph, function(elem) {
elem.endPos = elem.endPos.add(new Polar(thetaDiff, 0));
});
var mode = (Config.interpolation == 'linear')? 'linear' : 'polar';
GraphPlot.animate(this, $_.merge(this.controller, {
hideLabels:true,
modes: [mode],
onComplete: function() {
that.busy = false;
}
}));
}
}
};
/*
Class: Graph
A generic Graph class.
*/
/*
Constructor: Graph
Creates a new Graph instance.
*/
var Graph= function() {
//Property: nodes
//graph nodes
this.nodes= {};
};
Graph.prototype= {
/*
Method: getNode
Returns a <Graph.Node> from a specified _id_.
*/
getNode: function(id) {
if(this.hasNode(id)) return this.nodes[id];
return false;
},
/*
Method: getAdjacence
Returns an array of <Graph.Adjacence> that connects nodes with id _id_ and _id2_.
*/
getAdjacence: function (id, id2) {
var adjs = [];
if(this.hasNode(id) && this.hasNode(id2)
&& this.nodes[id].adjacentTo({ 'id':id2 }) && this.nodes[id2].adjacentTo({ 'id':id })) {
adjs.push(this.nodes[id].getAdjacency(id2));
adjs.push(this.nodes[id2].getAdjacency(id));
return adjs;
}
return false;
},
/*
Method: addNode
Adds a node.
Parameters:
obj - A <Graph.Node> object.
*/
addNode: function(obj) {
if(!this.nodes[obj.id]) {
this.nodes[obj.id] = new Graph.Node(obj.id, obj.name, obj.data);
}
return this.nodes[obj.id];
},
/*
Method: addAdjacence
Connects nodes specified by *obj* and *obj2*. If not found, nodes are created.
Parameters:
obj - a <Graph.Node> object.
obj2 - Another <Graph.Node> object.
data - A DataSet object.
*/
addAdjacence: function (obj, obj2, weight) {
var adjs = []
if(!this.hasNode(obj.id)) this.addNode(obj);
if(!this.hasNode(obj2.id)) this.addNode(obj2);
obj = this.nodes[obj.id]; obj2 = this.nodes[obj2.id];
for(var i in this.nodes) {
if(this.nodes[i].id == obj.id) {
if(!this.nodes[i].adjacentTo(obj2)) {
adjs.push(this.nodes[i].addAdjacency(obj2, weight));
}
}
if(this.nodes[i].id == obj2.id) {
if(!this.nodes[i].adjacentTo(obj)) {
adjs.push(this.nodes[i].addAdjacency(obj, weight));
}
}
}
return adjs;
},
/*
Method: removeNode
Removes a <Graph.Node> from <Graph> that matches the specified _id_.
*/
removeNode: function(id) {
if(this.hasNode(id)) {
var node = this.nodes[id];
for(var i=0 in node.adjacencies) {
var adj = node.adjacencies[i];
this.removeAdjacence(id, adj.nodeTo.id);
}
delete this.nodes[id];
}
},
/*
Method: removeAdjacence
Removes a <Graph.Adjacence> from <Graph> that matches the specified _id1_ and _id2_.
*/
removeAdjacence: function(id1, id2) {
if(this.hasNode(id1)) this.nodes[id1].removeAdjacency(id2);
if(this.hasNode(id2)) this.nodes[id2].removeAdjacency(id1);
},
/*
Method: hasNode
Returns a Boolean instance indicating if node belongs to graph or not.
Parameters:
id - Node id.
Returns:
A Boolean instance indicating if node belongs to graph or not.
*/
hasNode: function(id) {
return id in this.nodes;
}
};
/*
Class: Graph.Node
Behaviour of the <Graph> node.
*/
/*
Constructor: Graph.Node
Node constructor.
Parameters:
id - The node *unique identifier* id.
name - A node's name.
data - Place to store some extra information (can be left to null).
Returns:
A new <Graph.Node> instance.
*/
Graph.Node = function(id, name, data) {
//Property: id
//A node's id
this.id= id;
//Property: name
//A node's name
this.name = name;
//Property: data
//The dataSet object <http://blog.thejit.org/?p=7>
this.data = data;
//Property: drawn
//Node flag
this.drawn= false;
//Property: angle span
//allowed angle span for adjacencies placement
this.angleSpan= {
begin:0,
end:0
};
//Property: pos
//node position
this.pos= new Polar(0, 0);
//Property: startPos
//node from position
this.startPos= new Polar(0, 0);
//Property: endPos
//node to position
this.endPos= new Polar(0, 0);
//Property: alpha
//node alpha
this.alpha = 1;
//Property: startAlpha
//node start alpha
this.startAlpha = 1;
//Property: endAlpha
//node end alpha
this.endAlpha = 1;
//Property: adjacencies
//node adjacencies
this.adjacencies= {};
};
Graph.Node.prototype= {
/*
Method: adjacentTo
Indicates if the node is adjacent to the node indicated by the specified id
Parameters:
id - A node id.
Returns:
A Boolean instance indicating whether this node is adjacent to the specified by id or not.
*/
adjacentTo: function(node) {
return node.id in this.adjacencies;
},
/*
Method: getAdjacency
Returns a <Graph.Adjacence> that connects the current <Graph.Node> with the node having _id_ as id.
Parameters:
id - A node id.
*/
getAdjacency: function(id) {
return this.adjacencies[id];
},
/*
Method: addAdjacency
Connects the node to the specified by id.
Parameters:
id - A node id.
*/
addAdjacency: function(node, data) {
var adj = new Graph.Adjacence(this, node, data);
return this.adjacencies[node.id] = adj;
},
/*
Method: removeAdjacency
Deletes the <Graph.Adjacence> by _id_.
Parameters:
id - A node id.
*/
removeAdjacency: function(id) {
delete this.adjacencies[id];
}
};
/*
Class: Graph.Adjacence
Creates a new <Graph> adjacence.
*/
Graph.Adjacence = function(nodeFrom, nodeTo, data) {
//Property: nodeFrom
//One of the two <Graph.Node>s connected by this edge.
this.nodeFrom = nodeFrom;
//Property: nodeTo
//One of the two <Graph.Node>s connected by this edge.
this.nodeTo = nodeTo;
//Property: data
//A dataset object
this.data = data;
//Property: alpha
//node alpha
this.alpha = 1;
//Property: startAlpha
//node start alpha
this.startAlpha = 1;
//Property: endAlpha
//node end alpha
this.endAlpha = 1;
};
/*
Object: Trans
An object containing multiple type of transformations. Based on the mootools library <http://mootools.net>.
*/
var Trans = {
linear: function(p) { return p; },
Quart: function(p) {
return Math.pow(p, 4);
},
easeIn: function(transition, pos){
return transition(pos);
},
easeOut: function(transition, pos){
return 1 - transition(1 - pos);
},
easeInOut: function(transition, pos){
return (pos <= 0.5) ? transition(2 * pos) / 2 : (2 - transition(2 * (1 - pos))) / 2;
}
};
/*
Object: Animation
An object that performs animations. Based on Fx.Base from Mootools.
*/
var Animation = {
duration: Config.animationTime,
fps: Config.fps,
transition: function(p) {return Trans.easeInOut(Trans.Quart, p);},
//transition: Trans.linear,
controller: false,
getTime: function() {
var ans = (Date.now)? Date.now() : new Date().getTime();
return ans;
},
step: function(){
var time = this.getTime();
if (time < this.time + this.duration){
var delta = this.transition((time - this.time) / this.duration);
this.controller.compute(delta);
} else {
this.timer = clearInterval(this.timer);
this.controller.compute(1);
this.controller.complete();
}
},
start: function(){
this.time = 0;
this.startTimer();
return this;
},
startTimer: function(){
if (this.timer) return false;
this.time = this.getTime() - this.time;
this.timer = setInterval((function () { Animation.step(); }), Math.round(1000 / this.fps));
return true;
}
};
/*Jon's JIT Hacks */
Config.animationTime = 1000;
/*RGRAPH*/
RGraph.prototype.offsetCenter= function(x,y){
var d =this.controller.getOffset();
d.x = x;
d.y = y;
this.controller.setOffset(d);
};
RGraph.prototype.setAngularWidthForNodes= function() {
var rVal = Config.nodeRangeValues, rDiam = Config.nodeRangeDiameters, nr = Config.nodeRadius, allow = Config.allowVariableNodeDiameters;
var zoom = this.controller.getZoomLevel();
var diam = function(value) { return (((rDiam.max - rDiam.min)/(rVal.max - rVal.min)) * (value - rVal.min) + rDiam.min) };
GraphUtil.eachBFS(this.graph, this.root, function(elem, i) {
var dataValue = (allow && elem.data && elem.data.length > 0)? elem.data[0].value : nr;
var diamValue = diam(dataValue);
var rho = zoom * i;//jon
elem._angularWidth = diamValue / rho;
elem._radius = allow? diamValue / 2 : nr;
}, "ignore");
};
RGraph.prototype.computePositions= function(property) {
var propArray = (typeof property == 'array' || typeof property == 'object')? property : [property];
var aGraph = this.graph;
var GUtil = GraphUtil;
var root = this.graph.getNode(this.root);
for(var i=0; i<propArray.length; i++)
root[propArray[i]] = new Polar(0, 0);
root.angleSpan = {
begin: 0,
end: 2 * Math.PI
};
root._rel = 1;
var zoom =this.controller.getZoomLevel();
GUtil.eachBFS(this.graph, this.root, function (elem) {
var angleSpan = elem.angleSpan.end - elem.angleSpan.begin;
var rho = (elem._depth + 1) * zoom;//jon
var angleInit = elem.angleSpan.begin;
var totalAngularWidths = (function (element){
var total = 0;
GUtil.eachSubnode(aGraph, element, function(sib) {
total += sib._treeAngularWidth;
}, "ignore");
return total;
})(elem);
GUtil.eachSubnode(aGraph, elem, function(child) {
if(!child._flag) {
child._rel = child._treeAngularWidth / totalAngularWidths;
var angleProportion = child._rel * angleSpan;
var theta = angleInit + angleProportion / 2;
for(var i=0; i<propArray.length; i++)
child[propArray[i]] = new Polar(theta, rho);
child.angleSpan = {
begin: angleInit,
end: angleInit + angleProportion
};
angleInit += angleProportion;
}
}, "ignore");
}, "ignore");
};
RGraph.prototype.onClick= function(id) { //weird bug in here
if(this.root != id) {//jon
this.busy = true;
//we apply first constraint to the algorithm
var obj = this.getNodeAndParentAngle(id);
this.root = id, that = this;
this.controller.onBeforeCompute(this.graph.getNode(id));
this.compute('endPos');
var thetaDiff = obj.theta - obj._parent.endPos.theta;
GraphUtil.eachNode(this.graph, function(elem) {
elem.endPos = elem.endPos.add(new Polar(thetaDiff, 0));
});
var mode = (Config.interpolation == 'linear')? 'linear' : 'polar';
this.controller.modes = [mode];//jon
GraphPlot.animate(this, this.controller);//jon
}
};
/*GRAPH PLOT */
GraphPlot.plotLine = function(adj, canvas,controller) {//jon
var d = controller.getOffset();//jon
var node = adj.nodeFrom, child = adj.nodeTo;
var pos = node.pos.toComplex();
var posChild = child.pos.toComplex();
canvas.path('stroke', function(context) {
pos.x += d.x;//jon..
pos.y += d.y;
posChild.x += d.x;
posChild.y += d.y;//..jon
context.moveTo(pos.x, pos.y);
context.lineTo(posChild.x, posChild.y);
});
};
GraphPlot.getLabelContainer = function(controller){
return document.getElementById(controller.getNodeLabelContainer());
};
GraphPlot.fitsInCanvas= function(pos, canvas) {
//canvas.setPosition();
var size = canvas.getSize();
var offset1 = parseInt(size.x);
var offset2 = parseInt(size.y);
if(pos.x < 0 || pos.x > offset1 || pos.y < 0 || pos.y > offset2) return false;
else
return true;
};
GraphPlot.plotLabel= function(canvas, node, controller) {
var size = node._radius;
var id = controller.getNodeLabelPrefix() + node.id;//jon change
var d = controller.getOffset(); //jon
var pos = node.pos.toComplex();
var radius= canvas.getSize();
canvas.setPosition(); //jon
var cpos = canvas.getPosition();
var labelPos= {
x: Math.round((pos.x + radius.x/2 - size /2) +d.x),//jon
y: Math.round((pos.y + radius.y/2 - size /2) +d.y)//jon
};
var tag = this.getLabel(id);
if(!this.fitsInCanvas(labelPos,canvas)) {
//if(tag && tag.parentNode)tag.parentNode.removeChild(tag);
return;
}
if(!tag && !(tag = document.getElementById(id))) {
tag = document.createElement('div');
var container = this.getLabelContainer(controller); //jon change
container.style.position= 'relative';//jon change
container.appendChild(tag);
tag.id = id;
tag.className = 'node';
tag.style.position = 'absolute';
controller.onCreateLabel(tag, node);
}
tag.style.width = size + 'px';
tag.style.height = size + 'px';
tag.style.left = labelPos.x + 'px';
tag.style.top = labelPos.y + 'px';
tag.style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none';
controller.onPlaceLabel(tag, node);
};
/*overriding of several functions */
GraphPlot.plotNode = function(node, canvas,controller) {
var pos = node.pos.toComplex();
var d = controller.getOffset();
if(node.data.nodraw == undefined) //jon
canvas.path('fill', function(context) {
context.arc(pos.x +d.x, pos.y +d.y, node._radius, 0, Math.PI*2, true); //jon
});
};
GraphPlot.plot= function(viz, opt) {
var aGraph = viz.graph, canvas = viz.canvas, id = viz.root;
var controller = viz.controller;//jon
var container = this.getLabelContainer(controller); //jon change
container.innerHTML = "";
var that = this, ctx = canvas.getContext(), GUtil = GraphUtil;
canvas.clear();
if(Config.drawConcentricCircles) canvas.drawConcentricCircles(Config.drawConcentricCircles);
var T = !!aGraph.getNode(id).visited;
GUtil.eachNode(aGraph, function(node) {
GUtil.eachAdjacency(node, function(adj) {
if(!!adj.nodeTo.visited === T) {
opt.onBeforePlotLine(adj);
ctx.save();
ctx.globalAlpha = Math.min(Math.min(node.alpha, adj.nodeTo.alpha), adj.alpha);
that.plotLine(adj, canvas,controller);//jon
ctx.restore();
opt.onAfterPlotLine(adj);
}
});
ctx.save();
ctx.globalAlpha = node.alpha;
that.plotNode(node, canvas,controller); //jon
if(!that.labelsHidden && ctx.globalAlpha >= .95) that.plotLabel(canvas, node, opt);
else if(!that.labelsHidden && ctx.globalAlpha < .95) that.hideLabel(node);
ctx.restore();
node.visited = !T;
});
};
/***
!Layer 4: Support Internet Explorer (Safely remove if not required)
***/
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Known Issues:
//
// * Patterns are not implemented.
// * Radial gradient are not implemented. The VML version of these look very
// different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
// width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
// Quirks mode will draw the canvas using border-box. Either change your
// doctype to HTML5
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
// or use Box Sizing Behavior from WebFX
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Non uniform scaling does not correctly scale strokes.
// * Optimize. There is always room for speed improvements.
// Only add this code if we do not already have a canvas implementation
if (!document.createElement('canvas').getContext) {
(function() {
// alias some functions to make (compiled) code shorter
var m = Math;
var mr = m.round;
var ms = m.sin;
var mc = m.cos;
var max = m.max;
var abs = m.abs;
var sqrt = m.sqrt;
// this is used for sub pixel precision
var Z = 10;
var Z2 = Z / 2;
/**
* This funtion is assigned to the <canvas> elements as element.getContext().
* @this {HTMLElement}
* @return {CanvasRenderingContext2D_}
*/
function getContext() {
return this.context_ ||
(this.context_ = new CanvasRenderingContext2D_(this));
}
var slice = Array.prototype.slice;
/**
* Binds a function to an object. The returned function will always use the
* passed in {@code obj} as {@code this}.
*
* Example:
*
* g = bind(f, obj, a, b)
* g(c, d) // will do f.call(obj, a, b, c, d)
*
* @param {Function} f The function to bind the object to
* @param {Object} obj The object that should act as this when the function
* is called
* @param {*} var_args Rest arguments that will be used as the initial
* arguments when the function is called
* @return {Function} A new function that has bound this
*/
function bind(f, obj, var_args) {
var a = slice.call(arguments, 2);
return function() {
return f.apply(obj, a.concat(slice.call(arguments)));
};
}
var G_vmlCanvasManager_ = {
init: function(opt_doc) {
if (/MSIE/.test(navigator.userAgent) && !window.opera) {
var doc = opt_doc || document;
// Create a dummy element so that IE will allow canvas elements to be
// recognized.
doc.createElement('canvas');
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
}
},
init_: function(doc) {
// create xmlns
if (!doc.namespaces['g_vml_']) {
doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml');
}
// Setup default CSS. Only add one style sheet per document
if (!doc.styleSheets['ex_canvas_']) {
var ss = doc.createStyleSheet();
ss.owningElement.id = 'ex_canvas_';
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
// default size is 300x150 in Gecko and Opera
'text-align:left;width:300px;height:150px}' +
'g_vml_\\:*{behavior:url(#default#VML)}';
}
// find all canvas elements
var els = doc.getElementsByTagName('canvas');
for (var i = 0; i < els.length; i++) {
this.initElement(els[i]);
}
},
/**
* Public initializes a canvas element so that it can be used as canvas
* element from now on. This is called automatically before the page is
* loaded but if you are creating elements using createElement you need to
* make sure this is called on the element.
* @param {HTMLElement} el The canvas element to initialize.
* @return {HTMLElement} the element that was created.
*/
initElement: function(el) {
if (!el.getContext) {
el.getContext = getContext;
// do not use inline function because that will leak memory
el.attachEvent('onpropertychange', onPropertyChange);
el.attachEvent('onresize', onResize);
var attrs = el.attributes;
if (attrs.width && attrs.width.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setWidth_(attrs.width.nodeValue);
el.style.width = attrs.width.nodeValue + 'px';
} else {
el.width = el.clientWidth;
}
if (attrs.height && attrs.height.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setHeight_(attrs.height.nodeValue);
el.style.height = attrs.height.nodeValue + 'px';
} else {
el.height = el.clientHeight;
}
//el.getContext().setCoordsize_()
}
return el;
}
};
function onPropertyChange(e) {
var el = e.srcElement;
switch (e.propertyName) {
case 'width':
el.style.width = el.attributes.width.nodeValue + 'px';
el.getContext().clearRect();
break;
case 'height':
el.style.height = el.attributes.height.nodeValue + 'px';
el.getContext().clearRect();
break;
}
}
function onResize(e) {
var el = e.srcElement;
if (el.firstChild) {
el.firstChild.style.width = el.clientWidth + 'px';
el.firstChild.style.height = el.clientHeight + 'px';
}
}
G_vmlCanvasManager_.init();
// precompute "00" to "FF"
var dec2hex = [];
for (var i = 0; i < 16; i++) {
for (var j = 0; j < 16; j++) {
dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
}
}
function createMatrixIdentity() {
return [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
];
}
function matrixMultiply(m1, m2) {
var result = createMatrixIdentity();
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
var sum = 0;
for (var z = 0; z < 3; z++) {
sum += m1[x][z] * m2[z][y];
}
result[x][y] = sum;
}
}
return result;
}
function copyState(o1, o2) {
o2.fillStyle = o1.fillStyle;
o2.lineCap = o1.lineCap;
o2.lineJoin = o1.lineJoin;
o2.lineWidth = o1.lineWidth;
o2.miterLimit = o1.miterLimit;
o2.shadowBlur = o1.shadowBlur;
o2.shadowColor = o1.shadowColor;
o2.shadowOffsetX = o1.shadowOffsetX;
o2.shadowOffsetY = o1.shadowOffsetY;
o2.strokeStyle = o1.strokeStyle;
o2.globalAlpha = o1.globalAlpha;
o2.arcScaleX_ = o1.arcScaleX_;
o2.arcScaleY_ = o1.arcScaleY_;
o2.lineScale_ = o1.lineScale_;
}
function processStyle(styleString) {
var str, alpha = 1;
styleString = String(styleString);
if (styleString.substring(0, 3) == 'rgb') {
var start = styleString.indexOf('(', 3);
var end = styleString.indexOf(')', start + 1);
var guts = styleString.substring(start + 1, end).split(',');
str = '#';
for (var i = 0; i < 3; i++) {
str += dec2hex[Number(guts[i])];
}
if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
alpha = guts[3];
}
} else {
str = styleString;
}
return [str, alpha];
}
function processLineCap(lineCap) {
switch (lineCap) {
case 'butt':
return 'flat';
case 'round':
return 'round';
case 'square':
default:
return 'square';
}
}
/**
* This class implements CanvasRenderingContext2D interface as described by
* the WHATWG.
* @param {HTMLElement} surfaceElement The element that the 2D context should
* be associated with
*/
function CanvasRenderingContext2D_(surfaceElement) {
this.m_ = createMatrixIdentity();
this.mStack_ = [];
this.aStack_ = [];
this.currentPath_ = [];
// Canvas context properties
this.strokeStyle = '#000';
this.fillStyle = '#000';
this.lineWidth = 1;
this.lineJoin = 'miter';
this.lineCap = 'butt';
this.miterLimit = Z * 1;
this.globalAlpha = 1;
this.canvas = surfaceElement;
var el = surfaceElement.ownerDocument.createElement('div');
el.style.width = surfaceElement.clientWidth + 'px';
el.style.height = surfaceElement.clientHeight + 'px';
el.style.overflow = 'hidden';
el.style.position = 'absolute';
surfaceElement.appendChild(el);
this.element_ = el;
this.arcScaleX_ = 1;
this.arcScaleY_ = 1;
this.lineScale_ = 1;
}
var contextPrototype = CanvasRenderingContext2D_.prototype;
contextPrototype.clearRect = function() {
this.element_.innerHTML = '';
this.currentPath_ = [];
};
contextPrototype.beginPath = function() {
// TODO: Branch current matrix so that save/restore has no effect
// as per safari docs.
this.currentPath_ = [];
};
contextPrototype.moveTo = function(aX, aY) {
var p = this.getCoords_(aX, aY);
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
this.currentX_ = p.x;
this.currentY_ = p.y;
};
contextPrototype.lineTo = function(aX, aY) {
var p = this.getCoords_(aX, aY);
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
this.currentX_ = p.x;
this.currentY_ = p.y;
};
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
aCP2x, aCP2y,
aX, aY) {
var p = this.getCoords_(aX, aY);
var cp1 = this.getCoords_(aCP1x, aCP1y);
var cp2 = this.getCoords_(aCP2x, aCP2y);
bezierCurveTo(this, cp1, cp2, p);
};
// Helper function that takes the already fixed cordinates.
function bezierCurveTo(self, cp1, cp2, p) {
self.currentPath_.push({
type: 'bezierCurveTo',
cp1x: cp1.x,
cp1y: cp1.y,
cp2x: cp2.x,
cp2y: cp2.y,
x: p.x,
y: p.y
});
self.currentX_ = p.x;
self.currentY_ = p.y;
}
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
// the following is lifted almost directly from
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
var cp = this.getCoords_(aCPx, aCPy);
var p = this.getCoords_(aX, aY);
var cp1 = {
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
};
var cp2 = {
x: cp1.x + (p.x - this.currentX_) / 3.0,
y: cp1.y + (p.y - this.currentY_) / 3.0
};
bezierCurveTo(this, cp1, cp2, p);
};
contextPrototype.arc = function(aX, aY, aRadius,
aStartAngle, aEndAngle, aClockwise) {
aRadius *= Z;
var arcType = aClockwise ? 'at' : 'wa';
var xStart = aX + mc(aStartAngle) * aRadius - Z2;
var yStart = aY + ms(aStartAngle) * aRadius - Z2;
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
// IE won't render arches drawn counter clockwise if xStart == xEnd.
if (xStart == xEnd && !aClockwise) {
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
// that can be represented in binary
}
var p = this.getCoords_(aX, aY);
var pStart = this.getCoords_(xStart, yStart);
var pEnd = this.getCoords_(xEnd, yEnd);
this.currentPath_.push({type: arcType,
x: p.x,
y: p.y,
radius: aRadius,
xStart: pStart.x,
yStart: pStart.y,
xEnd: pEnd.x,
yEnd: pEnd.y});
};
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
};
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
// Will destroy any existing path (same as FF behaviour)
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.stroke();
this.currentPath_ = [];
};
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
// Will destroy any existing path (same as FF behaviour)
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.fill();
this.currentPath_ = [];
};
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
return new CanvasGradient_('gradient');
};
contextPrototype.createRadialGradient = function(aX0, aY0,
aR0, aX1,
aY1, aR1) {
var gradient = new CanvasGradient_('gradientradial');
gradient.radius1_ = aR0;
gradient.radius2_ = aR1;
gradient.focus_.x = aX0;
gradient.focus_.y = aY0;
return gradient;
};
contextPrototype.drawImage = function(image, var_args) {
var dx, dy, dw, dh, sx, sy, sw, sh;
// to find the original width we overide the width and height
var oldRuntimeWidth = image.runtimeStyle.width;
var oldRuntimeHeight = image.runtimeStyle.height;
image.runtimeStyle.width = 'auto';
image.runtimeStyle.height = 'auto';
// get the original size
var w = image.width;
var h = image.height;
// and remove overides
image.runtimeStyle.width = oldRuntimeWidth;
image.runtimeStyle.height = oldRuntimeHeight;
if (arguments.length == 3) {
dx = arguments[1];
dy = arguments[2];
sx = sy = 0;
sw = dw = w;
sh = dh = h;
} else if (arguments.length == 5) {
dx = arguments[1];
dy = arguments[2];
dw = arguments[3];
dh = arguments[4];
sx = sy = 0;
sw = w;
sh = h;
} else if (arguments.length == 9) {
sx = arguments[1];
sy = arguments[2];
sw = arguments[3];
sh = arguments[4];
dx = arguments[5];
dy = arguments[6];
dw = arguments[7];
dh = arguments[8];
} else {
throw Error('Invalid number of arguments');
}
var d = this.getCoords_(dx, dy);
var w2 = sw / 2;
var h2 = sh / 2;
var vmlStr = [];
var W = 10;
var H = 10;
// For some reason that I've now forgotten, using divs didn't work
vmlStr.push(' <g_vml_:group',
' coordsize="', Z * W, ',', Z * H, '"',
' coordorigin="0,0"' ,
' style="width:', W, ';height:', H, ';position:absolute;');
// If filters are necessary (rotation exists), create them
// filters are bog-slow, so only create them if abbsolutely necessary
// The following check doesn't account for skews (which don't exist
// in the canvas spec (yet) anyway.
if (this.m_[0][0] != 1 || this.m_[0][1]) {
var filter = [];
// Note the 12/21 reversal
filter.push('M11=', this.m_[0][0], ',',
'M12=', this.m_[1][0], ',',
'M21=', this.m_[0][1], ',',
'M22=', this.m_[1][1], ',',
'Dx=', mr(d.x / Z), ',',
'Dy=', mr(d.y / Z), '');
// Bounding box calculation (need to minimize displayed area so that
// filters don't waste time on unused pixels.
var max = d;
var c2 = this.getCoords_(dx + dw, dy);
var c3 = this.getCoords_(dx, dy + dh);
var c4 = this.getCoords_(dx + dw, dy + dh);
max.x = max(max.x, c2.x, c3.x, c4.x);
max.y = max(max.y, c2.y, c3.y, c4.y);
vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
filter.join(''), ", sizingmethod='clip');")
} else {
vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
}
vmlStr.push(' ">' ,
'<g_vml_:image src="', image.src, '"',
' style="width:', Z * dw, ';',
' height:', Z * dh, ';"',
' cropleft="', sx / w, '"',
' croptop="', sy / h, '"',
' cropright="', (w - sx - sw) / w, '"',
' cropbottom="', (h - sy - sh) / h, '"',
' />',
'</g_vml_:group>');
this.element_.insertAdjacentHTML('BeforeEnd',
vmlStr.join(''));
};
contextPrototype.stroke = function(aFill) {
var lineStr = [];
var lineOpen = false;
var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
var color = a[0];
var opacity = a[1] * this.globalAlpha;
var W = 10;
var H = 10;
lineStr.push('<g_vml_:shape',
' filled="', !!aFill, '"',
' style="position:absolute;width:', W, ';height:', H, ';"',
' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
' stroked="', !aFill, '"',
' path="');
var newSeq = false;
var min = {x: null, y: null};
var max = {x: null, y: null};
for (var i = 0; i < this.currentPath_.length; i++) {
var p = this.currentPath_[i];
var c;
switch (p.type) {
case 'moveTo':
c = p;
lineStr.push(' m ', mr(p.x), ',', mr(p.y));
break;
case 'lineTo':
lineStr.push(' l ', mr(p.x), ',', mr(p.y));
break;
case 'close':
lineStr.push(' x ');
p = null;
break;
case 'bezierCurveTo':
lineStr.push(' c ',
mr(p.cp1x), ',', mr(p.cp1y), ',',
mr(p.cp2x), ',', mr(p.cp2y), ',',
mr(p.x), ',', mr(p.y));
break;
case 'at':
case 'wa':
lineStr.push(' ', p.type, ' ',
mr(p.x - this.arcScaleX_ * p.radius), ',',
mr(p.y - this.arcScaleY_ * p.radius), ' ',
mr(p.x + this.arcScaleX_ * p.radius), ',',
mr(p.y + this.arcScaleY_ * p.radius), ' ',
mr(p.xStart), ',', mr(p.yStart), ' ',
mr(p.xEnd), ',', mr(p.yEnd));
break;
}
// TODO: Following is broken for curves due to
// move to proper paths.
// Figure out dimensions so we can do gradient fills
// properly
if (p) {
if (min.x == null || p.x < min.x) {
min.x = p.x;
}
if (max.x == null || p.x > max.x) {
max.x = p.x;
}
if (min.y == null || p.y < min.y) {
min.y = p.y;
}
if (max.y == null || p.y > max.y) {
max.y = p.y;
}
}
}
lineStr.push(' ">');
if (!aFill) {
var lineWidth = this.lineScale_ * this.lineWidth;
// VML cannot correctly render a line if the width is less than 1px.
// In that case, we dilute the color to make the line look thinner.
if (lineWidth < 1) {
opacity *= lineWidth;
}
lineStr.push(
'<g_vml_:stroke',
' opacity="', opacity, '"',
' joinstyle="', this.lineJoin, '"',
' miterlimit="', this.miterLimit, '"',
' endcap="', processLineCap(this.lineCap), '"',
' weight="', lineWidth, 'px"',
' color="', color, '" />'
);
} else if (typeof this.fillStyle == 'object') {
var focus = {x: '50%', y: '50%'};
var width = max.x - min.x;
var height = max.y - min.y;
var dimension = width > height ? width : height;
focus.x = mr(this.fillStyle.focus_.x / width * 100 + 50) + '%';
focus.y = mr(this.fillStyle.focus_.y / height * 100 + 50) + '%';
var colors = [];
// inside radius (%)
if (this.fillStyle.type_ == 'gradientradial') {
var inside = this.fillStyle.radius1_ / dimension * 100;
// percentage that outside radius exceeds inside radius
var expansion = this.fillStyle.radius2_ / dimension * 100 - inside;
} else {
var inside = 0;
var expansion = 100;
}
var insidecolor = {offset: null, color: null};
var outsidecolor = {offset: null, color: null};
// We need to sort 'colors' by percentage, from 0 > 100 otherwise ie
// won't interpret it correctly
this.fillStyle.colors_.sort(function(cs1, cs2) {
return cs1.offset - cs2.offset;
});
for (var i = 0; i < this.fillStyle.colors_.length; i++) {
var fs = this.fillStyle.colors_[i];
colors.push(fs.offset * expansion + inside, '% ', fs.color, ',');
if (fs.offset > insidecolor.offset || insidecolor.offset == null) {
insidecolor.offset = fs.offset;
insidecolor.color = fs.color;
}
if (fs.offset < outsidecolor.offset || outsidecolor.offset == null) {
outsidecolor.offset = fs.offset;
outsidecolor.color = fs.color;
}
}
colors.pop();
lineStr.push('<g_vml_:fill',
' color="', outsidecolor.color, '"',
' color2="', insidecolor.color, '"',
' type="', this.fillStyle.type_, '"',
' focusposition="', focus.x, ', ', focus.y, '"',
' colors="', colors.join(''), '"',
' opacity="', opacity, '" />');
} else {
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
'" />');
}
lineStr.push('</g_vml_:shape>');
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
};
contextPrototype.fill = function() {
this.stroke(true);
}
contextPrototype.closePath = function() {
this.currentPath_.push({type: 'close'});
};
/**
* @private
*/
contextPrototype.getCoords_ = function(aX, aY) {
var m = this.m_;
return {
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
}
};
contextPrototype.save = function() {
var o = {};
copyState(this, o);
this.aStack_.push(o);
this.mStack_.push(this.m_);
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
};
contextPrototype.restore = function() {
copyState(this.aStack_.pop(), this);
this.m_ = this.mStack_.pop();
};
contextPrototype.translate = function(aX, aY) {
var m1 = [
[1, 0, 0],
[0, 1, 0],
[aX, aY, 1]
];
this.m_ = matrixMultiply(m1, this.m_);
};
contextPrototype.rotate = function(aRot) {
var c = mc(aRot);
var s = ms(aRot);
var m1 = [
[c, s, 0],
[-s, c, 0],
[0, 0, 1]
];
this.m_ = matrixMultiply(m1, this.m_);
};
contextPrototype.scale = function(aX, aY) {
this.arcScaleX_ *= aX;
this.arcScaleY_ *= aY;
var m1 = [
[aX, 0, 0],
[0, aY, 0],
[0, 0, 1]
];
var m = this.m_ = matrixMultiply(m1, this.m_);
// Get the line scale.
// Determinant of this.m_ means how much the area is enlarged by the
// transformation. So its square root can be used as a scale factor
// for width.
var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
this.lineScale_ = sqrt(abs(det));
};
/******** STUBS ********/
contextPrototype.clip = function() {
// TODO: Implement
};
contextPrototype.arcTo = function() {
// TODO: Implement
};
contextPrototype.createPattern = function() {
return new CanvasPattern_;
};
// Gradient / Pattern Stubs
function CanvasGradient_(aType) {
this.type_ = aType;
this.radius1_ = 0;
this.radius2_ = 0;
this.colors_ = [];
this.focus_ = {x: 0, y: 0};
}
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
aColor = processStyle(aColor);
this.colors_.push({offset: 1 - aOffset, color: aColor});
};
function CanvasPattern_() {}
// set up externs
G_vmlCanvasManager = G_vmlCanvasManager_;
CanvasRenderingContext2D = CanvasRenderingContext2D_;
CanvasGradient = CanvasGradient_;
CanvasPattern = CanvasPattern_;
})();
} // if
[[GettingStarted]]
[[Rechtssystematik]]
[[Prinzipien]]
[[Gesetze]]
[[Entscheidungen]]
[[Tools]]
[[Impressum]]
@@display:none;@@[img[andreani|http://www.andreanis.de/_tiddly/uploads/logoverlag.jpg][http://www.andreanis.de]]
!Format text
|!Format|!It will look like this...|!...if you format it like this...|
|Bold-faced type|''text''|{{{''text''}}}|
|Italic text|//text//|{{{//text//}}}|
|Underlined text|__text__|{{{__text__}}}|
|Strike-through text|--text--|{{{--text--}}}|
|Colored text|@@color(green):green colored@@|{{{@@color(green):green colored@@}}}|
|Text with colored background|@@bgcolor(#ff0000):color(#ffffff):red colored@@|{{{@@bgcolor(#ff0000):color(#ffffff):red colored@@}}}|
|Highlighting|@@text@@|{{{@@text@@}}}|
|Superscript|2^^3^^=8|{{{2^^3^^=8}}}|
|Subscript|a~~ij~~ = -a~~ji~~|{{{a~~ij~~ = -a~~ji~~}}}|
!Make the first letter of a paragraph extra large
(from Morris Gray's TW Help)
''Sample'':
{{firstletter{
@@color:#bbbbbb;O@@}}}kay, so you know how to use ~TiddlyWiki, but now you want more. You want to change the color or layout. You want to add features to it. As the subtitle says, this is an entry-level introduction, so I am not going to show you how to do every possible thing you can do with ~TiddlyWiki. I probably don't know half of what can be done. Advanced documentation such as that found at http://www.tiddlywiki.org/wiki and http://tiddlyspot.com/twhelp/ can hopefully expand your horizons.
''How to do it:''
1. Add the following code to your StyleSheet:
{{{
.firstletter{ float:left; width:0.75em; font-size:400%; font-family:times,arial; line-height:60%; }
}}}
2. Add the following code to your tiddler at the place where your enlarged letter would go (replacing "O" with the appropriate letter):
{{{
{{firstletter{
@@color:#c06;O@@
}}}
}}}
.firstletter{ float:left; width:0.75em; font-size:250%; font-family:verdana; line-height:50%; }
.nodeName {font-size:3.0em}
.nodeNameLength:30
.nodeLabel:hover {color:#19A463;font-size:70%}
.nodeLabel {cursor:pointer;z-index:1;font-size:70%}
.ttmm canvas {z-index:0;}
.ttmm div {z-index:1;}
.shape {z-index:0;}
.ttmm {border: none;border_width : 0px;}
.siteTitle {font-size:150%;position: relative;float: right;width: auto;padding: 0.2em 0.2em 0.2em 0.2em;}
.siteSubtitle {font-size:0.5em;}
|bgcolor(#dddddd):Links with wikiwords|EnchiLada (inactive link - no tiddler yet)<br>WikiWord (active link to tiddler)|{{{EnchiLada}}}<br>{{{WikiWord}}}|
|bgcolor(#dddddd):~De-Wikify a ~WikiWord|~WikiWord, ~EnchiLada|{{{~WikiWord, ~EnchiLada}}}|
|bgcolor(#dddddd):Links with brackets|[[How to add background images]]|{{{[[How to add background images]]}}}|
|bgcolor(#dddddd):Pretty links|[[display text|ColorSchemes]] - links to the tiddler of color schemes|{{{[[display text|ColorSchemes]]}}}|
|bgcolor(#dddddd):External links work the same way:|http://groups.google.com/group/TiddlyWiki <br><br>[[TiddlyWiki Google group|http://groups.google.com/group/TiddlyWiki]]|{{{http://groups.google.com/group/TiddlyWiki}}} <br><br> {{{[[TiddlyWiki Google group|http://groups.google.com/group/TiddlyWiki]]}}}|
|bgcolor(#dddddd):Links to local files|To a file on a CD in your D drive: <br><br>To a file on your USB stick on your e drive: <br><br>To a file in your hard drive:|{{{file:///D:/filename.doc/}}}<br><br>{{{file:///E:/filename.doc/}}}<br><br>{{{file:///C:/filepath/filename.doc/}}}|
''Images:''
{{{[img[http://farm1.static.flickr.com/39/122259544_6913ca58f3_m.jpg]]}}} is the formatting for:
[img[http://farm1.static.flickr.com/39/122259544_6913ca58f3_m.jpg]]
''A tip from Jeremy Hodge:''
"...[You] may add an image as a local file with the following: {{{[img[.\filepath\filename.jpg]]}}} which adds a picture from the directory that is contained within the same directory as TW. This is very useful for me or anyone who carries their own TW on a USB drive such as myself."
Mark this side at your @@color:#900;favorite Network@@
<html>
<h3>Social Networks</h3>
<table>
<tr>
<td>twitter</td>
<td>facebook</td>
<td>delicious</td>
</tr>
<tr>
<td><a href="http://twitter.com/home?status=http%3A%2F%2Fwww.andreanis.de/_tiddly/index.php" target="_blank" title="Twitter"><img src="/_tiddly/uploads/twitter.gif" width="16" height="16" border="0" hspace="0" alt="Twitter"/></a></td>
<td><a href="http://de.facebook.com/sharer.php?u=http%3A%2F%2Fwww.andreanis.de/_tiddly/index.php" target="_blank"><img src="/_tiddly/uploads/facebook.gif" alt="Facebook" title="Facebook" align="left" border="0" height="16" hspace="0" width="16"></a></td>
<td><a href="http://del.icio.us/post?url=http%3A%2F%2Fwww.andreanis.de/_tiddly/index.php" target="_blank"><img src="/_tiddly//uploads/delicious.gif" alt="deli.cio.us" title="deli.cio.us" align="left" border="0" height="16" hspace="0" width="16"></a></td>
</tr>
</table>
</html>
Type the text for 'KaufR'
Type the text for 'Rechtsgebiet'
Type the text for 'AufenthaltsRecht'
Einerseits git es die für 3 Monate befristete Variante des Schengen-VISA, die einen Aufenhalt für die beantragte Dauer bis höchstens 3 Monaten einräumt.
Anderseits ist der Aufenthalt an einen Aufenthaltszweck geknüpft:
http://www.wien.diplo.de/Vertretung/wien/de/04/Seite_20Langzeit-Visa.html
<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>
/*
vismo library is designed to make it easier to bring cross browser visualisations to Firefox/IE using canvas and vml
Some plugins are dependent on it.
Including GeoTiddlyWiki, TiddlyTagMindMap and ImageTaggingPlugin
If you have any of these installed in the condensed form you must install this!
*/
var VismoLibraryInstalled = true;var VismoOptimisations = {
packCoordinates: function(coordlist){
var res = [];
for(var i=0; i < coordlist.length-1; i+=2){
res.push([coordlist[i],coordlist[i+1]]);
}
return res;
}
,unpackCoordinates: function(coordlist){
var res = [];
for(var i=0; i < coordlist.length; i+=1){
res.push(coordlist[i][0]);
res.push(coordlist[i][1]);
}
return res;
}
//coords in form [[x1,y1],[x2,y2]]
,douglasPeucker: function(coords,tolerance, start,end){
var results = [];
if(!start) start = 0;
if(!end) end = coords.length - 1;
if(start >= coords.length || end >= coords.length || start == end -1){
return [];
}
var midpoint = {};
midpoint.x = (coords[end][0] + coords[start][0]) /2;
midpoint.y = (coords[end][1] + coords[start][1]) /2;
var bestPoint = {distance:-1, index:-1};
for(var i=start+1; i < end; i++){
var x = coords[i][0];
var y = coords[i][1];
var deltax = midpoint.x - x;
var deltay= midpoint.y - y;
var perpendicular_d = Math.sqrt((deltax * deltax ) + (deltay *deltay)); //this is not perpendicular distancd.. i think!
if(perpendicular_d > bestPoint.distance){
bestPoint.index = i;
bestPoint.distance = perpendicular_d;
}
}
if(bestPoint.index ==-1 || bestPoint.distance<tolerance){
var res = [];
res.push(coords[start]);
//res.push(coords[end])
return res; //none of these points are interesting except last
}
else{
results.push(coords[start]);
var ref = bestPoint.index;
var splice1 = VismoOptimisations.douglasPeucker(coords,tolerance,start+1,ref);
var splice2 = VismoOptimisations.douglasPeucker(coords,tolerance,ref,end);
results = results.concat(splice1);
results = results.concat(splice2);
results.push(coords[end]);
return results;
}
}
,vismoShapeIsInVisibleArea: function(vismoShape,canvas,transformation){
var left = 0,top = 0;
var right = parseInt(canvas.width) + left;
var bottom = parseInt(canvas.height) + top;
var topleft = VismoClickingUtils.undotransformation(left,top,transformation);
var bottomright = VismoClickingUtils.undotransformation(right,bottom,transformation);
var frame = {};
frame.top = topleft.y;
frame.bottom = bottomright.y;
frame.right = bottomright.x;
frame.left = topleft.x;
var g = vismoShape.getBoundingBox();
if(g.x2 < frame.left) {
return false;}
if(g.y2 < frame.top) {
return false;}
if(g.x1 > frame.right){
return false;
}
if(g.y1 > frame.bottom){
return false;
}
return true;
}
,vismoShapeIsTooSmall: function(vismoShape,transformation){
if(!transformation ||!transformation.scale) return false;
var g = vismoShape.getBoundingBox();
var s = transformat