3 classvar <>defaultHomeUrl;
4 classvar <>openNewWindows = false;
16 NotificationCenter.register(SCDoc, \didIndexAllDocs, this) {
17 if(WebView.implClass.respondsTo(\clearCache)) {
25 if( singleton.isNil ) {
31 *new { arg aHomeUrl, newWin;
32 if( aHomeUrl.isNil ) {
33 aHomeUrl = defaultHomeUrl ?? { SCDoc.helpTargetDir ++ "/Help.html" };
35 ^super.new.init( aHomeUrl, newWin ?? { openNewWindows } );
43 var w = if(openNewWindows,{this.new},{this.instance});
48 *openBrowsePage {|category|
49 category = if(category.notNil) {"#"++category} {""};
50 this.goTo(SCDoc.helpTargetDir++"/Browse.html"++category);
52 *openSearchPage {|text|
53 text = if(text.notNil) {"#"++text} {""};
54 this.goTo(SCDoc.helpTargetDir++"/Search.html"++text);
58 { w.startAnim; w.goTo(SCDoc.findHelpFile(text)) }.fork(AppClock);
60 *openHelpForMethod {|method|
61 var cls = method.ownerClass;
62 var met = method.name.asString;
64 cls = cls.name.asString.drop(5);
67 cls = cls.name.asString;
70 this.goTo(SCDoc.helpTargetDir+/+"Classes"+/+cls++".html#"++met);
74 ^("file://" ++ SCDoc.helpTargetDir +/+ "OldHelpWrapper.html#"++url++"?"++
75 SCDoc.helpTargetDir +/+ if((c=url.basename.split($.).first).asSymbol.asClass.notNil)
76 {"Classes" +/+ c ++ ".html"}
77 {"Guides/WritingHelp.html"})
79 cmdPeriod { rout.play(AppClock) }
80 goTo {|url, brokenAction|
81 var newPath, oldPath, plainTextExts = #[".sc",".scd",".txt",".schelp",".rtf"];
85 ^this.openTextFile(url);
92 brokenAction = brokenAction ? {SCDoc.helpTargetDir++"/BrokenLink.html#"++url};
96 url = SCDoc.prepareHelpForURL(url) ?? brokenAction;
97 #newPath, oldPath = [url,webView.url].collect {|x|
98 if(x.notEmpty) {x.findRegexp("(^\\w+://)?([^#]+)(#.*)?")[1..].flop[1][1]}
100 // detect old helpfiles and open them in OldHelpWrapper
101 if(url.beginsWith("sc://")) {
102 url = SCDoc.findHelpFile(newPath);
106 // this didn't work for quarks due to difference between registered old help path and the quarks symlink in Extensions.
107 // we could use File.realpath(path) below but that would double the execution time,
108 // so let's just assume any local file outside helpTargetDir is an old helpfile.
111 if(url.endsWith(path)) {
116 newPath.beginsWith(SCDoc.helpTargetDir).not and: { url.beginsWith("file://") }
118 url = HelpBrowser.getOldWrapUrl(url)
122 // needed since onLoadFinished is not called if the path did not change:
123 if(newPath == oldPath) {webView.onLoadFinished.value};
126 webView.html = err.errorString;
129 CmdPeriod.remove(this);
135 goHome { this.goTo(homeUrl); }
137 goBack { webView.back; }
139 goForward { webView.forward; }
141 /* ------------------------------ private ------------------------------ */
143 init { arg aHomeUrl, aNewWin;
145 var lblFind, txtFind, findView, saveSize, toggleFind;
146 var strh = "Tj".bounds.height;
147 var vPad = 10, hPad = 20;
155 winRect = Rect(0, 0, 800, (Window.screenBounds.height * 0.8).floor);
156 winRect = winRect.moveToPoint(winRect.centerIn(Window.screenBounds));
158 window = Window.new( bounds: winRect ).name_("SuperCollider Help");
162 if(singleton == this) {
171 [[\Back,"<"], [\Forward,">"], [\Reload, "Reload"]].do { |item|
173 var w = str.bounds.width + hPad;
174 toolbar[item[0]] = Button( window, Rect(x,y,w,h) ).states_([[str]]);
179 str = "Quick lookup:";
180 w = str.bounds.width + 5;
181 StaticText(window, Rect(x,y,w,h)).string_(str);
184 srchBox = TextField.new( window, Rect(x,y,w,h) ).resize_(1);
185 if(GUI.current.id == \qt) {
186 srchBox.toolTip = "Smart quick help lookup. Prefix with # to just search.";
188 srchBox.action = {|x|
189 if(x.string.notEmpty) {
190 this.goTo(if(x.string.first==$#)
191 {SCDoc.helpTargetDir++"/Search.html#"++x.string.drop(1)}
192 {SCDoc.findHelpFile(x.string)}
197 openNewWin = aNewWin;
199 if(GUI.current.respondsTo(\checkBox)) {
200 str = "Open links in new window";
201 w = str.bounds.width + 50;
202 CheckBox.new (window, Rect(x, y, w, h) )
206 .action_({ |b| openNewWin = b.value });
208 str = "Open links in same window";
209 w = str.bounds.width + 5;
210 Button.new( window, Rect(x, y, w, h) )
212 .states_([[str],["Open links in new window"]])
213 .value_(openNewWin.asInteger)
214 .action_({ |b| openNewWin = b.value.asBoolean });
220 findView = CompositeView(window, Rect(x,y,w,h+10)).visible_(false).resize_(2);
223 x = winRect.width - marg - w;
224 txtFind = TextField.new( findView, Rect(x,y,w,h) ).resize_(3);
225 str = "Find text in document:";
226 w = str.bounds.width + 5;
228 lblFind = StaticText.new( findView, Rect(x, y, w, h) )
234 w = winRect.width - 10;
235 h = winRect.height - y - marg;
236 webView = WebView.new( window, Rect(x,y,w,h) ).resize_(5);
237 webView.html = "Please wait while initializing Help... (This might take several seconds the first time)";
239 if(webView.respondsTo(\setFontFamily)) {
240 webView.setFontFamily(\fixed, Platform.case(
242 \linux, { "Andale Mono" },
247 webView.onLoadFinished = {
249 window.name = "SuperCollider Help: %".format(webView.title);
251 webView.onLoadFailed = { this.stopAnim };
252 webView.onLinkActivated = {|wv, url|
253 var newPath, oldPath;
255 #newPath, oldPath = [url,webView.url].collect {|x|
256 if(x.notEmpty) {x.findRegexp("(^\\w+://)?([^#]+)(#.*)?")[1..].flop[1][1]}
259 if(newPath!=oldPath) {
260 HelpBrowser.new(newWin:true).goTo(url);
265 if(webView.respondsTo(\onReload_)) {
266 webView.onReload = {|wv, url|
267 if(WebView.implClass.respondsTo(\clearCache)) {
273 if(webView.respondsTo(\onJavaScriptMsg_)) {
274 webView.onJavaScriptMsg = {|wv, err, type|
275 "JavaScript %: %".format(if(type==0,"Error","Message"),err).postln;
280 if(findView.visible.not) {
281 saveSize = webView.bounds;
282 h = findView.bounds.height + marg;
283 webView.bounds = Rect(saveSize.left,saveSize.top+h,saveSize.width,saveSize.height-h);
284 findView.visible = true;
287 webView.bounds = saveSize;
288 findView.visible = false;
292 webView.enterInterpretsSelection = true;
293 webView.keyDownAction = { arg view, char, mods;
294 if( (char.ascii == 13) && (mods.isCtrl || mods.isCmd || mods.isShift) ) {
295 view.tryPerform(\evaluateJavaScript,"selectLine()");
298 window.view.keyDownAction = { arg view, char, mods, uni, kcode, key;
299 if( ((key == 70) && mods.isCtrl) || (char == $f && mods.isCmd) ) {
303 if(findView.visible) {toggleFind.value};
307 toolbar[\Back].action = { this.goBack };
308 toolbar[\Forward].action = { this.goForward };
309 toolbar[\Reload].action = { this.goTo( webView.url ) };
310 if(GUI.id === \cocoa) {
311 txtFind.action = { |x| webView.focus; AppClock.sched(0, {webView.findText( x.string );}) };
313 txtFind.action = { |x| webView.findText( x.string ) };
318 var win, winRect, txt, file, fonts;
319 path = path.replace("%20"," ").findRegexp("(^\\w+://)?([^#]+)(#.*)?")[1..].flop[1][1];
320 if(File.exists(path)) {
323 webView.url = SCDoc.helpTargetDir++"/BrokenLink.html#"++path;
329 var progress = [">---","->--","-->-","--->"];
336 window.name = ("Loading"+p);
338 if(loading.not) {break.value};
342 // lblStatus.string_("");