Back to skills
extension
Category: Development & EngineeringNo API key required

Gallery Editor Child SDK

Guide for integrating Gallery Editor capabilities into a Gallery static HTML page (child iframe). Use when building or modifying a Gallery page that needs config editing and asset uploading via Penpal parent-child iframe communication.

personAuthor: xishan01hubModelScope

Gallery Editor Child SDK

概述

本 Skill 描述了 Gallery 静态网页(子页面)如何通过 Penpal 接收 ModelScope 主站 Gallery Editor(父页面)注入的编辑能力。

子页面被嵌入 /tools/gallery-editor?galleryId=xx/xx 的 iframe 中时,父页面通过 Penpal 向其注入方法:

  • getConfig() — 获取 gallery 域名下 /config.json 的完整内容
  • saveGallery(files) — 全量更新 gallery 所有文件并发布
  • saveConfig(json) — ⚠️ 暂不支持,请使用 saveGallery
  • uploadAsset(fileBase64, filename) — ⚠️ 暂不支持,请使用 saveGallery

前提条件

  • 子页面需引入 Penpal v6.x
  • 子页面需被 g-{gid}.ms.show 域名托管(即存储在 Gallery 中的静态 HTML)

接口协议

| 方法 | 方向 | 签名 | 说明 | |------|------|------|------| | getConfig | 子 → 父 | () => Promise<object \| null> | 从 gallery 域名下读取 /config.json,不存在则返回 null | | saveGallery | 子 → 父 | (files: {filename, contentBase64}[]) => Promise<{success}> | 全量更新 gallery 所有文件并发布 | | saveConfig | 子 → 父 | (json: object) => Promise<{success}> | ⚠️ 暂不支持,会抛出错误 | | uploadAsset | 子 → 父 | (fileBase64, filename) => Promise<string> | ⚠️ 暂不支持,会抛出错误 |

最小集成代码(CDN 方式)

<!-- 引入 Penpal CDN -->
<script src="https://resources.modelscope.cn/third-part/js/penpal/6.2.2/dist/penpal.min.js"></script>

<script>
(function() {
  // 检测是否在 iframe 中
  if (window.self === window.top) {
    console.log('[GallerySDK] Not in iframe, editor disabled');
    return;
  }

  var connection = Penpal.connectToParent({
    // 子页面可暴露方法给父页面(可选)
    methods: {
      onConfigUpdated: function(config) {
        console.log('[GallerySDK] Config updated from parent:', config);
      }
    }
  });

  connection.promise.then(function(parent) {
    console.log('[GallerySDK] Connected to editor');

    // 将 parent API 挂载到全局
    window.__galleryEditor = {
      ready: true,
      getConfig: parent.getConfig,
      saveGallery: parent.saveGallery,
    };

    // 派发自定义事件,通知业务代码编辑器已就绪
    window.dispatchEvent(new CustomEvent('gallery-editor-ready', {
      detail: { parent: parent }
    }));
  });
})();
</script>

TypeScript 类型声明

如果子页面是 TypeScript 项目,可创建如下类型声明文件:

// gallery-editor-sdk.d.ts

interface GalleryEditorAPI {
  ready: boolean;
  getConfig(): Promise<Record<string, any> | null>;
  saveGallery(files: { filename: string; contentBase64: string }[]): Promise<{ success: boolean }>;
}

declare global {
  interface Window {
    __galleryEditor?: GalleryEditorAPI;
  }
  interface WindowEventMap {
    'gallery-editor-ready': CustomEvent<{ parent: GalleryEditorAPI }>;
  }
}

export {};

使用示例

1. 读取配置

window.addEventListener('gallery-editor-ready', async function() {
  var editor = window.__galleryEditor;

  // 读取当前配置(从 gallery 域名的 /config.json 读取)
  var config = await editor.getConfig();
  if (config === null) {
    console.log('config.json 不存在,使用默认配置');
    config = { title: '默认标题' };
  }
  console.log('当前配置:', config);
});

2. 全量更新 Gallery 文件

window.addEventListener('gallery-editor-ready', async function() {
  var editor = window.__galleryEditor;

  // 准备所有要提交的文件(内容需为 Base64)
  var files = [
    {
      filename: 'config.json',
      contentBase64: btoa(JSON.stringify({ title: '新标题', theme: 'dark' }, null, 2)),
    },
    {
      filename: 'index.html',
      contentBase64: btoa('<html><body>Hello</body></html>'),
    }
  ];

  var result = await editor.saveGallery(files);
  console.log('全量更新结果:', result); // { success: true }
});

3. 上传文件并全量提交

window.addEventListener('gallery-editor-ready', function() {
  var editor = window.__galleryEditor;

  document.getElementById('file-input').addEventListener('change', async function(e) {
    var selectedFiles = e.target.files;
    if (!selectedFiles.length) return;

    var fileList = [];
    for (var i = 0; i < selectedFiles.length; i++) {
      var file = selectedFiles[i];
      var base64 = await fileToBase64(file);
      fileList.push({ filename: file.name, contentBase64: base64 });
    }

    var result = await editor.saveGallery(fileList);
    console.log('提交成功:', result);
  });
});

function fileToBase64(file) {
  return new Promise(function(resolve) {
    var reader = new FileReader();
    reader.onload = function() {
      resolve(reader.result.split(',')[1]);
    };
    reader.readAsDataURL(file);
  });
}

3. 检测编辑模式并切换 UI

// 方式一:监听事件
window.addEventListener('gallery-editor-ready', function() {
  document.getElementById('edit-toolbar').style.display = 'block';
  document.body.classList.add('editor-mode');
});

// 方式二:轮询检查(用于懒加载场景)
function isInEditorMode() {
  return !!(window.__galleryEditor && window.__galleryEditor.ready);
}

注意事项

  1. 全量更新: gallery 当前只支持全量更新(saveGallery),saveConfig 和 uploadAsset 暂不支持
  2. 文件大小限制: saveGallery 使用 Base64 编码传输,建议单文件不超过 10MB
  3. 仅在 iframe 中生效: 直接访问 Gallery URL 时 connectToParent 不会触发,编辑能力不会开启
  4. 异步操作: 所有方法均为 Promise,需 await 或 .then() 处理
  5. getConfig 读取方式: 直接从 gallery 域名下的 /config.json 读取,返回 null 表示文件不存在
  6. 发布延迟: saveGallery 包含发布步骤,更新后可能需要几秒才能在域名上看到新内容