@@ -23,8 +23,8 @@ const REFERENCE_SOURCES: ItemReferenceSource[] = ['facebook', 'google', 'instagr
2323
2424// Parse DMS (Degrees Minutes Seconds) format to decimal
2525// Supports formats like: 50° 22' 51.51" N or 50°22'51.51"N or 50 22 51.51 N
26- function parseDMS ( dms : string ) : number | null {
27- const dmsPattern = / ( \d + ) [ ° \s ] + ( \d + ) [ ' \s ] + ( \d + (?: \. \d + ) ? ) [ " \s ] * ( [ N S E W ] ) ? / i
26+ export function parseDMS ( dms : string ) : number | null {
27+ const dmsPattern = / ( \d + ) [ ° \s ] + ( \d + ) [ \' ’ ′ \s ] + ( \d + (?: \. \d + ) ? ) [ \" ” ″ \s ] * ( [ N S E W ] ) ? / i
2828 const match = dms . trim ( ) . match ( dmsPattern )
2929
3030 if ( ! match ) return null
@@ -44,6 +44,50 @@ function parseDMS(dms: string): number | null {
4444 return decimal
4545}
4646
47+ export function parseLatInput ( value : string , prevGeo ?: RawXmlItem [ 'geo' ] ) : RawXmlItem [ 'geo' ] | undefined {
48+ const trimmed = value . trim ( )
49+ const hasDms = / \d + [ ° \s ] + \d + [ \' ’ ′ \s ] + \d + / . test ( trimmed )
50+ const hasComma = trimmed . includes ( ',' )
51+
52+ const splitDmsPair = ( input : string ) : [ string , string ] | null => {
53+ if ( hasComma ) {
54+ const parts = input . split ( ',' ) . map ( s => s . trim ( ) ) . filter ( Boolean )
55+ return parts . length === 2 ? [ parts [ 0 ] , parts [ 1 ] ] : null
56+ }
57+ const match = input . match ( / \d + [ ° \s ] + \d + [ \' ’ ′ \s ] + \d + (?: \. \d + ) ? [ \" ” ″ \s ] * [ N S E W ] ? / ig)
58+ if ( match && match . length >= 2 ) {
59+ return [ match [ 0 ] . trim ( ) , match [ 1 ] . trim ( ) ]
60+ }
61+ return null
62+ }
63+
64+ // Check if value contains DMS format (degrees, minutes, seconds)
65+ if ( hasDms ) {
66+ const pair = splitDmsPair ( trimmed )
67+ if ( pair ) {
68+ const lat = parseDMS ( pair [ 0 ] )
69+ const lon = parseDMS ( pair [ 1 ] )
70+ if ( lat !== null && lon !== null ) {
71+ return { lat : lat . toString ( ) , lon : lon . toString ( ) , accuracy : prevGeo ?. accuracy || '' }
72+ }
73+ }
74+ const lat = parseDMS ( trimmed )
75+ if ( lat !== null ) {
76+ return { lat : lat . toString ( ) , lon : prevGeo ?. lon || '' , accuracy : prevGeo ?. accuracy || '' }
77+ }
78+ }
79+
80+ // Check if the value contains a comma (decimal lat,lon format)
81+ if ( hasComma ) {
82+ const [ lat , lon ] = trimmed . split ( ',' ) . map ( s => s . trim ( ) )
83+ return { lat : lat || '' , lon : lon || '' , accuracy : prevGeo ?. accuracy || '' }
84+ }
85+
86+ // Plain value for latitude
87+ const lat = trimmed
88+ return lat || prevGeo ?. lon ? { lat, lon : prevGeo ?. lon || '' , accuracy : prevGeo ?. accuracy || '' } : undefined
89+ }
90+
4791export default function Fields (
4892 { xmlAlbum, gallery, item, children, onItemUpdate, onXmlGenerated, editedItems, applyEditsToItems } :
4993 {
@@ -212,51 +256,10 @@ export default function Fields(
212256 value = { editedItem ?. geo ?. lat ?? '' }
213257 onChange = { ( e ) => {
214258 const value = e . target . value
215-
216- // Check if value contains DMS format (degrees, minutes, seconds)
217- if ( / \d + [ ° \s ] + \d + [ ' \s ] + \d + / . test ( value ) ) {
218- // Split by comma to check for lat,lon DMS pair
219- const parts = value . split ( ',' ) . map ( s => s . trim ( ) )
220-
221- if ( parts . length === 2 ) {
222- // Parse both lat and lon as DMS
223- const lat = parseDMS ( parts [ 0 ] )
224- const lon = parseDMS ( parts [ 1 ] )
225- if ( lat !== null && lon !== null ) {
226- updateItem ( ( prev : RawXmlItem | null ) => prev ? {
227- ...prev ,
228- geo : { lat : lat . toString ( ) , lon : lon . toString ( ) , accuracy : prev . geo ?. accuracy || '' } ,
229- } : null )
230- return
231- }
232- } else {
233- // Single DMS value for latitude only
234- const lat = parseDMS ( value )
235- if ( lat !== null ) {
236- updateItem ( ( prev : RawXmlItem | null ) => prev ? {
237- ...prev ,
238- geo : { lat : lat . toString ( ) , lon : prev . geo ?. lon || '' , accuracy : prev . geo ?. accuracy || '' } ,
239- } : null )
240- return
241- }
242- }
243- }
244-
245- // Check if the value contains a comma (decimal lat,lon format)
246- if ( value . includes ( ',' ) ) {
247- const [ lat , lon ] = value . split ( ',' ) . map ( s => s . trim ( ) )
248- updateItem ( ( prev : RawXmlItem | null ) => prev ? {
249- ...prev ,
250- geo : { lat : lat || '' , lon : lon || '' , accuracy : prev . geo ?. accuracy || '' } ,
251- } : null )
252- } else {
253- // Plain value for latitude
254- const lat = value
255- updateItem ( ( prev : RawXmlItem | null ) => prev ? {
256- ...prev ,
257- geo : lat || prev . geo ?. lon ? { lat, lon : prev . geo ?. lon || '' , accuracy : prev . geo ?. accuracy || '' } : undefined ,
258- } : null )
259- }
259+ updateItem ( ( prev : RawXmlItem | null ) => prev ? {
260+ ...prev ,
261+ geo : parseLatInput ( value , prev . geo ) ,
262+ } : null )
260263 } }
261264 placeholder = "Latitude (or lat,lon or DMS)"
262265 title = "Latitude (geo.lat) - paste lat,lon or DMS format to auto-split"
0 commit comments