*Site author.\n*Student at [[Brigham Young University-Idaho|http://www.byui.edu]]\n*Home page at http://checkettsweb.com
/***\n!Generic rules /% ============================================================= %/\n***/\n/*{{{*/\nbody {\nbackground-color: #303030;\nfont-size: 1.1em\n}\n\nimg{\n display: block;\n margin: 0 auto;\n}\n\n#toc{\n background: #000;\n}\n/*}}}*/\n/***\n!Link styles /% ============================================================= %/\n***/\n/*{{{*/\na,\na.button,\n#mainMenu a.button,\n#sidebarOptions .sliderPanel a{\n color: #ffbf00;\n border: 0;\n}\n\na:hover,\na.button:hover,\n#mainMenu a.button:hover,\n#sidebarOptions .sliderPanel a:hover\n#sidebarOptions .sliderPanel a:active{\n color: #ff7f00;\n border: 0;\n border-bottom: #ff7f00 1px dashed;\n background: transparent;\n text-decoration: none;\n}\n\n#displayArea .button.highlight{\n color: #ffbf00;\n background: #4c4c4c;\n}\n/*}}}*/\n/***\n!Tiddler Display styles /% ============================================================= %/\n***/\n/*{{{*/\n.slide{\n margin: .5em 4em;\n}\n\n.title{display: none;}\nh1, h2, h3, h4, h5 {\n color: #fff;\n background-color: transparent;\n border-bottom: 1px solid #333;\n}\n\n.subtitle{\n color: #666;\n}\n\n.viewer {color: #fff;}\n\n.viewer table{background: #666; color: #fff;}\n\n.viewer th {background-color: #996; color: #fff;}\n\n.viewer pre, .viewer code {color: #ddd; background-color: #4c4c4c; border: 1px solid #ffbf00; font-size: .8em}\n\n.viewer hr {color: #666;}\n\n.tiddler .button {color: #4c4c4c;}\n.tiddler .button:hover { color: #ffbf00; background-color: #4c4c4c;}\n.tiddler .button:active {color: #ffbf00; background-color: #4c4c4c;}\n\n.toolbar {\n color: #4c4c4c;\n}\n\n.toolbar a.button,\n.editorFooter a{\n border: 0;\n}\n\nul,ol{\n margin: 0;\n padding: 0;\n}\n/*}}}*/
\n\n![[Editing Options|EditingOptions]]\n<<upload http://www.checkettsweb.com/ruby/store.php index.htm backups>>
!!Start the <<slideShow style:"DarkRails">>\n\nThis presentation covers the //how//, not so much the //why// of getting started with Ruby and TiddlyWiki. I've included a couple of packages to download; I am not maintaining them for others, nor will I be providing any trouble shooting for them except at the [[IS455]] presentation on Tuesday, January 30 2006, 3 PM. (There is a [[KnowledgeLibrary|http://checkettsweb.com/files/RubyKnowLib.zip]] zip too)\n\nThis presentation was created using [[TiddlyWiki]], a [[Slide Show Plugin|SlideshowPlugin]], and some good clean CSS.\n\n!Overview\n*Ruby\n*Rails\n*A nifty package\n*H*llo W*rld\n\n!Ruby\n*Interpreted language\n*Everything is an object (really!)\n*More info at [[Wikipedia|http://en.wikipedia.org/wiki/Ruby_programming_language]]\n\n!Rails\n*MVC Framework\n*'Convention over Configuration'\n*DRY, POLS, CRUD etc.\n*Iterative design\n\n!~RailbyDev Package\n*[[InstantRails|http://instantrails.rubyforge.org/wiki/wiki.pl]]\n**[[Ruby|http://rubyforge.org/projects/rubyinstaller/]]\n**[[Rails|http://www.rubyonrails.org/down]]\n**~MySQL\n*[[jEdit|http://jedit.org/]] with some plugins\n\nAvailable at: http://checkettsweb.com/files/railbydev.zip (50 meg download)<<br>> ^^(usb [[drive E: setup|http://checkettsweb.com/files/railbydevUSB.zip]] too)^^\n\n!Installation\n#Un-zip the package onto the root of your drive (C: or E: depending on the package) We'll use 'C' for this tutorial.\n#Go into C:\srubydev (the folder that was created by the un-zip)\n#Run ''~InstantRails.exe'' (if it detects that the folder has changed, click 'yes' so it updates the config paths)\n#Done! No more installing, just play time!\n\n!Instant Rails\n[img[instantrails.png]]\n(Your new best friend)\n\n!Firing up IRB\n[img[instantrailshelp.png]]\n#Click on the black 'I'\n#Select: ''Help'' > ''fxri - Interactive Ruby Help - irb Console''\n\n!~IRB- Interactive Ruby\n[img[fxriblank.png]]\nRuby instant feedback mode\n!Direct command\n{{{\nputs "Hello World"\n\nputs("Hello World")\n}}}\n\n!Calling a function\n{{{\ndef sayHello\n puts "Hello World!"\nend\n\nsayHello\nsayHello()\n}}}\n\n!Objects\n{{{\nclass Say\n def initialize(toWhoever = "World")\n @toWhoever = toWhoever\n end\n\n def say\n puts "Hello "+@toWhoever+"!"\n end\nend\n\nworld = Say.new\neveryone = Say.new("IS455")\n\nworld.hello\neveryone.hello\n}}}\n!IRB with output\n[img[fxri.png]]\n\n!Bring in jEdit\n*Development environment\n*Pre-setup with Ruby touches\n*Go to ''C:\srubydev'' run the ''jEdit'' shortcut\n\n!Hello World redux\n[img[jeditstart.png]]\nIts all set up, just click the ''blue triangle''\n!Where is Rails?\nBack to Instant Rails\n[img[instantrailsmanage.png]]\nManage rails apps\n[img[instantcreate.png]]\n\n!Generating files\nType in:\n{{{\nrails demo2\n}}}\n*Problems? Drawbacks?\n*Convention over configuration\n\n!Lets get the server running\n[img[webrick.png]]\n#Go back to the 'Manage Rails Applications' window\n#Hit the ''Refresh List'' button\n#Check the box for ''Demo 2''\n#Click the ''Start with ~WEBrick'' button<<br>>^^(a console will appear with the ~WEBrick server running in it)^^\n\n!Make a controller (remember MVC?)\nGo into the directory\n{{{\ncd demo2\n}}}\n\nRun generate script\n{{{\nruby script/generate controller Say\n}}}\n\nWhat was created!?! \n*Directory for views\n*Controller\n*Unit tests and helper\n\n!Bring it into jEdit\n[img[jeditproject.png]]\n[img[jeditproject2.png]]\n!Open up the controller\n[img[saycontroller.png]]\nMake a 'hello' activity\n{{{\nclass SayController < ApplicationController\n def hello \n end\nend\n}}}\n\n!Check it in the browser\nWe already started the web server\n*But we don't have to restart it!\n{{{\nhttp://localhost:3000/say/hello\n}}}\n[img[firefoxnotemplate.png]]\n\n*No template?\nWe have a controller but no //view//!\n\n!Create hello.rhtml view\nThe view is similar to a JSP\n*Normal HTML\n*Embed ruby in it\n*RHTML extension\n[img[rhtml1.png]]\n\n\n!Make view dynamic\n[img[rhtml2.png]]\n\n!Move the time into the controller\n[img[rhtml3.png]]\n\n[img[firefoxend.png]]
*[[Official Ruby Site|http://www.ruby-lang.org/en/]]\n*[[Ruby Quiz|http://www.rubyquiz.com/]]\n*[[RubyForge|http://rubyforge.org]]\n**InstantRails\n**OneClickInstaller\n\n!Tutorials\n*[[Rolling with instant rails|http://instantrails.rubyforge.org/tutorial/index.html]]
Information System 455 is a senior level course at [[BYU-Idaho|http://www.byui.edu]]. It is an advanced web languages course.\n\nEach student was allowed to choose a programming language of interest in which he had no previous experience. To class's goals are to make each student an expert in their chosen language, and the student in turn will teach the rest of the class how to use that language.\n\nThis site is an ongoing presention during the semester of [[my|Clint Checketts]] learning of Ruby and the Rails framework.
!Presentations\nGettingStarted\n^^(Jan 31, 2006)^^\n==[[Loops and Such]]==\n==[[Unit Testing]]==\n==[[Completed Project]]==
<div class='header' macro='gradient vert #390108 #900'>\n<div class='headerShadow'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> \n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n<div class='headerForeground'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> \n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n</div>\n<div id='mainMenu'>\n<div refresh='content' tiddler='MainMenu'></div>\n<div refresh='content' tiddler='EditingOptions'></div>\n</div>\n<div id='sidebar'>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n<div id='messageArea'></div>\n<div id='tiddlerDisplay'></div>\n</div>
by [[Clint Checketts]]
Ruby and the Rails Framework
/***\n|!Name:|SlideShowPlugin |\n|!Version:|1.3.0 - 26/02/2006|\n|!Source:|http://www.math.ist.utl.pt/~psoares/addons.html |\n|!Authors:|[[Paulo Soares|mailto:psoares@math.ist.utl.pt]] and [[Clint Checketts|http://www.checkettsweb.com]] |\n|!Type:|Macro |\n|!Requires:|TiddlyWiki >= 2.0.0 |\n!Description\nThis plugin turns a TiddlyWiki tiddler into a simple slide show type display. You can have looping, timed or themed slide shows. It should work in a way that does not interfere with TiddlyWiki. When you close the slide show you get back to your good old TW. \n\nThis plugin has been tested in Firefox, Internet Explorer, Safari, and Opera. Let us know if something seems broken.\n!Usage\nTo use this plugin you //must// be using TiddlyWiki 2.0. Install this tiddler and drop {{{<<slideShow>>}}} at the beginning of the tiddler. Use ! to start each slide with or without a title. Mark the end of your slides with a rule (- - - -). Everything that appears before the first header or after the closing rule is not shown in the slide show. \nThere are also a few navigation buttons and a table of contents that shows up if you click the slide number.\nSee other options in this [[SlideShowExample]].\n!Revision history\nv1.3.0 26/02/2006 - restore open tiddlers on exit, fixed problem with markup in headers (should work with NestedSlidersPlugin), added slide comments (blocks of text in the tiddler that don't show up in the presentation)\nv1.2.1 28/01/2006 - pause timed slideshow with spacebar, clock with 3 different modes, fixed bugs with style and abbreviation options, general cleanup\nv1.2.0 07/01/2006 - added a resume feature and themes support\nv1.1.5 Beta 12/14/2005 - added mouse support and cleaned up navbar generation\nv1.1.0 Beta 12/12/2005 - added support for IE, added key listeners\nv1.0.0 12/11/2005 - initial release\n!Todo\n*Incremental advancement within a slide\n*Cross fade effects\n!Code\n***/\n//{{{\n\nconfig.formatters.push({\n name: "slideShowComment",\n match: "%%",\n lookahead: "%%((?:.|\s\sn)*?)%%",\n className: "slideShowComment",\n handler: function(w) {\n var lookaheadRegExp = new RegExp(this.lookahead,"mg");\n lookaheadRegExp.lastIndex = w.matchStart;\n var lookaheadMatch = lookaheadRegExp.exec(w.source)\n var p = createTiddlyElement(w.output,"span",null,this.className);\n wikify( lookaheadMatch[1], p, null, w.tiddler);\n w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;\n }\n});\n\nconfig.macros.slideShow = {label: "slide show", maxTOCLength: 30};\nconfig.macros.slideShow.messages = {gotoLabel: "Go to slide:"};\nconfig.views.wikified.slideShow = {text: "slide show", tooltip: "Start slide show"};\nconfig.views.wikified.slideShow.quit = {text: "end", tooltip: "Quit the slide show"};\nconfig.views.wikified.slideShow.firstSlide = {text: "<<", tooltip: "first slide"};\nconfig.views.wikified.slideShow.previousSlide = {text: "<", tooltip: "previous slide"};\nconfig.views.wikified.slideShow.nextSlide = {text: ">", tooltip: "next slide"};\nconfig.views.wikified.slideShow.lastSlide = {text: ">>", tooltip: "last slide"};\n\nfunction changeStyleSheet(tiddlerName) {\n if (tiddlerName == null) tiddlerName = "StyleSheet";\n setStylesheet(store.getTiddlerText("StyleSheetColors"),"StyleSheetColors");\n setStylesheet(store.getTiddlerText("StyleSheetLayout"),"StyleSheetLayout");\n var theCSS = store.getRecursiveTiddlerText(tiddlerName,"");\n setStylesheet(theCSS,"StyleSheet");\n}\n\n//Excellent (and versatile) reparser created by Paul Petterson for parsing the paramString in a macro\nfunction reparse( params ) {\n var re = /([^:\ss]+)(?:\s:((?:\sd+)|(?:["'](?:[^"']+)["']))|\ss|$)/g;\n var ret = new Array() ;\n var m ;\n while( (m = re.exec( params )) != null ) ret[ m[1] ] = m[2]?m[2]:true ;\n return ret ;\n}\n\n// 'keys' code adapted from S5 which in turn was adapted from MozPoint (http://mozpoint.mozdev.org/)\nfunction keys(key) {\n if (!key) {\n key = event;\n key.which = key.keyCode;\n }\n if (document.getElementById('contentWrapper').className == "slideShowMode"){\n switch (key.which) {\n case 32: // spacebar\n if(time>0){\n if(autoAdvance){\n clearInterval(autoAdvance);\n autoAdvance = null;\n } else {\n autoAdvance=setInterval("GoToSlide(1)", time);\n }\n }\n break;\n case 34: // page down\n case 39: // rightkey\n case 40: // downkey\n GoToSlide(1);\n break;\n case 33: // page up\n case 37: // leftkey\n case 38: // upkey\n GoToSlide(-1);\n break;\n case 36: // home\n GoToSlide("f");\n break;\n case 35: // end\n GoToSlide("l");\n break;\n case 27: // escape\n endSlideShow();\n break;\n }\n\n }\n return false;\n}\n\nfunction clicker(e) {\n if (!e) var e = window.event;\n var target = resolveTarget(e);\n //Whenever something is clicked that won't advance the slide make sure that the table of contents gets hidden\n if (target.getAttribute('href') != null || isParentOrSelf(target, 'toc') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object') || isParentOrSelf(target, 'pageFooter') || isParentOrSelf(target, 'navigator')){\n //Don't hide the TOC if the indexNumbers (which trigger the index) is clicked\n if(isParentOrSelf(target,'indexNumbers') || isParentOrSelf(target,'jumpInput')){\n return true;\n }\n showHideTOC('none');\n return true;\n }\n \n //Advance a slide if the TOC is visible otherwise make sure that the TOC gets hidden\n if ((!e.which && e.button == 1) || e.which == 1) {\n if (document.getElementById('toc').style.display != 'block'){\n GoToSlide(1);\n } else {\n showHideTOC('none');\n }\n }\n \n if ((!e.which && e.button == 2) || e.which == 3) {\n if (document.getElementById('toc').style.display != 'block'){\n GoToSlide(-1);\n } else {\n showHideTOC('none');\n }\n return false;\n }\n}\n\nfunction isParentOrSelf(element, id) {\n if (element == null || element.nodeName=='BODY') return false;\n else if (element.id == id) return true;\n else return isParentOrSelf(element.parentNode, id);\n}\n\nfunction GoToSlide(step) {\n var new_pos;\n var slideHolder = document.getElementById('slideContainer');\n //The parse float ensures that the attribute is returned as a number and not a string.\n var cur_pos = parseFloat(slideHolder.getAttribute('currentslide'));\n var numberSlides = slideHolder.getElementsByTagName("div").length;\n switch (step) {\n case "f":\n new_pos=0;\n break;\n case "l":\n new_pos=numberSlides-1;\n break;\n default:\n new_pos=cur_pos+step;\n }\n \n if(slideShowCircularMode && new_pos == numberSlides) new_pos=0;\n if(slideShowCircularMode && new_pos<0) new_pos=(numberSlides - 1);\n if(step!=0 && new_pos>=0 && new_pos<numberSlides) {\n slideHolder.childNodes[cur_pos].style.display='none';\n slideHolder.childNodes[new_pos].style.display='block';\n slideHolder.setAttribute('currentslide',new_pos);\n new_pos++;\n var indexNumbers = document.getElementById('indexNumbers');\n indexNumbers.firstChild.data = new_pos+'/'+numberSlides;\n if((new_pos==numberSlides) && !slideShowCircularMode && autoAdvance) clearInterval(autoAdvance);\n return true;\n }\n return false;\n}\n\nfunction tocShowSlide(e) {\n if (!e) var e = window.event;\n var target = resolveTarget(e);\n var slide = target.getAttribute('slideNumber');\n var cur_pos = document.getElementById('slideContainer').getAttribute('currentslide');\n var step = slide-cur_pos;\n if(step!=0) GoToSlide(step);\n showHideTOC('none');\n return;\n}\n\n//Toggle the display of the table of contents\nfunction showHideTOC(display){\n var toc = document.getElementById('toc');\n //Reset the input box\n document.getElementById('jumpInput').value = "";\n\n if (display == null || display.length == null){\n if (toc.style.display == 'none' || toc.style.display == ''){\n toc.style.display = 'block';\n document.getElementById('jumpInput').focus();\n } else {\n toc.style.display = 'none';\n }\n } else {\n toc.style.display = display;\n if (display == 'block')\n document.getElementById('jumpInput').focus();\n }\n}\n\nfunction makeSignature(title,params){\n var signature = title+store.getTiddler(title).modified;\n if(params['style']) signature += params['style'];\n if(params['repeat']) signature += "repeat";\n if(params['slidePause'] > 0) signature += params['slidePause'];\n if(params['tocLabel']) signature += params['tocLabel'];\n if(params['autostart']) signature += "autostart";\n if(params['clock']) signature += params['clock'];\n return signature;\n}\n\nfunction padZero(par){\n if(par<10) par="0"+par;\n return par;\n}\n\nfunction setClock(){\n var actualTime = new Date();\n var newTime = actualTime - clockStartTime;\n newTime = clockMultiplier*newTime+clockInterval-3600000;\n actualTime.setTime(newTime);\n newTime = padZero(actualTime.getHours()) + ":" + padZero(actualTime.getMinutes())+ ":" + padZero(actualTime.getSeconds());\n var clock = document.getElementById('slideClock');\n clock.firstChild.nodeValue = newTime;\n}\n\nfunction resetClock(){\n var time = new Date(70,1,1,0,0,0);\n if(clockStartTime-time>0) clockStartTime = new Date();\n}\n\nvar title;\nvar place;\nvar autoAdvance=null;\nvar slideClock=null;\nvar time = 0;\nvar slideShowCircularMode;\nvar slideShowStyleSheet;\nvar slideShowParams;\nvar clockMultiplier;\nvar clockInterval;\nvar clockStartTime;\nvar openTiddlers;\n\nconfig.macros.slideShow.handler = function(aPlace,macroName,params,wikifier,paramString,tiddler){\n if(tiddler instanceof Tiddler){\n var lingo = config.views.wikified.slideShow;\n var autostart = false;\n if (!e) var e = window.event;\n \n place = aPlace;\n title = tiddler.title;\n params = reparse(paramString);\n var onclick = function(){config.macros.slideShow.onClickSlideShow(params);};\n createTiddlyButton(aPlace,lingo.text,lingo.tooltip,onclick);\n \n var slideShowHolder = document.getElementById('slideShowWrapper');\n //If no show exist previously, create it\n if(params['autostart']){\n if(slideShowHolder != null){\n var signature = slideShowHolder.getAttribute('showSignature');\n if(signature.indexOf("autostart")==-1) autostart = true;\n } else {autostart = true;}\n if(autostart){\n slideShowParams = params;\n setTimeout("config.macros.slideShow.onClickSlideShow(slideShowParams);",10);\n }\n }\n }\n}\n\nvar disableFunction = function(e){return false;}\nvar enableFunction = function(e){}\n\nconfig.macros.slideShow.onClickSlideShow = function(newParams) {\n\nopenTiddlers = new Array;\nvar viewer=document.getElementById('tiddlerDisplay');\nfor(var i=0; i<viewer.childNodes.length; i++){\n var name = viewer.childNodes[i].getAttribute('tiddler');\n openTiddlers.push(name);\n}\n\n document.oncontextmenu = disableFunction;\n clockMultiplier = 1;\n clockInterval = 0;\n clockStartTime = new Date(70,1,1,0,0,0);\n slideShowCircularMode = false;\n time = 0;\n slideShowStyleSheet = null;\n if(newParams['style']){\n slideShowStyleSheet = eval(newParams['style']);\n } \n if(newParams['repeat']){\n slideShowCircularMode = true;\n }\n if(newParams['slidePause'] > 0){\n time = newParams['slidePause'];\n }\n if(newParams['clock']){\n clockStartTime = new Date();\n var clockType= eval(newParams['clock']);\n if(clockType != '+') {\n clockMultiplier = -1;\n clockInterval = -clockType*60000;\n }\n }\n\n var contentWrapper = document.getElementById('contentWrapper');\n if (contentWrapper.className != "slideShowMode"){\n clearMessage();\n //Attach the key and mouse listeners\n document.onkeyup = keys;\n document.onmouseup = clicker;\n \n var slideShowHolder = document.getElementById('slideShowWrapper');\n //If no show exist previously, create it\n if(slideShowHolder == null){\n createSlides(newParams);\n //If there was once waiting in the background and it matches the one we just started, resume it\n } else if (slideShowHolder.getAttribute('showSignature') == makeSignature(title,newParams)){\n \n //Remove dblClick on edit function\n var theTiddler = document.getElementById("tiddler"+title);\n theTiddler.ondblclick = function() {};\n\n // Grab the 'viewer' element and give it a signature so the show can be resumed if stopped\n var tiddlerElements = theTiddler.childNodes;\n var viewer;\n for (var i = 0; i < tiddlerElements.length; i++){\n if (tiddlerElements[i].className == "viewer") viewer = tiddlerElements[i];\n }\n theTiddler.insertBefore(slideShowHolder,viewer);\n theTiddler.removeChild(viewer);\n slideShowHolder.style.display = 'block';\n document.getElementById("pageFooter").className = "pageFooterOff";\n \n //If the show we started it totally new than the resumable one, create the new one and kill the resumable one\n } else {\n slideShowHolder.parentNode.removeChild(slideShowHolder);\n createSlides(newParams);\n }\n slideClock=setInterval("setClock()", 1000); \n if(time>0) autoAdvance=setInterval("GoToSlide(1)", time); \n story.closeAllTiddlers(title);\n toggleSlideStyles();\n } else {\n endSlideShow();\n }\n return ;\n \n}\n\nfunction endSlideShow(){\n //Set aside show so it can be resumed later\n var showHolder = document.getElementById('slideShowWrapper');\n showHolder.style.display = 'none';\n document.getElementById('contentWrapper').parentNode.appendChild(showHolder);\n document.oncontextmenu = enableFunction;\n if(autoAdvance) clearInterval(autoAdvance);\n if(slideClock) clearInterval(slideClock);\n story.refreshTiddler(title,null,true);\n story.closeAllTiddlers();\n story.displayTiddlers(null,openTiddlers,DEFAULT_VIEW_TEMPLATE);\n document.onmouseup = function(){};\n toggleSlideStyles();\n}\n\nfunction isInteger(s){\n var i;\n for (i = 0; i < s.length; i++){\n // Check that current character is number.\n var c = s.charAt(i);\n if (((c < "0") || (c > "9"))) return false;\n }\n // All characters are numbers.\n return true;\n}\n\nfunction jumpInputToSlide(e){\n if (!e) {\n e = window.event;\n e.which = e.keyCode;\n }\n if(e.which==13){\n var jumpInput= document.getElementById("jumpInput").value;\n if(isInteger(jumpInput)){\n var step=jumpInput-document.getElementById('slideContainer').getAttribute('currentslide')-1;\n if (GoToSlide(step)){\n showHideTOC('none'); \n }\n }\n }\n return;\n}\n\n//Used to shorten the TOC fields\nfunction abbreviateLabel(label){\n// if (label == null) label = "A Slide" //This is just a place holder fix\n var maxTOCLength = config.macros.slideShow.maxTOCLength;\n if(label.length>maxTOCLength) {\n var temp = new Array();\n temp = label.split(' ');\n label = temp[0];\n for(var j=1; j<temp.length; j++){\n if((label.length+temp[j].length)<=maxTOCLength){\n label += " " + temp[j];\n } else {\n label += " ...";\n break;\n }\n }\n }\n return label;\n}\n\ncreateSlides = function(newParams){\n var lingo = config.views.wikified.slideShow;\n\n //Remove dblClick on edit function\n var theTiddler = document.getElementById("tiddler"+title);\n theTiddler.ondblclick = function() {};\n\n // Grab the 'viewer' element and give it a signature so the show can be resumed if stopped\n var tiddlerElements = theTiddler.childNodes;\n var viewer;\n for (var i = 0; i < tiddlerElements.length; i++){\n if (tiddlerElements[i].className == "viewer") viewer = tiddlerElements[i];\n }\n viewer.id = 'slideShowWrapper';\n viewer.setAttribute("showSignature",makeSignature(title,newParams));\n\n //Hide the text that comes before the first H1 element (I think I may put this into a cover page type thing)\n while(viewer.childNodes.length > 0 && viewer.firstChild.nodeName.toUpperCase() != "H1") {\n viewer.removeChild(viewer.firstChild);\n }\n \n //Cycle through the content an each time you hit an H1 begin a new slide div\n var slideNumber = 0;\n var slideHolder = document.createElement('DIV');\n slideHolder.id = "slideContainer";\n \n while(viewer.childNodes.length > 0){\n //Create a new slide a append it to the slide holder\n if (viewer.firstChild.nodeName == "H1"){\n slideNumber++;\n var slide = document.createElement('DIV');\n slide.id = "slideNumber"+slideNumber;\n slide.className = "slide";\n if (slideNumber > 1) {\n slideHolder.setAttribute('currentslide',0);\n slide.style.display='none';\n } else {\n slide.style.display='block';\n }\n slideHolder.appendChild(slide); \n }\n\n //Grab the first thing in the viewer and check to see if its an H1, if so put it in a slide, it will shift everything else forward\n slide.appendChild(viewer.firstChild);\n\nif(viewer.childNodes.length > 0 && viewer.firstChild.className=="slideShowComment") {\n viewer.removeChild(viewer.firstChild);\n }\n\n //If you hit a horizontal rule (HR) remove the remaining elements until you hit an H1\n if(viewer.childNodes.length > 0 && viewer.firstChild.nodeName=="HR") {\n while(viewer.childNodes.length > 0 && viewer.firstChild.nodeName != "H1") {\n viewer.removeChild(viewer.firstChild);\n }\n }\n }\n \n //Stick the slides back into the viewer\n viewer.appendChild(slideHolder);\n\n \n //Create the navigation bar\n var pagefooter = createTiddlyElement(viewer,"DIV","pageFooter","pageFooterOff");\n var navigator = createTiddlyElement(pagefooter,"SPAN","navigator");\n\n //Make it so that when the footer is hovered over the class will change to make it visible\n pagefooter.onmouseover = function () {pagefooter.className = "pageFooterOn"};\n pagefooter.onmouseout = function () {pagefooter.className = "pageFooterOff"};\n\n //Create the control button for the navigation \n var onClickQuit = function(){endSlideShow();};\n createTiddlyButton(navigator,lingo.quit.text,lingo.quit.tooltip,onClickQuit);\n createTiddlyButton(navigator,lingo.firstSlide.text,lingo.firstSlide.tooltip,first_slide);\n createTiddlyButton(navigator,lingo.previousSlide.text,lingo.previousSlide.tooltip,previous_slide);\n createTiddlyButton(navigator,lingo.nextSlide.text,lingo.nextSlide.tooltip,next_slide);\n createTiddlyButton(navigator,lingo.lastSlide.text,lingo.lastSlide.tooltip,last_slide); \n\n var clock = createTiddlyElement(navigator,"SPAN","slideClock","slideClock","");\n clock.onclick = resetClock;\n\n var indexNumbers = createTiddlyElement(pagefooter,"SPAN","indexNumbers","indexNumbers","1/"+slideNumber)\n indexNumbers.onclick = showHideTOC;\n\n var toc = createTiddlyElement(pagefooter,"UL","toc");\n\n \n for (var i=0;i<slideHolder.childNodes.length;i++) {\n //Loop through each slide and check the header's content\n var tocLabel = null;\n\n if(slideHolder.childNodes[i].firstChild.hasChildNodes()){\n var htstring = slideHolder.childNodes[i].firstChild.innerHTML;\n var stripped = htstring.replace(/(<([^>]+)>)/ig,""); \n tocLabel = abbreviateLabel(stripped);\n } else if (newParams['tocLabel'] != null){\n j=i+1;\n tocLabel = eval(newParams['tocLabel'])+" "+j;\n }\n \n //If the slide doesn't have a title (explicit or generated) don't include it in the table of contents\n if (tocLabel != null){\n var tocItem = createTiddlyElement(toc,"LI",null,"tocLevel1");\n var tocLink = createTiddlyElement(tocItem,"A",null,"tocItem",tocLabel);\n tocLink.setAttribute("slideNumber",i);\n tocLink.onclick=tocShowSlide; \n }\n \n\n for (var j=1;j<slideHolder.childNodes[i].childNodes.length;j++) {\n var node = slideHolder.childNodes[i].childNodes[j];\n if(node.nodeName=="H2" || node.nodeName=="H3" || node.nodeName=="H4") {\n var htstring = node.innerHTML;\n var stripped = htstring.replace(/(<([^>]+)>)/ig,"");\n tocLabel = abbreviateLabel(stripped);\n switch (node.nodeName) {\n case "H2":\n var tocItem = createTiddlyElement(toc,"LI",null,"tocLevel2");\n break;\n case "H3":\n var tocItem = createTiddlyElement(toc,"LI",null,"tocLevel3");\n break;\n case "H4":\n var tocItem = createTiddlyElement(toc,"LI",null,"tocLevel4");\n }\n var tocLink = createTiddlyElement(tocItem,"A",null,"tocItem",tocLabel);\n tocLink.setAttribute("slideNumber",i);\n tocLink.onclick=tocShowSlide;\n }\n }\n }\n \n\n //Input box to jump to s specific slide\n var tocItem = createTiddlyElement(toc,"LI",null,"tocJumpItem",config.macros.slideShow.messages.gotoLabel);\n var tocJumpInput = createTiddlyElement(tocItem,"INPUT","jumpInput");\n tocJumpInput.type="text";\n tocJumpInput.onkeyup=jumpInputToSlide;\n}\n\nvar next_slide= function(e){GoToSlide(1);}\nvar first_slide= function(e){GoToSlide("f");}\nvar previous_slide= function(e){GoToSlide(-1);}\nvar last_slide= function(e){GoToSlide("l");}\n\nfunction toggleSlideStyles(){\n var contentWrapper = document.getElementById('contentWrapper');\n if (contentWrapper.className == "slideShowMode"){\n contentWrapper.className = "";\n if(slideShowStyleSheet) changeStyleSheet();\n } else{\n contentWrapper.className = "slideShowMode";\n if(slideShowStyleSheet) changeStyleSheet(slideShowStyleSheet);\n }\n}\n\nsetStylesheet("/***\sn!Slide Mode Styles\sn***/\sn/*{{{*/\sn#contentWrapper.slideShowMode #slideContainer{\sn display: block;\sn}\sn\sn#jump{\sn text-align: right;\sn}\sn\sn.pageFooterOff #navigator{\sn visibility: hidden;\sn}\sn\sn.pageFooterOn #navigator{\sn visibility: visible;\sn}\sn\sn#contentWrapper.slideShowMode #slideClock{\sn cursor: pointer; margin: 0 5px 0 5px; border: 1px solid #db4\sn}\sn\sn#contentWrapper.slideShowMode,\sn #contentWrapper.slideShowMode #displayArea{\sn width: 100%;\sn font-size: 1.5em;\sn margin: 0;\sn padding: 0;\sn}\sn\sn#slideContainer{\sn display: none;\sn}\sn\sn#contentWrapper.slideShowMode #sidebar,\sn#contentWrapper.slideShowMode #mainMenu,\sn#contentWrapper.slideShowMode .header,\sn#contentWrapper.slideShowMode #displayArea .toolbar,\sn#contentWrapper.slideShowMode #displayArea .footer,\sn#contentWrapper.slideShowMode #displayArea .subtitle,\sn#contentWrapper.slideShowMode #displayArea .tagged,\sn#contentWrapper.slideShowMode #displayArea .tagging\sn{\sn display:none;\sn}\sn\sn.indexNumbers{\sn cursor: pointer;\sn}\sn\sn#navigator{\sn visibility: hidden;\sn bottom: 0;\sn}\sn\sn#toc{\sn display: none;\sn position: absolute;\sn font-size: .75em;\sn bottom: 2em;\sn right: 0;\sn background: #fff;\sn border: 1px solid #000;\sn text-align: left;\sn}\sn\snul#toc, #toc li{\sn margin: 0;\sn padding: 0;\sn list-style: none;\sn line-height: 1em;\sn}\sn\sn.tocJumpItem{\sn margin-right: 2em;\sn}\sn\sn.tocJumpItem input{\snmargin-right: 1em;\sn border: 0;\sn}\sn\sn#toc a,\sn#toc a.button{\sn display: block;\sn padding: .1em;\sn}\sn\sn#toc .tocLevel1{\snfont-size: .8em;\sn}\sn\sn#toc .tocLevel2{\sn margin-left: 1em;\sn font-size: .75em;\sn}\sn\sn#toc .tocLevel3{\sn margin-left: 2em;\snfont-size: .75em;\sn}\sn\sn#toc .tocLevel4{\sn margin-left: 3em;\snfont-size: .65em;\sn}\sn\sn#toc a{\sn cursor: pointer;\sn}\sn\snh1{\sn min-height: 1em;\sn}\sn\sn.slide h1{\sn min-height: 0;\sn}\sn\sn/* The '>' selector is ignored by IE6 and earlier so the proper rules are given */\sn#pageFooter{\sn position: fixed;\sn bottom: 2px;\sn right: 2px;\sn width: 100%;\sn text-align: right;\sn}\sn\sn/* This is a hack to trick IE6 and earlier to put the navbar on the bottom of the page */\sn* html #pageFooter {\sn position: absolute;\sn width: 100%;\sn text-align: right;\sn right: auto; bottom: auto;\sn left: expression( ( -20 - pageFooter.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\sn top: expression( ( -10 - pageFooter.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\sn}\sn\sn\sn\sn/*}}}*/","slideShowStyles");\n//}}}
/***\n!Devfire\nStyle by Clint Checketts (http://www.checkettsweb.com) for TiddlyWiki 2.0\nInspired by the GLP'd Darkfire Wordpress skin.\n\n!Sections in this Tiddler:\n*Generic rules\n*Links styles\n*Header\n*Main menu\n*Sidebar\n**Sidebar options\n**Sidebar tabs\n*Message area\n*Popup\n*Tabs\n*Tiddler display\n**Viewer\n**Editor\n*Misc. rules\n!Generic rules /% ============================================================= %/\n***/\n/*{{{*/\nbody {\nbackground-color: #000;\n}\n/*}}}*/\n/***\n!Link styles /% ============================================================= %/\n***/\n/*{{{*/\na,\na.button,\n#mainMenu a.button,\n#sidebarOptions .sliderPanel a{\n color: #ffbf00;\n border: 0;\n}\n\na:hover,\na.button:hover,\n#mainMenu a.button:hover,\n#sidebarOptions .sliderPanel a:hover\n#sidebarOptions .sliderPanel a:active{\n color: #ff7f00;\n border: 0;\n border-bottom: #ff7f00 1px dashed;\n background: transparent;\n text-decoration: none;\n}\n\n#displayArea .button.highlight{\n color: #ffbf00;\n background: #4c4c4c;\n}\n/*}}}*/\n/***\n!Header styles /% ============================================================= %/\n***/\n/*{{{*/\n.header{\n border-bottom: 2px solid #ffbf00;\n color: #fff;\n}\n\n.headerForeground a {\n color: #fff;\n}\n\n.header a:hover {\n border-bottom: 1px dashed #fff;\n}\n/*}}}*/\n/***\n!Main menu styles /% ============================================================= %/\n***/\n/*{{{*/\n#mainMenu {color: #fff;}\n#mainMenu h1{\n font-size: 1.1em;\n}\n#mainMenu li,#mainMenu ul{\n list-style: none;\n margin: 0;\n padding: 0;\n}\n/*}}}*/\n/***\n!Sidebar styles /% ============================================================= %/\n***/\n/*{{{*/\n#sidebar {\n right: 0;\n color: #fff;\n border: 2px solid #ffbf00;\n border-width: 0 0 2px 2px;\n}\n#sidebarOptions {\n background-color: #4c4c4c;\n padding: 0;\n}\n\n#sidebarOptions a{\n margin: 0;\n color: #ffbf00;\n border: 0;\n}\n#sidebarOptions a:hover {\n color: #4c4c4c;\n background-color: #ffbf00;\n\n}\n\n#sidebarOptions a:active {\n color: #ffbf00;\n background-color: transparent;\n}\n\n#sidebarOptions .sliderPanel {\n background-color: #333;\n margin: 0;\n}\n\n#sidebarTabs {background-color: #4c4c4c;}\n#sidebarTabs .tabSelected {\n padding: 3px 3px;\n cursor: default;\n color: #ffbf00;\n background-color: #666;\n}\n#sidebarTabs .tabUnselected {\n color: #ffbf00;\n background-color: #5f5f5f;\n padding: 0 4px;\n}\n\n#sidebarTabs .tabUnselected:hover,\n#sidebarTabs .tabContents {\n background-color: #666;\n}\n\n.listTitle{color: #FFF;}\n#sidebarTabs .tabContents a{\n color: #ffbf00;\n}\n\n#sidebarTabs .tabContents a:hover{\n color: #ff7f00;\n background: transparent;\n}\n\n#sidebarTabs .txtMoreTab .tabSelected,\n#sidebarTabs .txtMoreTab .tab:hover,\n#sidebarTabs .txtMoreTab .tabContents{\n color: #ffbf00;\n background: #4c4c4c;\n}\n\n#sidebarTabs .txtMoreTab .tabUnselected {\n color: #ffbf00;\n background: #5f5f5f;\n}\n\n.tab.tabSelected, .tab.tabSelected:hover{color: #ffbf00; border: 0; background-color: #4c4c4c;cursor:default;}\n.tab.tabUnselected {background-color: #666;}\n.tab.tabUnselected:hover{color:#ffbf00; border: 0;background-color: #4c4c4c;}\n.tabContents {\n background-color: #4c4c4c;\n border: 0;\n}\n.tabContents .tabContents{background: #666;}\n.tabContents .tabSelected{background: #666;}\n.tabContents .tabUnselected{background: #5f5f5f;}\n.tabContents .tab:hover{background: #666;}\n/*}}}*/\n/***\n!Message area styles /% ============================================================= %/\n***/\n/*{{{*/\n#messageArea {background-color: #666; color: #fff; border: 2px solid #ffbf00;}\n#messageArea a:link, #messageArea a:visited {color: #ffbf00; text-decoration:none;}\n#messageArea a:hover {color: #ff7f00;}\n#messageArea a:active {color: #ff7f00;}\n#messageArea .messageToolbar a{\n border: 1px solid #ffbf00;\n background: #4c4c4c;\n}\n/*}}}*/\n/***\n!Popup styles /% ============================================================= %/\n***/\n/*{{{*/\n#popup {color: #fff; background-color: #4c4c4c; border: 1px solid #ffbf00;}\n#popup a {color: #ffbf00; }\n#popup a:hover { background: transparent; color: #ff7f00; border: 0;}\n#popup hr {color: #ffbf00; background: #ffbf00;}\n/*}}}*/\n/***\n!Tiddler Display styles /% ============================================================= %/\n***/\n/*{{{*/\n.title{color: #fff;}\nh1, h2, h3, h4, h5 {\n color: #fff;\n background-color: transparent;\n border-bottom: 1px solid #333;\n}\n\n.subtitle{\n color: #666;\n}\n\n.viewer {color: #fff; }\n\n.viewer table{background: #666; color: #fff;}\n\n.viewer th {background-color: #996; color: #fff;}\n\n.viewer pre, .viewer code {color: #ddd; background-color: #4c4c4c; border: 1px solid #ffbf00;}\n\n.viewer hr {color: #666;}\n\n.tiddler .button {color: #4c4c4c;}\n.tiddler .button:hover { color: #ffbf00; background-color: #4c4c4c;}\n.tiddler .button:active {color: #ffbf00; background-color: #4c4c4c;}\n\n.toolbar {\n color: #4c4c4c;\n}\n\n.toolbar a.button,\n.editorFooter a{\n border: 0;\n}\n\n.footer {\n color: #ddd;\n}\n\n.selectedTiddler .footer {\n color: #888;\n}\n\n.highlight, .marked {\n color: #000;\n background-color: #ffe72f;\n}\n.editorFooter {\n color: #aaa;\n}\n\n.tab{\n-moz-border-radius-topleft: 3px;\n-moz-border-radius-topright: 3px;\n}\n\n.tagging,\n.tagged{\n background: #4c4c4c;\n border: 1px solid #4c4c4c; \n}\n\n.selected .tagging,\n.selected .tagged{\n background: #000;\n border: 1px solid #ffbf00;\n}\n\n.tagging .listTitle,\n.tagged .listTitle{\n color: #fff;\n}\n\n.tagging .button,\n.tagged .button{\n color: #ffbf00;\n border: 0;\n padding: 0;\n}\n\n.tagging .button:hover,\n.tagged .button:hover{\nbackground: transparent;\n}\n\n.cascade {\n background: #4c4c4c;\n color: #ddd;\n border: 1px solid #ffbf00;\n}\n/*}}}*/
Web 2.5 Technology. I contribute to this project. More info can be found at http://www.TiddlyWiki.com
|!Date|!url|!toFilename|!backupDir|!user|!status|\n| 28/1/2006 15:28:55 | [[store.php|http://www.checkettsweb.com/store.php]] | [[index.htm|http://www.checkettsweb.com/index.htm]] | backups | Clint Checketts | ok |\n| 28/1/2006 15:31:59 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 28/1/2006 15:35:10 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 28/1/2006 15:36:13 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 28/1/2006 15:37:1 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 28/1/2006 15:37:38 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 28/1/2006 18:28:5 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 28/1/2006 18:29:24 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 28/1/2006 18:30:10 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts |\n| 31/1/2006 12:53:7 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 31/1/2006 12:54:55 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 31/1/2006 13:56:12 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | YourName |\n| 3/2/2006 20:42:31 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts | ok |\n| 3/2/2006 22:1:17 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts |\n| 27/2/2006 11:20:45 | [[store.php|http://www.checkettsweb.com/ruby/store.php]] | [[index.htm|http://www.checkettsweb.com/ruby/index.htm]] | backups | Clint Checketts |
/***\n\n\n----\nUploadPlugin, with [[store.php]] and [[.htaccess]] provide the @@upload@@ and the @@save to web@@ functions. See HowToUpload.\nThe french translation available as a separate tiddler UploadPluginMsgFR\n----\n\n\n***/\n\n/***\n|''Name:''|UploadPlugin|\n|''Type:''|Plugin|\n|''Version:''|3.0.3 (03/02/2006)|\n|''Source:''|[[TiddlyWiki.BidiX.info|http://tiddlywiki.BidiX.info/#UploadPlugin]]|\n|''Author:''|BidiX[at]BidiX.info|\n|''Compatibility:''|TW1.2 & TW2|\n!Usage : \n{{{\n<<upload storeUrl [toFilename [backupDir]]>>\n storeUrl : the url of the store.php to POST the TiddlyWiki\n toFilename : the filename in the storeUrl directory\n backupDir : if present backup the previous toFilename file\n to the backupDir directory\n}}}\n\nInstall the {{{<<upload ... >>}}} macro in SideBarOptions just below the {{{<<saveChanges>>}}} macro.\n\n!Description\n!!Plugin\n*If the TiddlyWiki came from @@local disk@@ :\n**{{{<<saveChanges>>}}} \n***display as ''save to disk''\n***work as usual\n**{{{<<upload ...>>}}}\n***display as ''upload''\n***after saving to disk, upload in the storeUrl directory.\n*If the TiddlyWiki came from @@website@@ :\n**{{{<<saveChanges>>}}} \n***print nothing\n***has been disabled\n**{{{<<upload ...>>}}}\n***display as '''save to web''\n***save in the storeUrl directory.\n*If GenerateAnRssFeed is set :\n**generate the content of the RSSFeed \n**upload the RssFile\n**Caution : use the SiteUrl tiddler to specify url of the TiddlyWiki in the generated RssFile\n*DisplayMessage\n*Log upload in UploadLog\nhint : if UploadLog is the first tiddler in the Timeline Tab, no tiddler has been updated since last upload.\n\n!!store.php\n*method GET\n**display an information page\n*method POST\n**if toFilename already exists and backDir parameter specified\n***rename toFilename to backupDir/toFilename.AAAAMMDD.HHSS.html\n**copy temporaryUploadedFile to toFilename\n** return status\n!User manual\nSee HowToUpload\n!Installation :\n*Install the UploadPlugin as usual\n*Upload the [[store.php]] file on your php aware webserver in your TiddlyWiki directory\n*Protect your directory : \n**for Apache web server ([[for detail see Apache documentation|http://httpd.apache.org/docs/1.3/howto/htaccess.html]]) : \n***configure the [[.htaccess]] :\n****Set the /full/path/from/root/to/your/.passwd file\n****<limit xxx> :\n*****For a private access to your TiddlyWiki directory set ''<limit GET POST>''\n*****For a public access to your TiddlyWiki files, but a private uploading facility set ''<limit POST>''\n***Upload [[.passwd]] and [[.htaccess]] files\n**for other web servers see the appropriate documentation\n*Configure an upload button, for example in the SideBarOptions\n!Suppported Browser\n*Firefox : Ok\n*Internet Explorer : Ok\n*Others : Not tested, please report status.\n\n!Revision history\n* v1.0.0 (17-Dec-2005)\n** first public working version\n*v1.0.1 (23-Dec-2005)\n**reformatting code\n*v1.0.2 (24-Dec-2005)\n**Optional parameter toFilename\n**Optional parameter backupDir\n*v1.0.3 (26-Dec-2005)\n**UploadLog tiddler\n*v1.1.0 (27-Dec-2005)\n**Upload RSS File\n*V2.0.0 (3-Jan-2006)\n**Save to web\n**Compatibilty with TiddlyWiki 1.2.39 and TiddlyWiki 2.0.0 Beta 6\n*V2.0.1 (8-Jan-2006)\n**Compatibilty with TiddlyWiki 2.0.1\n*V2.0.2 (8-Jan-2006)\n**SiteTitle and SiteSubtitle in web page Title\n*V3.0.0 (15-Jan-2006)\n**Asynchronous upload\n**Synchronous upload before unload of the page\n**All strings extracted in macro config\n**Compatibility checked with TW 2.0.2 & TW 1.2.39 for both FF 1.5 and IE 6\n*V3.0.1 (18-Jan-2006)\n**UTF8toUnicode conversion problem in Firefox\n*V3.0.2 (25-Jan-2006)\n**HTTPS compatible\n*V3.0.3 (03/02/2006)\n**Firefox 1.5.0.1 crashes due to global var fixed\n\n!Code\n***/\n//{{{\nversion.extensions.UploadPlugin = {major: 3, minor: 0, revision: 3, date: new Date(2006,2,3)};\n\n//\n// Upload Macro\n//\n\nconfig.macros.upload = {\n label: "upload", \n saveLabel: "save to web", \n prompt: "Save and Upload this TiddlyWiki in ", \n accessKey: "U",\n formName: "UploadPlugin",\n contentType: "text/html;charset=UTF-8",\n defaultStoreScript: "store.php"\n};\n\n// only this config need to be translated\nconfig.macros.upload.messages = {\n aboutToUpload: "About to upload TiddlyWiki to %0",\n errorDownloading: "Error downloading",\n errorUploadingContent: "Error uploading content",\n fileNotFound: "file to upload not found",\n fileNotUploaded: "File %0 NOT uploaded",\n label: "upload", \n mainFileUploaded: "Main TiddlyWiki file uploaded to %0",\n prompt: "Save and Upload this TiddlyWiki in ", \n urlParamMissing: "url param missing",\n rssFileNotUploaded: "RssFile %0 NOT uploaded",\n rssFileUploaded: "Rss File uploaded to %0",\n saveLabel: "save to web", \n saveToDisk: "save to disk"\n};\n\nconfig.macros.upload.label = config.macros.upload.messages.label; \nconfig.macros.upload.saveLabel = config.macros.upload.messages.saveLabel; \nconfig.macros.upload.prompt = config.macros.upload.messages.prompt;\n\n\nconfig.macros.upload.handler = function(place,macroName,params){\n var url;\n if (params[0]) {\n url = params[0];\n this.defaultStoreScript = basename(url);\n }\n else\n url = dirname(document.location.toString())+"/"+ this.defaultStoreScript;\n var toFilename=params[1];\n var backupDir=params[2];\n var label;\n if (document.location.toString().substr(0,4) == "http")\n label = this.saveLabel;\n else\n label = this.label;\n createTiddlyButton(place, label, this.prompt+dirname(url), \n function () {upload(url, toFilename, backupDir, true); return false;}, \n null, null, this.accessKey);\n};\n\n//\n// TiddlyWiki Core patches\n//\n\n// overwrite the saveChanges handler \n// configure no Macro instead of saveChanges Macro in case of http: access\nconfig.macros.saveChanges.label = config.macros.upload.messages.saveToDisk;\nconfig.macros.saveChanges.handler = function(place,macroName,params)\n{\n if(!readOnly) {\n if (document.location.toString().substr(0,4) != "http") \n createTiddlyButton(place,this.label,this.prompt,function () {saveChanges(); return false;},null,null,this.accessKey);\n // else no TiddlyButton\n }\n}\n\n// Check if there is any unsaved changes before exiting\n// if unsaved changes : saveOrUpload\n//function checkUnsavedChanges()\ncheckUnsavedChanges = function ()\n{\n if(store && store.dirty) {\n if(confirm(config.messages.unsavedChangesWarning))\n saveOrUpload(false); // Because called by <body onunload=... Upload must be synchronous\n }\n}\n\n//\n// Utility functions \n//\n\nfunction dirname(filePath)\n{\n if ((lastpos = filePath.lastIndexOf("/")) != -1)\n return filePath.substring(0, lastpos);\n else\n return filePath.substring(0, filePath.lastIndexOf("\s\s"));\n}\n\nfunction basename(filePath)\n{\n if ((lastpos = filePath.lastIndexOf("#")) != -1) \n filePath = filePath.substring(0, lastpos);\n if ((lastpos = filePath.lastIndexOf("/")) != -1)\n return filePath.substring(lastpos + 1);\n else\n return filePath.substring(filePath.lastIndexOf("\s\s")+1);\n}\n\n// TiddlyWiki utilities\n\nfunction getLocalPath() {\n //extract from the Jeremy's SaveFile \n var originalPath = document.location.toString();\n // Check we were loaded from a file URL\n if(originalPath.substr(0,5) != "file:")\n {\n alert(config.messages.notFileUrlError);\n displayTiddler(null,"SaveChanges",0,null,null,false,false);\n return;\n }\n // Remove any location part of the URL\n var hashPos = originalPath.indexOf("#");\n if(hashPos != -1)\n originalPath = originalPath.substr(0,hashPos);\n // Convert to a native file format assuming\n // "file:///x:/path/path/path..." - pc local file --> "x:\spath\spath\spath..."\n // "file://///server/share/path/path/path..." - FireFox pc network file --> "\s\sserver\sshare\spath\spath\spath..."\n // "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."\n // "file://server/share/path/path/path..." - pc network file --> "\s\sserver\sshare\spath\spath\spath..."\n var localPath;\n if(originalPath.charAt(9) == ":") // pc local file\n localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\s\s");\n else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file\n localPath = "\s\s\s\s" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\s\s");\n else if(originalPath.indexOf("file:///") == 0) // mac/unix local file\n localPath = unescape(originalPath.substr(7));\n else if(originalPath.indexOf("file:/") == 0) // mac/unix local file\n localPath = unescape(originalPath.substr(5));\n else // pc network file\n localPath = "\s\s\s\s" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\s\s");\n return localPath;\n}\n\n//\n// LogUpload\n//\n\nfunction getLogUploadTiddler() {\n var tiddler;\n if (version.major < 2)\n tiddler = store.tiddlers['UploadLog'];\n else\n tiddler = store.getTiddler("UploadLog");\n if (!tiddler) \n {\n tiddler = new Tiddler();\n tiddler.title = 'UploadLog';\n tiddler.text = "|!Date|!url|!toFilename|!backupDir|!user|!status|";\n if (version.major < 2)\n store.tiddlers['UploadLog'] = tiddler;\n else\n store.addTiddler(tiddler);\n }\n return tiddler;\n}\n\nfunction logUpload(url, toFilename, backupDir) \n{\n var tiddler = getLogUploadTiddler();\n var now = new Date();\n var newText = "| ";\n //newText += now.toLocaleString() + " | ";\n \n newText += now.getDate()+"/"+(now.getMonth()+1)+"/"+now.getFullYear() + " ";\n newText += now.getHours()+":"+now.getMinutes()+":"+now.getSeconds()+" | ";\n newText += "[["+basename(url)+"|"+url + "]] | ";\n newText += "[["+basename(toFilename) + "|" + dirname(url)+"/"+basename(toFilename) + "]] | ";\n newText += backupDir + " | ";\n newText += config.options.txtUserName + " |";\n\n tiddler.text = tiddler.text + "\sn" + newText;\n tiddler.modifier = config.options.txtUserName;\n tiddler.modified = new Date();\n if (version.major < 2)\n store.tiddlers['UploadLog'] = tiddler;\n else\n store.addTiddler(tiddler);\n //displayTiddler(document.getElementById('sidebar'),"UploadLog",1,null,null,false);\n if (version.major < 2)\n store.notifyAll();\n}\n\nfunction logUploadStatusOk() \n{\n var tiddler = getLogUploadTiddler();\n var newText = " ok |";\n tiddler.text = tiddler.text + newText;\n tiddler.modifier = config.options.txtUserName;\n tiddler.modified = new Date();\n if (version.major < 2)\n store.tiddlers['UploadLog'] = tiddler;\n else\n store.addTiddler(tiddler);\n //displayTiddler(document.getElementById('sidebar'),"UploadLog",1,null,null,false);\n if (version.major < 2)\n store.notifyAll();\n store.notify('UploadLog',true);\n}\n\n//\n// download file before save it\n// \n\nfunction download(uploadUrl, uploadToFilename, uploadBackupDir, asynchronous) {\n var request;\n try {\n request = new XMLHttpRequest();\n } \n catch (e) { \n request = new ActiveXObject("Msxml2.XMLHTTP"); \n }\n try {\n if (uploadUrl.substr(0,4) == "http") {\n netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");\n }\n else {\n netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");\n }\n } catch (e) { }\n\n request.open("GET",document.location.toString(), asynchronous);\n if (asynchronous) {\n request.onreadystatechange = function () {\n if (request.readyState == 4) {\n if(request.status == 200) {\n uploadChangesFrom(uploadUrl, uploadToFilename, uploadBackupDir, request.responseText, asynchronous);\n }\n else\n alert(config.macros.upload.messages.errorDownloading.format([document.location.toString()]));\n }\n }\n }\n request.send(null);\n if (! asynchronous) {\n if(request.status == 200) {\n uploadChangesFrom(uploadUrl, uploadToFilename, uploadBackupDir, request.responseText, asynchronous);\n }\n else\n alert(config.macros.upload.messages.errorDownloading.format([document.location.toString()]));\n }\n\n}\n\n// saveOrUpload\n\nfunction saveOrUpload(asynchronous) {\n if (document.location.toString().substr(0,4) == "http") {\n // try a default synchronous upload\n var url = dirname(document.location.toString())+"/"+ config.macros.upload.defaultStoreScript;\n upload(url, null, null, asynchronous);\n }\n else \n saveChanges();\n}\n\n//\n//Upload\n//\n\nfunction upload(url, toFilename, backupDir, asynchronous)\n{\n clearMessage();\n // only for forcing the message to display\n if (version.major < 2)\n store.notifyAll();\n if (url == null) {\n alert(config.macros.upload.messages.urlParamMissing);\n return;\n }\n if (backupDir == null)\n backupDir = '';\n var toPath;\n if (toFilename)\n toPath = toFilename;\n else {\n toPath = basename(document.location.toString());\n }\n logUpload(url, toPath, backupDir);\n if (document.location.toString().substr(0,5) == "file:") {\n saveChanges();\n }\n displayMessage(config.macros.upload.messages.aboutToUpload.format([dirname(url)]), dirname(url));\n uploadChanges(url, toPath, backupDir, asynchronous);\n if(config.options.chkGenerateAnRssFeed) {\n //var rssContent = convertUnicodeToUTF8(generateRss());\n var rssContent = generateRss();\n var rssPath = toPath.substr(0,toPath.lastIndexOf(".")) + ".xml";\n uploadContent(url, rssContent, rssPath, '', asynchronous, function (responseText) {\n if (responseText.substring(0,1) != 0) {\n alert(responseText);\n displayMessage(config.macros.upload.messages.rssFileNotUploaded.format([rssPath]));\n }\n else {\n displayMessage(config.macros.upload.messages.rssFileUploaded.format([dirname(url)+"/"+basename(rssPath)]), dirname(url)+"/"+basename(rssPath));\n }\n // for debugging store.php uncomment last line\n //DEBUG alert(responseText);\n }\n );\n }\n return;\n}\n\nfunction uploadChanges(url, toFilename, backupDir, asynchronous)\n{\n var original;\n if (document.location.toString().substr(0,4) == "http") {\n original = download(url, toFilename, backupDir, asynchronous);\n return;\n }\n else {\n // standard way : Local file\n original = loadFile(getLocalPath());\n if(window.Components)\n // it's a mozilla browser\n try {\n netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");\n var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]\n .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);\n converter.charset = /* The character encoding you want, using UTF-8 here */ "UTF-8";\n original = converter.ConvertToUnicode(original);\n }\n catch(e) {\n }\n }\n //DEBUG alert(original);\n uploadChangesFrom(url, toFilename, backupDir, original, asynchronous);\n}\n\nfunction uploadChangesFrom(url, toFilename, backupDir, original, asynchronous)\n{\n\n var startSaveArea = '<div id="' + 'storeArea">'; // Split up into two so that indexOf() of this source doesn't find it\n var endSaveArea = '</d' + 'iv>';\n // Locate the storeArea div's\n var posOpeningDiv = original.indexOf(startSaveArea);\n var posClosingDiv = original.lastIndexOf(endSaveArea);\n if((posOpeningDiv == -1) || (posClosingDiv == -1))\n {\n alert(config.messages.invalidFileError.format([document.location.toString()]));\n return;\n }\n // I think conversion is automatically done\n //var revised = original.substr(0,posOpeningDiv + startSaveArea.length) + \n // convertUnicodeToUTF8(allTiddlersAsHtml()) + "\sn\st\st" +\n // original.substr(posClosingDiv);\n \n var revised = original.substr(0,posOpeningDiv + startSaveArea.length) + \n allTiddlersAsHtml() + "\sn\st\st" +\n original.substr(posClosingDiv);\n\n // I think conversion is automatically done\n // var newSiteTitle = convertUnicodeToUTF8((getElementText("siteTitle") + " - " + getElementText("siteSubtitle")).htmlEncode());\n var newSiteTitle;\n if(version.major < 2){ //version is set in core TW code\n newSiteTitle = (getElementText("siteTitle") + " - " + getElementText("siteSubtitle")).htmlEncode();\n } else {\n newSiteTitle = (wikifyPlain ("SiteTitle") + " - " + wikifyPlain ("SiteSubtitle")).htmlEncode();\n }\n revised = revised.replace(new RegExp("<title>[^<]*</title>", "im"),"<title>"+ newSiteTitle +"</title>");\n var response = uploadContent(url, revised, toFilename, backupDir, asynchronous, function (responseText) {\n if (responseText.substring(0,1) != 0) {\n alert(responseText);\n displayMessage(config.macros.upload.messages.fileNotUploaded.format([getLocalPath()]));\n }\n else {\n displayMessage(config.macros.upload.messages.mainFileUploaded.format([dirname(url)+"/"+basename(toFilename)]), dirname(url)+"/"+basename(toFilename));\n logUploadStatusOk();\n store.setDirty(false);\n }\n // for debugging store.php uncomment last line\n //DEBUG alert(responseText);\n }\n );\n}\n\nfunction uploadContent(url, content, toPath, backupDir, asynchronous, callbackFn) {\n var boundary = "---------------------------"+"AaB03x";\n //Create XMLHttpRequest Object\n var request;\n try {\n request = new XMLHttpRequest();\n } \n catch (e) { \n request = new ActiveXObject("Msxml2.XMLHTTP"); \n }\n try {\n // Needed for Mozilla if local file tries to access an http URL\n if (document.location.toString().substr(0,4) == "http") {\n netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");\n }\n else {\n netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");\n }\n } catch (e) { }\n // compose headers data\n var sheader = "\sr\sn";\n sheader += "--" + boundary + "\sr\snContent-disposition: form-data;name=\s"" + config.macros.upload.formName +"\s"\sr\sn\sr\sn";\n sheader += "backupDir="+backupDir+";user=" + config.options.txtUserName + "\sr\sn"; \n sheader += "\sr\sn" + "--" + boundary + "\sr\sn";\n sheader += "Content-disposition: form-data;name=\s"userfile\s";filename=\s""+toPath+"\s"\sr\sn";\n sheader += "Content-Type: " + config.macros.upload.contentType + "\sr\sn";\n sheader += "Content-Length: " + content.length + "\sr\sn\sr\sn";\n // compose trailer data\n var strailer = new String();\n strailer = "\sr\sn--" + boundary + "--\sr\sn";\n var data;\n data = sheader + content + strailer;\n request.open("POST",url,asynchronous);\n if (asynchronous) {\n request.onreadystatechange = function () {\n if (request.readyState == 4) {\n if(request.status == 200)\n callbackFn(request.responseText);\n else\n alert(config.macros.upload.messages.errorUploadingContent);\n }\n };\n }\n request.setRequestHeader("Content-Length",data.length);\n request.setRequestHeader("Content-Type","multipart/form-data; boundary="+boundary);\n request.send(data); \n if (! asynchronous) {\n if(request.status == 200)\n callbackFn(request.responseText);\n else\n alert(config.macros.upload.messages.errorUploadingContent);\n }\n\n}\n\n//}}}
<div class='header' macro='gradient vert #390108 #900'>\n<div class='headerShadow'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> \n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n<div class='headerForeground'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> \n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n</div>\n<div id='mainMenu'>\n<div refresh='content' tiddler='MainMenu'></div>\n</div>\n<div id='sidebar'>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n<div id='messageArea'></div>\n<div id='tiddlerDisplay'></div>\n</div>
/***\n!WebTemplatePlugin with ViewSourcePlugin and 404TiddlerPlugin\n''Version'': 0.3 (19 Jan 2006)\n''Author'': Clint Checketts\n\n!Instructions\nWebPageTemplate\nWebViewTemplate\nWebEditTemplate\n\n!Code\n***/\n//{{{\nconfig.options.chkHttpReadOnly = true;\nreadOnly = (document.location.toString().substr(0,4) == "http") ? config.options.chkHttpReadOnly : false;\n\nconfig.shadowTiddlers['WebPageTemplate'] = config.shadowTiddlers['PageTemplate'];\nconfig.shadowTiddlers['WebViewTemplate'] = "<!--{{{-->\sn<div class='toolbar' macro='toolbar closeTiddler permalink +viewSource'></div>\sn<div class='title' macro='view title'></div>\sn<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date [[DD MMM YYYY]]'></span> (created <span macro='view created date [[DD MMM YYYY]]'></span>)</div>\sn<div class='tagging' macro='tagging'></div>\sn<div class='tagged' macro='tags'></div>\sn<div class='viewer' macro='view text wikified'></div>\sn<div class='tagClear'></div>\sn<!--}}}-->";\nconfig.shadowTiddlers['WebEditTemplate'] = "<!--{{{-->\sn<div class='toolbar' macro='toolbar -cancelTiddler'></div>\sn<div class='title'><span macro='view title'></span> (source code)</div>\sn<div class='editor' macro='edit text'></div>\sn<!--}}}-->\sn";\n\nif(readOnly){ \n showWebView();\n}\n\nwindow.applyPageTemplateWebTemplate = window.applyPageTemplate;\nwindow.applyPageTemplate = function(title){\n if(readOnly && store.tiddlerExists('WebPageTemplate')) title = 'WebPageTemplate';\n applyPageTemplateWebTemplate(title);\n}\n\nfunction showWebView(){\n config.tiddlerTemplates[1] = "WebViewTemplate";\n config.tiddlerTemplates[2] = "WebEditTemplate";\n}\n\nconfig.macros.testWebView = {}\nconfig.macros.testWebView.handler = function(place,macroName,params)\n{\n createTiddlyButton(place,"ToggleWebTemplates","Toggle the web mode",toggleWebView);\n}\n\nvar toggleWebView = function(){\n readOnly = !readOnly;\n if(readOnly){\n showWebView();\n } else {\n config.tiddlerTemplates[1] = "ViewTemplate";\n config.tiddlerTemplates[2] = "EditTemplate";\n }\n store.notifyAll();\n}\n//}}}\n/***\n!View Source Plugin\n***/\n//{{{\nvar viewSourceSelectAllByDefault = true;\n\nconfig.commands.viewSource = {text: "view source", tooltip: "View this tiddler's wiki markup"},\nconfig.commands.viewSource.handler = function(event,src,title){\n clearMessage();\n story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE);\n\n var theTiddler = document.getElementById("tiddler"+title);\n var tiddlerElements = theTiddler.getElementsByTagName("textarea")\n\n for (var i = 0; i < tiddlerElements.length; i++){\n tiddlerElements[i].setAttribute("readonly","readonly");\n }\n\n if (tiddlerElements.length > 0){\n tiddlerElements[0].focus();\n if (viewSourceSelectAllByDefault) tiddlerElements[0].select();\n }\n return false;\n}\n//}}}\n/***\n!404 Tiddler Plugin\n***/\n//{{{\n//config.shadowTiddlers['404 Error'] = "The tiddler you were looking for doesn't exist.\sn\snTry a <<search>> for the information you were looking for.";\nconfig.shadowTiddlers['404Template'] = "<div class='toolbar' macro='toolbar -closeTiddler closeOthers'></div><div class='title'>404 Error: <span macro='view title'></span></div><div class='viewer'>The page '<span macro='view title'></span>' doesn't exist.<br /><br />Try a <span macro='search'></span> for the information you were looking for.</div>";\n\n\nStory.prototype.displayTiddler404 = Story.prototype.displayTiddler;\nStory.prototype.displayTiddler = function(srcElement,title,template,animate,slowly)\n{\n// if (readOnly && !store.tiddlerExists(title) && !store.isShadowTiddler(title)){title = '404 Error'}\n if (readOnly && !store.tiddlerExists(title) && !store.isShadowTiddler(title)){template = '404Template';}\n this.displayTiddler404(srcElement,title,template,animate,slowly);\n}\n\n//}}}