Skip to content

Commit 43746e5

Browse files
committed
Move text view to a WinBox popup instead of an ExtJS tab
1 parent a612b02 commit 43746e5

6 files changed

Lines changed: 151 additions & 643 deletions

File tree

app/Application.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,12 @@ Ext.define('EdiromOnline.Application', {
4141
'window.WindowController',
4242
'window.XmlView',
4343
'window.concordanceNavigator.ConcordanceNavigator',
44-
'window.audio.AudioView',
4544
'window.source.SourceView',
4645
'window.source.PageBasedView',
4746
'window.source.MeasureBasedView',
4847
'window.source.VerovioView',
4948
'window.text.FacsimileView',
50-
'window.text.TextFacsimileSplitView',
51-
'window.text.TextView'
49+
'window.text.TextFacsimileSplitView'
5250
],
5351

5452
models: [

app/controller/desktop/Desktop.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,115 @@ Ext.define('EdiromOnline.controller.desktop.Desktop', {
601601
});
602602
},
603603

604+
// Text window — renders the existing backend-generated text HTML directly
605+
// inside the WinBox web-component host. No separate text web component is
606+
// needed. Chapter navigation and internal/footnote links are wired with
607+
// native DOM events because the content lives inside the shadow root.
608+
openTextView: function(uri, label, textConfig) {
609+
var me = this;
610+
var desktop = me.desktop;
611+
textConfig = textConfig || {};
612+
613+
var existing = null;
614+
desktop.getActiveWindowsSet().each(function(w) {
615+
if (w && w.isTextProxy && w.uri === uri) { existing = w; return false; }
616+
});
617+
if (existing) {
618+
existing.show();
619+
if (textConfig.internalId && existing.scrollToTextId) {
620+
existing.scrollToTextId(textConfig.internalId);
621+
}
622+
return;
623+
}
624+
625+
var winId = 'text-window-' + Date.now();
626+
var idPrefix = winId + '_';
627+
628+
window.doAJAXRequest('data/xql/getText.xql',
629+
'GET',
630+
{
631+
uri: uri,
632+
idPrefix: idPrefix,
633+
term: textConfig.term || '',
634+
path: textConfig.path || ''
635+
},
636+
function(response) {
637+
var chapterLabel = getLangString('view.window.text.TextView_gotoMenu');
638+
var html = ''
639+
+ '<div class="textWindow" style="display:flex;flex-direction:column;height:100%;box-sizing:border-box;">'
640+
+ '<div class="textWindowToolbar" style="display:none;padding:4px 6px;border-bottom:1px solid #ccc;">'
641+
+ '<label>' + chapterLabel + ': '
642+
+ '<select class="textChapterSelect"></select>'
643+
+ '</label>'
644+
+ '</div>'
645+
+ '<div class="textWindowScroller" style="flex:1;overflow:auto;">'
646+
+ '<div class="textViewContent" style="padding:10px;">' + response.responseText + '</div>'
647+
+ '</div>'
648+
+ '</div>';
649+
650+
me.createWinBoxWindow({
651+
id: winId,
652+
title: label || getLangString('controller.window.Window_textView'),
653+
maxWidth: 900,
654+
html: html,
655+
findExisting: function(w) { return !!(w && w.isTextProxy && w.uri === uri); },
656+
proxyExtras: { isTextProxy: true, uri: uri },
657+
onOpen: function(winbox, winboxEl, host, proxy) {
658+
var scrollToId = function(id) {
659+
if (!id) return;
660+
var target = host.shadowRoot.getElementById(idPrefix + id)
661+
|| host.shadowRoot.getElementById(id);
662+
if (target) target.scrollIntoView({ block: 'start' });
663+
};
664+
665+
proxy.scrollToTextId = scrollToId;
666+
me.wireInPageAnchors(winboxEl, host);
667+
668+
if (winboxEl) {
669+
winboxEl.addEventListener('click', function(e) {
670+
var link = e.target && e.target.closest
671+
? e.target.closest('.scrollto[data-footnote]')
672+
: null;
673+
if (!link) return;
674+
e.preventDefault();
675+
scrollToId(link.getAttribute('data-footnote'));
676+
});
677+
}
678+
679+
window.doAJAXRequest('data/xql/getChapters.xql',
680+
'GET',
681+
{ uri: uri },
682+
function(chapterResponse) {
683+
var chapters;
684+
try {
685+
chapters = Ext.JSON.decode(chapterResponse.responseText);
686+
} catch (e) {
687+
chapters = [];
688+
}
689+
if (!chapters || !chapters.length || !winboxEl) return;
690+
691+
var toolbar = winboxEl.querySelector('.textWindowToolbar');
692+
var select = winboxEl.querySelector('.textChapterSelect');
693+
Ext.Array.each(chapters, function(chapter) {
694+
var option = document.createElement('option');
695+
option.value = chapter.id;
696+
option.textContent = chapter.name;
697+
select.appendChild(option);
698+
});
699+
select.addEventListener('change', function() {
700+
scrollToId(select.value);
701+
});
702+
toolbar.style.display = '';
703+
}
704+
);
705+
706+
if (textConfig.internalId) scrollToId(textConfig.internalId);
707+
}
708+
});
709+
}
710+
);
711+
},
712+
604713
// Audio window — rendered with the WinBox web component (mirrors openHelp /
605714
// openAbout / openSearch). Called by SingleWindowController.onMetaDataLoaded
606715
// instead of adding an ExtJS audioView tab whenever a clicked resource's

app/controller/window/SingleWindowController.js

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ Ext.define('EdiromOnline.controller.window.SingleWindowController', {
2929
'EdiromOnline.view.window.source.VerovioView',
3030
'EdiromOnline.view.window.source.SourceView',
3131
'EdiromOnline.view.window.text.FacsimileView',
32-
'EdiromOnline.view.window.text.TextFacsimileSplitView',
33-
'EdiromOnline.view.window.text.TextView'
32+
'EdiromOnline.view.window.text.TextFacsimileSplitView'
3433
],
3534

3635
views: [
@@ -40,10 +39,9 @@ Ext.define('EdiromOnline.controller.window.SingleWindowController', {
4039
init: function() {
4140
},
4241

43-
// Called by WindowController right after the window is created, while it is
44-
// STILL HIDDEN. The window is only ever shown once we know its content (see
45-
// onMetaDataLoaded) — audio-only resources are never shown at all, so no empty
46-
// ExtJS window flashes on screen before the audio popup appears.
42+
// Called by WindowController before the ExtJS window is registered with the
43+
// desktop. Metadata decides whether the resource uses WinBox or ExtJS, so
44+
// audio and text resources never create an ExtJS view or taskbar entry.
4745
loadWindowContent: function(win) {
4846
var me = this;
4947
var lang = getPreference('application_language');
@@ -68,48 +66,55 @@ Ext.define('EdiromOnline.controller.window.SingleWindowController', {
6866
onMetaDataLoaded: function(config, win) {
6967

7068
var me = this;
69+
var desktopController = this.application.getController('desktop.Desktop');
70+
var handledByWebComponent = false;
71+
72+
// Decide whether the resource belongs in a web-component window before
73+
// creating any ExtJS views. This prevents hidden MEI/text views from
74+
// being initialized for resources handled by WinBox.
75+
Ext.Array.each(config.views, function(view) {
76+
if(view.type == 'audioView') {
77+
handledByWebComponent = true;
78+
desktopController.openAudioView(view.uri, view.label || config.title);
79+
} else if(view.type == 'textView') {
80+
handledByWebComponent = true;
81+
desktopController.openTextView(view.uri, config.title || view.label, {
82+
term: config.term,
83+
path: config.path,
84+
internalId: config.internalId
85+
});
86+
}
87+
});
88+
89+
if(handledByWebComponent) {
90+
win.destroy();
91+
return;
92+
}
93+
7194
var views = [];
72-
var hasAudioView = false;
73-
7495
Ext.Array.each(config.views, function(view) {
75-
var uri = view.uri;
76-
77-
if(view.type == "iFrameView" && config["term"] != "" && config["path"] != "") {
78-
uri = uri + "?term=" + config["term"] + "&path=" + config["path"] + "#searchTarget";
79-
}
80-
81-
if(view.type == "iFrameView" && config["internalId"] != "") {
82-
uri = uri + "#" + config["internalId"];
83-
}
84-
85-
// Audio content opens in its own WinBox popup instead of an ExtJS tab.
86-
if(view.type == "audioView") {
87-
hasAudioView = true;
88-
this.application.getController('desktop.Desktop').openAudioView(uri, view.label);
89-
return;
96+
var uri = view.uri;
97+
98+
if(view.type == 'iFrameView' && config.term != '' && config.path != '') {
99+
uri = uri + '?term=' + config.term + '&path=' + config.path + '#searchTarget';
100+
}
101+
102+
if(view.type == 'iFrameView' && config.internalId != '') {
103+
uri = uri + '#' + config.internalId;
90104
}
91105

92106
views.push(this.createView(view.type, {
93-
window:win,
94-
type:config.type,
107+
window: win,
108+
type: config.type,
95109
viewType: view.type,
96110
viewLabel: view.label,
97111
defaultView: view.defaultView,
98-
uri:uri
112+
uri: uri
99113
}));
100-
101114
}, me);
102115

103-
// Audio resources open exclusively in the audio-player popup. The window
104-
// was never shown (see loadWindowContent), so just discard it — nothing
105-
// was ever painted, unlike the old win.close() which closed an already-
106-
// visible window.
107-
if(hasAudioView) {
108-
win.destroy();
109-
return;
110-
}
111-
112116
config.views = views;
117+
desktopController.addWindowToActiveDesktop(win);
113118
win.setWindowConfig(config);
114119
win.show();
115120
},
@@ -138,7 +143,6 @@ Ext.define('EdiromOnline.controller.window.SingleWindowController', {
138143
case 'verovioView': return getLangString('controller.window.Window_verovioView');
139144
case 'headerView': return getLangString('controller.window.Window_headerView');
140145
case 'facsimileView': return 'Facsimile';
141-
case 'textView': return getLangString('controller.window.Window_textView');
142146
case 'annotationView': return getLangString('controller.window.Window_annotationView');
143147
case 'textFacsimileSplitView': return getLangString('controller.window.Window_textFacsimileSplitView');
144148
//TODO:case 'searchView': return 'Suche';
@@ -153,7 +157,6 @@ Ext.define('EdiromOnline.controller.window.SingleWindowController', {
153157
case 'sourceView': return 'EdiromOnline.view.window.source.SourceView';
154158
case 'verovioView': return 'EdiromOnline.view.window.source.VerovioView';
155159
case 'headerView': return 'EdiromOnline.view.window.HeaderView';
156-
case 'textView': return 'EdiromOnline.view.window.text.TextView';
157160
case 'facsimileView': return 'EdiromOnline.view.window.text.FacsimileView';
158161
case 'annotationView': return 'EdiromOnline.view.window.AnnotationView';
159162
case 'textFacsimileSplitView': return 'EdiromOnline.view.window.text.TextFacsimileSplitView';

app/controller/window/WindowController.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ Ext.define('EdiromOnline.controller.window.WindowController', {
4545
});
4646

4747
var win = new EdiromOnline.view.window.Window(config);
48-
this.application.getController('desktop.Desktop').addWindowToActiveDesktop(win);
49-
5048
this.application.getController('window.SingleWindowController').loadWindowContent(win);
5149

5250
return win;

0 commit comments

Comments
 (0)