modelscope.cn

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.

Installation

$ npx skills add https://modelscope.cn

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from modelscope.cn · top by installs.

npx skills add https://modelscope.cn

Browse all from modelscope.cn

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,334 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

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 包含发布步骤,更新后可能需要几秒才能在域名上看到新内容