diff --git a/client/src/sagas/mediafiles.sagas.ts b/client/src/sagas/mediafiles.sagas.ts index b54abb159..9194e4cb0 100644 --- a/client/src/sagas/mediafiles.sagas.ts +++ b/client/src/sagas/mediafiles.sagas.ts @@ -29,6 +29,7 @@ function* initialize(api: PodloveApiClient) { yield takeEvery(mediafiles.DISABLE, handleDisable, api) yield takeEvery(mediafiles.VERIFY, handleVerify, api) yield takeEvery(episode.SAVED, maybeReverify, api) + yield takeEvery(episode.SAVED, maybeUpdateSlug, api) yield throttle( 2000, [mediafiles.ENABLE, mediafiles.DISABLE, mediafiles.UPDATE], @@ -101,6 +102,50 @@ function* maybeReverify(api: PodloveApiClient, action: { type: string; payload: yield all(mediaFiles.map((file) => call(verifyEpisodeAsset, api, episodeId, file.asset_id))) } +// THOUGHTS +// - auto gen logic is both here and in the wordpress saga. needs to at least be +// dry +// - previous slug generation was on PHP side, using WordPress' sanitize_title, +// which I do not want to reimplement in PHP +// - maybe have a dedicated endpoint to push an unsanitized slug? But then I +// might as well send a "just generate me a slug" ping instead and do +// everything on the backend. Sounds best actually. +function* maybeUpdateSlug(api: PodloveApiClient, action: { type: string; payload: object }) { + const changedKeys = Object.keys(action.payload) + const interestingKeys = ['title', 'number'] + const slugNeedsUpdating = changedKeys.some((key) => interestingKeys.includes(key)) + + const generateTitle: boolean = yield select(selectors.settings.autoGenerateEpisodeTitle) + const template: string = yield select(selectors.settings.blogTitleTemplate) + const title: string = yield select(selectors.episode.title) + const episodeNumber: string = yield select(selectors.episode.number) + const mnemonic: string = yield select(selectors.podcast.mnemonic) + // TODO: get from episode? + const seasonNumber: string = '' + const padding: number = yield select(selectors.settings.episodeNumberPadding) + + // So ugly: I don't want to have to know about the title template here, or if it's even used + if (slugNeedsUpdating) { + let newSlug = '' + + if (generateTitle && template) { + const generatedTitle = template + .replace('%mnemonic%', mnemonic || '') + .replace('%episode_number%', (episodeNumber || '').padStart(padding || 0, '0')) + .replace('%season_number%', seasonNumber || '') + .replace('%episode_title%', title || '') + newSlug = generatedTitle + } else { + newSlug = title + } + + // FIXME: `newSlug` is currently just the title. Needs to be slugged. But + // maybe I don't do all that here anyway, see thoughts above. + + yield put(episode.update({ prop: 'slug', value: newSlug })) + } +} + function* verifyEpisodeAsset(api: PodloveApiClient, episodeId: number, assetId: number) { const mediaFiles: MediaFile[] = yield select(selectors.mediafiles.files) const prevMediaFile: MediaFile | undefined = mediaFiles.find((mf) => mf.asset_id == assetId) diff --git a/client/src/store/mediafiles.store.ts b/client/src/store/mediafiles.store.ts index 100559f7e..77abd5cbf 100644 --- a/client/src/store/mediafiles.store.ts +++ b/client/src/store/mediafiles.store.ts @@ -11,11 +11,13 @@ export type MediaFile = { export type State = { is_initializing: boolean + slug_autogeneration_enabled: boolean files: MediaFile[] } export const initialState: State = { is_initializing: true, + slug_autogeneration_enabled: true, files: [], } @@ -86,5 +88,6 @@ export const reducer = handleActions( export const selectors = { isInitializing: (state: State) => state.is_initializing, + slugAutogenerationEnabled: (state: State) => state.slug_autogeneration_enabled, files: (state: State) => state.files, } diff --git a/js/src/admin/episode.js b/js/src/admin/episode.js index 0806d95b2..3959069ae 100644 --- a/js/src/admin/episode.js +++ b/js/src/admin/episode.js @@ -7,32 +7,6 @@ var PODLOVE = PODLOVE || {} PODLOVE.Episode = function (container) { var o = {} - // private - - function maybe_update_episode_slug(title) { - if (o.slug_field.data('auto-update')) { - update_episode_slug(title) - } - } - - // current ajax object to ensure only the latest one is active - var update_episode_slug_xhr - - function update_episode_slug(title) { - if (update_episode_slug_xhr) update_episode_slug_xhr.abort() - - update_episode_slug_xhr = $.ajax({ - url: ajaxurl, - data: { - action: 'podlove-episode-slug', - title: title, - }, - context: o.slug_field, - }).done(function (slug) { - $(this).val(slug).blur() - }) - } - o.slug_field = container.find('[name*=slug]') $('#_podlove_meta_subtitle').count_characters({ @@ -63,12 +37,6 @@ var PODLOVE = PODLOVE || {} } }) - o.slug_field - .data('auto-update', !Boolean(o.slug_field.val())) // only auto-update if it is empty - .on('keyup', function () { - o.slug_field.data('auto-update', false) // stop autoupdate on manual change - }) - var typewatch = (function () { var timer = 0 return function (callback, ms) { @@ -97,9 +65,6 @@ var PODLOVE = PODLOVE || {} // update episode title $('#_podlove_meta_title').attr('placeholder', title) - - // maybe update episode slug - maybe_update_episode_slug(title) }) .trigger('titleHasChanged') diff --git a/lib/ajax/ajax.php b/lib/ajax/ajax.php index 42f218df3..0ce5f72a9 100644 --- a/lib/ajax/ajax.php +++ b/lib/ajax/ajax.php @@ -39,7 +39,6 @@ public function __construct() 'analytics-global-total-downloads', 'analytics-global-total-downloads-by-show', 'analytics-csv-episodes-table', - 'episode-slug', 'admin-news', 'job-create', 'job-get', @@ -915,13 +914,6 @@ public function get_license_parameters_from_url() self::respond_with_json(\Podlove\Model\License::get_license_from_url($_REQUEST['url'])); } - public function episode_slug() - { - echo sanitize_title($_REQUEST['title']); - - exit; - } - private static function analytics_date_condition() { $from = filter_input(INPUT_GET, 'date_from');