From 3167a0bb91790c39d6c1713473e19a9260d947bb Mon Sep 17 00:00:00 2001 From: Daniel Lo Nigro Date: Tue, 19 Feb 2019 23:33:17 -0800 Subject: [PATCH 1/4] Load per-directory option overrides --- src/_h5ai/private/php/ext/class-custom.php | 36 ++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/_h5ai/private/php/ext/class-custom.php b/src/_h5ai/private/php/ext/class-custom.php index ab1628ed2..4478576c1 100644 --- a/src/_h5ai/private/php/ext/class-custom.php +++ b/src/_h5ai/private/php/ext/class-custom.php @@ -21,11 +21,42 @@ private function read_custom_file($path, $name, &$content, &$type) { } } + /** + * Load custom options for the specified path. Traverses the directory structure to include + * options for all parent directories too. Options in children will override the options + * inherited from their ancestors. + * + * @param $href string + * @return array + */ + private function get_options(string $href) { + if (!$this->context->query_option('custom.enabled', false)) { + return []; + } + + $file_prefix = $this->context->get_setup()->get('FILE_PREFIX'); + $root_path = $this->context->get_setup()->get('ROOT_PATH'); + + // Find all options files, from the current path all the way to the root + $option_files = []; + $path = $this->context->to_path($href); + do { + $file = $path . '/' . $file_prefix . '.options.json'; + if (is_readable($file)) { + $option_files[] = Json::load($file); + } + $path = Util::normalize_path(dirname($path)); + } while ($path !== $root_path && $path !== '/' && $href !== '/'); + + return count($option_files) === 0 ? [] : array_merge(...array_reverse($option_files)); + } + public function get_customizations($href) { if (!$this->context->query_option('custom.enabled', false)) { return [ 'header' => ['content' => null, 'type' => null], - 'footer' => ['content' => null, 'type' => null] + 'footer' => ['content' => null, 'type' => null], + 'options' => [], ]; } @@ -59,7 +90,8 @@ public function get_customizations($href) { return [ 'header' => ['content' => $header, 'type' => $header_type], - 'footer' => ['content' => $footer, 'type' => $footer_type] + 'footer' => ['content' => $footer, 'type' => $footer_type], + 'options' => self::get_options($href), ]; } } From 0a003e07b77ba4d78e30744ff123aa7f84169e58 Mon Sep 17 00:00:00 2001 From: Daniel Lo Nigro Date: Wed, 20 Feb 2019 23:34:13 -0800 Subject: [PATCH 2/4] Don't save default view and size to local storage Instead, getSize and getView should return the default if an explicit override has not been provided. --- src/_h5ai/public/js/lib/view/view.js | 41 +++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/_h5ai/public/js/lib/view/view.js b/src/_h5ai/public/js/lib/view/view.js index aff35efb0..3740b78b1 100644 --- a/src/_h5ai/public/js/lib/view/view.js +++ b/src/_h5ai/public/js/lib/view/view.js @@ -86,15 +86,15 @@ const addCssStyles = () => { dom('').text(styles.join('\n')).appTo('head'); }; -const set = (mode, size) => { - const stored = store.get(storekey); +const getModes = () => checkedModes; +const getMode = () => store.get(storekey) && store.get(storekey).mode || settings.modes[0]; - mode = mode || stored && stored.mode; - size = size || stored && stored.size; - mode = includes(settings.modes, mode) ? mode : settings.modes[0]; - size = includes(settings.sizes, size) ? size : settings.sizes[0]; - store.put(storekey, {mode, size}); +const getSizes = () => sortedSizes; +const getSize = () => store.get(storekey) && store.get(storekey).size || settings.sizes[0]; +const updateView = () => { + const mode = getMode(); + const size = getSize(); each(checkedModes, m => { if (m === mode) { $view.addCls('view-' + m); @@ -114,12 +114,27 @@ const set = (mode, size) => { event.pub('view.mode.changed', mode, size); }; -const getModes = () => checkedModes; -const getMode = () => store.get(storekey).mode; -const setMode = mode => set(mode, null); +const set = (mode, size) => { + const stored = store.get(storekey); -const getSizes = () => sortedSizes; -const getSize = () => store.get(storekey).size; + mode = mode || stored && stored.mode; + size = size || stored && stored.size; + mode = includes(settings.modes, mode) ? mode : settings.modes[0]; + size = includes(settings.sizes, size) ? size : settings.sizes[0]; + + // Unset if it's being set back to the default value + if (mode === settings.modes[0]) { + mode = undefined; + } + if (size === settings.sizes[0]) { + size = undefined; + } + + store.put(storekey, {mode, size}); + updateView(); +}; + +const setMode = mode => set(mode, null); const setSize = size => set(null, size); const onMouseenter = ev => { @@ -260,7 +275,7 @@ const onResize = () => { const init = () => { addCssStyles(); - set(); + updateView(); $view.appTo(base.$content); $hint.hide(); From a46e734ff83b45e82d951c5af3d4c6d6a16bedcc Mon Sep 17 00:00:00 2001 From: Daniel Lo Nigro Date: Wed, 20 Feb 2019 23:47:55 -0800 Subject: [PATCH 3/4] Allow folder-specific view options --- src/_h5ai/private/php/ext/class-custom.php | 4 ++-- src/_h5ai/public/js/lib/ext/custom.js | 1 + src/_h5ai/public/js/lib/view/view.js | 17 +++++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/_h5ai/private/php/ext/class-custom.php b/src/_h5ai/private/php/ext/class-custom.php index 4478576c1..d169ba451 100644 --- a/src/_h5ai/private/php/ext/class-custom.php +++ b/src/_h5ai/private/php/ext/class-custom.php @@ -56,7 +56,7 @@ public function get_customizations($href) { return [ 'header' => ['content' => null, 'type' => null], 'footer' => ['content' => null, 'type' => null], - 'options' => [], + 'options' => (object)[], ]; } @@ -91,7 +91,7 @@ public function get_customizations($href) { return [ 'header' => ['content' => $header, 'type' => $header_type], 'footer' => ['content' => $footer, 'type' => $footer_type], - 'options' => self::get_options($href), + 'options' => (object)self::get_options($href), ]; } } diff --git a/src/_h5ai/public/js/lib/ext/custom.js b/src/_h5ai/public/js/lib/ext/custom.js index 2e86fba6c..cf048af76 100644 --- a/src/_h5ai/public/js/lib/ext/custom.js +++ b/src/_h5ai/public/js/lib/ext/custom.js @@ -27,6 +27,7 @@ const onLocationChanged = item => { server.request({action: 'get', custom: item.absHref}).then(response => { const data = response && response.custom; each(['header', 'footer'], key => update(data, key)); + event.pub('custom.optionsLoaded', data.options); }); }; diff --git a/src/_h5ai/public/js/lib/view/view.js b/src/_h5ai/public/js/lib/view/view.js index 3740b78b1..198722287 100644 --- a/src/_h5ai/public/js/lib/view/view.js +++ b/src/_h5ai/public/js/lib/view/view.js @@ -18,6 +18,7 @@ const settings = Object.assign({ setParentFolderLabels: false, sizes }, allsettings.view); +let folderSettings = null; const sortedSizes = settings.sizes.sort((a, b) => a - b); const checkedModes = intersection(settings.modes, modes); const storekey = 'view'; @@ -87,10 +88,16 @@ const addCssStyles = () => { }; const getModes = () => checkedModes; -const getMode = () => store.get(storekey) && store.get(storekey).mode || settings.modes[0]; +const getMode = () => + (folderSettings && folderSettings.mode) || + (store.get(storekey) && store.get(storekey).mode) || + settings.modes[0]; const getSizes = () => sortedSizes; -const getSize = () => store.get(storekey) && store.get(storekey).size || settings.sizes[0]; +const getSize = () => + (folderSettings && folderSettings.size) || + (store.get(storekey) && store.get(storekey).size) || + settings.sizes[0]; const updateView = () => { const mode = getMode(); @@ -273,6 +280,11 @@ const onResize = () => { } }; +const onCustomOptionsLoaded = options => { + folderSettings = options && options.view; + updateView(); +}; + const init = () => { addCssStyles(); updateView(); @@ -285,6 +297,7 @@ const init = () => { event.sub('location.changed', onLocationChanged); event.sub('location.refreshed', onLocationRefreshed); event.sub('resize', onResize); + event.sub('custom.optionsLoaded', onCustomOptionsLoaded); onResize(); }; From 5c6f90a335465ac1c48069a3c5d383147db0c81c Mon Sep 17 00:00:00 2001 From: Daniel Lo Nigro Date: Thu, 21 Feb 2019 21:37:55 -0800 Subject: [PATCH 4/4] Validate mode and size on get rather than on set --- src/_h5ai/public/js/lib/view/view.js | 29 ++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/_h5ai/public/js/lib/view/view.js b/src/_h5ai/public/js/lib/view/view.js index 198722287..47f06f959 100644 --- a/src/_h5ai/public/js/lib/view/view.js +++ b/src/_h5ai/public/js/lib/view/view.js @@ -87,17 +87,28 @@ const addCssStyles = () => { dom('').text(styles.join('\n')).appTo('head'); }; +// Gets the first truthy value in `candidates` that is also listed in `validOptions` +const findFirstValid = (candidates, validOptions) => candidates.find(x => x && includes(validOptions, x)); + const getModes = () => checkedModes; -const getMode = () => - (folderSettings && folderSettings.mode) || - (store.get(storekey) && store.get(storekey).mode) || - settings.modes[0]; +const getMode = () => findFirstValid( + [ + (store.get(storekey) && store.get(storekey).mode), + (folderSettings && folderSettings.mode), + settings.modes[0] + ], + settings.modes +); const getSizes = () => sortedSizes; -const getSize = () => - (folderSettings && folderSettings.size) || - (store.get(storekey) && store.get(storekey).size) || - settings.sizes[0]; +const getSize = () => findFirstValid( + [ + (store.get(storekey) && store.get(storekey).size), + (folderSettings && folderSettings.size), + settings.sizes[0] + ], + settings.sizes +); const updateView = () => { const mode = getMode(); @@ -126,8 +137,6 @@ const set = (mode, size) => { mode = mode || stored && stored.mode; size = size || stored && stored.size; - mode = includes(settings.modes, mode) ? mode : settings.modes[0]; - size = includes(settings.sizes, size) ? size : settings.sizes[0]; // Unset if it's being set back to the default value if (mode === settings.modes[0]) {