feat(media): Embed Google Photo Picker via Popup Flow

- Revert 'Unified Embedded Picker' which caused 403 errors due to iframe restrictions on the Google Photos Picker.
- Implement a 'Popup Window' flow for Google Photos selections, keeping the Media Manager active.
- Restore 'Classic' Embedded Picker for Google Drive (DocsView) as it is compatible with iframes.
- Update ppsscript.json with drive.photos.readonly scope for correct permissions.
- Update Media Manager UI to separate Drive and Photos buttons.
This commit is contained in:
Ben Miller
2025-12-29 01:47:31 -07:00
parent d9fe81f282
commit 4b156cb371
2 changed files with 525 additions and 496 deletions

View File

@ -404,6 +404,8 @@
<div id="photos-session-status" style="font-size:11px; color:#64748b; text-align:center;">Initializing...</div>
</div>
<div class="card" style="padding-bottom: 0;">
<div class="header" style="margin-bottom:8px; display:flex; justify-content:space-between; align-items:center;">
<div style="display:flex; align-items:baseline; gap:12px;">
@ -698,6 +700,44 @@
this.saveBtn.innerText = enable ? "Save Changes" : "No Changes";
};
UI.prototype.showPhotoSession = function (url) {
var uiEl = document.getElementById('photos-session-ui');
var link = document.getElementById('photos-session-link');
var status = document.getElementById('photos-session-status');
uiEl.style.display = 'block';
link.href = url;
// We also open it automatically in a popup
const width = 1200;
const height = 800;
const left = (screen.width - width) / 2;
const top = (screen.height - height) / 2;
// Attempt popup
const popup = window.open(url, 'googlePhotos', `width=${width},height=${height},top=${top},left=${left}`);
if (popup) {
link.innerText = "Re-open Popup ↗";
link.onclick = function (e) {
e.preventDefault();
window.open(url, 'googlePhotos', `width=${width},height=${height},top=${top},left=${left}`);
}
} else {
link.innerText = "Open Google Photos ↗";
link.onclick = null; // Default href behavior
}
status.innerText = "Waiting for selection in popup...";
};
UI.prototype.closePhotoSession = function () {
document.getElementById('photos-session-ui').style.display = 'none';
};
UI.prototype.updatePhotoStatus = function (msg) {
document.getElementById('photos-session-status').innerText = msg;
};
UI.prototype.render = function (items) {
this.grid.innerHTML = '';
var _this = this; // Capture 'this' for callbacks
@ -900,25 +940,6 @@
document.getElementById('details-modal').style.display = 'none';
};
UI.prototype.showPhotoSession = function (url) {
var uiEl = document.getElementById('photos-session-ui');
var link = document.getElementById('photos-session-link');
var status = document.getElementById('photos-session-status');
uiEl.style.display = 'block';
link.href = url;
link.style.display = 'block';
status.innerText = "Waiting for selection...";
};
UI.prototype.closePhotoSession = function () {
document.getElementById('photos-session-ui').style.display = 'none';
};
UI.prototype.updatePhotoStatus = function (msg) {
document.getElementById('photos-session-status').innerText = msg;
};
var ui = new UI();
window.ui = ui;
@ -1104,6 +1125,7 @@
});
},
// --- Picker ---
// --- Picker ---
openPicker() {
if (!pickerApiLoaded) return alert("API Loading...");
@ -1116,7 +1138,7 @@
.importFromPicker(state.sku, fileId, mime, name, url);
},
// --- Photos ---
// --- Photos (Popup Flow) ---
startPhotoSession() {
ui.updatePhotoStatus("Starting session...");
google.script.run
@ -1165,7 +1187,11 @@
});
},
// --- Legacy Photos Session (Removed in favor of Embedded Picker) ---
// startPhotoSession() { ... }
// --- Compatibility / Matching Logic ---
matches: [],
currentMatchIndex: 0,
hasRunMatching: false,
@ -1319,18 +1345,20 @@
.setMimeTypes("image/png,image/jpeg,image/jpg,video/mp4")
.setIncludeFolders(true)
.setSelectFolderEnabled(false);
const photosView = new google.picker.PhotosView();
new google.picker.PickerBuilder()
.addView(view)
.addView(photosView)
const builder = new google.picker.PickerBuilder();
builder.addView(view)
.setOAuthToken(config.token)
.setDeveloperKey(config.apiKey)
.setOrigin(window.location.protocol + '//' + window.location.host)
.setCallback(data => {
if (data.action == google.picker.Action.PICKED) {
const doc = data.docs[0];
const url = (doc.thumbnails && doc.thumbnails.length > 0) ? doc.thumbnails[doc.thumbnails.length - 1].url : null;
controller.importFromPicker(doc.id, doc.mimeType, doc.name, url);
const isDrive = doc.serviceId === 'docs';
// Drive File (Always, since we removed Photos view)
controller.importFromPicker(doc.id, doc.mimeType, doc.name, null);
}
})
.build()

View File

@ -18,6 +18,7 @@
"https://www.googleapis.com/auth/script.scriptapp",
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/photospicker.mediaitems.readonly"
"https://www.googleapis.com/auth/photospicker.mediaitems.readonly",
"https://www.googleapis.com/auth/drive.photos.readonly"
]
}