@21epub/epub-thirdparty
Version:
epub-thirdparty
508 lines (507 loc) • 22.5 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
import * as dom from '../../../base/browser/dom.js';
import { DisposableStore } from '../../../base/common/lifecycle.js';
import * as strings from '../../../base/common/strings.js';
import { URI } from '../../../base/common/uri.js';
import { AbstractCodeEditorService } from './abstractCodeEditorService.js';
import { isThemeColor } from '../../common/editorCommon.js';
import { OverviewRulerLane } from '../../common/model.js';
import { IThemeService } from '../../../platform/theme/common/themeService.js';
export class RefCountedStyleSheet {
constructor(parent, editorId, styleSheet) {
this._parent = parent;
this._editorId = editorId;
this._styleSheet = styleSheet;
this._refCount = 0;
}
ref() {
this._refCount++;
}
unref() {
var _a;
this._refCount--;
if (this._refCount === 0) {
(_a = this._styleSheet.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this._styleSheet);
this._parent._removeEditorStyleSheets(this._editorId);
}
}
insertRule(rule, index) {
const sheet = this._styleSheet.sheet;
sheet.insertRule(rule, index);
}
removeRulesContainingSelector(ruleName) {
dom.removeCSSRulesContainingSelector(ruleName, this._styleSheet);
}
}
export class GlobalStyleSheet {
constructor(styleSheet) {
this._styleSheet = styleSheet;
}
ref() {
}
unref() {
}
insertRule(rule, index) {
const sheet = this._styleSheet.sheet;
sheet.insertRule(rule, index);
}
removeRulesContainingSelector(ruleName) {
dom.removeCSSRulesContainingSelector(ruleName, this._styleSheet);
}
}
let CodeEditorServiceImpl = class CodeEditorServiceImpl extends AbstractCodeEditorService {
constructor(styleSheet, themeService) {
super();
this._decorationOptionProviders = new Map();
this._editorStyleSheets = new Map();
this._globalStyleSheet = styleSheet ? styleSheet : null;
this._themeService = themeService;
}
_getOrCreateGlobalStyleSheet() {
if (!this._globalStyleSheet) {
this._globalStyleSheet = new GlobalStyleSheet(dom.createStyleSheet());
}
return this._globalStyleSheet;
}
_getOrCreateStyleSheet(editor) {
if (!editor) {
return this._getOrCreateGlobalStyleSheet();
}
const domNode = editor.getContainerDomNode();
if (!dom.isInShadowDOM(domNode)) {
return this._getOrCreateGlobalStyleSheet();
}
const editorId = editor.getId();
if (!this._editorStyleSheets.has(editorId)) {
const refCountedStyleSheet = new RefCountedStyleSheet(this, editorId, dom.createStyleSheet(domNode));
this._editorStyleSheets.set(editorId, refCountedStyleSheet);
}
return this._editorStyleSheets.get(editorId);
}
_removeEditorStyleSheets(editorId) {
this._editorStyleSheets.delete(editorId);
}
registerDecorationType(description, key, options, parentTypeKey, editor) {
let provider = this._decorationOptionProviders.get(key);
if (!provider) {
const styleSheet = this._getOrCreateStyleSheet(editor);
const providerArgs = {
styleSheet: styleSheet,
key: key,
parentTypeKey: parentTypeKey,
options: options || Object.create(null)
};
if (!parentTypeKey) {
provider = new DecorationTypeOptionsProvider(description, this._themeService, styleSheet, providerArgs);
}
else {
provider = new DecorationSubTypeOptionsProvider(this._themeService, styleSheet, providerArgs);
}
this._decorationOptionProviders.set(key, provider);
this._onDecorationTypeRegistered.fire(key);
}
provider.refCount++;
}
removeDecorationType(key) {
const provider = this._decorationOptionProviders.get(key);
if (provider) {
provider.refCount--;
if (provider.refCount <= 0) {
this._decorationOptionProviders.delete(key);
provider.dispose();
this.listCodeEditors().forEach((ed) => ed.removeDecorations(key));
}
}
}
resolveDecorationOptions(decorationTypeKey, writable) {
const provider = this._decorationOptionProviders.get(decorationTypeKey);
if (!provider) {
throw new Error('Unknown decoration type key: ' + decorationTypeKey);
}
return provider.getOptions(this, writable);
}
};
CodeEditorServiceImpl = __decorate([
__param(1, IThemeService)
], CodeEditorServiceImpl);
export { CodeEditorServiceImpl };
export class DecorationSubTypeOptionsProvider {
constructor(themeService, styleSheet, providerArgs) {
this._styleSheet = styleSheet;
this._styleSheet.ref();
this._parentTypeKey = providerArgs.parentTypeKey;
this.refCount = 0;
this._beforeContentRules = new DecorationCSSRules(3 /* BeforeContentClassName */, providerArgs, themeService);
this._afterContentRules = new DecorationCSSRules(4 /* AfterContentClassName */, providerArgs, themeService);
}
getOptions(codeEditorService, writable) {
const options = codeEditorService.resolveDecorationOptions(this._parentTypeKey, true);
if (this._beforeContentRules) {
options.beforeContentClassName = this._beforeContentRules.className;
}
if (this._afterContentRules) {
options.afterContentClassName = this._afterContentRules.className;
}
return options;
}
dispose() {
if (this._beforeContentRules) {
this._beforeContentRules.dispose();
this._beforeContentRules = null;
}
if (this._afterContentRules) {
this._afterContentRules.dispose();
this._afterContentRules = null;
}
this._styleSheet.unref();
}
}
export class DecorationTypeOptionsProvider {
constructor(description, themeService, styleSheet, providerArgs) {
this._disposables = new DisposableStore();
this.description = description;
this._styleSheet = styleSheet;
this._styleSheet.ref();
this.refCount = 0;
const createCSSRules = (type) => {
const rules = new DecorationCSSRules(type, providerArgs, themeService);
this._disposables.add(rules);
if (rules.hasContent) {
return rules.className;
}
return undefined;
};
const createInlineCSSRules = (type) => {
const rules = new DecorationCSSRules(type, providerArgs, themeService);
this._disposables.add(rules);
if (rules.hasContent) {
return { className: rules.className, hasLetterSpacing: rules.hasLetterSpacing };
}
return null;
};
this.className = createCSSRules(0 /* ClassName */);
const inlineData = createInlineCSSRules(1 /* InlineClassName */);
if (inlineData) {
this.inlineClassName = inlineData.className;
this.inlineClassNameAffectsLetterSpacing = inlineData.hasLetterSpacing;
}
this.beforeContentClassName = createCSSRules(3 /* BeforeContentClassName */);
this.afterContentClassName = createCSSRules(4 /* AfterContentClassName */);
if (providerArgs.options.beforeInjectedText && providerArgs.options.beforeInjectedText.contentText) {
const beforeInlineData = createInlineCSSRules(5 /* BeforeInjectedTextClassName */);
this.beforeInjectedText = {
content: providerArgs.options.beforeInjectedText.contentText,
inlineClassName: beforeInlineData === null || beforeInlineData === void 0 ? void 0 : beforeInlineData.className,
inlineClassNameAffectsLetterSpacing: (beforeInlineData === null || beforeInlineData === void 0 ? void 0 : beforeInlineData.hasLetterSpacing) || providerArgs.options.beforeInjectedText.affectsLetterSpacing
};
}
if (providerArgs.options.afterInjectedText && providerArgs.options.afterInjectedText.contentText) {
const afterInlineData = createInlineCSSRules(6 /* AfterInjectedTextClassName */);
this.afterInjectedText = {
content: providerArgs.options.afterInjectedText.contentText,
inlineClassName: afterInlineData === null || afterInlineData === void 0 ? void 0 : afterInlineData.className,
inlineClassNameAffectsLetterSpacing: (afterInlineData === null || afterInlineData === void 0 ? void 0 : afterInlineData.hasLetterSpacing) || providerArgs.options.afterInjectedText.affectsLetterSpacing
};
}
this.glyphMarginClassName = createCSSRules(2 /* GlyphMarginClassName */);
const options = providerArgs.options;
this.isWholeLine = Boolean(options.isWholeLine);
this.stickiness = options.rangeBehavior;
const lightOverviewRulerColor = options.light && options.light.overviewRulerColor || options.overviewRulerColor;
const darkOverviewRulerColor = options.dark && options.dark.overviewRulerColor || options.overviewRulerColor;
if (typeof lightOverviewRulerColor !== 'undefined'
|| typeof darkOverviewRulerColor !== 'undefined') {
this.overviewRuler = {
color: lightOverviewRulerColor || darkOverviewRulerColor,
darkColor: darkOverviewRulerColor || lightOverviewRulerColor,
position: options.overviewRulerLane || OverviewRulerLane.Center
};
}
}
getOptions(codeEditorService, writable) {
if (!writable) {
return this;
}
return {
description: this.description,
inlineClassName: this.inlineClassName,
beforeContentClassName: this.beforeContentClassName,
afterContentClassName: this.afterContentClassName,
className: this.className,
glyphMarginClassName: this.glyphMarginClassName,
isWholeLine: this.isWholeLine,
overviewRuler: this.overviewRuler,
stickiness: this.stickiness,
before: this.beforeInjectedText,
after: this.afterInjectedText
};
}
dispose() {
this._disposables.dispose();
this._styleSheet.unref();
}
}
export const _CSS_MAP = {
color: 'color:{0} !important;',
opacity: 'opacity:{0};',
backgroundColor: 'background-color:{0};',
outline: 'outline:{0};',
outlineColor: 'outline-color:{0};',
outlineStyle: 'outline-style:{0};',
outlineWidth: 'outline-width:{0};',
border: 'border:{0};',
borderColor: 'border-color:{0};',
borderRadius: 'border-radius:{0};',
borderSpacing: 'border-spacing:{0};',
borderStyle: 'border-style:{0};',
borderWidth: 'border-width:{0};',
fontStyle: 'font-style:{0};',
fontWeight: 'font-weight:{0};',
fontSize: 'font-size:{0};',
fontFamily: 'font-family:{0};',
textDecoration: 'text-decoration:{0};',
cursor: 'cursor:{0};',
letterSpacing: 'letter-spacing:{0};',
gutterIconPath: 'background:{0} center center no-repeat;',
gutterIconSize: 'background-size:{0};',
contentText: 'content:\'{0}\';',
contentIconPath: 'content:{0};',
margin: 'margin:{0};',
padding: 'padding:{0};',
width: 'width:{0};',
height: 'height:{0};',
verticalAlign: 'vertical-align:{0};',
};
class DecorationCSSRules {
constructor(ruleType, providerArgs, themeService) {
this._theme = themeService.getColorTheme();
this._ruleType = ruleType;
this._providerArgs = providerArgs;
this._usesThemeColors = false;
this._hasContent = false;
this._hasLetterSpacing = false;
let className = CSSNameHelper.getClassName(this._providerArgs.key, ruleType);
if (this._providerArgs.parentTypeKey) {
className = className + ' ' + CSSNameHelper.getClassName(this._providerArgs.parentTypeKey, ruleType);
}
this._className = className;
this._unThemedSelector = CSSNameHelper.getSelector(this._providerArgs.key, this._providerArgs.parentTypeKey, ruleType);
this._buildCSS();
if (this._usesThemeColors) {
this._themeListener = themeService.onDidColorThemeChange(theme => {
this._theme = themeService.getColorTheme();
this._removeCSS();
this._buildCSS();
});
}
else {
this._themeListener = null;
}
}
dispose() {
if (this._hasContent) {
this._removeCSS();
this._hasContent = false;
}
if (this._themeListener) {
this._themeListener.dispose();
this._themeListener = null;
}
}
get hasContent() {
return this._hasContent;
}
get hasLetterSpacing() {
return this._hasLetterSpacing;
}
get className() {
return this._className;
}
_buildCSS() {
const options = this._providerArgs.options;
let unthemedCSS, lightCSS, darkCSS;
switch (this._ruleType) {
case 0 /* ClassName */:
unthemedCSS = this.getCSSTextForModelDecorationClassName(options);
lightCSS = this.getCSSTextForModelDecorationClassName(options.light);
darkCSS = this.getCSSTextForModelDecorationClassName(options.dark);
break;
case 1 /* InlineClassName */:
unthemedCSS = this.getCSSTextForModelDecorationInlineClassName(options);
lightCSS = this.getCSSTextForModelDecorationInlineClassName(options.light);
darkCSS = this.getCSSTextForModelDecorationInlineClassName(options.dark);
break;
case 2 /* GlyphMarginClassName */:
unthemedCSS = this.getCSSTextForModelDecorationGlyphMarginClassName(options);
lightCSS = this.getCSSTextForModelDecorationGlyphMarginClassName(options.light);
darkCSS = this.getCSSTextForModelDecorationGlyphMarginClassName(options.dark);
break;
case 3 /* BeforeContentClassName */:
unthemedCSS = this.getCSSTextForModelDecorationContentClassName(options.before);
lightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.before);
darkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.before);
break;
case 4 /* AfterContentClassName */:
unthemedCSS = this.getCSSTextForModelDecorationContentClassName(options.after);
lightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.after);
darkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.after);
break;
case 5 /* BeforeInjectedTextClassName */:
unthemedCSS = this.getCSSTextForModelDecorationContentClassName(options.beforeInjectedText);
lightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.beforeInjectedText);
darkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.beforeInjectedText);
break;
case 6 /* AfterInjectedTextClassName */:
unthemedCSS = this.getCSSTextForModelDecorationContentClassName(options.afterInjectedText);
lightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.afterInjectedText);
darkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.afterInjectedText);
break;
default:
throw new Error('Unknown rule type: ' + this._ruleType);
}
const sheet = this._providerArgs.styleSheet;
let hasContent = false;
if (unthemedCSS.length > 0) {
sheet.insertRule(`${this._unThemedSelector} {${unthemedCSS}}`, 0);
hasContent = true;
}
if (lightCSS.length > 0) {
sheet.insertRule(`.vs${this._unThemedSelector} {${lightCSS}}`, 0);
hasContent = true;
}
if (darkCSS.length > 0) {
sheet.insertRule(`.vs-dark${this._unThemedSelector}, .hc-black${this._unThemedSelector} {${darkCSS}}`, 0);
hasContent = true;
}
this._hasContent = hasContent;
}
_removeCSS() {
this._providerArgs.styleSheet.removeRulesContainingSelector(this._unThemedSelector);
}
/**
* Build the CSS for decorations styled via `className`.
*/
getCSSTextForModelDecorationClassName(opts) {
if (!opts) {
return '';
}
const cssTextArr = [];
this.collectCSSText(opts, ['backgroundColor'], cssTextArr);
this.collectCSSText(opts, ['outline', 'outlineColor', 'outlineStyle', 'outlineWidth'], cssTextArr);
this.collectBorderSettingsCSSText(opts, cssTextArr);
return cssTextArr.join('');
}
/**
* Build the CSS for decorations styled via `inlineClassName`.
*/
getCSSTextForModelDecorationInlineClassName(opts) {
if (!opts) {
return '';
}
const cssTextArr = [];
this.collectCSSText(opts, ['fontStyle', 'fontWeight', 'textDecoration', 'cursor', 'color', 'opacity', 'letterSpacing'], cssTextArr);
if (opts.letterSpacing) {
this._hasLetterSpacing = true;
}
return cssTextArr.join('');
}
/**
* Build the CSS for decorations styled before or after content.
*/
getCSSTextForModelDecorationContentClassName(opts) {
if (!opts) {
return '';
}
const cssTextArr = [];
if (typeof opts !== 'undefined') {
this.collectBorderSettingsCSSText(opts, cssTextArr);
if (typeof opts.contentIconPath !== 'undefined') {
cssTextArr.push(strings.format(_CSS_MAP.contentIconPath, dom.asCSSUrl(URI.revive(opts.contentIconPath))));
}
if (typeof opts.contentText === 'string') {
const truncated = opts.contentText.match(/^.*$/m)[0]; // only take first line
const escaped = truncated.replace(/['\\]/g, '\\$&');
cssTextArr.push(strings.format(_CSS_MAP.contentText, escaped));
}
this.collectCSSText(opts, ['verticalAlign', 'fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'textDecoration', 'color', 'opacity', 'backgroundColor', 'margin', 'padding'], cssTextArr);
if (this.collectCSSText(opts, ['width', 'height'], cssTextArr)) {
cssTextArr.push('display:inline-block;');
}
}
return cssTextArr.join('');
}
/**
* Build the CSS for decorations styled via `glpyhMarginClassName`.
*/
getCSSTextForModelDecorationGlyphMarginClassName(opts) {
if (!opts) {
return '';
}
const cssTextArr = [];
if (typeof opts.gutterIconPath !== 'undefined') {
cssTextArr.push(strings.format(_CSS_MAP.gutterIconPath, dom.asCSSUrl(URI.revive(opts.gutterIconPath))));
if (typeof opts.gutterIconSize !== 'undefined') {
cssTextArr.push(strings.format(_CSS_MAP.gutterIconSize, opts.gutterIconSize));
}
}
return cssTextArr.join('');
}
collectBorderSettingsCSSText(opts, cssTextArr) {
if (this.collectCSSText(opts, ['border', 'borderColor', 'borderRadius', 'borderSpacing', 'borderStyle', 'borderWidth'], cssTextArr)) {
cssTextArr.push(strings.format('box-sizing: border-box;'));
return true;
}
return false;
}
collectCSSText(opts, properties, cssTextArr) {
const lenBefore = cssTextArr.length;
for (let property of properties) {
const value = this.resolveValue(opts[property]);
if (typeof value === 'string') {
cssTextArr.push(strings.format(_CSS_MAP[property], value));
}
}
return cssTextArr.length !== lenBefore;
}
resolveValue(value) {
if (isThemeColor(value)) {
this._usesThemeColors = true;
const color = this._theme.getColor(value.id);
if (color) {
return color.toString();
}
return 'transparent';
}
return value;
}
}
class CSSNameHelper {
static getClassName(key, type) {
return 'ced-' + key + '-' + type;
}
static getSelector(key, parentKey, ruleType) {
let selector = '.monaco-editor .' + this.getClassName(key, ruleType);
if (parentKey) {
selector = selector + '.' + this.getClassName(parentKey, ruleType);
}
if (ruleType === 3 /* BeforeContentClassName */) {
selector += '::before';
}
else if (ruleType === 4 /* AfterContentClassName */) {
selector += '::after';
}
return selector;
}
}