@ -22,6 +22,22 @@ async function load() {
// Schrankliste, falls vorher schon getestet (im Storage gecached)
// Schrankliste, falls vorher schon getestet (im Storage gecached)
const cached = ( await browser . storage . local . get ( "cabinets" ) ) . cabinets || [ ] ;
const cached = ( await browser . storage . local . get ( "cabinets" ) ) . cabinets || [ ] ;
fillCabinets ( cached , s . defaultCabinetId ) ;
fillCabinets ( cached , s . defaultCabinetId ) ;
// Best-effort: Felder des Standard-Archivs gleich laden – nur wenn schon ein
// Sitzungs-Token da ist (sonst wählt der Nutzer das Archiv manuell).
if ( s . defaultCabinetId && [ ... $ ( "mapCabinet" ) . options ] . some ( ( o ) => o . value === s . defaultCabinetId ) ) {
$ ( "mapCabinet" ) . value = s . defaultCabinetId ;
try {
const stt = await browser . runtime . sendMessage ( { type : "auth:status" } ) ;
if ( stt && stt . hasToken && stt . token ) {
Auth . setToken ( stt . token ) ;
availableFields = ( await DocuWare . cabinetFieldNames ( s , s . defaultCabinetId ) )
. filter ( ( n ) => n && ! /^DW[A-Z]/ . test ( n ) ) . sort ( ) ;
refreshFieldSelects ( ) ;
$ ( "mapFieldStatus" ) . textContent = ` ${ availableFields . length } Felder zur Auswahl geladen. ` ;
}
} catch ( _ ) { /* egal – Archiv kann manuell gewählt werden */ }
}
}
}
function setMailFormat ( v ) {
function setMailFormat ( v ) {
@ -83,6 +99,7 @@ async function ensureToken() {
// --- Feld-Mapping-Editor ---------------------------------------------------
// --- Feld-Mapping-Editor ---------------------------------------------------
const CONST _OPT = "__const__" ; // Sentinel im Quelle-Dropdown für „Fester Wert"
const CONST _OPT = "__const__" ; // Sentinel im Quelle-Dropdown für „Fester Wert"
let availableFields = [ ] ; // Feldnamen aus dem zuletzt gewählten Archiv
// Zerlegt einen Mapping-Wert (Token-String ODER { const } / { token }) in den UI-Zustand.
// Zerlegt einen Mapping-Wert (Token-String ODER { const } / { token }) in den UI-Zustand.
function mapValueState ( value ) {
function mapValueState ( value ) {
@ -94,49 +111,71 @@ function mapValueState(value) {
return { sel : "" , konst : "" } ;
return { sel : "" , konst : "" } ;
}
}
// Befüllt ein Feldname-Dropdown mit den Archiv-Feldern + dem aktuellen Wert (bleibt erhalten).
function fillFieldSelect ( sel , current ) {
sel . innerHTML = "" ;
const empty = document . createElement ( "option" ) ;
empty . value = "" ; empty . textContent = "— Feld wählen —" ;
sel . appendChild ( empty ) ;
[ ... new Set ( [ ... ( availableFields || [ ] ) , current ] . filter ( Boolean ) ) ] . sort ( ) . forEach ( ( n ) => {
const o = document . createElement ( "option" ) ;
o . value = n ; o . textContent = n ;
sel . appendChild ( o ) ;
} ) ;
sel . value = current || "" ;
}
// Aktualisiert alle Feldname-Dropdowns auf die aktuelle Archiv-Feldliste (Auswahl bleibt).
function refreshFieldSelects ( ) {
document . querySelectorAll ( "#mapBody .map-field" ) . forEach ( ( sel ) => fillFieldSelect ( sel , sel . value ) ) ;
}
function addMapRow ( field = "" , value = "" ) {
function addMapRow ( field = "" , value = "" ) {
const st = mapValueState ( value ) ;
const st = mapValueState ( value ) ;
const tr = document . createElement ( "tr" ) ;
const row = document . createElement ( "div" ) ;
row . className = "map-row" + ( st . sel === CONST _OPT ? " has-const" : "" ) ;
const inp = document . createElement ( "input" ) ;
// Links gestapelt: Feldname (Dropdown) über Mail-Attribut.
inp . type = "text" ; inp . className = "map-field" ; inp . value = field ;
const left = document . createElement ( "div" ) ; left . className = "map-left" ;
inp . placeholder = "EML_SUBJECT" ;
inp . setAttribute ( "list" , "fieldNames" ) ; // Vorschläge aus gewähltem Archiv
const tdF = document . createElement ( "td" ) ; tdF . appendChild ( inp ) ;
const sel = document . createElement ( "select" ) ; sel . className = "map-source" ;
const fieldSel = document . createElement ( "select" ) ; fieldSel . className = "map-field" ;
fillFieldSelect ( fieldSel , field ) ;
const src = document . createElement ( "select" ) ; src . className = "map-source" ;
const none = document . createElement ( "option" ) ; none . value = "" ; none . textContent = "— nichts —" ;
const none = document . createElement ( "option" ) ; none . value = "" ; none . textContent = "— nichts —" ;
sel . appendChild ( none ) ;
s rc . appendChild ( none ) ;
MAIL _TOKENS . forEach ( ( t ) => {
MAIL _TOKENS . forEach ( ( t ) => {
const o = document . createElement ( "option" ) ;
const o = document . createElement ( "option" ) ;
o . value = t . key ; o . textContent = t . label ;
o . value = t . key ; o . textContent = t . label ;
if ( t . key === st . sel ) o . selected = true ;
if ( t . key === st . sel ) o . selected = true ;
sel . appendChild ( o ) ;
s rc . appendChild ( o ) ;
} ) ;
} ) ;
const co = document . createElement ( "option" ) ;
const co = document . createElement ( "option" ) ;
co . value = CONST _OPT ; co . textContent = "★ Fester Wert" ;
co . value = CONST _OPT ; co . textContent = "★ Fester Wert" ;
if ( st . sel === CONST _OPT ) co . selected = true ;
if ( st . sel === CONST _OPT ) co . selected = true ;
s el . appendChild ( co ) ;
s rc . appendChild ( co ) ;
left . append ( fieldSel , src ) ;
// Rechts (breit): fester Wert – nur sichtbar bei „Fester Wert".
const right = document . createElement ( "div" ) ; right . className = "map-right" ;
const konst = document . createElement ( "input" ) ;
const konst = document . createElement ( "input" ) ;
konst . type = "text" ; konst . className = "map-const" ; konst . placeholder = "z. B. NEU" ;
konst . type = "text" ; konst . className = "map-const" ; konst . placeholder = " Fester Wert, z. B. NEU";
konst . value = st . konst ; konst . style . marginTop = "6px" ;
konst . value = st . konst ;
konst . style . display = st . sel === CONST _OPT ? "" : "none" ;
right. appendChild ( konst ) ;
sel . addEventListener ( "change" , ( ) => {
src . addEventListener ( "change" , ( ) => {
konst . style . display = sel . value === CONST _OPT ? "" : "none" ;
const isConst = src . value === CONST _OPT ;
if ( sel . value === CONST _OPT ) konst . focus ( ) ;
row . classList . toggle ( "has-const" , isConst ) ;
if ( isConst ) konst . focus ( ) ;
} ) ;
} ) ;
const tdT = document . createElement ( "td" ) ; tdT . appendChild ( sel ) ; tdT . appendChild ( konst ) ;
const del = document . createElement ( "button" ) ;
const del = document . createElement ( "button" ) ;
del . type = "button" ; del . className = "icon-btn" ; del . textContent = "✕" ; del . title = "Zeile entfernen" ;
del . type = "button" ; del . className = "icon-btn" ; del . textContent = "✕" ; del . title = "Zeile entfernen" ;
del . addEventListener ( "click" , ( ) => tr . remove ( ) ) ;
del . addEventListener ( "click" , ( ) => row . remove ( ) ) ;
const tdX = document . createElement ( "td" ) ; tdX . className = "del" ; tdX . appendChild ( del ) ;
tr. append ( tdF , tdT , tdX ) ;
row. append ( left , right , del ) ;
$ ( "mapBody" ) . appendChild ( t r) ;
$ ( "mapBody" ) . appendChild ( row ) ;
}
}
function loadMapping ( map ) {
function loadMapping ( map ) {
@ -146,12 +185,12 @@ function loadMapping(map) {
function collectMapping ( ) {
function collectMapping ( ) {
const map = { } ;
const map = { } ;
document . querySelectorAll ( "#mapBody tr ") . forEach ( ( t r) => {
document . querySelectorAll ( "#mapBody .map-row ") . forEach ( ( row ) => {
const f = t r. querySelector ( ".map-field" ) . value . trim ( ) ;
const f = row . querySelector ( ".map-field" ) . value . trim ( ) ;
if ( ! f ) return ; // ohne Feldname ignorieren
if ( ! f ) return ; // ohne Feldname ignorieren
const sel = t r. querySelector ( ".map-source" ) . value ;
const sel = row . querySelector ( ".map-source" ) . value ;
if ( sel === CONST _OPT ) {
if ( sel === CONST _OPT ) {
const c = t r. querySelector ( ".map-const" ) . value ;
const c = row . querySelector ( ".map-const" ) . value ;
if ( c !== "" ) map [ f ] = { const : c } ; // fester Wert
if ( c !== "" ) map [ f ] = { const : c } ; // fester Wert
} else if ( sel ) {
} else if ( sel ) {
map [ f ] = sel ; // Mail-Token (als String, abwärtskompatibel)
map [ f ] = sel ; // Mail-Token (als String, abwärtskompatibel)
@ -248,23 +287,18 @@ $("mappingPull").addEventListener("click", async () => {
// Archiv wählen -> dessen Indexfelder als Vorschläge (datalist) für alle Feldnamen.
// Archiv wählen -> dessen Indexfelder als Vorschläge (datalist) für alle Feldnamen.
$ ( "mapCabinet" ) . addEventListener ( "change" , async ( ) => {
$ ( "mapCabinet" ) . addEventListener ( "change" , async ( ) => {
const id = $ ( "mapCabinet" ) . value ;
const id = $ ( "mapCabinet" ) . value ;
const dl = $ ( "fieldNames" ) ;
const st = $ ( "mapFieldStatus" ) ;
const st = $ ( "mapFieldStatus" ) ;
if ( ! id ) { dl. innerHTML = "" ; st . textContent = "" ; return ; }
if ( ! id ) { availableFields = [ ] ; refreshFieldSelects ( ) ; st . textContent = "" ; return ; }
st . textContent = "Lade Felder …" ;
st . textContent = "Lade Felder …" ;
try {
try {
const s = await Settings . get ( ) ;
const s = await Settings . get ( ) ;
const ok = await ensureToken ( ) ;
const ok = await ensureToken ( ) ;
if ( ! ok ) { st . textContent = "Erst „Verbindung testen“ (Passwort nötig)." ; return ; }
if ( ! ok ) { st . textContent = "Erst „Verbindung testen“ (Passwort nötig)." ; return ; }
const names = ( await DocuWare . cabinetFieldNames ( s , id ) )
availableFields = ( await DocuWare . cabinetFieldNames ( s , id ) )
. filter ( ( n ) => n && ! /^DW[A-Z]/ . test ( n ) ) ; // DW*-Systemfelder ausblenden
. filter ( ( n ) => n && ! /^DW[A-Z]/ . test ( n ) ) // DW*-Systemfelder ausblenden
dl . innerHTML = "" ;
. sort ( ) ;
names . sort ( ) . forEach ( ( n ) => {
refreshFieldSelects ( ) ;
const o = document . createElement ( "option" ) ;
st . textContent = ` ${ availableFields . length } Felder zur Auswahl geladen. ` ;
o . value = n ;
dl . appendChild ( o ) ;
} ) ;
st . textContent = ` ${ names . length } Felder als Vorschlag geladen. ` ;
} catch ( e ) {
} catch ( e ) {
st . textContent = ` Fehler: ${ e . message } ` ;
st . textContent = ` Fehler: ${ e . message } ` ;
}
}