@lvce-editor/extension-detail-view 6.2.0 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -681,7 +681,7 @@ const existsJson = async schemaUrl => {
681
681
  }
682
682
  };
683
683
 
684
- const isExternalLink$1 = schema => {
684
+ const isExternalLink$2 = schema => {
685
685
  return schema.startsWith('http://') || schema.startsWith('https://');
686
686
  };
687
687
  const hasWhitespace = value => {
@@ -728,7 +728,7 @@ const getSchemaLinkUrl = (schema, extensionUri) => {
728
728
  if (trimmed !== schema) {
729
729
  return '';
730
730
  }
731
- if (isExternalLink$1(schema)) {
731
+ if (isExternalLink$2(schema)) {
732
732
  return isValidHttpUrl(schema) ? schema : '';
733
733
  }
734
734
  if (!isValidRelativePath(schema)) {
@@ -1022,11 +1022,12 @@ const TargetName = 'event.target.name';
1022
1022
  const Script$1 = 2;
1023
1023
 
1024
1024
  const ExtensionDetailReadme = 20;
1025
- const ExtensionDetailIconContextMenu$3 = 4091;
1025
+ const ExtensionDetailIconContextMenu$2 = 4091;
1026
1026
 
1027
1027
  const None$2 = 0;
1028
1028
 
1029
1029
  const Web$1 = 1;
1030
+ const Electron$1 = 2;
1030
1031
 
1031
1032
  const ExtensionHostWorker = 44;
1032
1033
  const ExtensionManagementWorker = 9006;
@@ -2315,6 +2316,9 @@ const sendMessagePortToExtensionManagementWorker = async (port, rpcId) => {
2315
2316
  const command = 'Extensions.handleMessagePort';
2316
2317
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionManagementWorker', port, command, rpcId);
2317
2318
  };
2319
+ const getPreference = async key => {
2320
+ return await invoke$1('Preferences.get', key);
2321
+ };
2318
2322
  const getAllExtensions$1 = async () => {
2319
2323
  return invoke$1('ExtensionManagement.getAllExtensions');
2320
2324
  };
@@ -2337,7 +2341,11 @@ const setExtensionsSearchValue = async searchValue => {
2337
2341
  // @ts-ignore
2338
2342
  return invoke$1('Extensions.handleInput', searchValue, Script$1);
2339
2343
  };
2340
- const openUrl$1 = async uri => {
2344
+ const openExternal$1 = async uri => {
2345
+ // @ts-ignore
2346
+ await invoke$1('Open.openExternal', uri);
2347
+ };
2348
+ const openUrl = async uri => {
2341
2349
  // @ts-ignore
2342
2350
  await invoke$1('Open.openUrl', uri);
2343
2351
  };
@@ -2543,6 +2551,7 @@ const HandleAdditionalDetailContextMenu = 15;
2543
2551
  const HandleReadmeClick = 16;
2544
2552
  const HandleSelectionChange = 17;
2545
2553
  const HandleTabFocus = 18;
2554
+ const HandleResourceLinkClick = 19;
2546
2555
 
2547
2556
  const ActivationEvents = 'ActivationEvents';
2548
2557
  const Changelog = 'Changelog';
@@ -3059,6 +3068,9 @@ const readFileAsBlob = async uri => {
3059
3068
  };
3060
3069
 
3061
3070
  const getImageCopyUrl = (iconSrc, locationProtocol, locationHost) => {
3071
+ if (!iconSrc) {
3072
+ return '';
3073
+ }
3062
3074
  const prefix = `${locationProtocol}//${locationHost}`;
3063
3075
  const absoluteIconSrc = `${prefix}${iconSrc}`;
3064
3076
  return absoluteIconSrc;
@@ -3083,6 +3095,9 @@ const copyImageUrl = async state => {
3083
3095
  locationProtocol
3084
3096
  } = state;
3085
3097
  const absoluteIconSrc = getImageCopyUrl(iconSrc, locationProtocol, locationHost);
3098
+ if (!absoluteIconSrc) {
3099
+ return state;
3100
+ }
3086
3101
  await writeText(absoluteIconSrc);
3087
3102
  return state;
3088
3103
  };
@@ -3137,6 +3152,7 @@ const create = (uid, uri, x, y, width, height, platform, assetDir) => {
3137
3152
  importTime: 0,
3138
3153
  installationEntries: [],
3139
3154
  jsonValidation: [],
3155
+ linkProtectionEnabled: false,
3140
3156
  locationHost: '',
3141
3157
  locationProtocol: '',
3142
3158
  marketplaceEntries: [],
@@ -3279,7 +3295,7 @@ const getMenuEntriesImage = (state, props) => {
3279
3295
  };
3280
3296
 
3281
3297
  const getMenuEntries2 = (state, props) => {
3282
- if (props.menuId === ExtensionDetailIconContextMenu$3) {
3298
+ if (props.menuId === ExtensionDetailIconContextMenu$2) {
3283
3299
  return getMenuEntriesImage();
3284
3300
  }
3285
3301
  if (props.menuId === ExtensionDetailReadme && props.href) {
@@ -3349,7 +3365,6 @@ const getLinkMenuEntries = props => {
3349
3365
 
3350
3366
  const getMenuEntries = props => [...getLinkMenuEntries(props), ...getImageMenuEntries(props), getCopyMenuEntry()];
3351
3367
 
3352
- const ExtensionDetailIconContextMenu$2 = 4091;
3353
3368
  const getMenuIds = () => {
3354
3369
  return [ExtensionDetailReadme, ExtensionDetailIconContextMenu$2];
3355
3370
  };
@@ -3669,6 +3684,15 @@ const getExtensionIdFromUri = uri => {
3669
3684
  return id;
3670
3685
  };
3671
3686
 
3687
+ const getLinkProtectionEnabled = async () => {
3688
+ try {
3689
+ const setting = await getPreference('application.linkProtectionEnabled');
3690
+ return setting === true || setting === 'true';
3691
+ } catch {
3692
+ return false;
3693
+ }
3694
+ };
3695
+
3672
3696
  const interpolate = (value, inMin, inMax, outMin, outMax) => {
3673
3697
  const clamped = Math.min(Math.max(value, inMin), inMax);
3674
3698
  const ratio = (clamped - inMin) / (inMax - inMin);
@@ -4037,6 +4061,7 @@ const supportsFileSize = uri => {
4037
4061
  }
4038
4062
  return true;
4039
4063
  };
4064
+
4040
4065
  const getFolderSize = async uri => {
4041
4066
  if (!uri) {
4042
4067
  throw new VError(`uri is required`);
@@ -4096,11 +4121,6 @@ const getMarketplaceEntries = isBuiltin => {
4096
4121
  }];
4097
4122
  };
4098
4123
 
4099
- const getLicenseLink = extension => {
4100
- // TODO
4101
- return '#';
4102
- };
4103
-
4104
4124
  const ensureValidLink = link => {
4105
4125
  if (!link) {
4106
4126
  return '';
@@ -4127,21 +4147,40 @@ const getRepositoryLink = extension => {
4127
4147
  const validLink = ensureValidLink(raw);
4128
4148
  return validLink;
4129
4149
  };
4150
+
4151
+ const isGitHubRepository$1 = url => {
4152
+ return url.startsWith('https://github.com/');
4153
+ };
4130
4154
  const getIssuesLink = extension => {
4131
4155
  const repositoryLink = getRepositoryLink(extension);
4132
4156
  if (!repositoryLink) {
4133
4157
  return '';
4134
4158
  }
4135
- if (repositoryLink && repositoryLink.startsWith('https://github.com')) {
4159
+ if (isGitHubRepository$1(repositoryLink)) {
4136
4160
  return `${repositoryLink}/issues`;
4137
4161
  }
4138
4162
  return '';
4139
4163
  };
4140
4164
 
4165
+ const isGitHubRepository = url => {
4166
+ return url.startsWith('https://github.com/');
4167
+ };
4168
+ const getLicenseLink = extension => {
4169
+ const repositoryLink = getRepositoryLink(extension);
4170
+ if (!repositoryLink) {
4171
+ return '#';
4172
+ }
4173
+ if (isGitHubRepository(repositoryLink)) {
4174
+ const normalizedLink = repositoryLink.replace(/\/+$/, '');
4175
+ return `${normalizedLink}/blob/main/license.md`;
4176
+ }
4177
+ return '#';
4178
+ };
4179
+
4141
4180
  const getResources = (isBuiltin, extension) => {
4142
4181
  const repositoryLink = getRepositoryLink(extension);
4143
4182
  const issueLink = getIssuesLink(extension);
4144
- const licenseLink = getLicenseLink();
4183
+ const licenseLink = getLicenseLink(extension);
4145
4184
  // TODO hide marketplace link for builtin extensions
4146
4185
  return [{
4147
4186
  icon: 'LinkExternal',
@@ -4297,6 +4336,7 @@ const loadContent = async (state, platform, savedState, isTest = false) => {
4297
4336
  const padding = getPadding(width);
4298
4337
  const sideBarWidth = getSideBarWidth(width);
4299
4338
  const showSideBar = sideBarWidth > 0;
4339
+ const linkProtectionEnabled = await getLinkProtectionEnabled();
4300
4340
  return {
4301
4341
  ...state,
4302
4342
  badge,
@@ -4320,12 +4360,14 @@ const loadContent = async (state, platform, savedState, isTest = false) => {
4320
4360
  hasReadme,
4321
4361
  iconSrc,
4322
4362
  installationEntries,
4363
+ linkProtectionEnabled,
4323
4364
  locationHost,
4324
4365
  locationProtocol,
4325
4366
  marketplaceEntries,
4326
4367
  name,
4327
4368
  paddingLeft: padding,
4328
4369
  paddingRight: padding,
4370
+ platform,
4329
4371
  rating,
4330
4372
  readmeScrollTop,
4331
4373
  readmeUrl,
@@ -4386,17 +4428,48 @@ const handleImageContextMenu = async (state, eventX, eventY) => {
4386
4428
  return state;
4387
4429
  };
4388
4430
 
4389
- const isExternalLink = href => {
4431
+ const openExternalElectron = async uri => {
4432
+ await openExternal$1(uri);
4433
+ };
4434
+ const openExternalWeb = async uri => {
4435
+ await openUrl(uri);
4436
+ };
4437
+ const openExternal = async (uri, platform) => {
4438
+ if (platform === Electron$1) {
4439
+ await openExternalElectron(uri);
4440
+ } else {
4441
+ await openExternalWeb(uri);
4442
+ }
4443
+ };
4444
+
4445
+ const handleReadmeLinkClick = async (linkProtectionEnabled, platform, href) => {
4446
+ // TODO what to do about relative links? open them in editor?
4447
+ // TODO what to do about mail links?
4448
+ if (linkProtectionEnabled) {
4449
+ const message = `Do you want to open this external link?\n\n${href}`;
4450
+ const confirmed = await confirm(message);
4451
+ if (!confirmed) {
4452
+ return;
4453
+ }
4454
+ }
4455
+ await openExternal(href, platform);
4456
+ return;
4457
+ };
4458
+
4459
+ const isExternalLink$1 = href => {
4390
4460
  return href.startsWith('http://') || href.startsWith('https://');
4391
4461
  };
4392
4462
  const handleReadmeClick = async (state, nodeName, href) => {
4393
- if (!href || !isExternalLink(href)) {
4463
+ const {
4464
+ linkProtectionEnabled,
4465
+ platform
4466
+ } = state;
4467
+ if (!href || !isExternalLink$1(href)) {
4394
4468
  return state;
4395
4469
  }
4396
4470
  // TODO what to do about relative links? open them in editor?
4397
4471
  // TODO what to do about mail links?
4398
- await openUrl$1(href);
4399
- // TODO check node name and href
4472
+ await handleReadmeLinkClick(linkProtectionEnabled, platform, href);
4400
4473
  return state;
4401
4474
  };
4402
4475
 
@@ -4414,6 +4487,21 @@ const handleReadmeContextMenu = async (state, x, y, nodeName, href) => {
4414
4487
  return state;
4415
4488
  };
4416
4489
 
4490
+ const isExternalLink = href => {
4491
+ return href.startsWith('http://') || href.startsWith('https://');
4492
+ };
4493
+ const handleResourceLinkClick = async (state, href) => {
4494
+ const {
4495
+ linkProtectionEnabled,
4496
+ platform
4497
+ } = state;
4498
+ if (!href || !isExternalLink(href)) {
4499
+ return state;
4500
+ }
4501
+ await handleReadmeLinkClick(linkProtectionEnabled, platform, href);
4502
+ return state;
4503
+ };
4504
+
4417
4505
  const handleScroll = (state, scrollTop, scrollSource = Script) => {
4418
4506
  const newScrollTop = Math.max(0, scrollTop);
4419
4507
  return {
@@ -4692,18 +4780,15 @@ const loadContent2 = async (state, savedState, isTest = false) => {
4692
4780
  return loadContent(state, state.platform, savedState, isTest);
4693
4781
  };
4694
4782
 
4695
- const openUrl = async uri => {
4696
- await openUrl$1(uri);
4697
- };
4698
-
4699
4783
  const openImageInNewTab = async state => {
4700
4784
  const {
4701
4785
  iconSrc,
4702
4786
  locationHost,
4703
- locationProtocol
4787
+ locationProtocol,
4788
+ platform
4704
4789
  } = state;
4705
4790
  const absoluteIconSrc = getImageCopyUrl(iconSrc, locationProtocol, locationHost);
4706
- await openUrl(absoluteIconSrc);
4791
+ await openExternal(absoluteIconSrc, platform);
4707
4792
  return state;
4708
4793
  };
4709
4794
 
@@ -4888,6 +4973,7 @@ const getResourceLinkVirtualDom = resource => {
4888
4973
  childCount: 1 + iconDomCount,
4889
4974
  className: Resource,
4890
4975
  href: url,
4976
+ onClick: HandleResourceLinkClick,
4891
4977
  rel: 'noopener noreferrer',
4892
4978
  target: '_blank',
4893
4979
  type: A
@@ -5313,7 +5399,7 @@ const render2 = (uid, diffResult) => {
5313
5399
  const renderEventListeners = () => {
5314
5400
  return [{
5315
5401
  name: HandleAdditionalDetailContextMenu,
5316
- params: ['handleAdditionalDetailsContextMenu', ClientX, ClientY, 'event.target.nodeName', 'event.target.href'],
5402
+ params: ['handleAdditionalDetailsContextMenu', ClientX, ClientY, 'event.target.nodeName', TargetHref],
5317
5403
  preventDefault: true
5318
5404
  }, {
5319
5405
  name: HandleClickCategory,
@@ -5356,7 +5442,11 @@ const renderEventListeners = () => {
5356
5442
  params: ['handleClickSettings']
5357
5443
  }, {
5358
5444
  name: HandleReadmeClick,
5359
- params: ['handleReadmeClick', 'event.target.nodeName', 'event.target.href'],
5445
+ params: ['handleReadmeClick', 'event.target.nodeName', TargetHref],
5446
+ preventDefault: true
5447
+ }, {
5448
+ name: HandleResourceLinkClick,
5449
+ params: ['handleResourceLinkClick', TargetHref],
5360
5450
  preventDefault: true
5361
5451
  }, {
5362
5452
  name: HandleClickUninstall,
@@ -5434,6 +5524,7 @@ const commandMap = {
5434
5524
  'ExtensionDetail.handleImageContextMenu': wrapCommand(handleImageContextMenu),
5435
5525
  'ExtensionDetail.handleReadmeClick': wrapCommand(handleReadmeClick),
5436
5526
  'ExtensionDetail.handleReadmeContextMenu': wrapCommand(handleReadmeContextMenu),
5527
+ 'ExtensionDetail.handleResourceLinkClick': wrapCommand(handleResourceLinkClick),
5437
5528
  'ExtensionDetail.handleScroll': wrapCommand(handleScroll),
5438
5529
  'ExtensionDetail.handleSelectionChange': wrapCommand(handleSelectionChange),
5439
5530
  'ExtensionDetail.handleTabFocus': wrapCommand(handleTabFocus),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/extension-detail-view",
3
- "version": "6.2.0",
3
+ "version": "6.4.0",
4
4
  "description": "Extension Detail View Worker",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,6 +11,6 @@
11
11
  "type": "module",
12
12
  "main": "dist/extensionDetailViewWorkerMain.js",
13
13
  "dependencies": {
14
- "@lvce-editor/constants": "^2.1.0"
14
+ "@lvce-editor/constants": "^2.4.0"
15
15
  }
16
16
  }