| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- /*
- The main object that will be provided to all scripts in VNoteX.
- Maintain a list of workers for different tasks.
- Main:
- - initialized()
- - ready()
- Markdown scenario:
- - markdownTextUpdated(p_text)
- - basicMarkdownRendered()
- - fullMarkdownRendered()
- */
- class VNoteX extends EventEmitter {
- constructor() {
- super();
- this.kickedOff = false;
- this.initialized = false;
- // Registered workers.
- // name -> worker.
- this.workers = new Map();
- this.numOfOngoingWorkers = 0;
- this.pendingData = {
- text: null,
- lineNumber: -1,
- anchor: null
- }
- this.numOfMuteScroll = 0;
- this.os = VNoteX.detectOS();
- this.turndown = null;
- this.sectionNumberBaseLevel = 2;
- // Dict mapping from {id, index} to callback for renderGraph().
- this.renderGraphCallbacks = {}
- window.addEventListener('load', () => {
- console.log('window load finished');
- // Init DOM nodes.
- this.contentContainer = document.getElementById('vx-content');
- this.inplacePreviewContainer = document.getElementById('vx-inplace-preview');
- this.nodeLineMapper = new NodeLineMapper(this, this.contentContainer);
- this.graphPreviewer = new GraphPreviewer(this, this.inplacePreviewContainer);
- this.crossCopyer = new CrossCopy(this);
- this.searcher = new MarkJs(this, this.contentContainer);
- this.sectionNumberBaseLevel = window.vxOptions.sectionNumberBaseLevel;
- if (this.sectionNumberBaseLevel > 3) {
- console.warn('only support section number base level less than 3', this.sectionNumberBaseLevel);
- this.sectionNumberBaseLevel = 3;
- }
- this.setContentContainerOption('vx-constrain-image-width',
- window.vxOptions.constrainImageWidthEnabled || !window.vxOptions.scrollable);
- this.setContentContainerOption('vx-image-align-center',
- window.vxOptions.imageAlignCenterEnabled);
- this.setContentContainerOption('vx-indent-first-line',
- window.vxOptions.indentFirstLineEnabled);
- this.setContentContainerOption('line-numbers',
- window.vxOptions.codeBlockLineNumberEnabled);
- this.setBodyOption('vx-transparent-background',
- window.vxOptions.transparentBackgroundEnabled);
- this.setContentContainerOption('vx-nonscrollable',
- !window.vxOptions.scrollable);
- this.setBodySize(window.vxOptions.bodyWidth, window.vxOptions.bodyHeight);
- document.body.style.height = '800';
- this.initialized = true;
- // Signal out.
- this.emit('initialized');
- this.emit('ready');
- });
- }
- setContentContainerOption(p_class, p_enabled) {
- if (p_enabled) {
- this.contentContainer.classList.add(p_class);
- } else {
- this.contentContainer.classList.remove(p_class);
- }
- }
- setBodyOption(p_class, p_enabled) {
- if (p_enabled) {
- document.body.classList.add(p_class);
- } else {
- document.body.classList.remove(p_class);
- }
- }
- registerWorker(p_worker) {
- this.workers.set(p_worker.name, p_worker);
- p_worker.register(this);
- }
- finishWorker(p_name) {
- --this.numOfOngoingWorkers;
- if (this.numOfOngoingWorkers == 0) {
- // Signal out anyway.
- this.emit('fullMarkdownRendered');
- window.vxMarkdownAdapter.setWorkFinished();
- // Check pending work.
- if (this.pendingData.text) {
- this.setMarkdownText(this.pendingData.text);
- } else if (this.pendingData.lineNumber > -1) {
- this.scrollToLine(this.pendingData.lineNumber);
- }
- }
- }
- getWorker(p_name) {
- return this.workers.get(p_name);
- }
- kickOffMarkdown() {
- if (this.kickedOff) {
- return;
- }
- console.log('viewer is ready now, kick off Markdown');
- this.kickedOff = true;
- window.vxMarkdownAdapter.setReady(true);
- }
- setMarkdownText(p_text) {
- if (this.numOfOngoingWorkers > 0) {
- this.pendingData.text = p_text;
- console.info('wait for last render finish with remaing workers',
- this.numOfOngoingWorkers);
- } else {
- this.numOfOngoingWorkers = this.workers.size;
- this.pendingData.text = null;
- console.log('start new round with ' + this.numOfOngoingWorkers + ' workers');
- this.emit('markdownTextUpdated', p_text);
- }
- }
- scrollToLine(p_lineNumber) {
- if (p_lineNumber < 0) {
- return;
- }
- if (this.numOfOngoingWorkers > 0) {
- this.pendingData.lineNumber = p_lineNumber;
- console.log('wait for render finish before scroll');
- } else {
- this.pendingData.lineNumber = -1;
- this.nodeLineMapper.scrollToLine(p_lineNumber);
- }
- }
- scrollToAnchor(p_anchor) {
- if (!p_anchor) {
- return;
- }
- if (this.numOfOngoingWorkers > 0) {
- this.pendingData.anchor = p_anchor;
- console.log('wait for render finish before scroll');
- } else {
- this.pendingData.anchor = '';
- this.nodeLineMapper.scrollToAnchor(p_anchor);
- }
- }
- setBasicMarkdownRendered() {
- this.emit('basicMarkdownRendered');
- }
- muteScroll() {
- ++this.numOfMuteScroll;
- }
- unmuteScroll() {
- window.setTimeout(() => {
- if (this.numOfMuteScroll > 0) {
- --this.numOfMuteScroll;
- if (this.numOfMuteScroll == 0) {
- this.nodeLineMapper.updateAfterScrollUnmuted();
- }
- }
- }, 1000);
- }
- isScrollMuted() {
- return this.numOfMuteScroll > 0;
- }
- setTopLineNumber(p_lineNumber) {
- window.vxMarkdownAdapter.setTopLineNumber(p_lineNumber);
- }
- previewGraph(p_id, p_timeStamp, p_lang, p_text) {
- if (this.graphPreviewer) {
- this.graphPreviewer.previewGraph(p_id, p_timeStamp, p_lang, p_text);
- }
- }
- previewMath(p_id, p_timeStamp, p_text) {
- if (this.graphPreviewer) {
- this.graphPreviewer.previewMath(p_id, p_timeStamp, p_text);
- }
- }
- setGraphPreviewData(p_data) {
- window.vxMarkdownAdapter.setGraphPreviewData(p_data.id,
- p_data.timeStamp,
- p_data.format,
- p_data.data,
- p_data.base64,
- p_data.needScale);
- }
- setMathPreviewData(p_data) {
- window.vxMarkdownAdapter.setMathPreviewData(p_data.id,
- p_data.timeStamp,
- p_data.format,
- p_data.data,
- p_data.base64,
- p_data.needScale);
- }
- setHeadings(p_headings) {
- window.vxMarkdownAdapter.setHeadings(p_headings);
- }
- setCurrentHeadingAnchor(p_idx, p_anchor) {
- window.vxMarkdownAdapter.setCurrentHeadingAnchor(p_idx, p_anchor);
- }
- setSectionNumberEnabled(p_enabled) {
- let sectionClass = 'vx-section-number';
- let sectionLevelClass = 'vx-section-number-' + this.sectionNumberBaseLevel;
- this.setContentContainerOption(sectionClass, p_enabled);
- this.setContentContainerOption(sectionLevelClass, p_enabled);
- }
- scroll(p_up) {
- EasyAccess.scroll(p_up);
- }
- setKeyPress(p_key, p_ctrl, p_shift, p_meta) {
- window.vxMarkdownAdapter.setKeyPress(p_key, p_ctrl, p_shift, p_meta);
- }
- zoom(p_zoomIn) {
- window.vxMarkdownAdapter.zoom(p_zoomIn);
- }
- htmlToMarkdown(p_id, p_timeStamp, p_html) {
- if (!this.turndown) {
- this.turndown = new TurndownConverter(this);
- }
- let markdown = this.turndown.turndown(p_html);
- window.vxMarkdownAdapter.setMarkdownFromHtml(p_id, p_timeStamp, markdown);
- }
- highlightCodeBlock(p_idx, p_timeStamp, p_text) {
- let match = /^```[^\S\n]*(\S+)?\s*\n([\s\S]+)\n```\s*$/.exec(p_text);
- if (!match || !match[1] || !match[2]) {
- window.vxMarkdownAdapter.setCodeBlockHighlightHtml(p_idx, p_timeStamp, '');
- return;
- }
- let lang = match[1];
- let body = match[2];
- if (Prism && Prism.languages[lang]) {
- let html = Prism.highlight(body, Prism.languages[lang], lang);
- window.vxMarkdownAdapter.setCodeBlockHighlightHtml(p_idx, p_timeStamp, html);
- } else {
- window.vxMarkdownAdapter.setCodeBlockHighlightHtml(p_idx, p_timeStamp, '');
- }
- }
- parseStyleSheet(p_id, p_styleSheet) {
- let doc = document.implementation.createHTMLDocument('');
- let styleEle = document.createElement('style');
- styleEle.textContent = p_styleSheet;
- doc.body.appendChild(styleEle);
- let styles = [];
- for (let i = 0; i < styleEle.sheet.cssRules.length; ++i) {
- let rule = styleEle.sheet.cssRules[i];
- if (rule.type != CSSRule.STYLE_RULE) {
- continue;
- }
- styles.push({
- selector: rule.selectorText,
- color: rule.style.color,
- backgroundColor: rule.style.backgroundColor,
- fontWeight: rule.style.fontWeight,
- fontStyle: rule.style.fontStyle
- });
- }
- window.vxMarkdownAdapter.setStyleSheetStyles(p_id, styles);
- }
- setCrossCopyTargets(p_targets) {
- window.vxMarkdownAdapter.setCrossCopyTargets(p_targets);
- }
- crossCopy(p_id, p_timeStamp, p_target, p_baseUrl, p_html) {
- this.crossCopyer.crossCopy(p_id, p_timeStamp, p_target, p_baseUrl, p_html);
- }
- setCrossCopyResult(p_id, p_timeStamp, p_html) {
- window.vxMarkdownAdapter.setCrossCopyResult(p_id, p_timeStamp, p_html);
- }
- findText(p_texts, p_options, p_currentMatchLine) {
- this.searcher.findText(p_texts, p_options, p_currentMatchLine);
- }
- showFindResult(p_texts, p_totalMatches, p_currentMatchIndex) {
- window.vxMarkdownAdapter.setFindText(p_texts, p_totalMatches, p_currentMatchIndex);
- }
- saveContent() {
- if (!this.initialized) {
- console.warn('saveContent() called before initialization');
- window.vxMarkdownAdapter.setSavedContent('', '', '');
- return;
- }
- window.vxMarkdownAdapter.setSavedContent("",
- Utils.fetchStyleContent(),
- this.contentContainer.outerHTML,
- document.body.classList.value);
- }
- setBodySize(p_width, p_height) {
- if (p_width > 0) {
- document.body.style.width = p_width + 'px';
- }
- if (p_height > 0) {
- document.body.style.height = p_height + 'px';
- }
- }
- renderGraph(p_id, p_index, p_format, p_lang, p_text, p_callback) {
- this.renderGraphCallbacks[p_id + '_' + p_index] = p_callback;
- window.vxMarkdownAdapter.renderGraph(p_id, p_index, p_format, p_lang, p_text);
- }
- graphRenderDataReady(p_id, p_index, p_format, p_data) {
- let key = p_id + '_' + p_index;
- if (key in this.renderGraphCallbacks) {
- this.renderGraphCallbacks[key](p_id, p_index, p_format, p_data);
- delete this.renderGraphCallbacks[key];
- }
- }
- static detectOS() {
- let osName="Unknown OS";
- if (navigator.appVersion.indexOf("Win")!=-1) {
- osName="Windows";
- } else if (navigator.appVersion.indexOf("Mac")!=-1) {
- osName="MacOS";
- } else if (navigator.appVersion.indexOf("X11")!=-1) {
- osName="UNIX";
- } else if (navigator.appVersion.indexOf("Linux")!=-1) {
- osName="Linux";
- }
- return osName
- }
- }
- window.vnotex = new VNoteX();
|