diff --git a/css/islandora.base.css b/css/islandora.base.css index 585ad756..28301aa1 100644 --- a/css/islandora.base.css +++ b/css/islandora.base.css @@ -1,4 +1,4 @@ -/* +/* Document : islandora_basic_collection.base.css Created on : May 23, 2012, 11:22:04 AM Description: @@ -19,7 +19,7 @@ /* * These rules will display DTs/DDs as columns. * Constructs must follow a key/value pair pattern. - * The three last declarations are meant to kill white space between DTs/DDs + * The three last declarations are meant to kill white space between DTs/DDs * (result of inline-block styling) */ @@ -43,7 +43,20 @@ dl.islandora-inline-metadata { padding-left: 40px; } -/* +dl.islandora-metadata-fields { + width:100%; +} + +.islandora-metadata dt, +.islandora-metadata dd { + border-top:1px solid #e5e5e5; +} + +.islandora-metadata dt.first, +.islandora-metadata dd.first { + border-top:0; +} +/* * In this rule, we reset the white-space (see hack above) */ .islandora-inline-metadata dt, diff --git a/css/islandora.print.css b/css/islandora.print.css index 45fca341..4b714bc5 100644 --- a/css/islandora.print.css +++ b/css/islandora.print.css @@ -4,15 +4,6 @@ * * We provide some sane print styling for Drupal, hiding most visuals. */ -a:link, -a:visited { /* underline all links */ - text-decoration: underline !important; -} - -#site-name a:link, -#site-name a:visited { /* Don't underline header */ - text-decoration: none !important; -} #content a[href^="javascript:"]:after, #content a[href^="#"]:after { /* Only display useful links. */ @@ -66,6 +57,7 @@ body.sidebar-first { .book-navigation, .forum-topic-navigation, .pager, +.contextual-links-region, .feed-icons { /* Hide sidebars and nav elements */ visibility: hidden !important; display: none !important; diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index 7edd0f60..f9ed2b21 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -697,11 +697,48 @@ function islandora_ingest_form_ingest_button(array &$form_state) { '#type' => 'submit', '#name' => 'ingest', '#value' => t('Ingest'), + '#process' => array('islandora_ingest_form_ingest_button_process'), '#validate' => $validate, '#submit' => $submit, ); } +/** + * Process hook for the ingest button, adds the please wait spinning icon. + */ +function islandora_ingest_form_ingest_button_process(array $element) { + $settings['spinner'][$element['#id']] = array( + 'message' => t('Please be patient while the the page loads.'), + 'options' => array( + 'lines' => 10, + 'length' => 20, + 'width' => 10, + 'radius' => 30, + 'corners' => 1, + 'rotate' => 0, + 'direction' => 1, + 'color' => '#000', + 'speed' => 1, + 'trail' => 60, + 'shadow' => FALSE, + 'hwaccel' => FALSE, + 'className' => 'spinner', + 'zIndex' => 2000000000, + 'top' => 'auto', + 'left' => 'auto', + ), + ); + drupal_add_js($settings, 'setting'); + $islandora_path = drupal_get_path('module', 'islandora'); + $element['#attached'] = array( + 'js' => array( + "$islandora_path/js/spin/spin.min.js", + "$islandora_path/js/spinner.js", + ), + ); + return $element; +} + /** * The submit handler for the ingest form. * diff --git a/includes/metadata.inc b/includes/metadata.inc new file mode 100644 index 00000000..bf59b830 --- /dev/null +++ b/includes/metadata.inc @@ -0,0 +1,171 @@ + t('None'), + 'description' => t("Don't show any metadata for displaying"), + ); + $viewers = array_merge_recursive($no_viewer, $defined_displays); + + $form['viewers'] = array( + '#type' => 'item', + '#title' => t('Select a viewer'), + '#description' => t('Preferred metadata display for Islandora. These may be provided by third-party modules.'), + '#tree' => TRUE, + '#theme' => 'islandora_viewers_table', + ); + + foreach ($viewers as $name => $profile) { + $options[$name] = ''; + $form['viewers']['name'][$name] = array( + '#type' => 'hidden', + '#value' => $name, + ); + $form['viewers']['label'][$name] = array( + '#type' => 'item', + '#markup' => $profile['label'], + ); + $form['viewers']['description'][$name] = array( + '#type' => 'item', + '#markup' => $profile['description'], + ); + $form['viewers']['configuration'][$name] = array( + '#type' => 'item', + '#markup' => (isset($profile['configuration']) AND $profile['configuration'] != '') ? l(t('configure'), $profile['configuration']) : '', + ); + } + $form['viewers']['default'] = array( + '#type' => 'radios', + '#options' => isset($options) ? $options : array(), + '#default_value' => variable_get('islandora_metadata_display', 'dublin_core'), + ); + } + else { + $form['viewers']['no_viewers'] = array( + '#markup' => t('No viewers detected.'), + ); + } + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save configuration'), + ); + return $form; +} + +/** + * Submit handler for the metadata display form which sets the default viewer. + * + * @param array $form + * An array representing a Drupal form. + * @param array $form_state + * An array containing the Drupal form state. + */ +function islandora_metadata_display_form_submit($form, $form_state) { + variable_set('islandora_metadata_display', $form_state['values']['viewers']['default']); + drupal_set_message(t('The configuration options have been saved.')); +} + +/** + * Metadata display callback for rendering Dublin Core metadata. + * + * @param AbstractObject $object + * An AbstractObject representing an object within Fedora. + * @param bool $print + * Whether the display is being printed or not. + * + * @return string + * Markup representing the rendered metadata from Dublin Core. + */ +function islandora_metadata_display_callback(AbstractObject $object, $print = FALSE) { + $elements = array( + 'islandora_object' => $object, + 'print' => $print, + ); + return theme('islandora_dublin_core_display', $elements); +} + +/** + * Metadata description callback for rendering Dublin Core description. + * + * @param AbstractObject $islandora_object + * An AbstractObject representing an object within Fedora. + * + * @return string + * Markup representing the rendered metadata from Dublin Core. + */ +function islandora_metadata_description_callback(AbstractObject $islandora_object) { + $elements = array( + 'islandora_object' => $islandora_object, + ); + return theme('islandora_dublin_core_description', $elements); +} diff --git a/includes/utilities.inc b/includes/utilities.inc index 6366305e..2139ae09 100644 --- a/includes/utilities.inc +++ b/includes/utilities.inc @@ -908,3 +908,19 @@ function islandora_as_renderable_array(&$markup_array) { } unset($value); } + +/** + * Sanitizes an input string to be valid XML. + * + * @param string $input + * An input string. + * @param string $replacement + * What we are replacing invalid characters with, defaults to ''. + * + * @return string + * The sanitized string. + */ +function islandora_sanitize_input_for_valid_xml($input, $replacement = '') { + $input = preg_replace('/[^\x9\xA\xD\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]/u', $replacement, $input); + return $input; +} diff --git a/islandora.api.php b/islandora.api.php index 0dff8d89..24d24528 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -691,3 +691,36 @@ function hook_islandora_update_related_objects_properties(AbstractObject $object function hook_islandora_breadcrumbs_alter(&$breadcrumbs, $context) { } + +/** + * Registry hook for metadata display viewers. + * + * Modules can use this hook to override the default Dublin Core display. + * This hook lets Islandora know which viewers there are available. + * + * @return array + * An associative array where the values are the following: + * -label: Human readable display label for selection. + * -description: A description of what the metadata display viewer does. + * -metadata callback: A callable function that provides the markup to be + * passed off to the template files. Returns markup or FALSE if the viewer + * wishes to default back to the Dublin Core display for the current object. + * -description callback: A callable function that provides the markup to be + * passed for the description. Returns markup or FALSE if the viewer + * wishes to default back to the Dublin Core display for the current object. + * -configuration (Optional): A path to the administration page for the + * metadata display. + + * @see islandora_retrieve_metadata_markup() + */ +function hook_islandora_metadata_display_info() { + return array( + 'hookable_displays_yay' => array( + 'label' => t('Hookable display yay!'), + 'description' => t('This is purely an example of how to implement this.'), + 'metadata callback' => 'hookable_displays_some_function_that_returns_metadata_markup', + 'description callback' => 'hookable_displays_some_function_that_returns_description_markup', + 'configuration' => 'admin/hookable_displays_yay/somepath', + ), + ); +} diff --git a/islandora.module b/islandora.module index 8823d25d..38951f89 100644 --- a/islandora.module +++ b/islandora.module @@ -99,6 +99,14 @@ function islandora_menu() { 'type' => MENU_NORMAL_ITEM, 'weight' => -1, ); + $items['admin/islandora/metadata'] = array( + 'title' => 'Metadata Display', + 'description' => 'Configure settings for metadata display on Islandora objects', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('islandora_metadata_display_form'), + 'file' => 'includes/metadata.inc', + 'access arguments' => array('administer site configuration'), + ); $items['admin/islandora/solution_packs'] = array( 'title' => 'Solution packs', 'description' => 'Install content models and collections required by installed solution packs.', @@ -445,6 +453,31 @@ function islandora_theme() { 'file' => 'theme/theme.inc', 'variables' => array('datastream' => NULL), ), + 'islandora_dublin_core_display' => array( + 'file' => 'theme/theme.inc', + 'template' => 'theme/islandora-dublin-core-display', + // We can add PIDs to the end of this pattern in our preprocess function + // and templates will be able to have have a pid appended to the + // template name to overide a template on a per object basis. + // An example template might be named: + // "islandora-dublin-core-display--islandora-27.tpl.php". + 'pattern' => 'islandora_dublin_core_display__', + 'variables' => array( + 'islandora_object' => NULL, + 'print' => NULL, + ), + ), + 'islandora_dublin_core_description' => array( + 'file' => 'theme/theme.inc', + 'template' => 'theme/islandora-dublin-core-description', + // We can add PIDs to the end of this pattern in our preprocess function + // and templates will be able to have have a pid appended to the + // template name to overide a template on a per object basis. + // An example template might be named: + // "islandora-dublin-core-description--islandora-27.tpl.php". + 'pattern' => 'islandora_dublin_core_description__', + 'variables' => array('islandora_object' => NULL), + ), ); } @@ -991,6 +1024,7 @@ function islandora_default_islandora_view_object($object) { function islandora_default_islandora_printer_object($object, $alter) { module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/datastream'); + module_load_include('inc', 'islandora', 'includes/metadata'); $path = drupal_get_path('module', 'islandora'); drupal_add_css($path . '/css/islandora.print.css'); @@ -1005,11 +1039,12 @@ function islandora_default_islandora_printer_object($object, $alter) { catch (Exception $e) { drupal_set_message(t('Error retrieving object %s %t', array('%s' => $islandora_object->id, '%t' => $e->getMessage())), 'error', FALSE); } - + $metadata = islandora_retrieve_metadata_markup($object, TRUE); $variables = isset($dc_object) ? $dc_object->asArray() : array(); $output = theme('islandora_object_print_object', array( 'object' => $object, 'dc_array' => $variables, + 'metadata' => $metadata, 'islandora_content' => $alter)); return array('Default output' => array('#markup' => $output)); @@ -1695,4 +1730,18 @@ function islandora_repair_drupal_filter() { else { drupal_set_message(format_plural($entries, "Removed 1 simpletest entry from the Drupal filter.", "Removed @count simpletest entries from the Drupal filter.")); } + + /** + * Implements hook_islandora_metadata_display_info(). + */ +function islandora_islandora_metadata_display_info() { + return array( + 'dublin_core' => array( + 'label' => t('Dublin Core'), + 'description' => t('Dublin Core metadata'), + 'metadata callback' => 'islandora_metadata_display_callback', + 'description callback' => 'islandora_metadata_description_callback', + ), + ); } + diff --git a/js/spin/LICENSE.txt b/js/spin/LICENSE.txt new file mode 100644 index 00000000..b0a7912e --- /dev/null +++ b/js/spin/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2011 Felix Gnass [fgnass at neteye dot de] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/js/spin/README.md b/js/spin/README.md new file mode 100755 index 00000000..f88c257b --- /dev/null +++ b/js/spin/README.md @@ -0,0 +1,11 @@ +CONTENTS OF THIS FILE +--------------------- + + * summary + +SUMMARY +------- + +This directory contains the spin.js library: http://fgnass.github.io/spin.js/ +downloaded from http://fgnass.github.io/spin.js/dist/spin.min.js on Sept 27th +2013. This project is under version control: https://github.com/fgnass/spin.js. diff --git a/js/spin/spin.min.js b/js/spin/spin.min.js new file mode 100644 index 00000000..d4283919 --- /dev/null +++ b/js/spin/spin.min.js @@ -0,0 +1 @@ +(function(t,e){if(typeof exports=="object")module.exports=e();else if(typeof define=="function"&&define.amd)define(e);else t.Spinner=e()})(this,function(){"use strict";var t=["webkit","Moz","ms","O"],e={},i;function o(t,e){var i=document.createElement(t||"div"),o;for(o in e)i[o]=e[o];return i}function n(t){for(var e=1,i=arguments.length;e>1):parseInt(n.left,10)+s)+"px",top:(n.top=="auto"?l.y-a.y+(t.offsetHeight>>1):parseInt(n.top,10)+s)+"px"})}r.setAttribute("role","progressbar");e.lines(r,e.opts);if(!i){var d=0,p=(n.lines-1)*(1-n.direction)/2,c,h=n.fps,m=h/n.speed,y=(1-n.opacity)/(m*n.trail/100),g=m/n.lines;(function v(){d++;for(var t=0;t>1)+"px"})}for(;r',e)}r.addRule(".spin-vml","behavior:url(#default#VML)");c.prototype.lines=function(e,i){var o=i.length+i.width,r=2*o;function s(){return f(t("group",{coordsize:r+" "+r,coordorigin:-o+" "+-o}),{width:r,height:r})}var a=-(i.width+i.length)*2+"px",l=f(s(),{position:"absolute",top:a,left:a}),u;function p(e,r,a){n(l,n(f(s(),{rotation:360/i.lines*e+"deg",left:~~r}),n(f(t("roundrect",{arcsize:i.corners}),{width:o,height:i.width,left:i.radius,top:-i.width>>1,filter:a}),t("fill",{color:d(i.color,e),opacity:i.opacity}),t("stroke",{opacity:0}))))}if(i.shadow)for(u=1;u<=i.lines;u++)p(u,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(u=1;u<=i.lines;u++)p(u);return n(e,l)};c.prototype.opacity=function(t,e,i,o){var n=t.firstChild;o=o.shadow&&o.lines||0;if(n&&e+o').text(settings.spinner[base].message); + $(id).after(message); + // Make UI changes. + spinner.spin(this); + $('#edit-next').hide(); + $('#edit-prev').hide(); + // Submit the form after a set timeout, this handles problems with + // safari, in that safari submit's immediately.. + if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { + $(':submit').attr('disabled', 'disabled'); + } + setTimeout(function() { + // Allow for the button to be clicked, then click it then + // prevent the default behavoir. + $(id).removeAttr('disabled') + .click() + .click(function(event) { + event.preventDefault(); + }); + }, 500); + } + return true; + }); + }); + } + } + }; +})(jQuery); diff --git a/theme/islandora-dublin-core-description.tpl.php b/theme/islandora-dublin-core-description.tpl.php new file mode 100644 index 00000000..2ff54cdc --- /dev/null +++ b/theme/islandora-dublin-core-description.tpl.php @@ -0,0 +1,20 @@ + + diff --git a/theme/islandora-dublin-core-display.tpl.php b/theme/islandora-dublin-core-display.tpl.php new file mode 100644 index 00000000..da67de18 --- /dev/null +++ b/theme/islandora-dublin-core-display.tpl.php @@ -0,0 +1,33 @@ + +
> + +
+ +
+
diff --git a/theme/islandora-object-print.tpl.php b/theme/islandora-object-print.tpl.php index b9569061..53fdc529 100644 --- a/theme/islandora-object-print.tpl.php +++ b/theme/islandora-object-print.tpl.php @@ -10,21 +10,5 @@
- + diff --git a/theme/theme.inc b/theme/theme.inc index 895ec8fe..8ffffc4f 100644 --- a/theme/theme.inc +++ b/theme/theme.inc @@ -423,3 +423,37 @@ function theme_islandora_datastream_version_link(array $vars) { return ''; } } + +/** + * Implements hook_preprocess(). + */ +function islandora_preprocess_islandora_dublin_core_display(array &$variables) { + $islandora_object = $variables['islandora_object']; + if (islandora_datastream_access(ISLANDORA_VIEW_OBJECTS, $islandora_object['DC'])) { + try { + $dc = $islandora_object['DC']->content; + $dc_object = DublinCore::importFromXMLString($dc); + } + catch (Exception $e) { + drupal_set_message(t('Error retrieving object %s %t', array('%s' => $islandora_object->id, '%t' => $e->getMessage())), 'error', FALSE); + } + } + $variables['dc_array'] = isset($dc_object) ? $dc_object->asArray() : array(); +} + +/** + * Implements hook_preprocess(). + */ +function islandora_preprocess_islandora_dublin_core_description(array &$variables) { + $islandora_object = $variables['islandora_object']; + if (islandora_datastream_access(ISLANDORA_VIEW_OBJECTS, $islandora_object['DC'])) { + try { + $dc = $islandora_object['DC']->content; + $dc_object = DublinCore::importFromXMLString($dc); + } + catch (Exception $e) { + drupal_set_message(t('Error retrieving object %s %t', array('%s' => $islandora_object->id, '%t' => $e->getMessage())), 'error', FALSE); + } + } + $variables['dc_array'] = isset($dc_object) ? $dc_object->asArray() : array(); +}