recognize usercss @updateURL
* installation URL is preferred - same behavior as before * @updateURL is used when the style was drag'n'dropped into the manage page because there's no real URL in this case * install-usercss page shows the new update URL, which is set as per the above, under the checkbox that enables updates
This commit is contained in:
		
							parent
							
								
									0659ff6233
								
							
						
					
					
						commit
						f337e18515
					
				|  | @ -78,8 +78,8 @@ var usercssHelper = (() => { | |||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   function openInstallPage(tab, {url = tab.url, direct} = {}) { | ||||
|     if (direct) { | ||||
|   function openInstallPage(tab, {url = tab.url, direct, downloaded} = {}) { | ||||
|     if (direct && !downloaded) { | ||||
|       prefetchCodeForInstallation(tab.id, url); | ||||
|     } | ||||
|     return wrapReject(openURL({ | ||||
|  |  | |||
|  | @ -64,6 +64,7 @@ | |||
|           <input type="checkbox"> | ||||
|           <svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg> | ||||
|           <span></span> | ||||
|           <p></p> | ||||
|         </label> | ||||
|         <label class="live-reload"> | ||||
|           <input type="checkbox"> | ||||
|  |  | |||
|  | @ -193,6 +193,17 @@ h2.installed.active { | |||
|   min-width: 0; | ||||
| } | ||||
| 
 | ||||
| .set-update-url { | ||||
|   flex-wrap: wrap; | ||||
| } | ||||
| 
 | ||||
| .set-update-url p { | ||||
|   word-break: break-all; | ||||
|   opacity: .5; | ||||
|   width: 100%; | ||||
|   margin: .25em 0 .25em; | ||||
| } | ||||
| 
 | ||||
| .external { | ||||
|   text-align: center; | ||||
| } | ||||
|  |  | |||
|  | @ -283,24 +283,28 @@ | |||
|     }; | ||||
| 
 | ||||
|     // set updateUrl
 | ||||
|     const setUpdate = $('.set-update-url input[type=checkbox]'); | ||||
|     const updateUrl = new URL(params.get('updateUrl')); | ||||
|     const checker = $('.set-update-url input[type=checkbox]'); | ||||
|     // prefer the installation URL unless drag'n'dropped on the manage page
 | ||||
|     const installationUrl = (params.get('updateUrl') || '').replace(/^blob.+/, ''); | ||||
|     const updateUrl = new URL(installationUrl || style.updateUrl || 'foo:bar'); | ||||
|     $('.set-update-url > span').textContent = t('installUpdateFromLabel'); | ||||
|     if (dup && dup.updateUrl === updateUrl.href) { | ||||
|       setUpdate.checked = true; | ||||
|       checker.checked = true; | ||||
|       // there is no way to "unset" updateUrl, you can only overwrite it.
 | ||||
|       setUpdate.disabled = true; | ||||
|       checker.disabled = true; | ||||
|     } else if (updateUrl.protocol === 'foo:') { | ||||
|       // drag'n'dropped on the manage page and the style doesn't have @updateURL
 | ||||
|       checker.disabled = true; | ||||
|     } else if (updateUrl.protocol !== 'file:') { | ||||
|       setUpdate.checked = true; | ||||
|       checker.checked = true; | ||||
|       style.updateUrl = updateUrl.href; | ||||
|     } | ||||
|     setUpdate.onchange = e => { | ||||
|       if (e.target.checked) { | ||||
|         style.updateUrl = updateUrl.href; | ||||
|       } else { | ||||
|         delete style.updateUrl; | ||||
|       } | ||||
|     checker.onchange = () => { | ||||
|       style.updateUrl = checker.checked ? updateUrl.href : null; | ||||
|     }; | ||||
|     checker.onchange(); | ||||
|     $('.set-update-url p').textContent = updateUrl.href.length < 300 ? updateUrl.href : | ||||
|       updateUrl.href.slice(0, 300) + '...'; | ||||
| 
 | ||||
|     if (!port) { | ||||
|       return; | ||||
|  |  | |||
							
								
								
									
										120
									
								
								js/usercss.js
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								js/usercss.js
									
									
									
									
									
								
							|  | @ -3,25 +3,34 @@ | |||
| 
 | ||||
| // eslint-disable-next-line no-var
 | ||||
| var usercss = (() => { | ||||
|   // true for global, false for private
 | ||||
|   const METAS = { | ||||
|     __proto__: null, | ||||
|     author: true, | ||||
|     advanced: false, | ||||
|     description: true, | ||||
|     homepageURL: false, | ||||
|     // icon: false,
 | ||||
|     license: false, | ||||
|     name: true, | ||||
|     namespace: false, | ||||
|     // noframes: false,
 | ||||
|     preprocessor: false, | ||||
|     supportURL: false, | ||||
|     'var': false, | ||||
|     version: false | ||||
|   }; | ||||
| 
 | ||||
|   // true = global
 | ||||
|   // false or 0 = private
 | ||||
|   // <string> = global key name
 | ||||
|   // <function> = (style, newValue)
 | ||||
|   const KNOWN_META = new Map([ | ||||
|     ['author', true], | ||||
|     ['advanced', 0], | ||||
|     ['description', true], | ||||
|     ['homepageURL', 'url'], | ||||
|     ['icon', 0], | ||||
|     ['license', 0], | ||||
|     ['name', true], | ||||
|     ['namespace', 0], | ||||
|     //['noframes', 0],
 | ||||
|     ['preprocessor', 0], | ||||
|     ['supportURL', 0], | ||||
|     ['updateURL', (style, newValue) => { | ||||
|       // always preserve locally installed style's updateUrl
 | ||||
|       if (!/^file:/.test(style.updateUrl)) { | ||||
|         style.updateUrl = newValue; | ||||
|       } | ||||
|     }], | ||||
|     ['var', 0], | ||||
|     ['version', 0], | ||||
|   ]); | ||||
|   const MANDATORY_META = ['name', 'namespace', 'version']; | ||||
|   const META_VARS = ['text', 'color', 'checkbox', 'select', 'dropdown', 'image']; | ||||
|   const META_URLS = [...KNOWN_META.keys()].filter(k => k.endsWith('URL')); | ||||
| 
 | ||||
|   const BUILDER = { | ||||
|     default: { | ||||
|  | @ -221,7 +230,7 @@ var usercss = (() => { | |||
|       } | ||||
|     } | ||||
|     state.usercssData.vars[result.name] = result; | ||||
|     validVar(result); | ||||
|     validateVar(result); | ||||
|   } | ||||
| 
 | ||||
|   function createOption(label, value) { | ||||
|  | @ -407,28 +416,39 @@ var usercss = (() => { | |||
|     function doParse() { | ||||
|       let match; | ||||
|       while ((match = re.exec(text))) { | ||||
|         state.key = match[1]; | ||||
|         if (!(state.key in METAS)) { | ||||
|         const key = state.key = match[1]; | ||||
|         const route = KNOWN_META.get(key); | ||||
|         if (route === undefined) { | ||||
|           continue; | ||||
|         } | ||||
|         if (state.key === 'var' || state.key === 'advanced') { | ||||
|           if (state.key === 'advanced') { | ||||
|         if (key === 'var' || key === 'advanced') { | ||||
|           if (key === 'advanced') { | ||||
|             state.maybeUSO = true; | ||||
|           } | ||||
|           parseVar(state); | ||||
|         } else { | ||||
|           parseStringToEnd(state); | ||||
|           usercssData[state.key] = state.value; | ||||
|           usercssData[key] = state.value; | ||||
|         } | ||||
|         if (state.key === 'version') { | ||||
|           usercssData[state.key] = normalizeVersion(usercssData[state.key]); | ||||
|           validVersion(usercssData[state.key]); | ||||
|         let value = state.value; | ||||
|         if (key === 'version') { | ||||
|           value = usercssData[key] = normalizeVersion(value); | ||||
|           validateVersion(value); | ||||
|         } | ||||
|         if (METAS[state.key]) { | ||||
|           style[state.key] = usercssData[state.key]; | ||||
|         if (META_URLS.includes(key)) { | ||||
|           validateUrl(key, value); | ||||
|         } | ||||
|         switch (typeof route) { | ||||
|           case 'function': | ||||
|             route(style, value); | ||||
|             break; | ||||
|           case 'string': | ||||
|             style[route] = value; | ||||
|             break; | ||||
|           default: | ||||
|             if (route) { | ||||
|               style[key] = value; | ||||
|             } | ||||
|         if (state.key === 'homepageURL' || state.key === 'supportURL') { | ||||
|           validUrl(usercssData[state.key]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | @ -446,12 +466,8 @@ var usercss = (() => { | |||
|     if (state.maybeUSO && !usercssData.preprocessor) { | ||||
|       usercssData.preprocessor = 'uso'; | ||||
|     } | ||||
|     if (usercssData.homepageURL) { | ||||
|       style.url = usercssData.homepageURL; | ||||
|     } | ||||
| 
 | ||||
|     validate(style); | ||||
| 
 | ||||
|     validateStyle(style); | ||||
|     return style; | ||||
|   } | ||||
| 
 | ||||
|  | @ -505,42 +521,32 @@ var usercss = (() => { | |||
|     return va[prop]; | ||||
|   } | ||||
| 
 | ||||
|   function validate(style) { | ||||
|     const {usercssData: data} = style; | ||||
|     // mandatory fields
 | ||||
|     for (const prop of ['name', 'namespace', 'version']) { | ||||
|   function validateStyle({usercssData: data}) { | ||||
|     for (const prop of MANDATORY_META) { | ||||
|       if (!data[prop]) { | ||||
|         throw new Error(chrome.i18n.getMessage('styleMissingMeta', prop)); | ||||
|       } | ||||
|     } | ||||
|     // validate version
 | ||||
|     validVersion(data.version); | ||||
| 
 | ||||
|     // validate URLs
 | ||||
|     validUrl(data.homepageURL); | ||||
|     validUrl(data.supportURL); | ||||
| 
 | ||||
|     // validate vars
 | ||||
|     for (const key of Object.keys(data.vars)) { | ||||
|       validVar(data.vars[key]); | ||||
|     } | ||||
|     validateVersion(data.version); | ||||
|     META_URLS.forEach(k => validateUrl(k, data[k])); | ||||
|     Object.keys(data.vars).forEach(k => validateVar(data.vars[k])); | ||||
|   } | ||||
| 
 | ||||
|   function validVersion(version) { | ||||
|   function validateVersion(version) { | ||||
|     semverCompare(version, '0.0.0'); | ||||
|   } | ||||
| 
 | ||||
|   function validUrl(url) { | ||||
|   function validateUrl(key, url) { | ||||
|     if (!url) { | ||||
|       return; | ||||
|     } | ||||
|     url = new URL(url); | ||||
|     if (url.protocol !== 'http:' && url.protocol !== 'https:') { | ||||
|       throw new Error(`${url.protocol} is not a valid protocol`); | ||||
|     if (!/^https?:/.test(url.protocol)) { | ||||
|       throw new Error(`${url.protocol} is not a valid protocol in ${key}`); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function validVar(va, value = 'default') { | ||||
|   function validateVar(va, value = 'default') { | ||||
|     if (va.type === 'select' || va.type === 'dropdown') { | ||||
|       if (va.options.every(o => o.name !== va[value])) { | ||||
|         throw new Error(chrome.i18n.getMessage('styleMetaErrorSelectValueMismatch')); | ||||
|  | @ -560,7 +566,7 @@ var usercss = (() => { | |||
|       if (oldVars[key] && oldVars[key].value) { | ||||
|         vars[key].value = oldVars[key].value; | ||||
|         try { | ||||
|           validVar(vars[key], 'value'); | ||||
|           validateVar(vars[key], 'value'); | ||||
|         } catch (e) { | ||||
|           vars[key].value = null; | ||||
|         } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user