throttle mozImport after 100ms, display progress after 500ms
* Ctrl-Enter = append button * Shift-Ctrl-Enter = replace button * instantaneous readiness of import dialog on non-blank input * code dedup: addSections() * trimNewLines() -> trim()
This commit is contained in:
		
							parent
							
								
									102b5e03d4
								
							
						
					
					
						commit
						8517e392fe
					
				
							
								
								
									
										180
									
								
								edit/edit.js
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								edit/edit.js
									
									
									
									
									
								
							|  | @ -1360,45 +1360,56 @@ function isUsercss(style) { | |||
| 
 | ||||
| function initWithSectionStyle({style, codeIsUpdated}) { | ||||
|   setStyleMeta(style); | ||||
| 
 | ||||
|   if (codeIsUpdated === false) { | ||||
|     setCleanGlobal(); | ||||
|     updateTitle(); | ||||
|     return; | ||||
|   if (codeIsUpdated !== false) { | ||||
|     editors.length = 0; | ||||
|     getSections().forEach(div => div.remove()); | ||||
|     addSections(style.sections.length ? style.sections : [{code: ''}]); | ||||
|     initHooks(); | ||||
|   } | ||||
|   // if this was done in response to an update, we need to clear existing sections
 | ||||
|   editors.length = 0; | ||||
|   getSections().forEach(div => div.remove()); | ||||
|   const queue = style.sections.length ? style.sections.slice() : [{code: ''}]; | ||||
|   const t0 = performance.now(); | ||||
|   maximizeCodeHeight.stats = null; | ||||
|   // after 100ms the sections will be added asynchronously
 | ||||
|   while (performance.now() - t0 <= 100 && queue.length) { | ||||
|     add(); | ||||
|   } | ||||
|   (function processQueue() { | ||||
|     if (queue.length) { | ||||
|       add(); | ||||
|       setTimeout(processQueue); | ||||
|       if (performance.now() - t0 > 500) { | ||||
|         setGlobalProgress(editors.length, style.sections.length); | ||||
|       } | ||||
|     } else { | ||||
|       setGlobalProgress(); | ||||
|     } | ||||
|   })(); | ||||
|   editors[0].focus(); | ||||
|   initHooks(); | ||||
|   setCleanGlobal(); | ||||
|   updateTitle(); | ||||
| } | ||||
| 
 | ||||
|   function add() { | ||||
|     const sectionDiv = addSection(null, queue.shift()); | ||||
|     maximizeCodeHeight(sectionDiv, !queue.length); | ||||
|     if (!queue.length) { | ||||
|       editors.last.state.renderLintReportNow = true; | ||||
|     } | ||||
| function addSections(sections, onAdded = () => {}) { | ||||
|   if (addSections.running) { | ||||
|     console.error('addSections cannot be re-entered: please report to the developers'); | ||||
|     // TODO: handle this properly e.g. on update/import
 | ||||
|     return; | ||||
|   } | ||||
|   addSections.running = true; | ||||
|   maximizeCodeHeight.stats = null; | ||||
|   // make a shallow copy since we might run asynchronously
 | ||||
|   // and the original array might get modified
 | ||||
|   sections = sections.slice(); | ||||
|   const t0 = performance.now(); | ||||
|   const divs = []; | ||||
|   let index = 0; | ||||
|   return new Promise(function run(resolve) { | ||||
|     while (index < sections.length) { | ||||
|       const div = addSection(null, sections[index]); | ||||
|       maximizeCodeHeight(div, index === sections.length - 1); | ||||
|       onAdded(div, index); | ||||
|       divs.push(div); | ||||
|       index++; | ||||
|       const elapsed = performance.now() - t0; | ||||
|       if (elapsed > 500) { | ||||
|         setGlobalProgress(index, sections.length); | ||||
|       } | ||||
|       if (elapsed > 100) { | ||||
|         // after 100ms the sections are added asynchronously
 | ||||
|         setTimeout(run, 0, resolve); | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|     if (divs[0]) { | ||||
|       makeSectionVisible(divs[0].CodeMirror); | ||||
|       divs[0].CodeMirror.focus(); | ||||
|     } | ||||
|     editors.last.state.renderLintReportNow = true; | ||||
|     addSections.running = false; | ||||
|     setGlobalProgress(); | ||||
|     resolve(divs); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| function setupOptionsExpand() { | ||||
|  | @ -1657,74 +1668,61 @@ function fromMozillaFormat() { | |||
|         name: 'import-replace', | ||||
|         textContent: t('importReplaceLabel'), | ||||
|         title: t('importReplaceTooltip'), | ||||
|         onclick: doImport, | ||||
|         onclick: () => doImport({replaceOldStyle: true}), | ||||
|       }), | ||||
|     ]})); | ||||
| 
 | ||||
|   const contents = $('.contents', popup); | ||||
|   contents.insertBefore(popup.codebox.display.wrapper, contents.firstElementChild); | ||||
|   popup.codebox.focus(); | ||||
|   popup.codebox.on('change', () => { | ||||
|     clearTimeout(popup.mozillaTimeout); | ||||
|     popup.mozillaTimeout = setTimeout(() => { | ||||
|       popup.classList.toggle('ready', trimNewLines(popup.codebox.getValue())); | ||||
|     }, 100); | ||||
|   popup.codebox.on('changes', cm => { | ||||
|     popup.classList.toggle('ready', !cm.isBlank()); | ||||
|   }); | ||||
|   // overwrite default extraKeys as those are inapplicable in popup context
 | ||||
|   popup.codebox.options.extraKeys = { | ||||
|     'Ctrl-Enter': doImport, | ||||
|     'Shift-Ctrl-Enter': () => doImport({replaceOldStyle: true}), | ||||
|   }; | ||||
| 
 | ||||
|   function doImport(event) { | ||||
|     const replaceOldStyle = event.target.name === 'import-replace'; | ||||
|     const mozStyle = trimNewLines(popup.codebox.getValue()); | ||||
| 
 | ||||
|     mozParser.parse(mozStyle) | ||||
|       .then(updateSection) | ||||
|       .then(() => { | ||||
|         editors.forEach(cm => updateLintReportIfEnabled(cm, 1)); | ||||
|         editors.last.state.renderLintReportNow = true; | ||||
|   function doImport({replaceOldStyle = false}) { | ||||
|     lockPageUI(true); | ||||
|     new Promise(setTimeout) | ||||
|       .then(() => mozParser.parse(popup.codebox.getValue().trim())) | ||||
|       .then(sections => { | ||||
|         removeOldSections(replaceOldStyle); | ||||
|         return addSections(sections, div => setCleanItem(div, false)); | ||||
|       }) | ||||
|       .then(sectionDivs => { | ||||
|         sectionDivs.forEach(div => updateLintReportIfEnabled(div.CodeMirror, 1)); | ||||
|         $('.dismiss', popup).onclick(); | ||||
|       }) | ||||
|       .catch(showError); | ||||
| 
 | ||||
|     function showError(errors) { | ||||
|       if (!Array.isArray(errors)) { | ||||
|         errors = [errors]; | ||||
|       } | ||||
|       showHelp(t('styleFromMozillaFormatError'), $element({ | ||||
|         tag: 'pre', | ||||
|         textContent: errors.join('\n'), | ||||
|       })); | ||||
|     } | ||||
| 
 | ||||
|     function updateSection(sections) { | ||||
|       if (replaceOldStyle) { | ||||
|         editors.slice(0).reverse().forEach(cm => { | ||||
|           removeSection({target: cm.getSection().firstElementChild}); | ||||
|         }); | ||||
|       } else if (!editors.last.getValue()) { | ||||
|         // nuke the last blank section
 | ||||
|         if ($('.applies-to-everything', editors.last.getSection())) { | ||||
|           removeSection({target: editors.last.getSection()}); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       const firstSection = sections[0]; | ||||
|       setCleanItem(addSection(null, firstSection), false); | ||||
|       const firstAddedCM = editors.last; | ||||
|       for (const section of sections.slice(1)) { | ||||
|         setCleanItem(addSection(null, section), false); | ||||
|       } | ||||
| 
 | ||||
|       delete maximizeCodeHeight.stats; | ||||
|       editors.forEach(cm => { | ||||
|         maximizeCodeHeight(cm.getSection(), cm === editors.last); | ||||
|       }); | ||||
| 
 | ||||
|       makeSectionVisible(firstAddedCM); | ||||
|       firstAddedCM.focus(); | ||||
|     } | ||||
|       .catch(showError) | ||||
|       .then(() => lockPageUI(false)); | ||||
|   } | ||||
| 
 | ||||
|   function trimNewLines(s) { | ||||
|     return s.replace(/^[\s\n]+/, '').replace(/[\s\n]+$/, ''); | ||||
|   function removeOldSections(removeAll) { | ||||
|     let toRemove; | ||||
|     if (removeAll) { | ||||
|       toRemove = editors.slice().reverse(); | ||||
|     } else if (editors.last.isBlank() && $('.applies-to-everything', editors.last.getSection())) { | ||||
|       toRemove = [editors.last]; | ||||
|     } else { | ||||
|       return; | ||||
|     } | ||||
|     toRemove.forEach(cm => removeSection({target: cm.getSection()})); | ||||
|   } | ||||
| 
 | ||||
|   function lockPageUI(locked) { | ||||
|     document.documentElement.style.pointerEvents = locked ? 'none' : ''; | ||||
|     popup.classList.toggle('ready', locked ? false : !popup.codebox.isBlank()); | ||||
|     popup.codebox.options.readOnly = locked; | ||||
|     popup.codebox.display.wrapper.style.opacity = locked ? '.5' : ''; | ||||
|   } | ||||
| 
 | ||||
|   function showError(errors) { | ||||
|     showHelp(t('styleFromMozillaFormatError'), $element({ | ||||
|       tag: 'pre', | ||||
|       textContent: Array.isArray(errors) ? errors.join('\n') : errors, | ||||
|     })); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user