forked from MapComplete/MapComplete
		
	Add attribution script and some attributions
This commit is contained in:
		
							parent
							
								
									99b0f937b7
								
							
						
					
					
						commit
						0fea2c87cd
					
				
					 11 changed files with 223 additions and 8 deletions
				
			
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -38,6 +38,7 @@ import Combine from "./UI/Base/Combine"; | ||||||
| import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler"; | import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler"; | ||||||
| import LZString from "lz-string"; | import LZString from "lz-string"; | ||||||
| import {LayoutConfigJson} from "./Customizations/JSON/LayoutConfigJson"; | import {LayoutConfigJson} from "./Customizations/JSON/LayoutConfigJson"; | ||||||
|  | import AttributionPanel from "./UI/BigComponents/AttributionPanel"; | ||||||
| 
 | 
 | ||||||
| export class InitUiElements { | export class InitUiElements { | ||||||
| 
 | 
 | ||||||
|  | @ -287,11 +288,7 @@ export class InitUiElements { | ||||||
|             const copyrightNotice = |             const copyrightNotice = | ||||||
|                 new ScrollableFullScreen( |                 new ScrollableFullScreen( | ||||||
|                     () => Translations.t.general.attribution.attributionTitle.Clone(), |                     () => Translations.t.general.attribution.attributionTitle.Clone(), | ||||||
|                     () => new Combine([ |                     () => new AttributionPanel(State.state.layoutToUse), | ||||||
|                         Translations.t.general.attribution.attributionContent, |  | ||||||
|                         "<br/>", |  | ||||||
|                         new Attribution(undefined, undefined, State.state.layoutToUse, undefined) |  | ||||||
|                     ]), |  | ||||||
|                     "copyright" |                     "copyright" | ||||||
|                 ) |                 ) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,6 +10,9 @@ import Loc from "../../Models/Loc"; | ||||||
| import LeafletMap from "../../Models/LeafletMap"; | import LeafletMap from "../../Models/LeafletMap"; | ||||||
| import * as L from "leaflet" | import * as L from "leaflet" | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * The bottom right attribution panel in the leaflet map | ||||||
|  |  */ | ||||||
| export default class Attribution extends UIElement { | export default class Attribution extends UIElement { | ||||||
|      |      | ||||||
|     private readonly _location: UIEventSource<Loc>; |     private readonly _location: UIEventSource<Loc>; | ||||||
|  |  | ||||||
							
								
								
									
										26
									
								
								UI/BigComponents/AttributionPanel.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								UI/BigComponents/AttributionPanel.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | import {UIElement} from "../UIElement"; | ||||||
|  | import Combine from "../Base/Combine"; | ||||||
|  | import Translations from "../i18n/Translations"; | ||||||
|  | import Attribution from "./Attribution"; | ||||||
|  | import State from "../../State"; | ||||||
|  | import {UIEventSource} from "../../Logic/UIEventSource"; | ||||||
|  | import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; | ||||||
|  | import {FixedUiElement} from "../Base/FixedUiElement"; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * The attribution panel shown on mobile | ||||||
|  |  */ | ||||||
|  | export default class AttributionPanel extends Combine { | ||||||
|  | 
 | ||||||
|  |     constructor(layoutToUse: UIEventSource<LayoutConfig>) { | ||||||
|  |         super([ | ||||||
|  |             Translations.t.general.attribution.attributionContent, | ||||||
|  |             Translations.t.general.attribution.themeBy.Subs({author: layoutToUse.data.maintainer}), | ||||||
|  |             "<br/>", | ||||||
|  |             new Attribution(undefined, undefined, State.state.layoutToUse, undefined), | ||||||
|  |             "<br/>", | ||||||
|  |             "<h4>", Translations.t.general.attribution.iconAttribution.title, "</h4>" | ||||||
|  | 
 | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -520,6 +520,14 @@ | ||||||
|       }, |       }, | ||||||
|       "attributionContent": { |       "attributionContent": { | ||||||
|         "en": "<p>All data is provided by <a href='https://osm.org' target='_blank'>OpenStreetMap</a>, freely reusable under <a href='https://osm.org/copyright' target='_blank'>the Open DataBase License</a>.</p><p>Some images are provided by Wikimedia</p>" |         "en": "<p>All data is provided by <a href='https://osm.org' target='_blank'>OpenStreetMap</a>, freely reusable under <a href='https://osm.org/copyright' target='_blank'>the Open DataBase License</a>.</p><p>Some images are provided by Wikimedia</p>" | ||||||
|  |       }, | ||||||
|  |       "themeBy": { | ||||||
|  |         "en": "Theme created by {author}" | ||||||
|  |       }, | ||||||
|  |       "iconAttribution": { | ||||||
|  |         "title": { | ||||||
|  |           "en": "Used icons" | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										28
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										28
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -4029,6 +4029,11 @@ | ||||||
|       "integrity": "sha512-29GS75BE8asnTno3yB6ubOJOO0FboExEqNJy4bpz0GSmW/8wPTNL4h9h63c6s1uTrOopCmJYe/4yJLh5r92ZUA==", |       "integrity": "sha512-29GS75BE8asnTno3yB6ubOJOO0FboExEqNJy4bpz0GSmW/8wPTNL4h9h63c6s1uTrOopCmJYe/4yJLh5r92ZUA==", | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|  |     "@types/prompt-sync": { | ||||||
|  |       "version": "4.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/prompt-sync/-/prompt-sync-4.1.0.tgz", | ||||||
|  |       "integrity": "sha1-utMynv9bQRXjTvRpgjckTUEdRHA=" | ||||||
|  |     }, | ||||||
|     "@types/q": { |     "@types/q": { | ||||||
|       "version": "1.5.4", |       "version": "1.5.4", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", |       "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", | ||||||
|  | @ -9903,6 +9908,29 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", |       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", | ||||||
|       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" |       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" | ||||||
|     }, |     }, | ||||||
|  |     "prompt-sync": { | ||||||
|  |       "version": "4.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/prompt-sync/-/prompt-sync-4.2.0.tgz", | ||||||
|  |       "integrity": "sha512-BuEzzc5zptP5LsgV5MZETjDaKSWfchl5U9Luiu8SKp7iZWD5tZalOxvNcZRwv+d2phNFr8xlbxmFNcRKfJOzJw==", | ||||||
|  |       "requires": { | ||||||
|  |         "strip-ansi": "^5.0.0" | ||||||
|  |       }, | ||||||
|  |       "dependencies": { | ||||||
|  |         "ansi-regex": { | ||||||
|  |           "version": "4.1.0", | ||||||
|  |           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", | ||||||
|  |           "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" | ||||||
|  |         }, | ||||||
|  |         "strip-ansi": { | ||||||
|  |           "version": "5.2.0", | ||||||
|  |           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", | ||||||
|  |           "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", | ||||||
|  |           "requires": { | ||||||
|  |             "ansi-regex": "^4.1.0" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "protocol-buffers-schema": { |     "protocol-buffers-schema": { | ||||||
|       "version": "3.5.1", |       "version": "3.5.1", | ||||||
|       "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz", |       "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz", | ||||||
|  |  | ||||||
|  | @ -13,11 +13,12 @@ | ||||||
|     "generate:editor-layer-index": "cd assets/ && wget https://osmlab.github.io/editor-layer-index/imagery.geojson --output-document=editor-layer-index.json", |     "generate:editor-layer-index": "cd assets/ && wget https://osmlab.github.io/editor-layer-index/imagery.geojson --output-document=editor-layer-index.json", | ||||||
|     "generate:images": "ts-node scripts/generateIncludedImages.ts", |     "generate:images": "ts-node scripts/generateIncludedImages.ts", | ||||||
|     "generate:translations": "ts-node scripts/generateTranslations.ts", |     "generate:translations": "ts-node scripts/generateTranslations.ts", | ||||||
|     "generate:layouts": "ts-node scripts/createLayouts.ts", |     "generate:layouts": "ts-node scripts/generateLayouts.ts", | ||||||
|  |     "generate:docs": "ts-node scripts/generateDocs.ts", | ||||||
|     "optimize-images": "cd assets/generated/ &&  find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'", |     "optimize-images": "cd assets/generated/ &&  find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'", | ||||||
|     "generate": "npm run generate:images && npm run generate:translations", |     "generate": "npm run generate:images && npm run generate:translations", | ||||||
|     "build": "rm -rf dist/ && npm run generate && parcel build --public-url ./ *.html assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*", |     "build": "rm -rf dist/ && npm run generate && parcel build --public-url ./ *.html assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*", | ||||||
|     "prepare-deploy": "npm run test && npm run generate:editor-layer-index && npm run generate:layouts && npm run generate && npm run build && rm -rf .cache", |     "prepare-deploy": "npm run test && npm run generate:editor-layer-index && npm run generate:layouts && npm run generate && npm run build && rm -rf .cache && npm run generate:docs", | ||||||
|     "deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/Staging/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/Staging/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", |     "deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/Staging/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/Staging/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", | ||||||
|     "deploy:pietervdvn": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", |     "deploy:pietervdvn": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", | ||||||
|     "deploy:production": "rm -rf ./assets/generated && npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/mapcomplete.github.io/* && cp -r dist/* /home/pietervdvn/git/mapcomplete.github.io/ && cd /home/pietervdvn/git/mapcomplete.github.io/ && echo \"mapcomplete.osm.be\" > CNAME  && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", |     "deploy:production": "rm -rf ./assets/generated && npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/mapcomplete.github.io/* && cp -r dist/* /home/pietervdvn/git/mapcomplete.github.io/ && cd /home/pietervdvn/git/mapcomplete.github.io/ && echo \"mapcomplete.osm.be\" > CNAME  && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", | ||||||
|  | @ -38,6 +39,7 @@ | ||||||
|     "@types/leaflet-providers": "^1.2.0", |     "@types/leaflet-providers": "^1.2.0", | ||||||
|     "@types/leaflet.markercluster": "^1.4.3", |     "@types/leaflet.markercluster": "^1.4.3", | ||||||
|     "@types/lz-string": "^1.3.34", |     "@types/lz-string": "^1.3.34", | ||||||
|  |     "@types/prompt-sync": "^4.1.0", | ||||||
|     "autoprefixer": "^9.8.6", |     "autoprefixer": "^9.8.6", | ||||||
|     "country-language": "^0.1.7", |     "country-language": "^0.1.7", | ||||||
|     "email-validator": "^2.0.4", |     "email-validator": "^2.0.4", | ||||||
|  | @ -58,6 +60,7 @@ | ||||||
|     "osmtogeojson": "^3.0.0-beta.4", |     "osmtogeojson": "^3.0.0-beta.4", | ||||||
|     "parcel": "^1.2.4", |     "parcel": "^1.2.4", | ||||||
|     "postcss": "^7.0.35", |     "postcss": "^7.0.35", | ||||||
|  |     "prompt-sync": "^4.2.0", | ||||||
|     "sharp": "^0.27.0", |     "sharp": "^0.27.0", | ||||||
|     "slick-carousel": "^1.8.1", |     "slick-carousel": "^1.8.1", | ||||||
|     "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2", |     "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2", | ||||||
|  |  | ||||||
							
								
								
									
										147
									
								
								scripts/generateLicenseInfo.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								scripts/generateLicenseInfo.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,147 @@ | ||||||
|  | import {Utils} from "../Utils"; | ||||||
|  | 
 | ||||||
|  | Utils.runningFromConsole = true; | ||||||
|  | 
 | ||||||
|  | import {existsSync, mkdirSync, readdirSync, readFileSync, writeFile, writeFileSync, lstatSync} from "fs"; | ||||||
|  | import {LicenseInfo} from "../Logic/Web/Wikimedia"; | ||||||
|  | import {icon, Icon} from "leaflet"; | ||||||
|  | 
 | ||||||
|  | interface SmallLicense { | ||||||
|  |     path: string, | ||||||
|  |     authors: string[], | ||||||
|  |     license: string, | ||||||
|  |     sources: string[] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Sweeps the entire 'assets/' (except assets/generated) directory for image files and any 'license_info.json'-file. | ||||||
|  |  * Checks that the license info is included for each of them and generates a compiles license_info.json for those | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | function readDirRecSync(path): string[] { | ||||||
|  |     const result = [] | ||||||
|  |     for (const entry of readdirSync(path)) { | ||||||
|  |         const fullEntry = path + "/" + entry | ||||||
|  |         const stats = lstatSync(fullEntry) | ||||||
|  |         if (stats.isDirectory()) { | ||||||
|  |             // Subdirectory
 | ||||||
|  |             // @ts-ignore
 | ||||||
|  |             result.push(...readDirRecSync(fullEntry)) | ||||||
|  |         } else { | ||||||
|  |             result.push(fullEntry) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function generateLicenseInfos(paths: string[]): SmallLicense[] { | ||||||
|  |     const licenses = [] | ||||||
|  |     for (const path of paths) { | ||||||
|  |         console.log("Reading info from " + path) | ||||||
|  |         const parsed = JSON.parse(readFileSync(path, "UTF-8")) | ||||||
|  |         if (Array.isArray(parsed)) { | ||||||
|  |             const l: SmallLicense[] = parsed | ||||||
|  |             for (const smallLicens of l) { | ||||||
|  |                 smallLicens.path = path.substring(0, path.length - "license_info.json".length) + smallLicens.path | ||||||
|  |             } | ||||||
|  |             licenses.push(...l) | ||||||
|  |         } else { | ||||||
|  |             const smallLicens: SmallLicense = parsed; | ||||||
|  |             smallLicens.path = path.substring(0, 1 + path.lastIndexOf("/")) + smallLicens.path | ||||||
|  |             licenses.push(smallLicens) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  |     return licenses | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function missingLicenseInfos(licenseInfos: SmallLicense[], allIcons: string[]) { | ||||||
|  |     const missing = [] | ||||||
|  | 
 | ||||||
|  |     const knownPaths = new Set<string>() | ||||||
|  |     for (const licenseInfo of licenseInfos) { | ||||||
|  |         knownPaths.add(licenseInfo.path) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (const iconPath of allIcons) { | ||||||
|  |         if (iconPath.indexOf("license_info.json") >= 0) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         if (knownPaths.has(iconPath)) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         missing.push(iconPath) | ||||||
|  |     } | ||||||
|  |     return missing; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const prompt = require('prompt-sync')(); | ||||||
|  | 
 | ||||||
|  | function promptLicenseFor(path): SmallLicense { | ||||||
|  |     const author = prompt("What is the author for artwork " + path + "? (me == Pieter Vander Vennet/CC0, Q to quit)  > ") | ||||||
|  |     path = path.substring(path.lastIndexOf("/") + 1) | ||||||
|  |     if (author == "me") { | ||||||
|  |         return { | ||||||
|  |             authors: ["Pieter Vander Vennet"], | ||||||
|  |             path: path, | ||||||
|  |             license: "CC0", | ||||||
|  |             sources: [] | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (author == "cf") { | ||||||
|  |         return { | ||||||
|  |             authors: ["Pieter Fiers", "Thibault Declercq", "Pierre Barban", "Joost Schouppe","Pieter Vander Vennet"], | ||||||
|  |             path: path, | ||||||
|  |             license: "CC-BY-SA", | ||||||
|  |             sources: ["https://osoc.be/editions/2020/cyclofix"] | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (author == "gitte") { | ||||||
|  |         return { | ||||||
|  |             authors: ["Gitte Vande Graveele"], | ||||||
|  |             path: path, | ||||||
|  |             license: "CC-BY-SA", | ||||||
|  |             sources: ["https://osoc.be/editions/2020/walk-by-brussels"] | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if(author == "s"){ | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |     if (author == "Q" || author == "q" || author == "") { | ||||||
|  |         throw "Quitting now!" | ||||||
|  |     } | ||||||
|  |     return { | ||||||
|  |         authors: author.split(";"), | ||||||
|  |         path: path, | ||||||
|  |         license: prompt("What is the license for artwork " + path + "?  > "), | ||||||
|  |         sources: prompt("Where was this artwork found?  > ").split(";") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function createLicenseInfoFor(path): void { | ||||||
|  |     const li = promptLicenseFor(path); | ||||||
|  |     if(li == null){ | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     writeFileSync(path + ".license_info.json", JSON.stringify(li, null, "  ")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | console.log("Checking and compiling license info") | ||||||
|  | const contents = readDirRecSync("./assets") | ||||||
|  |     .filter(entry => entry.indexOf("./assets/generated") != 0) | ||||||
|  | const licensePaths = contents.filter(entry => entry.indexOf("license_info.json") >= 0) | ||||||
|  | const licenseInfos = generateLicenseInfos(licensePaths); | ||||||
|  | writeFileSync("./assets/generated/license_info.json", JSON.stringify(licenseInfos, null, "  ")) | ||||||
|  | 
 | ||||||
|  | const artwork = contents.filter(pth => pth.match(/(.svg|.png|.jpg)$/i) != null) | ||||||
|  | const missingLicenses = missingLicenseInfos(licenseInfos, artwork) | ||||||
|  | 
 | ||||||
|  | console.log(`There are ${missingLicenses.length} licenses missing.`) | ||||||
|  | 
 | ||||||
|  | let i = 1; | ||||||
|  | for (const missingLicens of missingLicenses) { | ||||||
|  |     console.log(i + " / " + missingLicenses.length) | ||||||
|  |     createLicenseInfoFor(missingLicens) | ||||||
|  |     i++; | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue