/*** |Name|SnapshotPlugin| |Source|http://www.TiddlyTools.com/#SnapshotPlugin| |Documentation|http://www.TiddlyTools.com/#SnapshotPluginInfo| |Version|1.3.0| |Author|Eric Shulman| |License|http://www.TiddlyTools.com/#LegalStatements| |~CoreVersion|2.1| |Type|plugin| |Description|save or print HTML+CSS image of rendered document content| This plugin provides a macro as well as tiddler toolbar commands to create a file or browser window containing the //rendered// CSS-and-HTML that is currently being displayed for selected elements of the current document. !!!!!Documentation >see [[SnapshotPluginInfo]] !!!!!Configuration <<< <<option chkSnapshotHTMLOnly>> output HTML only (omit CSS) <<< !!!!!Revisions <<< 2009.10.12 1.3.0 added multi-file story snapshot |please see [[SnapshotPluginInfo]] for additional revision details| 2008.04.21 1.0.0 initial release - derived from [[NewDocumentPlugin]] with many improvements... <<< !!!!!Code ***/ //{{{ version.extensions.SnapshotPlugin= {major: 1, minor: 3, revision: 0, date: new Date(2009,10,12)}; if (config.options.chkSnapshotHTMLOnly===undefined) config.options.chkSnapshotHTMLOnly=false; config.macros.snapshot = { snapLabel: "save a snapshot", printLabel: "print a snapshot", snapPrompt: "save an HTML image", printPrompt: "print an HTML image", hereID: "here", viewerID: "viewer", storyID: "story", allID: "all", askID: "ask", askTiddlerID: "askTiddler", askDOMID: "askDOM", askMsg: "select an element...", hereItem: "tiddler: '%0'", viewerItem: "tiddler: '%0' (content only)", storyItem: "story column (one file)", storyFilesItem: "story column (multiple files)", allItem: "entire document", tiddlerItem: "select a tiddler...", IDItem: "select a DOM element by ID...", HTMLItem: "[%0] output HTML only (omit CSS)", fileMsg: "select or enter a target path/filename", defaultFilename: "snapshot.html", okmsg: "snapshot written to %0", failmsg: "An error occurred while creating %0", handler: function(place,macroName,params,wikifier,paramString,tiddler) { var printing=params[0]&¶ms[0]=="print"; if (printing) params.shift(); params = paramString.parseParams("anon",null,true,false,false); var id=getParam(params,"id","here"); var label=getParam(params,"label",printing?this.printLabel:this.snapLabel); var prompt=getParam(params,"prompt",printing?this.printPrompt:this.snapPrompt); var btn=createTiddlyButton(place,label,prompt, function(ev){ this.setAttribute("snapID",this.getAttribute("startID")); config.macros.snapshot.go(this,ev) }); btn.setAttribute("startID",id); btn.setAttribute("snapID",id); btn.setAttribute("printing",printing?"true":"false"); btn.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false"); }, go: function(here,ev) { var cms=config.macros.snapshot; // abbreviation var id=here.getAttribute("snapID"); var printing=here.getAttribute("printing")=="true"; var HTMLOnly=here.getAttribute("HTMLOnly")=="true"; if (id==cms.askID||id==cms.askTiddlerID||id==cms.askDOMID) { cms.askForID(here,ev); } else if (id==cms.storyID) { story.forEachTiddler(function(t,e) { var out=cms.getsnap(e,e.id,printing,HTMLOnly); if (printing) cms.printsnap(out); else cms.savesnap(out,e.getAttribute('tiddler')+'.html'); }); } else { if (id==cms.allID) id="contentWrapper"; var snapElem=document.getElementById(id); if (id==cms.hereID || id==cms.viewerID) var snapElem=story.findContainingTiddler(here); if (snapElem && hasClass(snapElem,"tiddler") && (id==cms.viewerID || HTMLOnly)) { // find viewer class element within tiddler element var nodes=snapElem.getElementsByTagName("*"); for (var i=0; i<nodes.length; i++) if (hasClass(nodes[i],"viewer")) { snapElem=nodes[i]; break; } } if (!snapElem) // not in a tiddler or no viewer element or unknown ID { e.cancelBubble=true; if(e.stopPropagation)e.stopPropagation(); return(false); } // write or print snapshot var out=cms.getsnap(snapElem,id,printing,HTMLOnly); if (printing) cms.printsnap(out); else cms.savesnap(out); } return false; }, askForID: function(here,ev) { var ev = ev ? ev : window.event; var cms=config.macros.snapshot; // abbreviation var id=here.getAttribute("snapID"); var indent='\xa0\xa0\xa0\xa0'; var p=Popup.create(here); if (!p) return false; p.className+=' sticky smallform'; var s=createTiddlyElement(p,'select'); s.button=here; if (id==cms.askID) { s.options[s.length]=new Option(cms.askMsg,cms.askID); var tid=story.findContainingTiddler(here); if(tid) { var title=tid.getAttribute("tiddler"); if (here.getAttribute("HTMLOnly")!="true") s.options[s.length]=new Option(indent+cms.hereItem.format([title]),cms.hereID); s.options[s.length]=new Option(indent+cms.viewerItem.format([title]),cms.viewerID); } s.options[s.length]=new Option(indent+cms.tiddlerItem,cms.askTiddlerID); s.options[s.length]=new Option(indent+cms.IDItem,cms.askDOMID); s.options[s.length]=new Option(indent+cms.storyItem,"tiddlerDisplay"); s.options[s.length]=new Option(indent+cms.storyFilesItem,cms.storyID); s.options[s.length]=new Option(indent+cms.allItem,"contentWrapper"); } if (id==cms.askDOMID) { s.options[s.length]=new Option(cms.IDItem,cms.askDOMID); var elems=document.getElementsByTagName("*"); var ids=[]; for (var i=0;i<elems.length;i++) if (elems[i].id.length && elems[i].className!="animationContainer") ids.push(elems[i].id); ids.sort(); for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i],ids[i]); } if (id==cms.askTiddlerID) { s.options[s.length]=new Option(cms.tiddlerItem,cms.askTiddlerID); var elems=document.getElementsByTagName("div"); var ids=[]; for (var i=0;i<elems.length;i++) { var id=elems[i].id; if (id.length && id.substr(0,story.idPrefix.length)==story.idPrefix && id!="tiddlerDisplay") ids.push(id); } ids.sort(); for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i].substr(story.idPrefix.length),ids[i]); } s.options[s.length]=new Option(cms.HTMLItem.format([here.getAttribute("HTMLOnly")=="true"?"\u221a":"_"]),cms.HTMLItem); s.onchange=function(ev){ var ev = ev ? ev : window.event; var cms=config.macros.snapshot; // abbreviation var here=this.button; if (this.value==cms.HTMLItem) { config.options.chkSnapshotHTMLOnly=!config.options.chkSnapshotHTMLOnly; here.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false"); config.macros.option.propagateOption("chkSnapshotHTMLOnly","checked", config.options.chkSnapshotHTMLOnly,"input"); } else here.setAttribute("snapID",this.value); config.macros.snapshot.go(here,ev); return false; }; Popup.show(); ev.cancelBubble=true; if(ev.stopPropagation)ev.stopPropagation(); return false; }, getpath: function() { // get current path var path=getLocalPath(window.location.href); var slashpos=path.lastIndexOf("/"); if (slashpos==-1) slashpos=path.lastIndexOf("\\"); if (slashpos!=-1) path=path.substr(0,slashpos+1); // trim filename return path; }, getsnap: function(snapElem,id,printing,HTMLOnly) { var cms=config.macros.snapshot; // abbreviation var out='<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />'; if (printing) out+='<base href="file:///'+cms.getpath().replace(/\\/g,'/')+'"></base>\n'; if (!HTMLOnly) { var styles=document.getElementsByTagName('style'); var fmt='<style>\n/* stylesheet=%0 */\n%1\n\n</style>\n'; for(var i=0; i < styles.length; i++) out+=fmt.format([styles[i].getAttribute('id'),styles[i].innerHTML]); } out+='</head>\n'; var elems=snapElem.getElementsByTagName('input'); for (var i=0; i<elems.length; i++) { var e=elems[i]; if (e.type=='text') e.defaultValue=e.value; if (e.type=='checkbox') e.defaultChecked=e.checked; if (e.type=='radiobutton') e.defaultChecked=e.checked; } var elems=snapElem.getElementsByTagName('textarea'); for (var i=0; i<elems.length; i++) elems[i].defaultValue=elems[i].value; var fmt='<body>\n\n<div class="%0">%1</div>\n\n</body>\n'; out+=fmt.format([(id==cms.viewerID?'tiddler viewer':''),snapElem.innerHTML]); return '<html>\n'+out+'</html>'; }, printsnap: function(out) { var win=window.open("","_blank",""); win.document.open(); win.document.writeln(out); win.document.close(); win.focus(); // bring to front win.print(); // trigger print dialog }, savesnap: function(out,target) { var cms=config.macros.snapshot; // abbreviation // make sure we are local if (window.location.protocol!="file:") { alert(config.messages.notFileUrlError); return; } var target=target||cms.askForFilename(cms.fileMsg,cms.getpath(),cms.defaultFilename); if (!target) return; // cancelled by user // if specified file does not include a path, assemble fully qualified path and filename var slashpos=target.lastIndexOf("/"); if (slashpos==-1) slashpos=target.lastIndexOf("\\"); if (slashpos==-1) { var h=document.location.href; var cwd=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf('/')+1))); target=cwd+target; } var link="file:///"+target.replace(/\\/g,'/'); // link for message text var ok=saveFile(target,convertUnicodeToUTF8(out)); var msg=ok?cms.okmsg.format([target]):cms.failmsg.format([target]); displayMessage(msg,link); }, askForFilename: function(msg,path,file) { if(window.Components) { // moz try { netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); var nsIFilePicker = window.Components.interfaces.nsIFilePicker; var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker); picker.init(window, msg, nsIFilePicker.modeSave); var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile); thispath.initWithPath(path); picker.displayDirectory=thispath; picker.defaultExtension='html'; picker.defaultString=file; picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML); if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor; } catch(e) { alert('error during local file access: '+e.toString()) } } else { // IE try { // XP/Vista only var s = new ActiveXObject('UserAccounts.CommonDialog'); s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|'; s.FilterIndex=3; // default to HTML files; s.InitialDir=path; s.FileName=file; if (s.showOpen()) var result=s.FileName; } catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE } return result; } }; //}}} // // TOOLBAR DEFINITIONS //{{{ config.commands.snapshotSave = { text: "snap", tooltip: config.macros.snapshot.snapPrompt, handler: function(ev,src,title) { src.setAttribute("snapID","ask"); src.setAttribute("printing","false"); src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false"); config.macros.snapshot.go(src,ev); return false; } }; config.commands.snapshotPrint = { text: "print", tooltip: config.macros.snapshot.printPrompt, handler: function(ev,src,title) { src.setAttribute("snapID","ask"); src.setAttribute("printing","true"); src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false"); config.macros.snapshot.go(src,ev); return false; } }; //}}} // // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY //{{{ if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false; Popup.stickyPopup_onDocumentClick = function(ev) { // if click is in a sticky popup, ignore it so popup will remain visible var e = ev ? ev : window.event; var target = resolveTarget(e); var p=target; while (p) { if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break; else p=p.parentNode; } if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling Popup.onDocumentClick(ev); return true; }; try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){}; try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){}; //}}}