commit e436b56e9e5da37ea305818962f77ef608125d1b Author: Alexander O'Neill Date: Tue Nov 23 17:35:47 2010 -0400 Migration to GitHub diff --git a/CollectionClass.inc b/CollectionClass.inc new file mode 100644 index 00000000..553634a4 --- /dev/null +++ b/CollectionClass.inc @@ -0,0 +1,400 @@ +collectionObject = new ObjectHelper($pid); + } + } + + /* gets objects related to this object. must include offset and limit + * calls getRelatedItems but enforces limit and offset + */ + + function getRelatedObjects($pid, $limit, $offset, $itqlquery=NULL) { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + $objectHelper = new ObjectHelper(); + if (!isset($itqlquery)) { + // $query_string = $objectHelper->getStream($pid, 'QUERY', 0); + $itqlquery = $objectHelper->getStream($pid, 'QUERY', 0); + } + return $this->getRelatedItems($pid, $itqlquery, $limit, $offset); + } + + /** + * Gets objects related to this item. It will query the object for a Query stream and use that as a itql query + * or if there is no query stream it will use the default. If you pass a query to this method it will use the passed in query no matter what + */ + function getRelatedItems($pid, $itqlquery = NULL, $limit = NULL, $offset = NULL) { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + if (!isset($limit)) { + $limit = 1000; + } + if (!isset($offset)) { + $offset = 0; + } + global $user; + if (!fedora_repository_access(OBJECTHELPER :: $OBJECT_HELPER_VIEW_FEDORA, $pid, $user)) { + drupal_set_message(t("You do not have access to Fedora objects within the attempted namespace or access to Fedora denied."), 'error'); + return ' '; + } + $objectHelper = new ObjectHelper(); + $query_string = $itqlquery; + if (!isset($query_string)) { + $query_string = $objectHelper->getStream($pid, 'QUERY', 0); + if ($query_string == NULL) { + $query_string = 'select $object $title $content from <#ri> + where ($object $title + and $object $content + and ($object + or $object ) + and $object ) + minus $content + order by $title'; + } + } + + $query_string = htmlentities(urlencode($query_string)); + + $content = ''; + $url = variable_get('fedora_repository_url', 'http://localhost:8080/fedora/risearch'); + $url .= "?type=tuples&flush=TRUE&format=Sparql&limit=$limit&offset=$offset&lang=itql&stream=on&query=" . $query_string; + $content .= do_curl($url); + + return $content; + } + + function getCollectionPolicyStream($collection_pid) { + if ($this->collectionPolicyStream != NULL) { + return $this->collectionPolicyStream; + } + $this->collectionPolicyStream = $this->getStream($collection_pid, CollectionClass :: $COLLECTION_CLASS_COLLECTION_POLICY_STREAM, 0); + return $this->collectionPolicyStream; + } + + function getRelationshipElement($collection_pid) { + $stream = $this->getCollectionPolicyStream($collection_pid); + try { + $xml = new SimpleXMLElement($stream); + } catch (Exception $e) { + drupal_set_message(t('Error getting relationship element from policy stream !e', array('!e' => $e->getMessage())), 'error'); + return; + } + $relationship = $xml->relationship[0]; + return $relationship; + } + + function getCollectionViewStream($collection_pid) { + $this->collectionViewStream = $this->getStream($collection_pid, CollectionClass :: $COLLECTION_CLASS_COLLECTION_VIEW_STREAM, 0); + return $this->collectionViewStream; + } + + function getStream($pid, $dsid, $showError = 1) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $item = new fedora_item($pid); + return isset($item->datastreams[$dsid]) ? $item->get_datastream_dissemination($dsid) : NULL; + } + + function getPidNameSpace($pid, $dsid) { + $stream = $this->getCollectionPolicyStream($pid); + try { + $xml = new SimpleXMLElement($stream); + } catch (Exception $e) { + drupal_set_message(t('Error getting PID namespace !e', array('!e' => $e->getMessage())), 'error'); + return; + } + foreach ($xml->contentmodels->contentmodel as $contentModel) { + // $contentModelName=strip_tags($contentModel['name']); + $contentdsid = strip_tags($contentModel->dsid); + if (strtolower($contentdsid) == strtolower($dsid)) { + return strip_tags($contentModel->pid_namespace->asXML()); + } + } + drupal_set_message(t('Error getting PID namespace! using collection pid of !pid and content model of !dsid', array('!pid' => $pid, '!dsid' => $dsid)), 'error'); + return NULL; + } + + /** + * gets a list of content models from a collection policy + */ + function getContentModels($collection_pid, $showError = TRUE) { + module_load_include('inc', 'Fedora_Repository', 'ContentModel'); + $collection_stream = $this->getCollectionPolicyStream($collection_pid); + try { + $xml = new SimpleXMLElement($collection_stream); + } catch (Exception $e) { + if ($showError) { + drupal_set_message(t("!e", array('!e' => $e->getMessage())), 'error'); + } + return NULL; + } + foreach ($xml->contentmodels->contentmodel as $content_model) { + $contentModel = new ContentModel(); + $contentModel->contentModelDsid = $content_model->dsid; + $contentModel->contentModelPid = $content_model->pid; + $contentModel->pidNamespace = $content_model->pidNamespace; + $contentModel->contentModelName = $content_model['name']; + $models[] = $contentModel; + } + return $models; + } + + /** + * using the collection policies pid namespace get a new pid by calling fedora' get next pid and appending it to the namespace + * $pid is the $pid of the content model + * $dsid is the datastream id of the content model. + */ + function getNextPid($pid, $dsid) { + module_load_include('inc', 'Fedora_Repository', 'ConnectionHelper'); + $pidNameSpace = $this->getPidNameSpace($pid, $dsid); + $pname = substr($pidNameSpace, 0, strpos($pidNameSpace, ":")); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + return Fedora_Item::get_next_pid_in_namespace($pname); + } + + /** + * gets the form handler file, class and method and returns them in an array + * + * @param string $pid The content model PID + * @param string $dsid The content model DSID + * @return array The file, class and method name to handle the ingest form. + */ + function getFormHandler($pid, $dsid) { + $stream = $this->getContentModelStream($pid, $dsid); + try { + $xml = new SimpleXMLElement($stream); + } catch (Exception $e) { + drupal_set_message(t('Error Getting FormHandler: !e', array('!e' => $e->getMessage())), 'error'); + return NULL; + } + $formHandler = $xml->ingest_form; + if ($formHandler != NULL) { + $handlerDsid = strip_tags($formHandler['dsid']); + $handlerMethod = strip_tags($formHandler->form_builder_method->form_handler->asXML()); + $handlerFile = strip_tags($formHandler->form_builder_method->file->asXML()); + $handlerClass = strip_tags($formHandler->form_builder_method->class_name->asXML()); + $handlerModule = strip_tags($formHandler->form_builder_method->module->asXML()); + $returnArray = array(); + $returnArray['module'] = $handlerModule; + $returnArray['method'] = $handlerMethod; + $returnArray['class'] = $handlerClass; + $returnArray['file'] = $handlerFile; + return $returnArray; + } + + drupal_set_message(t("Error getting form handler. No handler found for !pid - !dsid", array('!pid' => $pid, '!dsid' => $dsid)), 'error'); + return NULL; + } + + function getAllowedMimeTypes($contentModelPid, $contentModel_dsid) { + $stream = $this->getContentModelStream($contentModelPid, $contentModel_dsid); + try { + $xml = new SimpleXMLElement($stream); + } catch (Exception $e) { + drupal_set_message(t('Error getting content model stream for mime types !e', array('!e' => $e->getMessage())), 'error'); + return; + } + foreach ($xml->mimetypes->type as $type) { + $types[] = $type; + } + return $types; + } + + /** + * Grabs the rules from the content model stream + * file the file that has been uploaded + */ + function getAndDoRules($file, $mimetype, $pid, $dsid) { + if (!user_access('ingest new fedora objects')) { + drupal_set_message(t('You do not have permission to ingest objects.')); + return FALSE; + } + + $stream = $this->getContentModelStream($pid, $dsid); + + try { + $xml = new SimpleXMLElement($stream); + } catch (Exception $e) { + drupal_set_message(t('Error getting content model stream !e', array('!e' => $e->getMessage())), 'error'); + return FALSE; + } + foreach ($xml->ingest_rules->rule as $rule) { + foreach ($rule->applies_to as $type) { + if (!strcmp(trim($type), trim($mimetype))) { + $methods = $rule->methods->method; + return $this->callMethods($file, $methods); + } + } + } + } + + /** + * calls the methods defined in the content model rules .xml file stored in a Fedora object + */ + function callMethods($file, $methods) { + foreach ($methods as $method) { + $phpFile = strip_tags($method->file->asXML()); + $phpClass = strip_tags($method->class_name->asXML()); + $phpMethod = strip_tags($method->method_name->asXML()); + $file_ext = strip_tags($method->modified_files_ext->asXML()); + $parameters = $method->parameters->parameter; + $dsid = strip_tags($method->datastream_id); + $parametersArray = array(); + if (isset($parameters)) { + foreach ($parameters as $parameter) { + $name = strip_tags($parameter['name']); + $value = strip_tags($parameter->asXML()); + $parametersArray["$name"] = $value; + } + } + // module_load_include( $phpFile, 'Fedora_Repository', ' '); + require_once(drupal_get_path('module', 'fedora_repository') . '/' . $phpFile); + $thisClass = new $phpClass (); + $returnValue = $thisClass->$phpMethod($parametersArray, $dsid, $file, $file_ext); + if (!$returnValue) { + drupal_set_message('Error! Failed running content model method !m !rv', array('!m' => $phpMethod, '!rv' => $returnValue)); + return FALSE; + } + } + return TRUE; + } + + /** + * grabs a xml form definition from a content model and builds + * the form using drupals forms api + */ + function build_ingest_form(&$form, &$form_state, $contentModelPid, $contentModelDsid) { + $stream = $this->getContentModelStream($contentModelPid, $contentModelDsid); + try { + $xml = new SimpleXMLElement($stream); + } catch (Exception $e) { + drupal_set_message(t('Error getting ingest form stream !e', array('!e' => $e->getMessage())), 'error'); + return FALSE; + } + $docRoot = $_SERVER['DOCUMENT_ROOT']; + + $file = (isset($form_state['values']['ingest-file-location']) ? $form_state['values']['ingest-file-location'] : ''); + // $fullPath = $docRoot . '' . $file; + $fullpath = $file; + // $form = array(); + $form['step'] = array( + '#type' => 'hidden', + '#value' => (isset($form_state['values']['step']) ? $form_state['values']['step'] : 0) + 1, + ); + $form['ingest-file-location'] = array( + '#type' => 'hidden', + '#value' => $file, + ); + + $form['content_model_name'] = array( + '#type' => 'hidden', + '#value' => $contentModelDsid + ); + $form['models'] = array(//content models available + '#type' => 'hidden', + '#value' => $form_state['values']['models'], + ); + $form['fullpath'] = array( + '#type' => 'hidden', + '#value' => $fullpath, + ); + + $form['#attributes']['enctype'] = 'multipart/form-data'; + $form['indicator']['ingest-file-location'] = array( + '#type' => 'file', + '#title' => t('Upload Document'), + '#size' => 48, + '#description' => t('Full text'), + ); + if ($xml->ingest_form->hide_file_chooser == 'TRUE') { + $form['indicator']['ingest-file-location']['#type'] = 'hidden'; + } + $ingest_form = $xml->ingest_form; //should only be one + $drupal_module = strip_tags($ingest_form->form_builder_method->module->asXML()); + if (empty($drupal_module)) { + $drupal_module = 'fedora_repository'; + } + $phpFile = strip_tags($ingest_form->form_builder_method->file->asXML()); + $phpClass = strip_tags($ingest_form->form_builder_method->class_name->asXML()); + $phpMethod = strip_tags($ingest_form->form_builder_method->method_name->asXML()); + $dsid = strip_tags($ingest_form['dsid']); + // module_load_include('php', 'Fedora_Repository', $phpFile); + require_once(drupal_get_path('module', $drupal_module) . '/' . $phpFile); + $thisClass = new $phpClass (); + + return $thisClass->$phpMethod($form, $ingest_form, $form_state['values'], $form_state); + } + + //this will also create a personal collection for an existing user if they don't have one + //not using this function currently + function createUserCollection(& $user) { + if (isset($user->fedora_personal_pid)) { + return; + } + $username = array( + 'name' => variable_get('fedora_admin_user', 'fedoraAdmin') + ); + $admin_user = user_load($username); + module_load_include('inc', 'fedora_repository', 'ConnectionHelper'); + $connectionHelper = new ConnectionHelper(); + try { + $soapClient = $connectionHelper->getSoapClient(variable_get('fedora_soap_manage_url', 'http://localhost:8080/fedora/services/management?wsdl')); + $pidNameSpace = variable_get('fedora_repository_pid', 'vre:'); + $pidNameSpace = substr($pidNameSpace, 0, strpos($pidNameSpace, ":")); + $params = array( + 'numPIDs' => '', + 'pidNamespace' => $pidNameSpace + ); + $object = $soapClient->__soapCall('getNextPID', array( + $params + )); + } catch (exception $e) { + drupal_set_message(t('Error getting Next PID: !e', array('!e' => $e->getMessage())), 'error'); + return FALSE; + } + $pid = implode(get_object_vars($object)); + $pidNumber = strstr($pid, ":"); + $pid = $pidNameSpace . ':' . 'USER-' . $user->name . '-' . substr($pidNumber, 1); + $personal_collection_pid = array( + 'fedora_personal_pid' => $pid + ); + module_load_include('inc', 'fedora_repository', 'plugins/PersonalCollectionClass'); + $personalCollectionClass = new PersonalCollectionClass(); + if (!$personalCollectionClass->createCollection($user, $pid, $soapClient)) { + drupal_set_message("Did not create a personal collection object for !u", array('!u' => $user->name)); + return FALSE; //creation failed don't save the collection pid in drupal db + } + user_save($user, $personal_collection_pid); + return TRUE; + } + +} + diff --git a/CollectionPolicy.inc b/CollectionPolicy.inc new file mode 100644 index 00000000..cb769085 --- /dev/null +++ b/CollectionPolicy.inc @@ -0,0 +1,602 @@ +get_datastream_dissemination($dsid); + } else { + $ds=null; + } + + } + + if (!empty($ds) || !$preFetch) { + $ret=new CollectionPolicy($ds, $pid, $dsid); + } + } + catch (SOAPException $e) { + + $ret = FALSE; + } + return $ret; + } + + /** + * Ingests a new Collection Policy datastream to the specified + * PID with the DSID specified. The file should be a valid collection + * policy XML. Returns false on failure. + * + * @param string $pid + * @param string $name + * @param string $cpDsid + * @param string $file + * @return CollectionPolicy $ret + */ + public static function ingestFromFile($pid, $name, $cpDsid, $file) { + $ret = FALSE; + + if (($cp = self::loadFromCollection($pid, $cpDsid)) === FALSE && file_exists($file)) { + $cp = new ContentModel(file_get_contents($file), $pid, $cpDsid); + $rootEl = $cp->xml->getElementsByTagName('collection_policy')->item(0); + $rootEl->setAttribute('name', $name); + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $fedoraItem = new Fedora_Item($pid); + $fedoraItem->add_datastream_from_string($cp->dumpXml(), $cpDsid, $name, 'text/xml', 'X'); + $ret = $cp; + } + + return $ret; + } + + /** + * Ingests a new Collection Policy datastream to the specified + * PID with the DSID specified. Clones the collection policy from the + * source collection pid. Returns false on failure. + * + * @param string $pid + * @param string $name + * @param string $cpDsid + * @param string $copy_collection_pid + * @return CollectionPolicy $ret + */ + public static function ingestFromCollection($pid, $name, $cpDsid, $copy_collection_pid) { + $ret = FALSE; + + if (($cp = self::loadFromCollection($pid, $cpDsid)) === FALSE && ($copy_cp = self::loadFromCollection($copy_collection_pid)) !== FALSE && $copy_cp->validate()) { + $newDom = $copy_cp->xml; + $rootEl = $newDom->getElementsByTagName('collection_policy')->item(0); + $rootEl->setAttribute('name', $name); + + $cp = new CollectionPolicy($newDom, $pid, $cpDsid); + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $fedoraItem = new Fedora_Item($pid); + $fedoraItem->add_datastream_from_string($cp->dumpXml(), $cpDsid, $name, 'text/xml', 'X'); + $ret = $cp; + } + + return $ret; + } + + /** + * Ingests a new minimum Collection Policy datastream to the specified + * PID with the DSID specified. Initializes the policy with the specified values. + * Returns false on failure + * + * @param string $pid + * @param string $name + * @param string $cpDsid + * @param string $model_pid + * @param string $model_namespace + * @param string $relationshiop + * @param string $searchField + * @param string $searchValue + * @return CollectionPolicy $ret + */ + public static function ingestBlankPolicy($pid, $name, $policyDsid, $model_pid, $model_namespace, $relationship, $searchField, $searchValue) { + $ret = FALSE; + if (($cp = self::loadFromCollection($pid, $modelDsid)) === FALSE) { + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (($cm = ContentModel::loadFromModel($model_pid)) !== FALSE && $cm->validate()) { + $newDom = new DOMDocument('1.0', 'utf-8'); + $newDom->formatOutput = TRUE; + $rootEl = $newDom->createElement('collection_policy'); + $rootEl->setAttribute('name', $name); + $rootEl->setAttribute('xmlns', self::$XMLNS); + $rootEl->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $rootEl->setAttribute('xsi:schemaLocation', self::$XMLNS .' '. self::$SCHEMA_URI); + + $modelsEl = $newDom->createElement('content_models'); + + $cmEl = $newDom->createElement('content_model'); + $cmEl->setAttribute('name', $cm->getName()); + $cmEl->setAttribute('dsid', $cm->dsid); + $cmEl->setAttribute('namespace', $model_namespace); + $cmEl->setAttribute('pid', $cm->pid); + + $modelsEl->appendChild($cmEl); + $rootEl->appendChild($modelsEl); + + $relEl = $newDom->createElement('relationship', $relationship); + $rootEl->appendChild($relEl); + + $searchTermsEl = $newDom->createElement('search_terms'); + $newTermEl = $newDom->createElement('term', $searchValue); + $newTermEl->setAttribute('field', $searchField); + $searchTermsEl->appendChild($newTermEl); + $rootEl->appendChild($searchTermsEl); + + $newDom->appendChild($rootEl); + + $cp = new CollectionPolicy($newDom, $pid, $policyDsid); + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + + + $fedoraItem = new Fedora_Item($pid); + $fedoraItem->add_datastream_from_string($cp->dumpXml(), $policyDsid, $name, 'text/xml', 'X'); + $ret = $cp; + } + + } + + return $ret; + } + + /** + * Attempts to convert from the old XML schema to the new by + * traversing the XML DOM and building a new DOM. When done + * $this->xml is replaced by the newly created DOM.. + * + * @return void + */ + protected function convertFromOldSchema() { + if ($this->xml == NULL) { + $this->fetchXml(); + } + $sXml = simplexml_load_string($this->xml->saveXML()); + $newDom = new DOMDocument('1.0', 'utf-8'); + $newDom->formatOutput = TRUE; + + $rootEl = $newDom->createElement('collection_policy'); + $rootEl->setAttribute('name', $sXml['name']); + $rootEl->setAttribute('xmlns', self::$XMLNS); + $rootEl->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $rootEl->setAttribute('xsi:schemaLocation', self::$XMLNS .' '. self::$SCHEMA_URI); + + $content_modelsEl = $newDom->createElement('content_models'); + foreach ($sXml->contentmodels->contentmodel as $contentmodel) { + $content_modelEl = $newDom->createElement('content_model'); + $content_modelEl->setAttribute('name', $contentmodel['name']); + $content_modelEl->setAttribute('dsid', $contentmodel->dsid); + $content_modelEl->setAttribute('namespace', $contentmodel->pid_namespace); + $content_modelEl->setAttribute('pid', $contentmodel->pid); + $content_modelsEl->appendChild($content_modelEl); + } + $rootEl->appendChild($content_modelsEl); + + $search_termsEl = $newDom->createElement('search_terms'); + foreach ($sXml->search_terms->term as $term) { + $termEl = $newDom->createElement('term', $term->value); + $termEl->setAttribute('field', $term->field); + if (strval($sXml->search_terms->default) == $term->field) { + $termEl->setAttribute('default', 'true'); + } + $search_termsEl->appendChild($termEl); + } + $rootEl->appendChild($search_termsEl); + + $relationshipEl = $newDom->createElement('relationship', $sXml->relationship); + $rootEl->appendChild($relationshipEl); + + $newDom->appendChild($rootEl); + + $this->xml = DOMDocument::loadXML($newDom->saveXml()); + } + + + /** + * Gets the name of the relationship to use + * for members of this collection. + * Returns FALSE on failure. + * + * @return string $relationship + */ + public function getRelationship() { + $ret=FALSE; + if ($this->validate()) { + $ret=trim($this->xml->getElementsByTagName('relationship')->item(0)->nodeValue); + } + return $ret; + } + + /** + * Sets the name of the relationship to use + * for members of this collection. + * Returns FALSE on failure. + * + * @param string $relationship + * @return boolean $ret + */ + public function setRelationship($relationship) { + $ret=FALSE; + if ($this->validate()) { + $relationshipEl=$this->xml->getElementsByTagName('relationship')->item(0); + $relationshipEl->nodeValue=trim($relationship); + $ret = TRUE; + } + return $ret; + } + + /** + * Gets the path to the staging area to use for this + * collection. By default recurses to the parent collection + * if the staging area is undefined + * + * @param BOOLEAN $recurse + * @return string $path + */ + public function getStagingArea($recurse=TRUE) { + $ret=FALSE; + if ($this->validate()) { + if ($this->staging_area === NULL) { + $stagingEl=$this->xml->getElementsByTagName('staging_area'); + + if ($stagingEl->length > 0) { + $this->staging_area = trim($stagingEl->item(0)->nodeValue); + } elseif ($recurse) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $item=new Fedora_Item($this->pid); + $rels=$item->get_relationships(); + if (count($rels) > 0) { + foreach ($rels as $rel) { + $cp = CollectionPolicy::loadFromCollection($rel['object']); + if ($cp !== FALSE) { + $this->staging_area = $cp->getStagingArea(); + break; + } + } + } + } + } + + $ret = $this->staging_area; + + } + return $ret; + } + + /** + * Sets the path to the staging area to use for this + * collection. If specified path is blank (or false) it will + * remove the staging are path element from the collection policy. + * + * @param string $path + * + * @return string $relationship + */ + public function setStagingArea($path) { + $ret=FALSE; + if ($this->validate()) { + $rootEl=$this->xml->getElementsByTagName('collection_policy')->item(0); + $stagingEl=$this->xml->getElementsByTagName('staging_area'); + if ($stagingEl->length > 0) { + $stagingEl=$stagingEl->item(0); + if (trim($path) == '') { + $rootEl->removeChild($stagingEl); + } + else { + $stagingEl->nodeValue=trim($path); + } + } + elseif (trim($path) != '') { + $stagingEl=$this->xml->createElement('staging_area', trim($path)); + $rootEl->appendChild($stagingEl); + } + + $ret = TRUE; + } + return $ret; + } + + + /** + * Gets the next available PID for the + * content model specified by the DSID + * parameter. + * + * @param string $dsid + * @return string $nextPid + */ + public function getNextPid($dsid) { + $ret = FALSE; + if (self::validDsid($dsid) && $this->validate()) { + $content_models = $this->xml->getElementsByTagName('content_models')->item(0)->getElementsByTagName('content_model'); + $namespace = FALSE; + for ($i=0; $namespace === FALSE && $i<$content_models->length;$i++) { + if (strtolower($content_models->item($i)->getAttribute('dsid')) == strtolower($dsid)) { + $namespace = $content_models->item($i)->getAttribute('namespace'); + } + } + + $pname = substr($namespace, 0, strpos($namespace, ":")); + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $ret = Fedora_Item::get_next_pid_in_namespace($pname); + } + return $ret; + } + + /** + * Gets a list of ContentModel objects supported by this collection. + * + * @return ContentModel[] $models + */ + function getContentModels() { + $ret=FALSE; + if ($this->validate()) { + module_load_include('inc', 'Fedora_Repository', 'ContentModel'); + $ret=array(); + $content_models = $this->xml->getElementsByTagName('content_models')->item(0)->getElementsByTagName('content_model'); + for ($i=0;$i<$content_models->length;$i++) { + $cm=ContentModel::loadFromModel($content_models->item($i)->getAttribute('pid'), + $content_models->item($i)->getAttribute('dsid'), + $content_models->item($i)->getAttribute('namespace'), + $content_models->item($i)->getAttribute('name')); + if ($cm !== FALSE) { + $ret[]=$cm; + } + + } + } + return $ret; + } + + + + /** + * Gets a list of search terms from the Collection Policy. If asArray is set + * it will return an associative array with the value, field name, and the default value. + * If not set, an array of just the values will be returned. If $recurse is TRUE, it will + * recurseively return the parents search terms if it has none until it returns a set of terms or reaches + * the top level collection. If $cache is TRUE, it will return a cached version (if available). + * + * @param boolean $asArray + * @param boolean $recurse + * @param boolean $cache + * @return string[] $ret + */ + function getSearchTerms($asArray = FALSE, $recurse = FALSE, $cache = FALSE) { + $ret = FALSE; + + if ($cache == TRUE && ($cache = cache_get('collection_policy_search_terms-'.$this->pid)) !== 0 ) { + $ret=$cache->data; + } else { + + if ($this->xml == NULL) { + $fedoraItem = new Fedora_Item($this->pid); + $ds = $fedoraItem->get_datastream_dissemination($this->dsid); + $this->xml = DOMDocument::loadXML($ds); + } + + + if ($this->validate()) { + $ret=array(); + $terms= $this->xml->getElementsByTagName('search_terms')->item(0)->getElementsByTagName('term'); + for ($i=0;$i<$terms->length;$i++) { + $default = $terms->item($i)->attributes->getNamedItem('default'); + $default = ($default !== NULL) ? (strtolower($default->nodeValue) == 'true') : FALSE; + $ret[] = ($asArray)?array( 'value' => $terms->item($i)->nodeValue, + 'field' => $terms->item($i)->getAttribute('field'), + 'default' => $default): $terms->item($i)->nodeValue; + } + + + if ($recurse && count($ret) == 0) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $item=new Fedora_Item($this->pid); + $rels=$item->get_relationships(); + if (count($rels) > 0) { + foreach ($rels as $rel) { + $cp = CollectionPolicy::loadFromCollection($rel['object']); + if ($cp !== FALSE) { + $ret = $cp->getSearchTerms($asArray, $recurse); + break; + } + } + } + } + cache_set('collection_policy_search_terms-'.$this->pid, $ret, 'cache', time()+3600); + + } + } + return $ret; + } + + + /** + * Adds a search term to the collection policy. + * Returns fase on failure. + * + * @param string $field + * @param string $value + * @return boolean $success + */ + function addTerm($field, $value) { + $ret=FALSE; + if ($this->validate()) { + $search_termsEl = $this->xml->getElementsByTagName('search_terms')->item(0); + $terms= $search_termsEl->getElementsByTagName('term'); + $found=FALSE; + for ($i=0;!$found && $i<$terms->length;$i++) { + if ($terms->item($i)->getAttribute('field') == $field) { + $found = TRUE; + } + } + + if (!$found) { + $newTermEl = $this->xml->createElement('term', $value); + $newTermEl->setAttribute('field', $field); + $search_termsEl->appendChild($newTermEl); + $ret = TRUE; + } + } + return $ret; + } + + /** + * Removes the search term specified by the field parameter from the collection policy. + * + * @param string $field + * @return boolean $success + */ + function removeTerm($field) { + $ret=FALSE; + if ($this->validate()) { + $search_termsEl = $this->xml->getElementsByTagName('search_terms')->item(0); + $terms = $search_termsEl->getElementsByTagName('term'); + $found = FALSE; + for ($i=0; !$found && $i < $terms->length; $i++) { + if ($terms->item($i)->getAttribute('field') == $field) { + $found = $terms->item($i); + } + } + + if ($found !== FALSE) { + $search_termsEl->removeChild($found); + $ret = TRUE; + } + } + return $ret; + } + + + function setDefaultTerm($field) { + $ret = FALSE; + if ($this->validate()) { + $search_termsEl = $this->xml->getElementsByTagName('search_terms')->item(0); + $terms= $search_termsEl->getElementsByTagName('term'); + $found=FALSE; + for ($i=0;!$found && $i<$terms->length;$i++) { + if ($terms->item($i)->getAttribute('field') == $field) { + $found = $terms->item($i); + } + } + + if ($found !== FALSE) { + for ($i=0;$i<$terms->length;$i++) + if ($terms->item($i)->attributes->getNamedItem('default') !== NULL) { + $terms->item($i)->removeAttribute('default'); + } + $found->setAttribute('default', 'true'); + $ret = TRUE; + } + } + return $ret; + } + + + /** + * Removes the specified content model from the collection policy. This will only + * prevent future ingests of the removed model to the collection. $cm should be + * a valid ContentModel object. Returns false on failure or when the CM was not found in + * the collection policy. + * + * @param ContentModel $cm + * @return boolean $valid + */ + function removeModel($cm) { + $ret=FALSE; + if ($this->validate() && $cm->validate()) { + $contentmodelsEl = $this->xml->getElementsByTagName('content_models'); + $models = $contentmodelsEl->item(0)->getElementsByTagName('content_model'); + $found = FALSE; + for ($i=0; $found === FALSE && $i < $models->length; $i++) { + if ($models->item($i)->getAttribute('pid') == $cm->pid) { + $found=$models->item($i); + } + } + + if ($found !== FALSE && $models->length > 1) { + $contentmodelsEl->item(0)->removeChild($found); + $ret = TRUE; + } + } + return $ret; + } + + + + + function addModel($cm, $namespace) { + $ret = FALSE; + if (self::validPid($namespace) && $this->validate() && $cm->validate()) { + $contentmodelsEl = $this->xml->getElementsByTagName('content_models'); + $models = $contentmodelsEl->item(0)->getElementsByTagName('content_model'); + $found = FALSE; + for ($i=0;!$found && $i<$models->length;$i++) { + if ($models->item($i)->getAttribute('pid') == $cm->pid) + $found = TRUE; + } + + if (!$found) { + $cmEl = $this->xml->createElement('content_model'); + $cmEl->setAttribute('name', $cm->getName()); + $cmEl->setAttribute('dsid', $cm->dsid); + $cmEl->setAttribute('namespace', $namespace); + $cmEl->setAttribute('pid', $cm->pid); + $contentmodelsEl->item(0)->appendChild($cmEl); + } + + $ret = !$found; + } + return $ret; + } + + function getName() { + $ret=FALSE; + if ($this->validate()) { + $ret=$this->xml->getElementsByTagName('collection_policy')->item(0)->getAttribute('name'); + } + return $ret; + } + +} diff --git a/ConnectionHelper.inc b/ConnectionHelper.inc new file mode 100644 index 00000000..11aa868f --- /dev/null +++ b/ConnectionHelper.inc @@ -0,0 +1,79 @@ + $url))); + return NULL; + } + + return $new_url; + } + + function getSoapClient($url = NULL) { + if ($url == NULL) { + $url=variable_get('fedora_soap_url', 'http://localhost:8080/fedora/services/access?wsdl'); + } + global $user; + if ($user->uid == 0) { + //anonymous user. We will need an entry in the fedora users.xml file + //with the appropriate entry for a username of anonymous password of anonymous + try { + $client = new SoapClient($this->_fixURL($url, 'anonymous', 'anonymous'), array( + 'login' => 'anonymous', + 'password' => 'anonymous', + 'exceptions' => TRUE, + )); + } + catch (SoapFault $e) { + drupal_set_message(t("!e", array('!e' => $e->getMessage()))); + return NULL; + } + } + else { + try { + $client = new SoapClient($this->_fixURL($url, $user->name, $user->pass), array( + 'login' => $user->name, + 'password' => $user->pass, + 'exceptions' => TRUE, + )); + } + catch (SoapFault $e) { + drupal_set_message(t("!e", array('!e' => $e->getMessage()))); + return NULL; + } + } + return $client; + } +} + diff --git a/ContentModel.inc b/ContentModel.inc new file mode 100644 index 00000000..b952e2c7 --- /dev/null +++ b/ContentModel.inc @@ -0,0 +1,2016 @@ +get_content_models_list($pid); + foreach ($content_models as $content_model) { + if ($content_model != 'fedora-system:FedoraObject-3.0') { + $ret = self::loadFromModel($content_model); + break; + } + } + } + return $ret; + } + + /** + * Ingests a Content Model from a file to the specified pid/dsid . + * Returns false on failure. + * + * @param string $pid + * @param string $name + * @param string $modelDsid + * @param string $file + * @return ContentModel $cm + */ + public static function ingestFromFile($pid, $name, $modelDsid, $file) { + $ret = FALSE; + + if (($cm = self::loadFromModel($pid, $modelDsid)) === FALSE && file_exists($file)) { + $cm = new ContentModel(file_get_contents($file), $pid, $modelDsid); + $rootEl = $cm->xml->getElementsByTagName('content_model')->item(0); + $rootEl->setAttribute('name', $name); + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $fedoraItem = new Fedora_Item($pid); + $fedoraItem->add_datastream_from_string($cm->dumpXml(), $modelDsid, $name, 'text/xml', 'X'); + $ret= $cm; + } + + return $ret; + } + + + /** + * Ingests a Content Model from an existing model to the specified pid/dsid . + * Returns false on failure. + * + * @param string $pid + * @param string $name + * @param string $modelDsid + * @param string $copy_model_pid + * @return ContentModel $cm + */ + public static function ingestFromModel($pid, $name, $modelDsid, $copy_model_pid) { + $ret = FALSE; + + if (($cm = self::loadFromModel($pid, $modelDsid)) === FALSE && ($copy_cm = self::loadFromModel($copy_model_pid)) !== FALSE && $copy_cm->validate()) { + $newDom = $copy_cm->xml; + $rootEl = $newDom->getElementsByTagName('content_model')->item(0); + $rootEl->setAttribute('name', $name); + + $cm = new ContentModel($newDom, $pid, $modelDsid); + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $fedoraItem = new Fedora_Item($pid); + $fedoraItem->add_datastream_from_string($cm->dumpXml(), $modelDsid, $name, 'text/xml', 'X'); + $ret = $cm; +} + + return $ret; + } + + + /** + * Ingests a minimum Content Model to the specified pid/dsid. + * Returns false on failure. + * + * @param string $pid + * @param string $name + * @param string $modelDsid + * @param string $defaultMimetype + * @param string $ingestFromDsid + * @param integer $ingestFormPage + * @param boolean $ingestFormHideFileChooser + * @param string $ingestFormModule + * @param string $ingestFormModule + * @param string $ingestFormFile + * @param string $ingestFormClass + * @param string $ingestFormMethod + * @param string $ingestFormHandler + * + * @return ContentModel $cm + */ + public static function ingestBlankModel($pid, $name, $modelDsid, $defaultMimetype, $ingestFormDsid, $ingestFormPage, $ingestFormHideChooser, $ingestFormModule, $ingestFormModule, $ingestFormFile, $ingestFormClass, $ingestFormMethod, $ingestFormHandler) { + $ret = FALSE; + if (($cm = self::loadFromModel($pid, $modelDsid)) === FALSE) { + $newDom = new DOMDocument('1.0', 'utf-8'); + $newDom->formatOutput = TRUE; + $rootEl = $newDom->createElement('content_model'); + $rootEl->setAttribute('name', $name); + $rootEl->setAttribute('xmlns', self::$XMLNS); + $rootEl->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $rootEl->setAttribute('xsi:schemaLocation', self::$XMLNS .' '. self::$SCHEMA_URI); + + $mimeEl = $newDom->createElement('mimetypes'); + $typeEl=$newDom->createElement('type', $defaultMimetype); + $mimeEl->appendChild($typeEl); + $rootEl->appendChild($mimeEl); + + $ingestRulesEl = $newDom->createElement('ingest_rules'); + $rootEl->appendChild($ingestRulesEl); + + $ingestFormEl = $newDom->createElement('ingest_form'); + $ingestFormEl->setAttribute('dsid', $ingestFormDsid); + $ingestFormEl->setAttribute('page', $ingestFormPage); + if ($ingestFormHideChooser == 'true') { + $ingestFormEl->setAttribute('hide_file_chooser', 'true'); + } + + $builderEl= $newDom->createElement('form_builder_method'); + $builderEl->setAttribute('module', $ingestFormModule); + $builderEl->setAttribute('file', $ingestFormFile); + $builderEl->setAttribute('class', $ingestFormClass); + $builderEl->setAttribute('method', $ingestFormMethod); + $builderEl->setAttribute('handler', $ingestFormHandler); + $ingestFormEl->appendChild($builderEl); + + $elementsEl = $newDom->createElement('form_elements'); + $ingestFormEl->appendChild($elementsEl); + $rootEl->appendChild($ingestFormEl); + $newDom->appendChild($rootEl); + + $cm = new ContentModel($newDom, $pid, $modelDsid); + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $fedoraItem = new Fedora_Item($pid); + $fedoraItem->add_datastream_from_string($cm->dumpXml(), $modelDsid, $name, 'text/xml', 'X'); + $ret = $cm; + } + + return $ret; + } + + + /** + * Constructs a ContentModel object from the PID of the model in Fedora. + * If DSID is specified it will use that datastream as the model, otherwise it will + * use the default (usually ISLANDORACM). PID_NAMESPACE and name can also be initialized + * from the collection policy. + * Returns false on failure. + * + * NOTE: $name will be overwritten with the content model name found in the datastream + * when the model is first validated.\ + * + * @param string $pid + * @param string $dsid + * @param string $pid_namespace + * @param string $name + * @return ContentModel $cm + */ + public static function loadFromModel($pid, $dsid = NULL, $pid_namespace = NULL, $name = NULL) { + $ret = FALSE; + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + try { + if (self::validPid($pid)) { + $fedoraItem = new Fedora_Item($pid); + $dsid = ($dsid != NULL && self::validDsid($dsid)) ? $dsid : ContentModel::getDefaultDSID(); + $ds = $fedoraItem->get_datastream_dissemination($dsid); + if (!empty($ds)) { + $ret=new ContentModel($ds, $pid, $dsid, $pid_namespace, $name); + } + } + } + catch (SOAPException $e) { + $ret = FALSE; + } + return $ret; + } + + /** + * Constructor + * NOTE: Use the static constructor methods whenever possible. + * + * @param string $xmlStr + * @param string $pid + * @param string $dsid + * @param string $pid_namespace + * @param string $name + * @return XMLDatastream $cm + */ + public function __construct($xmlStr, $pid = NULL, $dsid = NULL, $pid_namespace = NULL, $name = NULL) { + parent::__construct($xmlStr, $pid, $dsid); + $this->pid_namespace = $pid_namespace; + + $this->name = $name; + } + + /** + * Attempts to convert from the old XML schema to the new by + * traversing the XML DOM and building a new DOM. When done + * $this->xml is replaced by the newly created DOM.. + * + * @return void + */ + protected function convertFromOldSchema() { + $sXml = simplexml_load_string($this->xml->saveXML()); + $newDom = new DOMDocument('1.0', 'utf-8'); + $newDom->formatOutput = TRUE; + $rootEl = $newDom->createElement('content_model'); + $rootEl->setAttribute('name', $sXml['name']); + $rootEl->setAttribute('xmlns', self::$XMLNS); + $rootEl->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $rootEl->setAttribute('xsi:schemaLocation', self::$XMLNS .' ' . self::$SCHEMA_URI); + + $mimeEl = $newDom->createElement('mimetypes'); + foreach ($sXml->mimetypes->type as $mime) { + $typeEl = $newDom->createElement('type', $mime); + $mimeEl->appendChild($typeEl); + } + $rootEl->appendChild($mimeEl); + + $ingestRulesEl = $newDom->createElement('ingest_rules'); + foreach ($sXml->ingest_rules->rule as $rule) { + $ruleEl = $newDom->createElement('rule'); + foreach ($rule->applies_to as $appTo) { + $applToEl = $newDom->createElement('applies_to', trim($appTo)); + $ruleEl->appendChild($applToEl); + } + if (isset($rule->methods->method) && count($rule->methods->method) > 0) { + $methodsEl = $newDom->createElement('ingest_methods'); + foreach ($rule->methods->method as $method) { + $methodEl = $newDom->createElement('ingest_method'); + $methodEl->setAttribute('module', $method->module); + $methodEl->setAttribute('file', $method->file); + $methodEl->setAttribute('class', $method->class_name); + $methodEl->setAttribute('method', $method->method_name); + $methodEl->setAttribute('dsid', $method->datastream_id); + $methodEl->setAttribute('modified_files_ext', $method->modified_files_ext); + + if (isset($method->parameters)) { + $paramsEl = $newDom->createElement('parameters'); + foreach ($method->parameters->parameter as $param) { + $paramEl = $newDom->createElement('parameter', $param); + $paramEl->setAttribute('name', $param['name']); + $paramsEl->appendChild($paramEl); + } + $methodEl->appendChild($paramsEl); + } + + + $methodsEl->appendChild($methodEl); + } + $ruleEl->appendChild($methodsEl); + $ingestRulesEl->appendChild($ruleEl); + } + + } + $rootEl->appendChild($ingestRulesEl); + + if (isset($sXml->display_in_fieldset) && count($sXml->display_in_fieldset->datastream) > 0) { + $datastreamsEl = $newDom->createElement('datastreams'); + + foreach ($sXml->display_in_fieldset->datastream as $ds) { + $dsEl = $newDom->createElement('datastream'); + $dsEl->setAttribute('dsid', $ds['id']); + + if (isset($ds->add_datastream_method)) { + $add_ds_methodEl = $newDom->createElement('add_datastream_method'); + $add_ds_methodEl->setAttribute('module', $ds->add_datastream_method->module); + $add_ds_methodEl->setAttribute('file', $ds->add_datastream_method->file); + $add_ds_methodEl->setAttribute('class', $ds->add_datastream_method->class_name); + $add_ds_methodEl->setAttribute('method', $ds->add_datastream_method->method_name); + $add_ds_methodEl->setAttribute('dsid', $ds->add_datastream_method->datastream_id); + $add_ds_methodEl->setAttribute('modified_files_ext', $ds->add_datastream_method->modified_files_ext); + + if (isset($ds->add_datastream_method->parameters)) { + $paramsEl = $newDom->createElement('parameters'); + foreach ($ds->add_datastream_method->parameters->parameter as $param) { + $paramEl = $newDom->createElement('parameter', $param); + $paramEl->setAttribute('name', $param['name']); + $paramsEl->appendChild($paramEl); + } + $add_ds_methodEl->appendChild($paramsEl); + } + + $dsEl->appendChild($add_ds_methodEl); + } + + foreach ($ds->method as $disp_meth) { + $disp_methEl = $newDom->createElement('display_method'); + $disp_methEl->setAttribute('module', $disp_meth->module); + $disp_methEl->setAttribute('file', $disp_meth->file); + $disp_methEl->setAttribute('class', $disp_meth->class_name); + $disp_methEl->setAttribute('method', $disp_meth->method_name); + $dsEl->appendChild($disp_methEl); + } + $datastreamsEl->appendChild($dsEl); + } + $rootEl->appendChild($datastreamsEl); + } + + $ingest_formEl = $newDom->createElement('ingest_form'); + $ingest_formEl->setAttribute('dsid', $sXml->ingest_form['dsid']); + $ingest_formEl->setAttribute('page', $sXml->ingest_form['page']); + if (isset($sXml->ingest_form['hide_file_chooser'])) { + $ingest_formEl->setAttribute('hide_file_chooser', (strtolower($sXml->ingest_form['hide_file_chooser']) == 'true') ? 'true' : 'false'); + } + + $form_builderEl = $newDom->createElement('form_builder_method'); + $form_builderEl->setAttribute('module', $sXml->ingest_form->form_builder_method->module); + $form_builderEl->setAttribute('file', $sXml->ingest_form->form_builder_method->file); + $form_builderEl->setAttribute('class', $sXml->ingest_form->form_builder_method->class_name); + $form_builderEl->setAttribute('method', $sXml->ingest_form->form_builder_method->method_name); + $form_builderEl->setAttribute('handler', $sXml->ingest_form->form_builder_method->form_handler); + $ingest_formEl->appendChild($form_builderEl); + + $form_elementsEl = $newDom->createElement('form_elements'); + foreach ($sXml->ingest_form->form_elements->element as $element) { + + //I found an XML where the label was HTML.. this code will attempt to + //walk the object setting the label to be the first string it finds. + if (count(get_object_vars($element->label)) > 0) { + $obj=$element->label; + while ($obj != NULL && !is_string($obj)) { + $keys = get_object_vars($obj); + $obj = array_shift($keys); + } + $element->label=($obj == NULL) ? '' : $obj; + } + + $elEl = $newDom->createElement('element'); + $elEl->setAttribute('label', $element->label); + $elEl->setAttribute('name', $element->name); + $elEl->setAttribute('type', $element->type); + if (strtolower($element->required) == 'true') { + $elEl->setAttribute('required', 'true'); + } + if (isset($element->description) && trim($element->description) != '') { + $descEl = $newDom->createElement('description', trim($element->description)); + $elEl->appendChild($descEl); + } + if (isset($element->authoritative_list)) { + $authListEl = $newDom->createElement('authoritative_list'); + foreach ($element->authoritative_list->item as $item) { + $itemEl = $newDom->createElement('item', trim($item->value)); + if (trim($item->value) != trim($item->field)) { + $itemEl->setAttribute('field', trim($item->field)); + } + $authListEl->appendChild($itemEl); + } + $elEl->appendChild($authListEl); + } + $form_elementsEl->appendChild($elEl); + } + $ingest_formEl->appendChild($form_builderEl); + $ingest_formEl->appendChild($form_elementsEl); + $rootEl->appendChild($ingest_formEl); + + if (isset($sXml->edit_metadata) && + trim($sXml->edit_metadata->build_form_method->module) != '' && + trim($sXml->edit_metadata->build_form_method->file) != '' && + trim($sXml->edit_metadata->build_form_method->class_name) != '' && + trim($sXml->edit_metadata->build_form_method->method_name) != '' && + trim($sXml->edit_metadata->submit_form_method->method_name) != '' && + trim($sXml->edit_metadata->build_form_method['dsid']) != '' + ) { + $edit_metadata_methodEl= $newDom->createElement('edit_metadata_method'); + $edit_metadata_methodEl->setAttribute('module', $sXml->edit_metadata->build_form_method->module); + $edit_metadata_methodEl->setAttribute('file', $sXml->edit_metadata->build_form_method->file); + $edit_metadata_methodEl->setAttribute('class', $sXml->edit_metadata->build_form_method->class_name); + $edit_metadata_methodEl->setAttribute('method', $sXml->edit_metadata->build_form_method->method_name); + $edit_metadata_methodEl->setAttribute('handler', $sXml->edit_metadata->submit_form_method->method_name); + $edit_metadata_methodEl->setAttribute('dsid', $sXml->edit_metadata->build_form_method['dsid']); + $rootEl->appendChild($edit_metadata_methodEl); + } + + $newDom->appendChild($rootEl); + + $this->xml = DOMDocument::loadXML($newDom->saveXml()); + + } + + /** + * Gets a list of service deployments that this model has. + * + * NOTE: Not currently being used. + * + * @return String[] $serviceDepPids + */ + public function getServices() { + $query = 'select $object $title from <#ri> + where ($object $title + and $object $deploymentOf + and $object + and $object pid .'> + and $object ) + order by $title'; + + module_load_include('inc', 'fedora_repository', 'CollectionClass'); + + $collectionHelper = new CollectionClass(); + $xml = simplexml_load_string($collectionHelper->getRelatedItems($this->pid, $query)); + + $results = array(); + foreach ($xml->results->result as $result) { + $pid = strval(($result->object['uri'])); + $pid = substr($pid, strpos($pid, "/") + 1, strlen($pid)); + $results[] = $pid; + } + + return $results; + } + + /** + * Gets the name of the ContentModel + * Returns false on failure. + * + * @return String $name + */ + public function getName() { + $ret = FALSE; + if ($this->name != NULL) { + $ret = $this->name; + } + elseif ($this->validate()) { + $rootEl = $this->xml->getElementsByTagName('content_model')->item(0); + $this->name = $rootEl->getAttribute('name'); + $ret = $this->name; + } + return $ret; + } + + + /** + * Gets the element corresponding to the datastream specified + * in the element of the schema. + * Returns FALSE on failure. + * + * @param $dsid + * @return DOMElement $datastream + */ + private function getDSModel($dsid) { + $ret = FALSE; + if (self::validDsid($dsid) && $this->validate()) { + $result=$this->xml->getElementsByTagName('datastreams'); + if ($result->length > 0) { + $result=$result->item(0)->getElementsByTagName('datastream'); + for ($i = 0; $ret == FALSE && $i < $result->length; $i++) { + if ($result->item($i)->getAttribute('dsid') == $dsid) + $ret=$result->item($i); + } + } + } + return $ret; + } + + /** + * Gets an array of form elements to use in the ingest form. The results of this array are passed + * to the specified ingest form builder. The form builder can optionally not use the elements as defined + * in the form builder if more complex forms or behaviour is required. + * Each element has the following keys: 'label', 'type', 'required', 'description', and if defined, 'authoritative_list' and/or 'parameters' + * + * @return string[] $elements + */ + public function getIngestFormElements() { + $ret = FALSE; + if ($this->validate()) { + $elements_array = array(); + $form_elements_wrapper = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements'); + + if ($form_elements_wrapper->length == 0) { + return $ret; + } + $elements = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0)->getElementsByTagName('element'); + for ($i=0;$i<$elements->length;$i++) { + $desc = $elements->item($i)->getElementsByTagName('description'); + $desc = ($desc->length > 0)?$desc->item(0)->nodeValue:''; + + $label = $elements->item($i)->getAttribute('label'); + if ($label == NULL) { + $label=$elements->item($i)->getAttribute('name'); + } + + $element=array('name' => $elements->item($i)->getAttribute('name'), + 'label' => $label, + 'type' => $elements->item($i)->getAttribute('type'), + 'required' => ($elements->item($i)->getAttribute('required') == 'true') ? TRUE : FALSE, + 'description' => $desc + ); + + $auth_list = $elements->item($i)->getElementsByTagName('authoritative_list'); + if ($auth_list->length > 0) { + $list = array(); + $items = $auth_list->item(0)->getElementsByTagName('item'); + for ($j = 0; $j < $items->length; $j++) { + $field = $items->item($j)->attributes->getNamedItem('field'); + $list[ $items->item($j)->nodeValue ] = ($field !== NULL) ? $field->nodeValue : $items->item($j)->nodeValue; + } + $element['authoritative_list']=$list; + } + + + $params = $elements->item($i)->getElementsByTagName('parameters'); + $list = array(); + if ($params->length > 0) { + $items = $params->item(0)->getElementsByTagName('parameter'); + for ($j = 0; $j < $items->length; $j++) { + $value = $items-> item($j)->nodeValue; + $list[$items->item($j)->getAttribute('name')] = (strtolower($value) == 'true' ? TRUE : (strtolower($value) == 'false' ? FALSE : $value)); + } + } + $element['parameters'] = $list; + + $elements_array[] = $element; + } + $ret = $elements_array; + } + + return $ret; + } + + /** + * Decrements an ingest form element in the list of elements. + * Updates the "order". This method is simply an overload to the incIngestFormElement + * which has a direction parameter. + * + * TODO: Might be useful to move multiple places at once, or define + * a method to move to an absolute position. + * + * @param String $name + * @return boolean $success + */ + public function decIngestFormElement($name) { + return $this->incIngestFormElement($name, 'dec'); + } + + /** + * Increments (or decrements) ingest form element in the list of elements. + * Updates the "order". The $reorder parameter accepts 'inc' or 'dec' to + * specify the direction to move (defaults to increment.) + * + * TODO: Might be useful to move multiple places at once, or define + * a method to move to an absolute position. + * + * @param String $name + * @param String $reorder + * @return boolean $success + */ + public function incIngestFormElement($name, $reorder = 'inc') { + $ret = FALSE; + if ($this->validate()) { + $elementsEl = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0); + $elements = $elementsEl->getElementsByTagName('element'); + $found = FALSE; + $refEl = FALSE; + for ($i = 0; $found === FALSE && $i < $elements->length; $i++) { + if ($elements->item($i)->getAttribute('name') == trim($name)) { + if ($reorder == 'inc') { + $found=$elements->item($i); + $refEl = ($i > 0)?$elements->item($i-1):false; + } + else { + $found = ($i + 1 < $elements->length) ? $elements->item($i + 1) : FALSE; + $refEl = $elements->item($i); + } + } + } + + if ($found !== FALSE) { + $elementsEl->removeChild($found); + $elementsEl->insertBefore($found, $refEl); + $ret = TRUE; + } + } + return $ret; + } + + /** + * Removes an ingest form element from the list of ingest form elements. + * @param String $name + * @return boolean $success + */ + public function removeIngestFormElement($name) { + $ret = FALSE; + if ($this->validate()) { + $elementsEl = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0); + $elements = $elementsEl->getElementsByTagName('element'); + $found = FALSE; + for ($i = 0; $found === FALSE && $i < $elements->length; $i++) { + if ($elements->item($i)->getAttribute('name') == trim($name)) { + $found=$elements->item($i); + } + } + + if ($found !== FALSE) { + $elementsEl->removeChild($found); + $ret = TRUE; + } + } + return $ret; + } + + /** + * Sets a parameter of an ingest form element. If the value of the element is FALSE the parameter + * will be removed entirely (if you want to store false as a value, then send the String "false"). + * + * @param String $elementName + * @param String $paramName + * @param String $paramValue + * @return boolean success + */ + public function setIngestFormElementParam($name, $paramName, $paramValue) { + $ret = FALSE; + + if ($this->validate()) { + $elements = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0)->getElementsByTagName('element'); + $element = FALSE; + for ($i = 0; $element === FALSE && $i < $elements->length; $i++) { + if ($elements->item($i)->getAttribute('name') == $name) { + $element = $elements->item($i); + } + } + + if ($element !== FALSE) { + $paramsEl = $element->getElementsByTagName('parameters'); + if ($paramsEl->length == 0) { + if ($paramValue !== FALSE) { + $paramsEl = $this->xml->createElement('parameters'); + $element->appendChild($paramsEl); + } + else { + $ret = TRUE; + } + } + else { + $paramsEl=$paramsEl->item(0); + } + + if (!$ret) { + $params = $paramsEl->getElementsByTagName('parameter'); + $found = FALSE; + for ($i = 0; $found === FALSE && $i < $params->length; $i++) { + if ($params->item($i)->getAttribute('name') == $paramName) { + $found=$params->item($i); + } + } + + if ($paramValue === FALSE) { + if ($found !== FALSE) { + $paramsEl->removeChild($found); + if ($params->length == 0) { + $element->removeChild($paramsEl); + } + } + $ret = TRUE; + } + else { + if ($found !== FALSE) { + $found->nodeValue = $paramValue; + } + else { + $paramEl=$this->xml->createElement('parameter', $paramValue); + $paramEl->setAttribute('name', $paramName); + $paramsEl->appendChild($paramEl); + } + $ret = TRUE; + } + } + } + } + + return $ret; + } + + +/** + * Gets a list of all parameters that belong to the specified ingest form element. + * + * @param String $elementName + * @return boolean success + */ + public function getIngestFormElementParams($name) { + $ret = FALSE; + + if ($this->validate()) { + $elements = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0)->getElementsByTagName('element'); + $element = FALSE; + for ($i=0; $element === FALSE && $i < $elements->length; $i++) { + if ($elements->item($i)->getAttribute('name') == $name) { + $element = $elements->item($i); + } + } + + if ($element !== FALSE) { + $ret = array(); + $paramsEl = $element->getElementsByTagName('parameters'); + + if ($paramsEl->length > 0) { + $params = $paramsEl->item(0)->getElementsByTagName('parameter'); + for ($i = 0; $i < $params->length; $i++) { + $ret[$params->item($i)->getAttribute('name')]=$params->item($i)->nodeValue; + } + } + } + } + + return $ret; + } + + /** + * Edits the ingest form element specified. + * NOTE: The element name can not be changed. To update an elements name + * it must be deleted and added with the new name. + * + * @param String $name + * @param String $label + * @param String $type + * @param boolean $required + * @param String description + * @return boolean success + */ + public function editIngestFormElement($name, $label, $type, $required, $description) { + $ret = FALSE; + if ($this->validate()) { + $elements = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0)->getElementsByTagName('element'); + $found = FALSE; + for ($i = 0; $found === FALSE && $i < $elements->length; $i++) { + if ($elements->item($i)->getAttribute('name') == $name) { + $found = $elements->item($i); + } + } + + $found->setAttribute('name', $name); + $found->setAttribute('type', $type); + $found->setAttribute('required', $required ? 'true' : 'false'); + if (trim($label) != '' && trim($label) != trim($name)) { + $found->setAttribute('label', $label); + } + elseif ($found->getAttribute('label') != '') { + $found->removeAttribute('label'); + } + + $descEl=$found->getElementsByTagName('description'); + if (trim($description) != '') { + if ($descEl->length > 0) { + $descEl=$descEl->item(0); + $descEl->nodeValue = $description; + } + else { + $descEl = $this->xml->createElement('description', $description); + $found->appendChild($descEl); + } + } + elseif ($descEl->length > 0) { + $found->removeChild($descEl->item(0)); + } + + if ($found->getAttribute('type') != 'select' && $found->getAttribute('type') != 'radio') { + $authList = $found->getElementsByTagName('authoritative_list'); + if ($authList->length > 0) { + $found->removeChild($authList->item(0)); + } + } + + $ret = TRUE; + } + return $ret; + } + + + /** + * Add an ingest form element to the model. + * + * @param String $name + * @param String $label + * @param String $type + * @param boolean $required + * @param String $description + * @return boolean $success + */ + public function addIngestFormElement($name, $label, $type, $required, $description = '') { + $ret = FALSE; + if ($this->validate()) { + $elements = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0); + $elementEl = $this->xml->createElement('element'); + $elementEl->setAttribute('name', $name); + $elementEl->setAttribute('type', $type); + $elementEl->setAttribute('required', $requiredi ? 'true' : 'false'); + if (trim($label) != '' && trim($label) != trim($name)) { + $elementEl->setAttribute('label', $label); + } + if (trim($description) != '') { + $descEl=$this->xml->createElement('description', $description); + $elementEl->appendChild($descEl); + } + $elements->appendChild($elementEl); + + $ret = TRUE; + } + return $ret; + } + + /** + * Decrements an authority list item from a form element in the list of elements. + * Updates the "order". This method is simply an overload to the incAuthListItem + * which has a direction parameter. + + * + * @param String $elementName + * @param String $value + * @return boolean $success + */ + public function decAuthListItem($elementName, $value) { + return $this->incAuthListItem($elementName, $value, 'dec'); + } + + /** + * Increments (or decrements) an authority list item from a form element in the list of elements. + * Updates the "order". + * + * @param String $elementName + * @param String $value + * @param String $direction + * @return boolean $success + */ + public function incAuthListItem($elementName, $value, $reorder = 'inc') { + $ret = FALSE; + if ($this->validate()) { + $elements = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0)->getElementsByTagName('element'); + $found = FALSE; + for ($i = 0; $found === FALSE && $i < $elements->length; $i++) { + if ($elements->item($i)->getAttribute('name') == $elementName) { + $found = $elements->item($i); + } + } + + if ($found !== FALSE) { + + $authListEl = $found->getElementsByTagName('authoritative_list'); + if ($authListEl->length > 0) { + $authListEl = $authListEl->item(0); + + $items = $authListEl->getElementsByTagName('item'); + $found = FALSE; + $refEl = FALSE; + for ($i = 0; $found === FALSE && $i < $items->length; $i++) { + if ($items->item($i)->nodeValue == $value) { + if ($reorder == 'inc') { + $refEl = ($i > 0) ? $items->item($i - 1) : FALSE; + $found = $items->item($i); + } + else { + $refEl = $items->item($i); + $found = ($i + 1 < $items->length) ? $items->item($i + 1) : FALSE; + } + } + } + + if ($found !== FALSE && $refEl !== FALSE) { + $authListEl->removeChild($found); + $authListEl->insertBefore($found, $refEl); + $ret = TRUE; + } + } + } + } + return $ret; + } + + /** + * Removes an authority list item from a form element. + @param String $elementName + @param String $value + @return boolean $success + */ + public function removeAuthListItem($elementName, $value) { + $ret = FALSE; + if ($this->validate()) { + $elements = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0)->getElementsByTagName('element'); + $found = FALSE; + for ($i = 0; $found === FALSE && $i < $elements->length; $i++) { + if ($elements->item($i)->getAttribute('name') == $elementName) { + $found = $elements->item($i); + } + } + + if ($found !== FALSE) { + $authListEl = $found->getElementsByTagName('authoritative_list'); + if ($authListEl->length > 0) { + $authListEl = $authListEl->item(0); + $items = $authListEl->getElementsByTagName('item'); + $found = FALSE; + for ($i = 0; $found === FALSE && $i < $items->length; $i++) { + if ($items->item($i)->nodeValue == $value) { + $found=$items->item($i); + } + } + + if ($found !== FALSE) { + if ($items->length == 1) { + $found->removeChild($authListEl); + } + else { + $authListEl->removeChild($found); + } + + $ret = TRUE; + } + } + } + } + return $ret; + } + + /** + * Adds an authority list item to a form element. + @param String $elementName + @param String $value + @param String $label (optional) + @return boolean $success + */ + public function addAuthListItem($elementName, $value, $label = '') { + $ret = FALSE; + if ($this->validate()) { + $elements = $this->xml->getElementsbyTagName('ingest_form')->item(0)->getElementsByTagName('form_elements')->item(0)->getElementsByTagName('element'); + $found = FALSE; + for ($i = 0; $found === FALSE && $i < $elements->length; $i++) { + if ($elements->item($i)->getAttribute('name') == $elementName) { + $found = $elements->item($i); + } + } + + if ($found !== FALSE) { + $authListEl = $found->getElementsByTagName('authoritative_list'); + if ($authListEl->length == 0) { + $authListEl = $this->xml->createElement('authoritative_list'); + $found->appendChild($authListEl); + } + else { + $authListEl = $authListEl->item(0); + } + + $items = $authListEl->getElementsByTagName('item'); + $found = FALSE; + for ($i = 0; $found == FALSE && $i < $items->length; $i++) { + if ($items->item($i)->nodeValue == $value) { + $found = TRUE; + } + } + + if (!$found) { + $itemEl = $this->xml->createElement('item', trim($value)); + if (trim($label) != '' && trim($label) != trim($value)) { + $itemEl->setAttribute('field', trim($label)); + } + $authListEl->appendChild($itemEl); + $ret = TRUE; + } + } + + } + return $ret; + } + + /** + * Builds an ingest form using the method specified in element of + * Returns FALSE on failure. + * + * @param &$form + * @param &$form_state + * @return string identifier + */ + public function buildIngestForm(&$form, &$form_state) { + $ret = FALSE; + if ($this->validate()) { + $docRoot = $_SERVER['DOCUMENT_ROOT']; + $file = (isset($form_state['values']['ingest-file-location']) ? $form_state['values']['ingest-file-location'] : ''); + + $fullpath = $file; + + $form['step'] = array( + '#type' => 'hidden', + '#value' => (isset($form_state['values']['step']) ? $form_state['values']['step'] : 0) + 1, + ); + $form['ingest-file-location'] = array( + '#type' => 'hidden', + '#value' => $file, + ); + $form['content_model_name'] = array( + '#type' => 'hidden', + '#value' => 'ISLANDORACM', + ); + $form['models'] = array( //content models available + '#type' => 'hidden', + '#value' => $form_state['values']['models'], + ); + $form['fullpath'] = array( + '#type' => 'hidden', + '#value' => $fullpath, + ); + + $form['#attributes']['enctype'] = 'multipart/form-data'; + $form['indicator']['ingest-file-location'] = array( + '#type' => 'file', + '#title' => t('Upload Document'), + '#size' => 48, + '#description' => t('Full text'), + ); + + $ingest_form = $this->xml->getElementsByTagName('ingest_form')->item(0); + + if (!empty($ingest_form)) { + if (strtolower($ingest_form->getAttribute('hide_file_chooser')) == 'true') { + $form['indicator']['ingest-file-location']['#type'] = 'hidden'; + } + } + $dsid = $ingest_form->getAttribute('dsid'); + + $method=$ingest_form->getElementsByTagName('form_builder_method')->item(0); + $module = $method->getAttribute('module'); + $path=drupal_get_path('module', !empty($module) ? $module : 'fedora_repository') . '/' . $method->getAttribute('file'); + if (!file_exists($path)) { + self::$errors[]='Build Ingest Form: file \''. $path .'\' does not exist.'; + } + else { + @require_once($path); + $className=$method->getAttribute('class'); + $methodName=($method->getAttribute('method')); + if (!class_exists($className)) { + self::$errors[] = 'Build Ingest Form: class \''. $className .' does not exist.'; + } + else { + $class = new $className; + $elements_array=$this->getIngestFormElements(); + if (method_exists($class, $methodName)) { + $ret = $class->$methodName ($form, $elements_array, $form_state); + } + else { + self::$errors[] = 'Build Ingest Form: method \''. $className .'->'. $methodName .'\' does not exist.'; + } + } + } + } + return $ret; + } + + /** + * Builds an edit metadata form using the method specified in the element += * The DSID specified must match the DSID attribute of . Returns FALSE on failure. + * + * @param string $dsid + * @return $form + */ + public function buildEditMetadataForm($pid, $dsid) { + $ret = FALSE; + if (self::validDsid($dsid) && $this->validate()) { + $method = $this->xml->getElementsByTagName('edit_metadata_method'); + if ($method->length > 0 && $method->item(0)->getAttribute('dsid') == $dsid) { + $method = $method->item(0); + $module = $method->getAttribute('module'); + $path = drupal_get_path('module', !empty($module) ? $module : 'fedora_repository') . '/' . $method->getAttribute('file') ; + if (!file_exists($path)) { + self::$errors[] = 'Build Edit Metadata Form: file \''. $path .'\' does not exist.'; + } + else { + @require_once($path ); + $className=$method->getAttribute('class'); + $methodName=($method->getAttribute('method')); + if (!class_exists($className)) { + self::$errors[] = 'Build Edit Metadata Form: class \''. $className .'\' does not exist.'; + } + else { + $class = new $className($pid); + if (!method_exists($class, $methodName)) { + self::$errors[] = 'Build Edit Metadata Form: method \''. $className .'->'. $methodName .'\' does not exist.'; + } + else { + $ret = $class->$methodName(); + } + } + } + } + } + return $ret; + } + + /** + * Handles the edit metadata form using the handler specified in the element + * Returns FALSE on failure. + * + * @param &$form_id + * @param &$form_values + * @param &$soap_client + * @return $result + */ + public function handleEditMetadataForm(&$form_id, &$form_state, &$soap_client) { + global $base_url; + $ret = FALSE; + if ($this->validate()) { + $method = $this->xml->getElementsByTagName('edit_metadata_method'); + if ($method->length > 0) { + $method=$method->item(0); + $module = $method->getAttribute('module'); + $path = drupal_get_path('module', !empty($module) ? $module : 'fedora_repository') . '/' . $method->getAttribute('file'); + if (!file_exists($path)) { + self::$errors[] = 'Handle Edit Metadata Form: file \''. $path .'\' does not exist.'; + } + else { + @require_once($path); + $className = $method->getAttribute('class'); + $methodName = ($method->getAttribute('handler')); + if (!class_exists($className)) { + self::$errors[] = 'Handle Edit Metadata Form: class \''. $className .'\' does not exist.'; + } + else { + $class = new $className($form_state['values']['pid']); + if (!method_exists($class, $methodName)) { + self::$errors[] = 'Handle Edit Metadata Form: metho \''. $className .'->'. $methodName .'\' does not exist.'; + } + else { + $ret = $class->$methodName($form_id, $form_state['values'], $soap_client); + } + } + } + } + else { + // Assume DC form if none is specified. + module_load_include('inc', 'fedora_repository', 'formClass'); + $metaDataForm = new formClass(); + $ret = $metaDataForm->updateMetaData($form_state['values']['form_id'], $form_state['values'], $soap_client); + $form_state['redirect'] = $base_url . '/fedora/repository/' . $form_state['values']['pid']; + + } + } + return $ret; + } + + + /** + * Gets an associative array describing the edit metadata method. + * Array has the following keys: 'file', 'class', 'method', 'handler', 'dsid' + * @return String[] $method + */ + public function getEditMetadataMethod() { + $ret = FALSE; + if ($this->validate()) { + $method=$this->xml->getElementsByTagName('content_model')->item(0)->getElementsByTagName('edit_metadata_method'); + if ($method->length > 0) { + $method = $method->item(0); + $ret = array('module' => $method->getAttribute('module') == '' ? 'fedora_repository' : $method->getAttribute('module'), + 'file' => $method->getAttribute('file'), + 'class' => $method->getAttribute('class'), + 'method' => $method->getAttribute('method'), + 'handler' => $method->getAttribute('handler'), + 'dsid' => $method->getAttribute('dsid') + ); + } + } + return $ret; + } + + /** + * Removes the edit data method from the Content Model. + * @return boolean $success + */ + public function removeEditMetadataMethod() { + $ret = FALSE; + if ($this->validate()) { + $rootEl=$this->xml->getElementsByTagName('content_model')->item(0); + $method = $rootEl->getElementsByTagName('edit_metadata_method'); + if ($method->length > 0) { + $rootEl->removeChild($method->item(0)); + $ret = TRUE; + } + } + return $ret; + } + + /** + * Update the Edit Metadata Method defined in the Content Model + * @param String $module + * @param String $file + * @param String $class + * @param String $method + * @param String $handler + * @param String $dsid + * @return boolean $success + */ + public function updateEditMetadataMethod($module, $file, $class, $method, $handler, $dsid) { + $ret = FALSE; + if (self::validDsid($dsid) && $this->validate()) { + $methodEl = $this->xml->getElementsByTagName('content_model')->item(0)->getElementsByTagName('edit_metadata_method'); + if ($methodEl->length > 0) { + $methodEl=$methodEl->item(0); + } + else { + $methodEl = $this->xml->createElement('edit_metadata_method'); + $this->xml->getElementsByTagName('content_model')->item(0)->appendChild($methodEl); + } + $methodEl->setAttribute('module', $module); + $methodEl->setAttribute('file', $file); + $methodEl->setAttribute('class', $class); + $methodEl->setAttribute('method', $method); + $methodEl->setAttribute('handler', $handler); + $methodEl->setAttribute('dsid', $dsid); + $ret = TRUE; + } + return $ret; + } + + /** + * Executes the add datastream method for the specified datastream on the specified file. + * Returns FALSE on failure. + * + * @param string $dsid + * @param string $filen + * @return $result + */ + public function execAddDatastreamMethods($dsid, $file) { + $ret = FALSE; + if (self::validDsid($dsid) && $this->validate() && ($ds = $this->getDSModel($dsid)) !== FALSE) { + $addMethod = $ds->getElementsByTagName('add_datastream_method'); + if ($addMethod->length > 0) { + $addMethod=$addMethod->item(0); + $paramArray = array(); + $params= $addMethod->getElementsByTagName('parameters'); + if ($params->length > 0) { + $params=$params->item(0)->getElementsByTagName('parameter'); + for ($i = 0; $i < $params->length; $i++) { + $paramsArray[$params->item($i)->getAttribute('name')] = $params->item($i)->nodeValue; + } + } + $module = $addMethod->getAttribute('module'); + $path = drupal_get_path('module', !empty($module) ? $module : 'fedora_repository') . '/' . $addMethod->getAttribute('file') ; + if (!file_exists($path)) { + self::$errors[] = 'Execute Add Datastream Methods: file \''. $path .'\' does not exist.'; + } + else { + @require_once($path); + $className = $addMethod->getAttribute('class'); + $methodName = $addMethod->getAttribute('method'); + if (!class_exists($className)) { + self::$errors[] = 'Execute Add Datastream Methods: class \''. $className .'\' does not exist.'; + } + else { + $class = new $className; + if (!method_exists($class, $methodName)) { + self::$errors[] = 'Execute Add Datastream Methods: method \''. $className .'->'. $methodName .'\' does not exist.'; + } + else { + $ret = $class->$methodName($paramsArray, $addMethod->getAttribute('dsid'), $file, $addMethod->getAttribute('modified_files_ext')); + } + } + } + } + } + return $ret; + } + + /** + * Executes the ingest rules that apply to the specified file/mimetype. + * Returns FALSE on failure. + * + * If $preview is TRUE, then only execute rules with + * a parameter 'preview'. Used to generate previews for the file chooser. + * + * @param string $file + * @param string $mimetype + * @param boolean $preview + * @return $result + */ + public function execIngestRules($file, $mimetype, $preview = FALSE) { + $ret = FALSE; + if ($this->validate()) { + $ret = TRUE; + $rules = $this->xml->getElementsByTagName('ingest_rules')->item(0)->getElementsByTagName('rule'); + for ($i = 0; $i < $rules->length; $i++) { + $rule=$rules->item($i); + $types = $rule->getElementsbyTagName('applies_to'); + $valid_types = array(); + for ($j = 0; $j < $types->length; $j++) { + $valid_types[]=trim($types->item($j)->nodeValue); + } + + if (in_array($mimetype, $valid_types)) { + $methods = $rule->getElementsByTagName('ingest_methods'); + if ($methods->length > 0) { + $methods = $methods->item(0)->getElementsbyTagName('ingest_method'); + for ($j = 0; $j < $methods->length; $j++) { + $method=$methods->item($j); + $param_array=array(); + $params=$method->getElementsByTagName('parameters'); + $param_array['model_pid'] = $this->pid; + if ($params->length > 0) { + $params = $params->item(0)->getElementsByTagName('parameter'); + for ($k = 0; $k < $params->length; $k++) + $param_array[$params->item($k)->getAttribute('name')]=$params->item($k)->nodeValue; + } + + + if (!$preview || isset($param_array['preview'])) { + $module = $method->getAttribute('module'); + $path = drupal_get_path('module', !empty($module) ? $module : 'fedora_repository') . '/' . $method->getAttribute('file') ; + + if (!file_exists($path) || substr_compare($path, 'fedora_repository/', -strlen('fedora_repository/'), strlen('fedora_repository/')) === 0) { + self::$errors[] = 'Execute Ingest Rules: file \''. $path .'\' does not exist.'; + $ret = FALSE; + } + else { + require_once($path); + $className=$method->getAttribute('class'); + $methodName=($method->getAttribute('method')); + if (!class_exists($className)) { + self::$errors[] = 'Execute Ingest Rules: class \''. $className .'\' does not exist.'; + $ret = FALSE; + } + else $class = new $className; + if (!method_exists($class, $methodName)) { + self::$errors[] = 'Execute Ingest Rules: method \''. $className .'->' . $methodName .'\' does not exist.'; + $ret = FALSE; + } + else { + $status = $class->$methodName($param_array, $method->getAttribute('dsid'), $file, $method->getAttribute('modified_files_ext')); + if ($status !== TRUE) { + $ret = FALSE; + } + } + } + } + } + } + } + } + + } + return $ret; + } + + /** + * Executes the form handler from the element of . + * + * @param &$formData + * @return boolean $success + */ + public function execFormHandler(&$data) { + $ret = FALSE; + if ($this->validate()) { + $method =$this->xml->getElementsByTagName('ingest_form')->item(0)->getElementsByTagName('form_builder_method')->item(0); + $module = $method->getAttribute('module'); + $path=drupal_get_path('module', !empty($module) ? $module : 'fedora_repository') . '/' . $method->getAttribute('file') ; + if (!file_exists($path)) { + self::$errors[] = 'Execute Form Handler: file \''. $path .'\' does not exist.'; + } + else { + require_once($path); + $className=$method->getAttribute('class'); + $methodName=($method->getAttribute('handler')); + if (!class_exists($className)) { + self::$errors[] = 'Execute Form Handler: class \''. $className .'\' does not exist.'; + } + else { + $class = new $className; + if (!method_exists($class, $methodName)) { + self::$errors[] = 'Execute Form Handler: method \''. $className .'->'. $methodName .'\' does not exist.'; + } + else { + $class->$methodName($data); + $ret = TRUE; + } + } + } + } + + return $ret; + } + + /** + * Gets a list of valid mimetypes that can apply to this model. + * Returns FALSE on failure. + * + * @return string[] $mimetypes + */ + public function getMimetypes() { + //only proceed if the xml is valid. + if ($this->validate()) { + if ($this->mimes === NULL) { + $result=$this->xml->getElementsByTagName('mimetypes'); + $result=$result->item(0)->getElementsByTagName('type'); + $mimes = array(); + for ($i = 0; $i < $result->length; $i++) { + $mimes[] = trim($result->item($i)->nodeValue); + } + $this->mimes=$mimes; + } + return $this->mimes; + } + } + + /** + * Calls all defined display methods for the ContentModel. + * The PID specified is passed to the constructor of the display + * class(es) specified in the Content Model. + * + * @param string $pid + * @return string $output + */ + public function displayExtraFieldset($pid) { + $output = ''; + if ($this->validate()) { + $datastreams = $this->xml->getElementsByTagName('datastreams'); + if ($datastreams->length > 0) { + $datastreams = $datastreams->item(0)->getElementsByTagName('datastream'); + for ($i=0; $i < $datastreams->length; $i++) { + $ds = $datastreams->item($i); + if ($ds->attributes->getNamedItem('display_in_fieldset') == NULL || strtolower($ds->getAttribute('display_in_fieldset')) != 'false' ) { + $dispMethods = $ds->getElementsByTagName('display_method'); + for ($j = 0; $j < $dispMethods->length; $j++) { + $method = $dispMethods->item($j); + $module = $method->getAttribute('module'); + $path=drupal_get_path('module', !empty($module) ? $module : 'fedora_repository') . '/' . $method->getAttribute('file') ; + if (!file_exists($path)) { + self::$errors[] = 'Execute Form Handler: file \''. $path .'\' does not exist.'; + } + else { + require_once($path); + $className = $method->getAttribute('class'); + $methodName = ($method->getAttribute('method')); + if (!class_exists($className)) { + self::$errors[] = 'Execute Form Handler: class \''. $className .'\' does not exist.'; + } + else { + $class = new $className($pid); + if (!method_exists($class, $methodName)) { + self::$errors[] = 'Execute Form Handler: method \''. $className .'->'. $methodName .'\' does not exist.'; + } + else { + $output .= $class->$methodName(); + } + } + } + } + } + } + } + } + + return $output; + } + + /** + * Gets a list of datastreams from the ContentModel + * (not including the QDC ds if it is listed). + * Returns FALSE on failure. + * + * @return string[] $datastreams + */ + public function listDatastreams() { + $ds_array=array(); + if ($this->validate()) { + $datastreams = $this->xml->getElementsByTagName('datastreams'); + if ($datastreams->length > 0) { + $datastreams=$datastreams->item(0)->getElementsByTagName('datastream'); + for ($i=0;$i<$datastreams->length;$i++) { + $dsName=$datastreams->item($i)->getAttribute('dsid'); + // if ($dsName != 'QDC') + // { + $ds_array[]=$dsName; + // } + } + } + } + + return $ds_array; + } + + /** + * Adds an allowed mimetype to the model. + * + * @param String $type + * @return boolean $success + */ + public function addMimetype($type) { + $ret=FALSE; + if ($this->validate()) { + $mimetypesEl = $this->xml->getElementsByTagName('mimetypes')->item(0); + $types= $mimetypesEl->getElementsByTagName('type'); + + $found = FALSE; + for ($i=0;!$found && $i<$types->length;$i++) { + if ($types->item($i)->nodeValue == $type) + $found = TRUE; + } + + if (!$found) { + $newTypeEl = $this->xml->createElement('type', $type); + $mimetypesEl->appendChild($newTypeEl); + $ret=TRUE; + } + + } + return $ret; + } + + /** + * Removes an allowed mimetype from the model. + * + * @param String $type + * @return boolean $success + */ + public function removeMimetype($type) { + $ret=FALSE; + if ($this->validate()) { + $mimetypesEl = $this->xml->getElementsByTagName('mimetypes')->item(0); + $types= $mimetypesEl->getElementsByTagName('type'); + $found=FALSE; + for ($i=0;!$found && $i<$types->length;$i++) { + if ($types->item($i)->nodeValue == $type) + $found=$types->item($i); + } + + if ($found !== FALSE && $types->length > 1) { + $mimetypesEl->removeChild($found); + $ret = TRUE; + } + + } + return $ret; + } + + public function getDisplayMethods($ds) { + $ret=FALSE; + if (($ds = $this->getDSModel($ds))!==FALSE) { + $ret=array(); + $dispMethods= $ds->getElementsByTagName('display_method'); + for ($i=0;$i<$dispMethods->length;$i++) { + $ret[] = array( 'module' => $dispMethods->item($i)->getAttribute('module')==''?'fedora_repository':$dispMethods->item($i)->getAttribute('module'), + 'file' => $dispMethods->item($i)->getAttribute('file'), + 'class' => $dispMethods->item($i)->getAttribute('class'), + 'method' => $dispMethods->item($i)->getAttribute('method'), + 'default' => ($dispMethods->item($i)->attributes->getNamedItem('default') !== NULL ? strtolower($dispMethods->item($i)->getAttribute('default')) == 'true' : FALSE)); + } + } + return $ret; + } + + public function addDs($dsid, $display_in_fieldset = FALSE) { + $ret=FALSE; + + if (self::validDsid($dsid) && ($ds = $this->getDSModel($dsid)) === FALSE) { + $datastreamsEl = $this->xml->getElementsByTagName('datastreams'); + if ($datastreamsEl->length > 0) { + $datastreamsEl=$datastreamsEl->item(0); + } + else { + $datastreamsEl = $this->xml->createElement('datastreams'); + $this->xml->getElementsByTagName('content_model')->item(0)->appendChild($datastreamsEl); + } + + $dsEl = $this->xml->createElement('datastream'); + $dsEl->setAttribute('dsid', $dsid); + if ($display_in_fieldset == TRUE) { + $dsEl->setAttribute('display_in_fieldset', 'true'); + } + $datastreamsEl->appendChild($dsEl); + $ret = TRUE; + } + return $ret; + } + + public function removeDs($dsid) { + $ret = FALSE; + + if (self::validDsid($dsid) && ($ds = $this->getDSModel($dsid)) !== FALSE) { + $datastreamsEl = $this->xml->getElementsByTagName('datastreams')->item(0); + $datastreamsEl->removeChild($ds); + $ret = TRUE; + } + return $ret; + } + + public function displayInFieldset($dsid) { + $ret = FALSE; + if (self::validDsid($dsid) && ($ds = $this->getDSModel($dsid)) !== FALSE) { + $ret = strtolower($ds->getAttribute('display_in_fieldset')) == 'true'; + } + return $ret; + } + + public function setDisplayInFieldset($dsid, $value = TRUE) { + $ret = FALSE; + if (self::validDsid($dsid) && ($ds = $this->getDSModel($dsid)) !== FALSE) { + if ($value == FALSE && $ds->attributes->getNamedItem('display_in_fieldset') !== NULL) { + $ds->removeAttribute('display_in_fieldset'); + $ret = TRUE; + } + elseif ($value == TRUE) { + $ds->setAttribute('display_in_fieldset', 'true'); + $ret = TRUE; + } + } + return $ret; + } + + public function setDefaultDispMeth($dsid, $module, $file, $class, $method) { + $ret = FALSE; + + if (self::validDsid($dsid) && ($ds = $this->getDSModel($dsid)) !== FALSE) { + $found = FALSE; + $dispMethods = $ds->getElementsByTagName('display_method'); + for ($i = 0; !$found && $i < $dispMethods->length; $i++) { + if ($module == ($dispMethods->item($i)->getAttribute('module') == '' ? 'fedora_repository' : $dispMethods->item($i)->getAttribute('module')) && + $file == $dispMethods->item($i)->getAttribute('file') && + $class == $dispMethods->item($i)->getAttribute('class') && + $method == $dispMethods->item($i)->getAttribute('method')) { + $found=$dispMethods->item($i); + } + } + + if ($found !== FALSE) { + + for ($i = 0; $i < $dispMethods->length; $i++) { + if ($dispMethods->item($i)->attributes->getNamedItem('default') !== NULL) { + $dispMethods->item($i)->removeAttribute('default'); + } + } + + $found->setAttribute('default', 'true'); + $ret = TRUE; + } + + } + return $ret; + } + + public function removeDispMeth($dsid, $module, $file, $class, $method) { + $ret = FALSE; + if (self::validDsid($dsid) && ($ds = $this->getDSModel($dsid)) !== FALSE) { + $found = FALSE; + $dispMethods= $ds->getElementsByTagName('display_method'); + for ($i=0;!$found && $i<$dispMethods->length;$i++) { + if ($module == ($dispMethods->item($i)->getAttribute('module') == '' ? 'fedora_repository' : $dispMethods->item($i)->getAttribute('module') == '') && + $file == $dispMethods->item($i)->getAttribute('file') && + $class == $dispMethods->item($i)->getAttribute('class') && + $method == $dispMethods->item($i)->getAttribute('method')) { + $found=$dispMethods->item($i); + } + } + + if ($found !== FALSE) { + $ds->removeChild($found); + $ret = TRUE; + } + + } + return $ret; + } + + public function addDispMeth($dsid, $module, $file, $class, $method, $default = FALSE) { + $ret=FALSE; + if (self::validDsid($dsid) && ($ds = $this->getDSModel($dsid))!==FALSE) { + $dispMethEl = $this->xml->createElement('display_method'); + $dispMethEl->setAttribute('module', $module); + $dispMethEl->setAttribute('file', $file); + $dispMethEl->setAttribute('class', $class); + $dispMethEl->setAttribute('method', $method); + if ($default==TRUE) { + $dispMethEl->setAttribute('default', TRUE); + } + $ds->appendChild($dispMethEl); + $ret = TRUE; + } + return $ret; + } + + public function getAddDsMethod($ds) { + $ret=FALSE; + if (($ds = $this->getDSModel($ds))!==FALSE) { + $addDsMethod= $ds->getElementsByTagName('add_datastream_method'); + if ($addDsMethod !== FALSE && $addDsMethod->length > 0) { + $ret = array('module' => $addDsMethod->item(0)->getAttribute('module') == '' ? 'fedora_repository' : $addDsMethod->item(0)->getAttribute('module'), + 'file' => $addDsMethod->item(0)->getAttribute('file'), + 'class' => $addDsMethod->item(0)->getAttribute('class'), + 'method' => $addDsMethod->item(0)->getAttribute('method'), + 'modified_files_ext' => $addDsMethod->item(0)->getAttribute('modified_files_ext'), + 'dsid' => $addDsMethod->item(0)->getAttribute('dsid') + ); + } + } + return $ret; + } + + public function getIngestRule($rule_id) { + $ret = FALSE; + if ($this->validate()) { + $rules = $this->xml->getElementsByTagName('ingest_rules')->item(0)->getElementsByTagName('rule'); + if ($rule_id < $rules->length) + $ret = $rules->item($rule_id); + } + return $ret; + } + + public function removeAppliesTo($rule_id, $type) { + $ret = FALSE; + if (($rule = $this->getIngestRule($rule_id)) !== FALSE) { + $applies = $rule->getElementsByTagName('applies_to'); + $found = FALSE; + for ($i=0; $found === FALSE && $i < $applies->length; $i++) { + if ($type == $applies->item($i)->nodeValue) { + $found = $applies->item($i); + } + } + + if ($found) { + $rule->removeChild($found); + $ret = TRUE; + } + } + return $ret; + } + + public function addAppliesTo($rule_id, $type) { + $ret=FALSE; + if (($rule = $this->getIngestRule($rule_id))!==FALSE) { + $applies = $rule->getElementsByTagName('applies_to'); + $found = FALSE; + for ($i=0;!$found && $i<$applies->length;$i++) { + $found = ($type == $applies->item($i)->nodeValue); + } + + if (!$found) { + $newAppliesTo = $this->xml->createElement('applies_to', $type); + $rule->insertBefore($newAppliesTo, $rule->getElementsByTagName('ingest_methods')->item(0)); + $ret = TRUE; + } + } + return $ret; + } + + public function addIngestMethod($rule_id, $module, $file, $class, $method, $dsid, $modified_files_ext) { + $ret=FALSE; + if (self::validDsid($dsid) && ($rule=$this->getIngestRule($rule_id))!==FALSE) { + $methodsEl = $rule->getElementsByTagName('ingest_methods')->item(0); + $meth = $this->xml->createElement('ingest_method'); + $meth->setAttribute('module', $module); + $meth->setAttribute('file', $file); + $meth->setAttribute('class', $class); + $meth->setAttribute('method', $method); + $meth->setAttribute('dsid', $dsid); + $meth->setAttribute('modified_files_ext', $modified_files_ext); + + $methodsEl->appendChild($meth); + $ret = TRUE; + } + return $ret; + } + + public function removeIngestMethod($rule_id, $module, $file, $class, $method) { + $ret=FALSE; + if (($rule=$this->getIngestRule($rule_id))!==FALSE) { + $found=FALSE; + $methodsEl = $rule->getElementsByTagName('ingest_methods')->item(0); + $methods = $methodsEl->getElementsByTagName('ingest_method'); + for ($i=0;!$found && $i<$methods->length;$i++) { + if ($methods->item($i)->getAttribute('module') == $module && $methods->item($i)->getAttribute('file') == $file && $methods->item($i)->getAttribute('class') == $class && $methods->item($i)->getAttribute('method') == $method) { + $found = $methods->item($i); + } + } + + if ($found !== FALSE && $methods->length > 1) { + $methodsEl->removeChild($found); + $ret = TRUE; + } + } + return $ret; + } + + public function addIngestMethodParam($rule_id, $module, $file, $class, $method, $name, $value) { + $ret = FALSE; + if (($rule=$this->getIngestRule($rule_id)) !== FALSE) { + $methods = $rule->getElementsByTagName('ingest_methods')->item(0)->getElementsByTagName('ingest_method'); + $found = FALSE; + for ($i = 0; $found === FALSE && $i < $methods->length; $i++) { + if (($methods->item($i)->getAttribute('module') == '' ? 'fedora_repository' : $methods->item($i)->getAttribute('module')) == $module && + $methods->item($i)->getAttribute('file') == $file && + $methods->item($i)->getAttribute('class') == $class && + $methods->item($i)->getAttribute('method') == $method) { + $found=$methods->item($i); + } + } + + if ($found !== FALSE) { + $paramsEl = $found->getElementsByTagName('parameters'); + if ($paramsEl->length == 0) { + $paramsEl=$found->appendChild($this->xml->createElement('parameters')); + } + else { + $paramsEl=$paramsEl->item(0); + } + + $params = $paramsEl->getElementsByTagName('parameter'); + $found = FALSE; + for ($i=0; $found === FALSE && $i < $params->length; $i++) { + if ($params->item($i)->getAttribute('name') == $name) { + $found = $params->item($i); + } + } + + if ($found === FALSE) { + $param = $this->xml->createElement('parameter', $value); + $param->setAttribute('name', $name); + $paramsEl->appendChild($param); + $ret = TRUE; + } + } + } + return $ret; + } + + public function removeIngestMethodParam($rule_id, $module, $file, $class, $method, $name) { + $ret = FALSE; + if (($rule=$this->getIngestRule($rule_id)) !== FALSE) { + $found = FALSE; + $methodsEl = $rule->getElementsByTagName('ingest_methods')->item(0); + $methods = $methodsEl->getElementsByTagName('ingest_method'); + for ($i=0; !$found && $i < $methods->length; $i++) { + if ($methods->item($i)->getAttribute('module') == $module && $methods->item($i)->getAttribute('file') == $file && $methods->item($i)->getAttribute('class') == $class && $methods->item($i)->getAttribute('method') == $method) { + $found = $methods->item($i); + } + } + + if ($found !== FALSE) { + $methodEl = $found; + $paramsEl = $found->getElementsByTagName('parameters'); + if ($paramsEl->length > 0) { + $paramsEl=$paramsEl->item(0); + $params = $paramsEl->getElementsByTagName('parameter'); + $found = FALSE; + for ($i=0; $found === FALSE && $i < $params->length; $i++) { + if ($params->item($i)->getAttribute('name') == $name) { + $found=$params->item($i); + } + } + + if ($found !== FALSE) { + $paramsEl->removeChild($found); + if ($params->length == 0) { + $methodEl->removeChild($paramsEl); + } + + $ret = TRUE; + } + } + + } + } + return $ret; + } + + public function removeIngestRule($rule_id) { + $ret = FALSE; + if (($rule = $this->getIngestRule($rule_id))!==FALSE) { + $ret = $this->xml->getElementsByTagName('ingest_rules')->item(0)->removeChild($rule); + } + return $ret; + } + + public function addIngestRule($applies_to, $module, $file, $class, $method, $dsid, $modified_files_ext) { + $ret = FALSE; + if (self::validDsid($dsid) && $this->validate()) { + $ingestRulesEl = $this->xml->getElementsByTagName('ingest_rules')->item(0); + $rule = $this->xml->createElement('rule'); + $ingestMethodsEl = $this->xml->createElement('ingest_methods'); + $rule->appendChild($ingestMethodsEl); + $ingestRulesEl->appendChild($rule); + $newRuleId = $ingestRulesEl->getElementsByTagName('rule')->length - 1; + $ret = ($this->addAppliesTo($newRuleId, $applies_to) && $this->addIngestMethod($newRuleId, $module, $file, $class, $method, $dsid, $modified_files_ext)); + } + return $ret; + } + + public function getIngestRules() { + $ret = FALSE; + if ($this->validate()) { + $ret = array(); + $rules = $this->xml->getElementsByTagName('ingest_rules')->item(0)->getElementsByTagName('rule'); + for ($i=0; $i < $rules->length; $i++) { + $rule = array('applies_to' => array(), + 'ingest_methods' => array()); + $applies_to = $rules->item($i)->getElementsByTagName('applies_to'); + for ($j=0; $j < $applies_to->length; $j++) { + $rule['applies_to'][] = trim($applies_to->item($j)->nodeValue); + } + + $methods = $rules->item($i)->getElementsByTagName('ingest_methods')->item(0)->getElementsByTagName('ingest_method'); + for ($j=0; $j < $methods->length; $j++) { + $method = array('module' => $methods->item($j)->getAttribute('module') == '' ? 'fedora_repository' : $methods->item($j)->getAttribute('module'), + 'file' => $methods->item($j)->getAttribute('file'), + 'class' => $methods->item($j)->getAttribute('class'), + 'method' => $methods->item($j)->getAttribute('method'), + 'dsid' => $methods->item($j)->getAttribute('dsid'), + 'modified_files_ext' => $methods->item($j)->getAttribute('modified_files_ext'), + 'parameters' => array()); + + $params = $methods->item($j)->getElementsByTagName('parameters'); + if ($params->length > 0) { + $params=$params->item(0)->getElementsByTagName('parameter'); + for ($k=0; $k < $params->length; $k++) { + $method['parameters'][$params->item($k)->getAttribute('name')] = $params->item($k)->nodeValue; + } + } + + $rule['ingest_methods'][] = $method; + + } + + $ret[] = $rule; + } + } + return $ret; + } + + public function getIngestFormAttributes() { + $ret = FALSE; + if ($this->validate()) { + $ingest_formEl = $this->xml->getElementsByTagName('ingest_form')->item(0); + $ret=array('dsid' => $ingest_formEl->getAttribute('dsid'), + 'page' => $ingest_formEl->getAttribute('page'), + 'hide_file_chooser' => strtolower($ingest_formEl->getAttribute('hide_file_chooser')) == 'true', + 'redirect' => strtolower($ingest_formEl->getAttribute('redirect')) == 'false' ? FALSE : TRUE); + + } + return $ret; + } + + public function editIngestFormAttributes($dsid, $page, $hide_file_chooser = FALSE, $redirect = TRUE) { + $ret = FALSE; + if (self::validDsid($dsid) && $this->validate()) { + $ingest_formEl = $this->xml->getElementsByTagName('ingest_form')->item(0); + $ingest_formEl->setAttribute('dsid', $dsid); + $ingest_formEl->setAttribute('page', $page); + if (!$redirect) { + $ingest_formEl->setAttribute('redirect', 'false'); + } + else { + $ingest_formEl->removeAttribute('redirect'); + } + if ($hide_file_chooser) { + $ingest_formEl->setAttribute('hide_file_chooser', 'true'); + } + else { + $ingest_formEl->removeAttribute('hide_file_chooser'); + } + $ret = TRUE; + } + return $ret; + } + + public function getIngestFormBuilderMethod() { + $ret = FALSE; + if ($this->validate()) { + $method = $this->xml->getElementsByTagName('ingest_form')->item(0)->getElementsByTagName('form_builder_method')->item(0); + $ret = array( 'module' => ($method->getAttribute('module')==''?'fedora_repository':$method->getAttribute('module')), + 'file' => $method->getAttribute('file'), + 'class' => $method->getAttribute('class'), + 'method' => $method->getAttribute('method'), + 'handler' => $method->getAttribute('handler')); + } + return $ret; + } + + public function editIngestFormBuilderMethod($module, $file, $class, $method, $handler) { + $ret = FALSE; + if ($this->validate()) { + $methodEl = $this->xml->getElementsByTagName('ingest_form')->item(0)->getElementsByTagName('form_builder_method')->item(0); + $methodEl->setAttribute('module', $module); + $methodEl->setAttribute('file', $file); + $methodEl->setAttribute('class', $class); + $methodEl->setAttribute('method', $method); + $methodEl->setAttribute('handler', $handler); + $ret = TRUE; + } + return $ret; + } +} diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/MimeClass.inc b/MimeClass.inc new file mode 100644 index 00000000..55228740 --- /dev/null +++ b/MimeClass.inc @@ -0,0 +1,336 @@ +mime). + * While I don't have a specific use case for a mime->extension lookup, I think + * it's good to have in here. + * + * Drupal 7 will have better mime handlers. See: + * http://api.drupal.org/api/function/file_default_mimetype_mapping/7 + * + */ + +class MimeClass { + private $private_mime_types = array( + /** + * This is a shortlist of mimetypes which should catch most + * mimetype<-->extension lookups in the context of Islandora collections. + * + * It has been cut from a much longer list. + * + * Two types of mimetypes should be put in this list: + * 1) Special emerging formats which may not yet be expressed in the system + * mime.types file. + * 2) Heavily used mimetypes of particular importance to the Islandora + * project, as lookups against this list will be quicker and less + * resource intensive than other methods. + * + * Lookups are first checked against this short list. If no results are found, + * then the lookup function may move on to check other sources, namely the + * system's mime.types file. + * + * In most cases though, this short list should suffice. + * + * If modifying this list, please note that for promiscuous mimetypes + * (those which map to multiple extensions, such as text/plain) + * The function get_extension will always return the *LAST* extension in this list, + * so you should put your preferred extension *LAST*. + * + * e.g... + * "jpeg" => "image/jpeg", + * "jpe" => "image/jpeg", + * "jpg" => "image/jpeg", + * + * $this->get_extension('image/jpeg') will always return 'jpg'. + * + */ + // openoffice: + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + // staroffice: + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + // k-office: + 'kil' => 'application/x-killustrator', + 'kpt' => 'application/x-kpresenter', + 'kpr' => 'application/x-kpresenter', + 'ksp' => 'application/x-kspread', + 'kwt' => 'application/x-kword', + 'kwd' => 'application/x-kword', + // ms office 97: + 'doc' => 'application/msword', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + // office2007: + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'docm' => 'application/vnd.ms-word.document.macroEnabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12', + // wordperfect (who cares?): + 'wpd' => 'application/wordperfect', + // common and generic containers: + 'pdf' => 'application/pdf', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'rtf' => 'text/rtf', + 'rtx' => 'text/richtext', + 'latex' => 'application/x-latex', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + // *ml: + 'css' => 'text/css', + 'htm' => 'text/html', + 'html' => 'text/html', + 'wbxml' => 'application/vnd.wap.wbxml', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xsl' => 'text/xml', + 'xml' => 'text/xml', + 'csv' => 'text/csv', + 'tsv' => 'text/tab-separated-values', + 'txt' => 'text/plain', + // images: + "bmp" => "image/bmp", + "gif" => "image/gif", + "ief" => "image/ief", + "jpeg" => "image/jpeg", + "jpe" => "image/jpeg", + "jpg" => "image/jpeg", + "jp2" => "image/jp2", + "png" => "image/png", + "tiff" => "image/tiff", + "tif" => "image/tif", + "djvu" => "image/vnd.djvu", + "djv" => "image/vnd.djvu", + "wbmp" => "image/vnd.wap.wbmp", + "ras" => "image/x-cmu-raster", + "pnm" => "image/x-portable-anymap", + "pbm" => "image/x-portable-bitmap", + "pgm" => "image/x-portable-graymap", + "ppm" => "image/x-portable-pixmap", + "rgb" => "image/x-rgb", + "xbm" => "image/x-xbitmap", + "xpm" => "image/x-xpixmap", + "xwd" => "image/x-windowdump", + // videos: + "mpeg" => "video/mpeg", + "mpe" => "video/mpeg", + "mpg" => "video/mpeg", + "qt" => "video/quicktime", + "mov" => "video/quicktime", + "mxu" => "video/vnd.mpegurl", + "avi" => "video/x-msvideo", + "movie" => "video/x-sgi-movie", + "flv" => "video/x-flv", + "swf" => "application/x-shockwave-flash", + // compressed formats: (note: http://svn.cleancode.org/svn/email/trunk/mime.types) + "tgz" => "application/x-gzip", + "gz" => "application/x-gzip", + "tar" => "application/x-tar", + "gtar" => "application/x-gtar", + "zip" => "application/x-zip", + // others: + 'bin' => 'application/octet-stream', + ); + + private $private_file_extensions; + private $system_types; + private $system_exts; + private $etc_mime_types = '/etc/mime.types'; + + public function __construct() { + + // populate the reverse shortlist: + $this->private_file_extensions = array_flip( $this->private_mime_types ); + + // pick up a local mime.types file if it is available + if (is_readable('mime.types') ) { + $this->etc_mime_types = 'mime.types'; + } + + } + + /** + * function: getType + * description: An alias to get_mimetype, + * for backwards-compatibility with our old mimetype class. + */ + public function getType( $filename ) { + return $this->get_mimetype( $filename ); + } + + /** + * function: get_mimetype + * description: returns a mimetype associated with the file extension of $filename + */ + public function get_mimetype( $filename, $debug = FALSE ) { + + $ext = strtolower( array_pop( explode( '.', $filename ) ) ); + + if ( ! empty( $this->private_mime_types[$ext] ) ) { + if ( TRUE === $debug ) + return array( 'mime_type' => $this->private_mime_types[$ext], 'method' => 'from_array' ); + return $this->private_mime_types[$ext]; + } + + if (function_exists('file_get_mimetype')) { + $drupal_mimetype = file_get_mimetype( $filename ); + if ('application/octet-stream' != $drupal_mimetype) { + if (TRUE == $debug) + return array('mime_type' => $drupal_mimetype, 'method' => 'file_get_mimetype'); + return $drupal_mimetype; + } + } + + if (!isset( $this->system_types)) + $this->system_types = $this->system_extension_mime_types(); + if (isset( $this->system_types[$ext])) { + if (TRUE == $debug) + return array('mime_type' => $this->system_types[$ext], 'method' => 'mime.types'); + return $this->system_types[$ext]; + } + + if ( TRUE === $debug ) + return array( 'mime_type' => 'application/octet-stream', 'method' => 'last_resort' ); + return 'application/octet-stream'; + + } + + /** + * function: get_extension + * description: returns *one* valid file extension for a given $mime_type + */ + public function get_extension( $mime_type, $debug = FALSE ) { + + if (!empty( $this->private_file_extensions[$mime_type])) { + if (TRUE == $debug) + return array( 'extension' => $this->private_file_extensions[$mime_type], 'method' => 'from_array' ); + return $this->private_file_extensions[$mime_type]; + } + + if (!isset ( $this->system_exts)) + $this->system_exts = $this->system_mime_type_extensions(); + if (isset( $this->system_exts[$mime_type])) { + if (TRUE == $debug) + return array( 'extension' => $this->system_exts[$mime_type], 'method' => 'mime.types' ); + return $this->system_exts[$mime_type]; + } + + if (TRUE == $debug) + return array( 'extension' => 'bin', 'method' => 'last_resort' ); + return 'bin'; + } + + /** + * function: system_mime_type_extensions + * description: populates an internal array of mimetype/extension associations + * from the system mime.types file, or a local mime.types if one is found (see + * __constuctor). + * return: array of mimetype => extension + */ + private function system_mime_type_extensions() { + $out = array(); + $file = fopen($this->etc_mime_types, 'r'); + while (($line = fgets($file)) !== FALSE) { + $line = trim(preg_replace('/#.*/', '', $line)); + if (!$line) + continue; + $parts = preg_split('/\s+/', $line); + if (count($parts) == 1) + continue; + // A single part means a mimetype without extensions, which we ignore. + $type = array_shift($parts); + if (!isset($out[$type])) + $out[$type] = array_shift($parts); + // We take the first ext from the line if many are present. + } + fclose($file); + return $out; + } + + /** + * function: system_mime_type_extensions + * description: populates an internal array of mimetype/extension associations + * from the system mime.types file, or a local mime.types if one is found (see + * __constuctor). + * return: array of extension => mimetype + */ + private function system_extension_mime_types() { + $out = array(); + $file = fopen($this->etc_mime_types, 'r'); + while (($line = fgets($file)) !== FALSE) { + $line = trim(preg_replace('/#.*/', '', $line)); + if (!$line) + continue; + $parts = preg_split('/\s+/', $line); + if (count($parts) == 1) + continue; + // A single part means a mimetype without extensions, which we ignore. + $type = array_shift($parts); + foreach ($parts as $part) + $out[$part] = $type; + } + fclose($file); + return $out; + } + +} + +/* +$helper = new MimeClass(); +print "get_extension('application/x-gzip'): \n"; +echo print_r( $helper->get_extension('application/x-gzip', true), true ) . "\n"; +print "get_extension('text/plain'): \n"; +echo print_r( $helper->get_extension('text/plain', true), true ) . "\n"; +print "get_mimetype('fucker/asdf.tar.gz'): \n"; +echo print_r( $helper->get_mimetype('fucker/asdf.tar.gz', true), true ) . "\n"; +print "get_mimetype('blah.tsp'): \n"; +echo print_r( $helper->get_mimetype('blah.tsp', true), true ) . "\n"; +/* */ diff --git a/ObjectHelper.inc b/ObjectHelper.inc new file mode 100644 index 00000000..d96fd83a --- /dev/null +++ b/ObjectHelper.inc @@ -0,0 +1,1025 @@ +fedoraUser = $connectionHelper->getUser(); + //$this->fedoraPass = $connectionHelper->getPassword(); + } + + /** + * Grabs a stream from fedora sets the mimetype and returns it. $dsID is the + * datastream id. + * @param $pid String + * @param $dsID String + */ + function makeObject($pid, $dsID, $asAttachment = FALSE, $label = NULL, $filePath=FALSE, $version=NULL) { + global $user; + module_load_include('inc','fedora_repository','ContentModel'); + if ($pid == NULL || $dsID == NULL) { + drupal_set_message(t("no pid or dsid given to create an object with"), 'error'); + return ' '; + } + $headers = module_invoke_all('file_download', "/fedora/repository/$pid/$dsID"); + if (in_array(-1, $headers)) { + drupal_set_message('hello'); + drupal_access_denied(); + + return ' '; + } + + + if (!fedora_repository_access(OBJECTHELPER :: $OBJECT_HELPER_VIEW_FEDORA, $pid, $user)) { + drupal_set_message(t("You do not have access Fedora objects within the attempted namespace."), 'error'); + drupal_access_denied(); + return ' '; + } + + if (($cm = ContentModel::loadFromObject($pid)) == FALSE) { + drupal_set_message(t("You do not have access to objects without an Islandora Content Model."), 'error'); + drupal_access_denied(); + return ' '; + } + + $cmDatastreams = $cm->listDatastreams(); + if (!in_array($dsID,$cmDatastreams)) { + drupal_set_message(t("You do not have access to the specified datastream."), 'error'); + drupal_access_denied(); + return ' '; + } + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $item = new Fedora_Item($pid); + + + if (isset($item->datastreams[$dsID])) { + $mimeType=$item->datastreams[$dsID]['MIMEType']; + if ($label == NULL) { + $label = $item->datastreams[$dsID]['label']; + } + } else { + drupal_not_found(); + exit(); + } + + + if ((!isset($user)) || $user->uid == 0) { + $fedoraUser = 'anonymous'; + $fedoraPass = 'anonymous'; + $contentSize= 0; + } else { + $fedoraUser = $user->name; + $fedoraPass = $user->pass; + $dataStreamInfo = $item->get_datastream_info($dsID); + $contentSize = $dataStreamInfo->datastream->size; + } + + if (function_exists("curl_init")) { + if (!isset($mimeType)) { + $pid = variable_get('fedora_default_display_pid', 'demo:10'); + $dsID = variable_get('fedora_default_display_dsid', 'TN'); + $mimeType = 'image/jpeg'; + } + + $url = variable_get('fedora_base_url', 'http://localhost:8080/fedora') . '/get/' . $pid . '/' . $dsID; + if ($version) { + $url .= '/' . $version; //drupal_urlencode($version); + } + $ch = curl_init(); + $user_agent = "Mozilla/4.0 pp(compatible; MSIE 5.01; Windows NT 5.0)"; + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); + curl_setopt($ch, CURLOPT_FAILONERROR, 1); // Fail on errors + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // allow redirects + //curl_setopt($ch, CURLOPT_TIMEOUT, 15); // times out after 15s + curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_USERPWD, "$fedoraUser:$fedoraPass"); + // There seems to be a bug in Fedora 3.1's REST authentication, removing this line fixes the authorization denied error. + // curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0); // return into a variable + + curl_setopt($ch, CURLOPT_URL, $url); + + if ($filePath !== FALSE) { + $fp = fopen($filePath, 'w'); + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_exec($ch); + fclose($fp); + } else { + + header("Content-type: $mimeType"); + if ($contentSize > 0) { + header("Content-length: $contentSize"); + } + + if ($asAttachment) { + $suggestedFileName = "$label"; + $pos = strpos($suggestedFileName, '.'); + /** + * Here we used to take an object of, say, type application/pdf with label, say, "My Document" + * and we assemble the output filename extension based on the post-slash portion of the mimetype. + * (If the label has a period anywhere in it, we leave it alone.) + * + * This is great for simple mimetypes like application/pdf, text/html, image/jpeg, etc. + * but it's terrible for, say, application/vnd.oasis.opendocument.text (.odt). + * + * Instead we'll use the get_extension function in MimeClass.inc to discover a valid extension + * for the mimetype in question. + */ + if ($pos === FALSE) { + module_load_include('inc', 'fedora_repository', 'MimeClass'); + $mimeclass = new MimeClass(); + $ext = $mimeclass->get_extension($mimeType); + $suggestedFileName = "$label.$ext"; + } + + header('Content-Disposition: attachment; filename="' . $suggestedFileName . '"'); + } + curl_exec($ch); + } + curl_close($ch); + } else { + drupal_set_message(t('No curl support.'), 'error'); + } + } + + //Gets collection objects t + function getCollectionInfo($pid, $query = NULL) { + module_load_include('inc', 'fedora_repository', 'CollectionClass'); + $collectionClass = new CollectionClass(); + $results = $collectionClass->getRelatedItems($pid, $query); + return $results; + } + + /** + * returns the mime type + */ + function getMimeType($pid, $dsID) { + global $user; + if (empty($pid) || empty($dsID)) { + drupal_set_message(t('You must specify an object pid and datastream ID.'), 'error'); + return ''; + } + if (!fedora_repository_access(ObjectHelper :: $OBJECT_HELPER_VIEW_FEDORA, $pid, $user)) { + drupal_set_message(t('You do not have the appropriate permissions'), 'error'); + return; + } + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $item = new fedora_item($pid); + $datastream_list = $item->get_datastreams_list_as_SimpleXML(); + if (!isset($datastream_list)) { + //drupal_set_message( t("No datastreams available."), 'status' ); + return ' '; + } + foreach ($datastream_list as $datastream) { + foreach ($datastream as $datastreamValue) { + if ($datastreamValue->ID == $dsID) { + return $datastreamValue->MIMEType; + } + } + } + return ''; + } + + function getDatastreamInfo($pid, $dsID) { + global $user; + if (empty($pid) || empty($dsID)) { + drupal_set_message(t('You must specify an object pid and datastream ID.'), 'error'); + return ''; + } + if (!fedora_repository_access(ObjectHelper :: $OBJECT_HELPER_VIEW_FEDORA, $pid, $user)) { + drupal_set_message(t('You do not have the appropriate permissions'), 'error'); + return; + } + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $item = new fedora_item($pid); + $datastream_list = $item->get_datastreams_list_as_SimpleXML(); + if (!isset($datastream_list)) { + //drupal_set_message( t("No datastreams available."), 'status' ); + return ' '; + } + foreach ($datastream_list as $datastream) { + foreach ($datastream as $datastreamValue) { + if ($datastreamValue->ID == $dsID) { + return $datastreamValue; + } + } + } + return ''; + } + + /** + * internal function + * @param $pid String + * @param $dataStreamValue Object + */ + function create_link_for_ds($pid, $dataStreamValue) { + global $base_url; + $path = drupal_get_path('module', 'fedora_repository'); + + require_once($path . '/api/fedora_item.inc'); + $item = new Fedora_Item($pid); + + if (user_access(ObjectHelper :: $PURGE_FEDORA_OBJECTSANDSTREAMS)) { + $allow=TRUE; + if (module_exists('fedora_fesl')) { + $allow= fedora_fesl_check_roles($pid,'write'); + } + if ($allow) { + $purgeImage = 'purge datastream'; + } + } else { + $purgeImage = ' '; + } + $fullPath = base_path() . $path; + + // Add an icon to replace a datastream + // @TODO Note: using l(theme_image(..), ...); for these image links (and other links) may remove the need to have clean urls enabled. + $replaceImage= ' '; + if (user_access(ObjectHelper :: $ADD_FEDORA_STREAMS)) { + $allow=TRUE; + if (module_exists('fedora_fesl')) { + $allow= fedora_fesl_check_roles($pid,'write'); + } + if ($allow) { + $replaceImage = 'label . '" href="' . $base_url . '/fedora/repository/replaceStream/' . $pid . '/' . $dataStreamValue->ID . '/' . $dataStreamValue->label . '">replace datastream'; + } + } + + $content = ''; + $id = $dataStreamValue->ID; + $label = $dataStreamValue->label; + $label = str_replace("_", " ", $label); + $mimeType = $dataStreamValue->MIMEType; + + $view = '' . t('View') . ''; + $action = "$base_url/fedora/repository/object_download/" . drupal_urlencode($pid) . '/' . $id . '/' . drupal_urlencode(preg_replace('/\//i', '${1}_', $label)); // Necessary to handle the case of Datastream labels that contain slashes. Ugh. + $downloadVersion = '
'; + if (user_access(ObjectHelper :: $EDIT_FEDORA_METADATA)) { + $versions = $item->get_datastream_history($id); + if (is_array($versions)) { + $downloadVersion = '
'; + $downloadVersion .= '
'; + } + } + + + $content .= "$label $view $downloadVersion $mimeType $replaceImage $purgeImage\n"; + //$content .= "Mime Type :$mimeType\n"; + return $content; + } + + /** + * Queries fedora for what we call the qualified dublin core. Currently only dc.coverage has + * any qualified fields + * Transforms the returned xml to html + * This is the default metadata view. With icons for searching a dublin core field + * @param $pid String + * @return String + */ + function getQDC($pid) { + global $base_url; + $path = drupal_get_path('module', 'fedora_repository'); + module_load_include('inc', 'fedora_repository', 'ConnectionHelper'); + + $soapHelper = new ConnectionHelper(); + $client = $soapHelper->getSoapClient(variable_get('fedora_soap_url', 'http://localhost:8080/fedora/services/access?wsdl')); + + $dsId = 'QDC'; + $params = array( + 'pid' => "$pid", + 'dsID' => "$dsId", + 'asOfDateTime' => "" + ); + try { + $object = $client->__soapCAll('getDatastreamDissemination', array( + 'parameters' => $params + )); + } catch (Exception $e) { + try { //probably no QDC so we will try for the DC stream. + $dsId = 'DC'; + $params = array( + 'pid' => "$pid", + 'dsID' => "$dsId", + 'asOfDateTime' => "" + ); + $object = $client->__soapCAll('getDatastreamDissemination', array( + 'parameters' => $params + )); + } catch (exception $e2) { + drupal_set_message($e2->getMessage(), 'error'); + return; + } + } + $xmlstr = $object->dissemination->stream; + try { + $proc = new XsltProcessor(); + } catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + return; + } + + $proc->setParameter('', 'baseUrl', $base_url); + $proc->setParameter('', 'path', $base_url . '/' . $path); + $input = NULL; + $xsl = new DomDocument(); + try { + $xsl->load($path . '/xsl/convertQDC.xsl'); + $input = new DomDocument(); + $input->loadXML(trim($xmlstr)); + } catch (exception $e) { + watchdog(t("Fedora_Repository"), t("Problem loading XSL file: !e", array('!e' => $e)), NULL, WATCHDOG_ERROR); + } + $xsl = $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + $output = $newdom->saveXML(); + $baseUrl = base_path(); + //$baseUrl=substr($baseUrl, 0, (strpos($baseUrl, "/")-1)); + if (user_access(ObjectHelper :: $EDIT_FEDORA_METADATA)) { + $allow=TRUE; + if (module_exists('fedora_fesl')) { + $allow= fedora_fesl_check_roles($pid,'write'); + } + if ($allow) { + $output .= '
' . t('Edit Meta Data') . ''; + } + } + return $output; + } + + /** + * Gets a list of datastreams from an object using its pid + * + * We make some assumptions here. We have implemented a policy that + * we ingest in our repository will have TN (thumbnail) datastream. Even audio + * will have a picture of a speaker or something. This is not critical + * but makes searches etc. look better if there is a TN stream. + * This diplays all the streams in a collapsed fieldset at the bottom of the object page. + * you can implement a content model if you would like certain streams displayed in certain ways. + * @param $object_pid String + * @return String + * + */ + function get_formatted_datastream_list($object_pid, $contentModels, &$fedoraItem) { + global $fedoraUser, $fedoraPass, $base_url; + module_load_include('inc', 'fedora_repository', 'ConnectionHelper'); + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + + $path = drupal_get_path('module', 'fedora_repository'); + $dataStreamBody = ''; + $fedoraItem = new Fedora_Item($object_pid); + + if (user_access(ObjectHelper :: $VIEW_DETAILED_CONTENT_LIST)) { + $availableDataStreamsText = 'Detailed List of Content'; + //$metaDataText='Description'; + $mainStreamLabel = NULL; + $object = $fedoraItem->get_datastreams_list_as_SimpleXML(); + if (!isset($object)) { + drupal_set_message(t("No datastreams available")); + return ' '; + } + $hasOBJStream = NULL; + $hasTNStream = FALSE; + $dataStreamBody = "
\n"; + + $dataStreamBody .= $this->get_parent_objects_asHTML($object_pid); + $dataStreamBody .= ''; + foreach ($object as $datastream) { + foreach ($datastream as $datastreamValue) { + if ($datastreamValue->ID == 'OBJ') { + $hasOBJStream = '1'; + $mainStreamLabel = $datastreamValue->label; + $mainStreamLabel = str_replace("_", " ", $mainStreamLabel); + } + if ($datastreamValue->ID == 'TN') { + $hasTNStream = TRUE; + } + //create the links to each datastream + $dataStreamBody .= $this->create_link_for_ds($object_pid, $datastreamValue); //"\n"; + } + } + $dataStreamBody .= "

' . t("!text", array('!text' => $availableDataStreamsText)) . '

$key :$value
\n"; + //if they have access let them add a datastream + if (user_access(ObjectHelper :: $ADD_FEDORA_STREAMS)) { + $allow=TRUE; + if (module_exists('fedora_fesl')) { + $allow= fedora_fesl_check_roles($object_pid,'write'); + } + if ($allow) { + $dataStreamBody .= drupal_get_form('add_stream_form', $object_pid); + } + } + $fieldset = array( + '#title' => t("!text", array('!text' => $availableDataStreamsText)), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#value' => $dataStreamBody + ); + $dataStreamBody = '
' . theme('fieldset', $fieldset) . '
'; + } + $content = ''; + + if (empty($contentModels)) { + //only show this stuff if there are no contentmodels + if (isset($hasOBJStream)) { + $content .= ''; + $content .= 'Thumbnail'; + $content .= ''; + } else { + //don't use thumbnail as link, we don't know which datastream to link to + $content .= '' . $object_pid . ''; + } + } + + foreach ($contentModels as $contentModel) { + $content .= $this->createExtraFieldsets($object_pid, $contentModel); + } + + $content .= $dataStreamBody; + + if (user_access(ObjectHelper :: $PURGE_FEDORA_OBJECTSANDSTREAMS)) { + $allow=TRUE; + if (module_exists('fedora_fesl')) { + $allow= fedora_fesl_check_roles($object_pid,'write'); + } + if ($allow) { + $purgeObject = '' . t('Purge Object') . '' . t('Purge Object') . ''; + } + } else { + $purgeObject = ' '; + } + $content .= $purgeObject; + + $addObject = " "; + if (user_access(ObjectHelper :: $OBJECT_HELPER_VIEW_FEDORA)) { + $addObject = theme('add_to_basket_link', $object_pid); + } + $content .= $addObject; + + return '
' . $content . '
'; + } + + /** + * Queries a collection object for an xslt to format how the + * collection of objects is displayed. + */ + function getXslContent($pid, $path, $canUseDefault = TRUE) { + module_load_include('inc', 'fedora_repository', 'CollectionClass'); + $collectionClass = new CollectionClass(); + $xslContent = $collectionClass->getCollectionViewStream($pid); + if (!$xslContent && $canUseDefault) { //no xslt so we will use the default sent with the module + $xslContent = file_get_contents($path . '/xsl/sparql_to_html.xsl'); + } + return $xslContent; + } + + /** + * returns a stream from a fedora object given a pid and dsid + * + */ + function getStream($pid, $dsid, $showError = FALSE) { + module_load_include('inc', 'fedora_repository', 'ConnectionHelper'); + $soapHelper = new ConnectionHelper(); + try { + $client = $soapHelper->getSoapClient(variable_get('fedora_soap_url', 'http://localhost:8080/fedora/services/access?wsdl')); + $params = array( + 'pid' => "$pid", + 'dsID' => "$dsid", + 'asOfDateTime' => "" + ); + + if (!isset($client)) { + drupal_set_message(t('Error connection to Fedora using soap client.')); + return NULL; + } + $object = $client->__soapCall('getDatastreamDissemination', array('parameters' => $params)); + } catch (Exception $e) { + if ($showError) { + drupal_set_message(t('Error getting Datastream for %pid and %datastream
', array('%pid' => $pid, '%datastream' => $dsid)), 'error'); + } + return NULL; + } + $content = $object->dissemination->stream; + $content = trim($content); + return $content; + } + + /* + * gets the name of the content models for the specified object + * this now returns an array of pids as in Fedora 3 we can have more then one Cmodel for an object + */ + + function get_content_models_list($pid, $include_fedora_system_content_models = FALSE) { + module_load_include('inc', 'fedora_repository', 'CollectionClass'); + $collectionHelper = new CollectionClass(); + $pids = array(); + $query = 'select $object from <#ri> + where $object + and $object '; + $content_models = $collectionHelper->getRelatedItems($pid, $query); + + if (empty($content_models)) { + return $pids; + } + + try { + $sxml = new SimpleXMLElement($content_models); + } catch (exception $e) { + watchdog(t("Fedora_Repository"), t("Could not find a parent object for %s", $pid), NULL, WATCHDOG_ERROR); + return $pids; + } + + if (!isset($sxml)) { + return $pids; + } + + foreach ($sxml->xpath('//@uri') as $uri) { + if (strpos($uri, 'fedora-system') != FALSE && $include_fedora_system_content_models == FALSE) { + continue; + } + $pids[] = substr(strstr($uri, '/'), 1); + } + + return $pids; + } + + /* + * determines whether we can see the object or not + */ + + function fedora_repository_access($op, $pid) { + global $user; + $returnValue = FALSE; + if ($pid == NULL) { + $pid = variable_get('fedora_repository_pid', 'islandora:top'); + } + $nameSpaceAllowed = explode(" ", variable_get('fedora_pids_allowed', 'default: demo: changeme: Islandora: ilives: ')); + $pos = NULL; + foreach ($nameSpaceAllowed as $nameSpace) { + $pos = stripos($pid, $nameSpace); + if ($pos === 0) { + $returnValue = TRUE; + } + } + if ($returnValue) { + $user_access = user_access($op); + if ($user_access == NULL) { + return FALSE; + } + return $user_access; + } else { + return FALSE; + } + } + + /** + * internal function + * uses an xsl to parse the sparql xml returned from the ITQL query + * + * + * @param $content String + */ + function parseContent($content, $pid, $dsId, $collection, $pageNumber = NULL) { + $path = drupal_get_path('module', 'fedora_repository'); + global $base_url; + $collection_pid = $pid; //we will be changing the pid later maybe + //module_load_include('php', ''Fedora_Repository'', 'ObjectHelper'); + $objectHelper = $this; + $parsedContent = NULL; + $contentModels = $objectHelper->get_content_models_list($pid); + $isCollection = FALSE; + //if this is a collection object store the $pid in the session as it will come in handy + //after a purge or ingest to return to the correct collection. + + $fedoraItem = NULL; + $datastreams = $this->get_formatted_datastream_list($pid, $contentModels, $fedoraItem); + + if (!empty($contentModels)) { + foreach ($contentModels as $contentModel) { + if ($contentModel == variable_get('fedora_collection_model_pid', 'islandora:collectionCModel')) { + $_SESSION['fedora_collection'] = $pid; + $isCollection = TRUE; + } + } + } + + if ($fedoraItem !== NULL) { + $dslist = $fedoraItem->get_datastreams_list_as_array(); + if (isset($dslist['COLLECTION_POLICY'])) { + $isCollection = TRUE; + } + } + + //$label=$content; + $collectionName = $collection; + if (!$pageNumber) { + $pageNumber = 1; + } + + if (!isset($collectionName)) { + $collectionName = variable_get('fedora_repository_name', 'Collection'); + } + $xslContent = $this->getXslContent($pid, $path); + + //get collection list and display using xslt------------------------------------------- + + if (isset($content) && $content != FALSE) { + $input = new DomDocument(); + $input->loadXML(trim($content)); + $results = $input->getElementsByTagName('result'); + if ($results->length > 0) { + try { + $proc = new XsltProcessor(); + $proc->setParameter('', 'collectionPid', $collection_pid); + $proc->setParameter('', 'collectionTitle', $collectionName); + $proc->setParameter('', 'baseUrl', $base_url); + $proc->setParameter('', 'path', $base_url . '/' . $path); + $proc->setParameter('', 'hitPage', $pageNumber); + $proc->registerPHPFunctions(); + $xsl = new DomDocument(); + $xsl->loadXML($xslContent); + // php xsl does not seem to work with namespaces so removing it below + // I may have just been being stupid here + // $content = str_ireplace('xmlns="http://www.w3.org/2001/sw/DataAccess/rf1/result"', '', $content); + + $xsl = $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + + $objectList = $newdom->saveXML(); //is the xml transformed to html as defined in the xslt associated with the collection object + + if (!$objectList) { + throw new Exception("Invalid XML."); + } + } catch (Exception $e) { + drupal_set_message(t('!e', array('!e' => $e->getMessage())), 'error'); + return ''; + } + } + } else { + drupal_set_message(t("No Objects in this collection or bad query.")); + } + + //-------------------------------------------------------------------------------- + //show the collections datastreams + if ($results->length > 0 || $isCollection == TRUE) { + // if(strlen($objectList)>22||$contentModel=='Collection'||$contentModel=='Community')//length of empty dom still equals 22 because of etc + module_load_include('inc', 'Fedora_Repository', 'CollectionPolicy'); + $collectionPolicyExists = $objectHelper->getMimeType($pid, CollectionPolicy::getDefaultDSID()); + if (user_access(ObjectHelper :: $INGEST_FEDORA_OBJECTS) && $collectionPolicyExists) { + if (!empty($collectionPolicyExists)) { + $allow=TRUE; + if (module_exists('fedora_fesl')) { + $allow= fedora_fesl_check_roles($pid,'write'); + } + if ($allow) { + // $ingestObject = ' $collectionName, '!collection_pid' => $collection_pid)) . '" href="' . base_path() . + 'fedora/ingestObject/' . $collection_pid . '/' . $collectionName . '">' . t('Add a New Object') . '' . t('Add to this Collection') . ''; + } + } + } + else { + $ingestObject = ' '; + } + + + $datastreams .= $ingestObject; + + $objectListOut = ''; + if (isset($objectList)) { + $object_list_fieldset = array( + '#title' => t('Items in this collection'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + '#value' => (isset($objectList) ? $objectList : ''), //collection list + ); + $objectListOut = theme('fieldset', $object_list_fieldset); + } + } else { + //$collectionName=''; + $collection_fieldset = array( + '#title' => "", + '#collapsible' => TRUE, + '#collapsed' => FALSE, + '#value' => $datastreams, + ); + $objectListOut = ''; //no collection objects to show so don't show field set + } + + $output = ''; + switch (variable_get('fedora_object_display_title', ObjectHelper::$DISPLAY_ALWAYS)) { + case ObjectHelper :: $DISPLAY_NEVER: break; + case ObjectHelper :: $DISPLAY_NO_MODEL_OUTPUT: + if (trim($datastreams) == '') { + $output .= '' . $collectionName . '
'; + } + break; + + case ObjectHelper :: $DISPLAY_ALWAYS: + default: + $output .= '' . $collectionName . '
'; + break; + } + + $output .= $datastreams; + + $showDesc = FALSE; + switch (variable_get('fedora_object_display_description', ObjectHelper :: $DISPLAY_NO_MODEL_OUTPUT)) { + case ObjectHelper :: $DISPLAY_NEVER: break; + case ObjectHelper :: $DISPLAY_NO_MODEL_OUTPUT: + if (trim($datastreams) == '') { + $showDesc = TRUE; + } + break; + + case ObjectHelper :: $DISPLAY_ALWAYS: + default: + $showDesc = TRUE; + break; + } + if ($showDesc) { + //just show default dc or qdc as we could not find a content model + $metaDataText = t('Description'); + $body = $this->getQDC($pid); + $fieldset = array( + '#title' => t("!metaDataText", array('!metaDataText' => $metaDataText)), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#value' => $body + ); + $output .= theme('fieldset', $fieldset); + } + + switch (variable_get('fedora_collection_display_list', ObjectHelper::$DISPLAY_ALWAYS)) { + case ObjectHelper :: $DISPLAY_NEVER: break; + case ObjectHelper :: $DISPLAY_NO_MODEL_OUTPUT: + if (trim($datastreams) == '') { + $output .= $objectListOut . '
'; + } + break; + + case ObjectHelper :: $DISPLAY_ALWAYS: + default: + $output .= $objectListOut . '
'; + break; + } + + return $output; + } + + /** + * Gets the parent objects that this object is related to + * + * @param unknown_type $pid + * @return unknown + */ + function get_parent_objects($pid) { + $query_string = 'select $object $title from <#ri> + where ($object $title + and $object + and $object ) + order by $title'; + $objects = $this->getCollectionInfo($pid, $query_string); + return $objects; + } + + function get_parent_objects_asHTML($pid) { + global $base_url; + $parent_collections = $this->get_parent_objects($pid); + try { + $parent_collections = new SimpleXMLElement($parent_collections); + } catch (exception $e) { + drupal_set_message(t('Error getting parent objects !e', array('!e' => $e->getMessage()))); + return; + } + + $parent_collections_HTML = ''; + foreach ($parent_collections->results->result as $result) { + $collection_label = $result->title; + foreach ($result->object->attributes() as $a => $b) { + if ($a == 'uri') { + $uri = (string) $b; + $uri = $base_url . '/fedora/repository' . substr($uri, strpos($uri, '/')) . '/-/' . $collection_label; + } + } + $parent_collections_HTML .= '' . $collection_label . '
'; + } + if (!empty($parent_collections_HTML)) { + $parent_collections_HTML = '
'; + } + + return $parent_collections_HTML; + } + + /** + * gets a list of datastreams and related function that we should use to show datastreams in their own fieldsets + * from the content model associated with the object + */ + function createExtraFieldsets($pid, $contentModel) { + //$models = $collectionHelper->getContentModels($collectionPid, FALSE); + // possible problem in below if the collection policy has multiple content models + //with different pids but same dsid we could get wrong one, low probability and functionality + // will probably change for fedora version 3. + if (empty($contentModel)) { + return NULL; + } + $output = ''; + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (($cm = ContentModel :: loadFromModel($contentModel)) !== FALSE && $cm->validate()) { + $output .= $cm->displayExtraFieldset($pid); + } + return $output; + } + + /** + * Look in the content model for rules to run on the specified datastream. + * + * @param string $pid + * @param string $dsid + * @return boolean + */ + function get_and_do_datastream_rules($pid, $dsid, $file = '') { + if (!user_access('ingest new fedora objects')) { + drupal_set_message(t('You do not have permission to add datastreams.')); + return FALSE; + } + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if ($dsid != NULL && $pid != NULL && ($cm = ContentModel::loadFromObject($pid)) !== FALSE) { + $cm->execAddDatastreamMethods($dsid, $file); + } + } + + /** + * Get a tree of related pids - for the basket functionality + */ + function get_all_related_pids($pid) { + if (!$pid) { + return FALSE; + } + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + + // Get title and descriptions for $pid + $query_string = 'select $title $desc from <#ri> + where $o $title + and $o $desc + and $o '; + + $url = variable_get('fedora_repository_url', 'http://localhost:8080/fedora/risearch'); + $url .= "?type=tuples&flush=true&format=csv&limit=1000&lang=itql&stream=on&query="; + $content = do_curl($url . htmlentities(urlencode($query_string))); + + $rows = explode("\n", $content); + $fields = explode(',', $rows[1]); + + $pids[$pid] = array('title' => $fields[0], 'description' => $fields[1]); + +// $pids += $this->get_child_pids(array($pid)); + + return $pids; + } + + /** + * Get children of PID - but only 2 levels deep + */ + function get_child_pids($pids) { + // Get pid, title and description for children of object $pid + $query_string = 'select $o $title from <#ri> ' . +// $query_string = 'select $o $title $desc from <#ri> '. + 'where $s $o ' . + 'and $o $title ' . +// 'and $o $desc '. + 'and ( '; + + foreach ($pids as $pid) { + $query_string .= '$s or '; + } + $query_string = substr($query_string, 0, -3) . ' )'; + + $url = variable_get('fedora_repository_url', 'http://localhost:8080/fedora/risearch'); + $url .= "?type=tuples&flush=true&format=csv&limit=1000&lang=itql&stream=on&query="; + $url .= htmlentities(urlencode($query_string)); + $content = $this->doCurl($url); + + $rows = explode("\n", $content); + // Knock of the first heading row + array_shift($rows); + + $child_pids = array(); + if (count($rows)) { + // iterate through each row + foreach ($rows as $row) { + if ($row == "") { + continue; + } + $fields = explode(',', $row); + $child_pid = substr($fields[0], 12); + $child_pids[$child_pid] = array('title' => $fields[1], 'description' => $fields[2]); + } + if (!empty($child_pids)) { + $child_pids += $this->get_child_pids(array_keys($child_pids)); + } + } + + return $child_pids; + } + + /** + * Returns XML description of the object (export). + */ + function getObject($pid, $context = 'archive', $format = FOXML_11) { + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + + $url = variable_get('fedora_base_url', 'http://localhost:8080/fedora') . '/objects/' . $pid . '/export?context=' . $context . '&format=' . $format; + $result_data = do_curl($url); + return $result_data; + } + + /** + * Builds an array of drupal links for use in breadcrumbs. + */ + function getBreadcrumbs($pid, &$breadcrumbs, $level=10) { + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + + $query_string = 'select $parentObject $title $content from <#ri> + where ( $title + and $parentObject $content + and ( $parentObject + or $parentObject) + and $parentObject ) + minus $content + order by $title'; + $query_string = htmlentities(urlencode($query_string)); + + $url = variable_get('fedora_repository_url', 'http://localhost:8080/fedora/risearch'); + $url .= "?type=tuples&flush=TRUE&format=CSV&limit=1&offset=0&lang=itql&stream=on&query=" . $query_string; + $result = preg_split('/[\r\n]+/',do_curl($url)); + array_shift($result); // throw away first line + $matches =str_getcsv(join("\n",$result)); + if ($matches !== NULL) { + $parent = preg_replace('/^info:fedora\//','',$matches[0]); + $breadcrumbs[] = l($matches[1], 'fedora/repository/' . $pid); + if ($parent == variable_get('fedora_repository_pid', 'islandora:top')) { + $breadcrumbs[] = l(t('Home'), ''); // l(t('Digital repository'), 'fedora/repository'); + } elseif ($level > 0) { + $this->getBreadcrumbs($parent, $breadcrumbs, $level - 1); + } + } + } + + function warnIfMisconfigured($app) { + $messMap = array( + 'Kakadu' => 'Full installation instructions for Kakadu can be found + Here', + 'ImageMagick' => 'Check the path settings in the configuration of your imageapi module.
+ Further details can be found Here', + ); + + $warnMess = "Creation of one or more datastreams failed.
"; + $configMess = "Please ensure that %app is installed and configured for this site. "; + drupal_set_message($warnMess, 'warning', false); + drupal_set_message(t($configMess . "
" . $messMap[$app] . "
", array('%app' => $app)), 'warning', false); + } + +} + diff --git a/SearchClass.inc b/SearchClass.inc new file mode 100644 index 00000000..21fa114e --- /dev/null +++ b/SearchClass.inc @@ -0,0 +1,601 @@ + $e->getMessage())), NULL, WATCHDOG_ERROR); + return 'Error getting solr search results class. Check watchdog for more info.'; + } + return $implementation->$solrFunction($query, $startPage, $fq, $dismax); + } + function build_solr_search_form($repeat = NULL, $pathToSearchTerms = NULL, $query = NULL) { + $types = $this->get_search_terms_array(NULL, 'solrSearchTerms.xml'); + $queryArray=NULL; + if (isset($query)) { + $queryArray = explode('AND', $query); + } + + $andOrArray = array( + 'AND' => 'and', + //'OR' => 'or' //removed or for now as it would be a pain to parse + ); + $form = array(); + + if (!isset($repeat)) { + $repeat = variable_get('islandora_solr_search_block_repeat', t('3')); + } + $var0 = explode(':', $queryArray[0]); + $var1 = explode(':', $queryArray[1]); + $form['search_type']['type1'] = array( + '#title' => t(''), + '#type' => 'select', + '#options' => $types, + '#default_value' => trim($var0[0]) + ); + $form['fedora_terms1'] = array( + '#size' => '24', + '#type' => 'textfield', + '#title' => t(''), + '#required' => TRUE, + '#default_value' => (count($var0) >= 2 ? trim($var0[1]) : ''), + ); + $form['andor1'] = array( + '#title' => t(''), + '#type' => 'select', + '#default_value' => 'AND', + '#options' => $andOrArray + ); + $form['search_type']['type2'] = array( + '#title' => t(''), + '#type' => 'select', + '#options' => $types, + '#default_value' => (count($var1) >= 2 ? trim($var1[0]) : ''), + ); + $form['fedora_terms2'] = array( + '#size' => '24', + '#type' => 'textfield', + '#title' => t(''), + '#default_value' => (count($var1) >= 2 ? $var1[1] : ''), + ); + if ($repeat>2 && $repeat < 9) { //don't want less then 2 or more then 9 + for ($i = 3; $i < $repeat + 1; $i++) { + $t = $i - 1; + $field_and_term = explode(':', $queryArray[$t]); + $form["andor$t"] = array( + '#title' => t(''), + '#type' => 'select', + '#default_value' => 'AND', + '#options' => $andOrArray + ); + $form['search_type']["type$i"] = array( + '#title' => t(''), + '#type' => 'select', + '#options' => $types, + '#default_value' => trim($field_and_term[0]) + ); + $form["fedora_terms$i"] = array( + '#size' => '24', + '#type' => 'textfield', + '#title' => t(''), + '#default_value' => (count($field_and_term) >= 2 ? trim($field_and_term[1]) : ''), + ); + } + } + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('search') + ); + return $form; + } + + function build_simple_solr_form() { + //$form = array(); + $form["search_query"] = array( + '#size' => '30', + '#type' => 'textfield', + '#title' => t(''), + // '#default_value' => (count($field_and_term) >= 2 ? trim($field_and_term[1]) : ''), + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('search') + ); + return $form; + } + function theme_solr_search_form($form) { + if (!isset($repeat)) { + $repeat = variable_get('islandora_solr_search_block_repeat', t('3')); + } + + $output = drupal_render($form['search_type']['type1']) ; + $output .= drupal_render($form['fedora_terms1']) ; + $output .= drupal_render($form['andor1']) . drupal_render($form['search_type']['type2']) ; + $output .= drupal_render($form['fedora_terms2']); + if ($repeat>2 && $repeat < 9) { + for ($i=3;$i<$repeat+1;$i++) { + $t = $i - 1; + $output .= drupal_render($form["andor$t"]) . drupal_render($form['search_type']["type$i"]) ; + $output .= drupal_render($form["fedora_terms$i"]) ; + } + } + $output .= drupal_render($form['submit']) ; + $output .= drupal_render($form); + return $output; + + + } + function quickSearch($type, $query, $showForm = 1, $orderBy = 0, & $userArray) { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + if (user_access('view fedora collection')) { + $numberOfHistPerPage = '5000'; //hack for IR they do not want next button + $luceneQuery = NULL; + // Demo search string ?operation=gfindObjects&indexName=DemoOnLucene&query=fgs.DS.first.text%3Achristmas&hitPageStart=11&hitPageSize=10 + $keywords = explode(' ', $query); + + foreach ($keywords as $keyword) { + $luceneQuery .= $type . ':'. $keyword . '+AND+'; + } + $luceneQuery = substr($luceneQuery, 0, strlen($luceneQuery) - 5); + + $indexName = variable_get('fedora_index_name', 'DemoOnLucene'); + $keys = htmlentities(urlencode($query)); + $searchUrl = variable_get('fedora_fgsearch_url', 'http://localhost:8080/fedoragsearch/rest'); + $searchString = '?operation=gfindObjects&indexName='. $indexName . '&restXslt=copyXml&query='. $luceneQuery; + $searchString .= '&hitPageSize='. $numberOfHistPerPage . '&hitPageStart=1'; + //$searchString = htmlentities($searchString); + $searchUrl .= $searchString; + + // $objectHelper = new ObjectHelper(); + + $resultData = do_curl($searchUrl, 1); + if (isset($userArray)) { + $doc = new DOMDocument(); + $doc->loadXML($resultData); + $xPath = new DOMXPath($doc); + // Add users to department list. This is a hack as not all users will be in dupal + $nodeList = $xPath->query('//field[@name="refworks.u1"]'); + foreach ($nodeList as $node) { + if (!in_array($node->nodeValue, $userArray)) { + $userArray[]=$node->nodeValue; + } + } + } + if ($showForm) { + $output = 'Quick Search

' . t("Belongs to these collections: ") . '

' . $parent_collections_HTML . '
'. drupal_get_form('fedora_repository_quick_search_form') . '
'; + } + $output .= $this->applyXSLT($resultData, $orderBy); + return $output; + } + } + + + // gets term from a lucene index and displays them in a list + function getTerms($fieldName, $startTerm, $displayName = NULL) { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + $indexName = variable_get('fedora_index_name', 'DemoOnLucene'); + $searchUrl = variable_get('fedora_fgsearch_url', 'http://localhost:8080/fedoragsearch/rest'); + if ($startTerm == NULL) { + $startTerm = ""; + } + $startTerm = drupal_urlencode($startTerm); + $query = 'operation=browseIndex&startTerm='. $startTerm . '&fieldName='. $fieldName . '&termPageSize=20&indexName='. $indexName . '&restXslt=copyXml&resultPageXslt=copyXml'; + // $query=drupal_urlencode($query); + $query = '?'. $query; + $searchString=$searchUrl . $query; + + $objectHelper = new ObjectHelper(); + + $resultData = do_curl($searchString, 1); + $path = drupal_get_path('module', 'Fedora_Repository'); + + $output .= $this->applySpecifiedXSLT($resultData, $path . '/xsl/browseIndexToResultPage.xslt', $displayName); + //$output .= '
'.$alpha_out; + return $output; + + } + + /* + function custom_search($query,$pathToXslt=NULL){ + module_load_include('php', 'Fedora_Repository', 'ObjectHelper'); + module_load_include('inc', 'Fedora_Repository', 'api/fedora_utils'); + if (user_access('view fedora collection')) { + $numberOfHistPerPage = '1000';//hack for IR they do not want next button + $luceneQuery = NULL; + //demo search string ?operation=gfindObjects&indexName=DemoOnLucene&query=fgs.DS.first.text%3Achristmas&hitPageStart=11&hitPageSize=10 + + + $indexName = variable_get('fedora_index_name', 'DemoOnLucene'); + $query=htmlentities(urlencode($query)); + + $searchUrl = variable_get('fedora_fgsearch_url', 'http://localhost:8080/fedoragsearch/rest'); + $searchString = '?operation=gfindObjects&indexName=' . $indexName . '&restXslt=copyXml&query=' . $query; + $searchString .= '&hitPageSize='.$numberOfHistPerPage.'&hitPageStart=1'; + //$searchString = htmlentities($searchString); + $searchUrl .= $searchString; + + $objectHelper = new ObjectHelper(); + + $resultData = do_curl($searchUrl,1); + //var_dump($resultData);exit(0); + // $doc = new DOMDocument(); + // $doc->loadXML($resultData); + if($pathToXslt==NULL) { + $output.=$this->applyLuceneXSLT($resultData,$query); + }else{ + $output.=$this->applySpecifiedXSLT($resultData,$pathToXslt); + } + + return $output; + + } + } + */ + + function custom_search($query, $startPage=1, $xslt= '/xsl/advanced_search_results.xsl', $numberOfHistPerPage = 50) { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + + if (user_access('view fedora collection')) { + //$numberOfHistPerPage = '50';//hack for IR they do not want next button + $luceneQuery = NULL; + $indexName = variable_get('fedora_index_name', 'DemoOnLucene'); + $copyXMLFile = 'copyXml'; + // if($indexName=='ilives' || $indexName=='BasicIndex'){ + // $copyXMLFile = 'copyXmliLives'; + // } + $query = trim($query); + $query = htmlentities(urlencode($query)); + $searchUrl = variable_get('fedora_fgsearch_url', 'http://localhost:8080/fedoragsearch/rest'); + $searchString = '?operation=gfindObjects&indexName=' . $indexName . '&restXslt='. $copyXMLFile . '&query=' . $query; + $searchString .= '&hitPageSize='. $numberOfHistPerPage . '&hitPageStart='. $startPage; + //$searchString = htmlentities($searchString); + $searchUrl .= $searchString; + + //$objectHelper = new ObjectHelper(); + + $resultData = do_curl($searchUrl, 1); + //var_dump($resultData);exit(0); + // $doc = new DOMDocument(); + // $doc->loadXML($resultData); + + $output .= $this->applyLuceneXSLT($resultData, $startPage, $xslt, $query); + return $output; + } + } + + + function applySpecifiedXSLT($resultData, $pathToXSLT, $displayName = NULL) { + $proc = NULL; + global $user; + if (!$resultData) { + drupal_set_message(t('No data found!')); + return ' '; //no results + } + try { + $proc = new XsltProcessor(); + } + catch (Exception $e) { + drupal_set_message(t('Error loading '. $pathToXSLT . ' xslt!') . $e->getMessage()); + return ' '; + } + + //$proc->setParameter('', 'searchUrl', url('search') . '/fedora_repository'); //needed in our xsl + $proc->setParameter('', 'objectsPage', base_path()); + $proc->setParameter('', 'userID', $user->uid); + if (isset($displayName)) { + $proc->setParameter('', 'displayName', $displayName); + } + else { + $proc->setParameter('', 'displayName', "test"); + } + + $xsl = new DomDocument(); + + $test= $xsl->load($pathToXSLT); + + if (!isset($test)) { + drupal_set_message(t('Error loading '. $pathToXSLT . ' xslt!')); + return t('Error loading !pathToXSLT xslt.', array('!pathToXSLT' => $pathToXSLT)); + } + + $input = new DomDocument(); + + $didLoadOk = $input->loadXML($resultData); + + if (!isset($didLoadOk)) { + drupal_set_message(t('Error loading XML data!')); + return t('Error loading XML data.'); + } + else { + $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + return $newdom->saveXML(); + } + } + //default function for lucene results + /* + function applyLuceneXSLT($resultData, $query = NULL){ + $path = drupal_get_path('module', 'Fedora_Repository'); + $proc = NULL; + if (!$resultData) { + drupal_set_message(t('No Results!')); + return ' '; //no results + } + try { + $proc = new XsltProcessor(); + } + catch (Exception $e) { + drupal_set_message(t('Error loading results xslt! ') . $e->getMessage()) ; + return ' '; + } + + //inject into xsl stylesheet + if(isset($query)){ + $proc->setParameter('', 'fullQuery', $query); + } + $proc->setParameter('', 'searchToken', drupal_get_token('fedora_repository_advanced_search')); //token generated by Drupal, keeps tack of what tab etc we are on + $proc->setParameter('', 'searchUrl', url('search') . '/fedora_repository'); //needed in our xsl + $proc->setParameter('', 'objectsPage', base_path()); + $proc->setParameter('', 'allowedPidNameSpaces', variable_get('fedora_pids_allowed', 'demo: changeme:')); + $proc->registerPHPFunctions(); + $xsl = new DomDocument(); + + $test= $xsl->load($path . '/xsl/results.xsl'); + if (!isset($test)) { + drupal_set_message(t('Error loading search results XSLT!')); + return t('Error loading search results XSLT.'); + } + + $input = new DomDocument(); + $didLoadOk = $input->loadXML($resultData); + + if (!isset($didLoadOk)) { + drupal_set_message(t('Error loading search results!')); + return t('Error loading search results.'); + } + else { + $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + return $newdom->saveXML(); + } + } + */ + + /** + * apply an xslt to lucene gsearch search results + * + * @param $resultData + * @param $startPage + * @param $xslt_file + * @param $query the query that was executed. May want to pass this on. + */ + function applyLuceneXSLT($resultData, $startPage = 1, $xslt_file = '/xsl/results.xsl', $query=NULL) { + $path = drupal_get_path('module', 'Fedora_Repository'); + $proc = NULL; + if (!$resultData) { + //drupal_set_message(t('No Results!')); + return ' '; //no results + } + try { + $proc = new XsltProcessor(); + } catch (Exception $e) { + drupal_set_message(t('Error loading results xslt!') . $e->getMessage()); + return ' '; + } + if (isset($query)) { + $proc->setParameter('', 'fullQuery', $query); + } + //inject into xsl stylesheet + global $user; + $proc->setParameter('', 'userID', $user->uid); + $proc->setParameter('', 'searchToken', drupal_get_token('fedora_repository_advanced_search')); //token generated by Drupal, keeps tack of what tab etc we are on + $proc->setParameter('', 'searchUrl', url('search') . '/fedora_repository'); //needed in our xsl + $proc->setParameter('', 'objectsPage', base_path()); + $proc->setParameter('', 'allowedPidNameSpaces', variable_get('fedora_pids_allowed', 'default: demo: changeme: Islandora: ilives: ')); + $proc->setParameter('', 'hitPageStart', $startPage); + $proc->registerPHPFunctions(); + $xsl = new DomDocument(); + + $test = $xsl->load($path . $xslt_file); + if (!isset($test)) { + drupal_set_message(t('Error loading search results xslt!')); + return t('Error loading search results XSLT.'); + } + + $input = new DomDocument(); + $didLoadOk = $input->loadXML($resultData); + + if (!isset($didLoadOk)) { + drupal_set_message(t('Error loading search results!')); + return t('Error loading search results.'); + } + else { + $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + return $newdom->saveXML(); + } + } + + //xslt for islandscholar these xslt functions can probably be pulled into one + function applyXSLT($resultData, $orderBy = 0) { + $path = drupal_get_path('module', 'Fedora_Repository'); + $proc = NULL; + if (!$resultData) { + //drupal_set_message(t('No Results!')); + return ' '; //no results + } + try { + $proc = new XsltProcessor(); + } catch (Exception $e) { + drupal_set_message(t('Error loading results xslt! ') . $e->getMessage()); + return ' '; + } + + //inject into xsl stylesheet + //$proc->setParameter('', 'searchToken', drupal_get_token('search_form')); //token generated by Drupal, keeps tack of what tab etc we are on + $proc->setParameter('', 'userID', $user->uid); + $proc->setParameter('', 'searchUrl', url('search') . '/fedora_repository'); //needed in our xsl + $proc->setParameter('', 'objectsPage', base_path()); + $proc->setParameter('', 'allowedPidNameSpaces', variable_get('fedora_pids_allowed', 'default: demo: changeme: Islandora: ilives: ')); + $proc->setParameter('', 'orderBy', $orderBy); + $xsl = new DomDocument(); + + $test=$xsl->load($path . '/ir/xsl/results.xsl'); + if (!isset($test)) { + drupal_set_message(t('Error loading search results xslt!')); + return t('Error loading search results XSLT.'); + } + + $input = new DomDocument(); + $didLoadOk = $input->loadXML($resultData); + + if (!isset($didLoadOk)) { + drupal_set_message(t('Error loading search results!')); + return t('Error loading search results.'); + } + else { + $xsl = $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + return $newdom->saveXML(); + } + } + + function theme_advanced_search_form($form, $repeat=NULL) { + if (!isset($repeat)) { + $repeat = variable_get('fedora_repository_advanced_block_repeat', t('3')); + } + + $output = drupal_render($form['search_type']['type1']) ; + $output .= drupal_render($form['fedora_terms1']) ; + $output .= drupal_render($form['andor1']) . drupal_render($form['search_type']['type2']) ; + $output .= drupal_render($form['fedora_terms2']); + if ($repeat>2 && $repeat < 9) { + for ($i=3;$i<$repeat+1;$i++) { + $t = $i - 1; + $output .= drupal_render($form["andor$t"]) . drupal_render($form['search_type']["type$i"]) ; + $output .= drupal_render($form["fedora_terms$i"]) ; + } + } + $output .= drupal_render($form['submit']) ; + $output .= drupal_render($form); + return $output; + } + + //build search form, custom blocks should set the number of repeats or it will use the default + function build_advanced_search_form($repeat = NULL, $pathToSearchTerms = NULL, $query = NULL) { + $types = $this->get_search_terms_array($pathToSearchTerms); + $queryArray=NULL; + if (isset($query)) { + $queryArray = explode('AND', $query); + } + + $andOrArray = array( + 'AND' => 'and', + //'OR' => 'or' //removed or for now as it would be a pain to parse + ); + $form = array(); + + if (!isset($repeat)) { + $repeat = variable_get('fedora_repository_advanced_block_repeat', t('3')); + } + $var0 = explode(':', $queryArray[0]); + $var1 = explode(':', $queryArray[1]); + $form['search_type']['type1'] = array( + '#title' => t(''), + '#type' => 'select', + '#options' => $types, + '#default_value' => trim($var0[0]) + ); + $form['fedora_terms1'] = array( + '#size' => '24', + '#type' => 'textfield', + '#title' => t(''), + '#required' => TRUE, + '#default_value' => (count($var0) >= 2 ? trim($var0[1]) : ''), + ); + $form['andor1'] = array( + '#title' => t(''), + '#type' => 'select', + '#default_value' => 'AND', + '#options' => $andOrArray + ); + $form['search_type']['type2'] = array( + '#title' => t(''), + '#type' => 'select', + '#options' => $types, + '#default_value' => (count($var1) >= 2 ? trim($var1[0]) : ''), + ); + $form['fedora_terms2'] = array( + '#size' => '24', + '#type' => 'textfield', + '#title' => t(''), + '#default_value' => (count($var1) >= 2 ? $var1[1] : ''), + ); + if ($repeat>2 && $repeat < 9) { //don't want less then 2 or more then 9 + for ($i = 3; $i < $repeat + 1; $i++) { + $t = $i - 1; + $field_and_term = explode(':', $queryArray[$t]); + $form["andor$t"] = array( + '#title' => t(''), + '#type' => 'select', + '#default_value' => 'AND', + '#options' => $andOrArray + ); + $form['search_type']["type$i"] = array( + '#title' => t(''), + '#type' => 'select', + '#options' => $types, + '#default_value' => trim($field_and_term[0]) + ); + $form["fedora_terms$i"] = array( + '#size' => '24', + '#type' => 'textfield', + '#title' => t(''), + '#default_value' => (count($field_and_term) >= 2 ? trim($field_and_term[1]) : ''), + ); + } + } + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('search') + ); + return $form; + } + + + function get_search_terms_array($path = NULL, $file = NULL) { + if (!isset($path)) { + $path = drupal_get_path('module', 'Fedora_Repository'); + } + $xmlDoc = new DomDocument(); + if (!isset($file)) { + $file = 'searchTerms.xml'; + } + $xmlDoc->load($path . '/'. $file); + $nodeList = $xmlDoc->getElementsByTagName('term'); + $types = array(); + for ($i = 0; $i < $nodeList->length; $i++) { + $field = $nodeList->item($i)->getElementsByTagName('field'); + $value = $nodeList->item($i)->getElementsByTagName('value'); + $fieldValue = $field->item(0)->nodeValue; + $valueValue = $value->item(0)->nodeValue; + $types["$fieldValue"] = "$valueValue"; + } + return $types; + } +} diff --git a/SecurityClass.inc b/SecurityClass.inc new file mode 100644 index 00000000..ded59cf3 --- /dev/null +++ b/SecurityClass.inc @@ -0,0 +1,203 @@ +getStream($collection_pid, SECURITYCLASS :: $SECURITY_CLASS_SECURITY_STREAM, FALSE); + + if ($policyStream == NULL) { + // no child policy stream so collection is wide open to anyone to ingest, that has the permission ingest in Drupal. + // maybe we should return FALSE here?? would be more secure. + return TRUE; + } + $allowedUsersAndRoles = $this->getAllowedUsersAndRoles($policyStream); + if (!$allowedUsersAndRoles) { + // error processing stream so don't let them ingest here. + return FALSE; + } + $allowedUsers = $allowedUsersAndRoles["users"]; + $allowedRoles = $allowedUsersAndRoles["roles"]; + + foreach ($user->roles as $role) { + if (in_array($role, $allowedRoles)) { + return TRUE; + } + } + + if (in_array($user->name, $allowedUsers)) { + return TRUE; + } + return FALSE; + } + + //parses our simple xacml policies checking for users or roles that are allowed to ingest + function getAllowedUsersAndRoles($policyStream) { + $allowedRoles = array(); + $allowedUsers = array(); + $usersAndRoles = array(); + try { + $xml = new SimpleXMLElement($policyStream); + } + catch (Exception $e) { + watchdog(t("Fedora_Repository"), t("No roles found in security policy, could not parse policy stream."), NULL, WATCHDOG_ERROR); + //we may not want to send this to the screen. + drupal_set_message(t('No roles found in security policy, could not parse policy stream: !message', array('!message' => $e->getMessage())), 'error'); + return NULL; + } + $xml->registerXPathNamespace('default', 'urn:oasis:names:tc:xacml:1.0:policy'); + + $conditions = $xml->xpath("//default:Condition"); + + foreach ($conditions as $condition) { + $designator = $condition->Apply->SubjectAttributeDesignator; + if (empty($designator)) {//$disignator may be wrapped by an or + $designator=$condition->Apply->Apply->SubjectAttributeDesignator; + } + $attributeId = strip_tags($designator['AttributeId']); + + if ($attributeId == "fedoraRole") { + foreach ($condition->Apply->Apply->AttributeValue as $attributeValue) { + $allowedRoles[] = strip_tags($attributeValue->asXML()); + } + foreach ($condition->Apply->Apply->Apply->AttributeValue as $attributeValue) { + $allowedRoles[] = strip_tags($attributeValue->asXML()); + } + } + if ($attributeId == "urn:fedora:names:fedora:2.1:subject:loginId") { + foreach ($condition->Apply->Apply->AttributeValue as $attributeValue) { + $allowedUsers[] = strip_tags($attributeValue->asXML()); + } + foreach ($condition->Apply->Apply->Apply->AttributeValue as $attributeValue) { + $allowedUsers[] = strip_tags($attributeValue->asXML()); + } + } + } + $usersAndRoles['users'] = $allowedUsers; + $usersAndRoles['roles'] = $allowedRoles; + return $usersAndRoles; + + } + // When a user's profile is saved in drupal we will attempt to create a collection for them in Fedora + // this will be their personal space. In the IR it is editable by users with the same role in the VRE + // it probably would not be. + function createPersonalPolicy($user) { + $doc = new DOMDocument(); + try { + $doc->load(drupal_get_path('module', 'Fedora_Repository') . '/policies/noObjectEditPolicy.xml'); + } + catch (exception $e) { + watchdog(t("Fedora_Repository"), t("Problem loading policy file."), NULL, WATCHDOG_ERROR); + } + $conditions = $doc->getElementsByTagName('Condition'); + foreach ($conditions as $condition) { + $designator = $condition->getElementsByTagName('SubjectAttributeDesignator'); + foreach ($designator as $des) { + $attributeId = $des->getAttribute('AttributeId'); + if ($attributeId == 'fedoraRole') { + $applies = $condition->getElementsByTagName('Apply'); + foreach ($applies as $apply) { + $functionId = $apply->getAttribute('FunctionId'); + if ($functionId == 'urn:oasis:names:tc:xacml:1.0:function:string-bag') { + foreach ($user->roles as $role) { + if (!($role == 'authenticated user' || $role == 'administrator')) { //don't want authenticated user included administrator already is included' + $newAttributeValue=$doc->createElement('AttributeValue', ''); + $newAttributeValue->setAttribute('DataType', 'http://www.w3.org/2001/XMLSchema#string'); + // $newAttributeValue->setAttribute('MustBePresent', 'FALSE'); + $apply->appendChild($newAttributeValue); + } + } + } + } + } + + if ($attributeId == 'urn:fedora:names:fedora:2.1:subject:loginId') { + $applies = $condition->getElementsByTagName('Apply'); + foreach ($applies as $apply) { + $functionId = $apply->getAttribute('FunctionId'); + if ($functionId == 'urn:oasis:names:tc:xacml:1.0:function:string-bag') { + $newAttributeValue=$doc->createElement('AttributeValue', $user->name); + $newAttributeValue->setAttribute('DataType', 'http://www.w3.org/2001/XMLSchema#string'); + //$newAttributeValue->setAttribute('MustBePresent', 'FALSE'); + $apply->appendChild($newAttributeValue); + } + } + } + } + } + + return $doc; //NULL; //$xml; + } + + /** + * Add a list of allowed users and roles to the given policy stream and return it. + * + * @param string $policy_stream + * @param array $users_and_roles + * @return DOMDocument + */ + function set_allowed_users_and_roles(&$policy_stream, $users_and_roles) { + $allowed_roles = $users_and_roles['roles']; + $allowed_users = $users_and_roles['users']; + $dom = new DOMDocument(); + $dom->loadXML($policy_stream); + $conditions = $dom->getElementsByTagName('Condition'); + foreach ($conditions as $condition) { + $designator = $condition->getElementsByTagName('SubjectAttributeDesignator'); + foreach ($designator as $des) { + $attributeId = $des->getAttribute('AttributeId'); + if ($attributeId == 'fedoraRole') { + // $applies = $condition->getElementsByTagName('Apply'); + $applies = $des->parentNode->getElementsByTagName('Apply'); + foreach ($applies as $apply) { + $functionId = $apply->getAttribute('FunctionId'); + if ($functionId == 'urn:oasis:names:tc:xacml:1.0:function:string-bag') { + foreach ($allowed_roles as $role) { + if (!($role == 'authenticated user' || $role == 'administrator')) { //don't want authenticated user included administrator already is included' + $newAttributeValue=$dom->createElement('AttributeValue', $role); + $newAttributeValue->setAttribute('DataType', 'http://www.w3.org/2001/XMLSchema#string'); + //$newAttributeValue->setAttribute('MustBePresent', 'FALSE'); + $apply->appendChild($newAttributeValue); + } + } + } + } + } + + if ($attributeId == 'urn:fedora:names:fedora:2.1:subject:loginId') { + // $applies = $condition->getElementsByTagName('Apply'); + $applies = $des->parentNode->getElementsByTagName('Apply'); + foreach ($applies as $apply) { + $functionId = $apply->getAttribute('FunctionId'); + if ($functionId == 'urn:oasis:names:tc:xacml:1.0:function:string-bag') { + foreach ( $allowed_users as $username ) { + $newAttributeValue=$dom->createElement('AttributeValue', $username ); + $newAttributeValue->setAttribute('DataType', 'http://www.w3.org/2001/XMLSchema#string'); + //$newAttributeValue->setAttribute('MustBePresent', 'FALSE'); + $apply->appendChild($newAttributeValue); + } + } + } + } + } + } + // $this->collection_policy_stream = $dom->saveXML(); + return $dom->saveXML(); + } +} diff --git a/XMLDatastream.inc b/XMLDatastream.inc new file mode 100644 index 00000000..e99cbbca --- /dev/null +++ b/XMLDatastream.inc @@ -0,0 +1,277 @@ +pid=$pid; + $this->dsid=$dsid; + + if ($xmlStr !== NULL) { + $this->xml = (is_object($xmlStr) && get_class($xmlStr) == DOMDocument)?$xmlStr : DOMDocument::loadXML($xmlStr); + } + } + + + /** + * Gets the identifier for this XMLDatastream + * Returns FALSE on failure. + * + * NOTE: not available if constructed directly from file. + * + * @return string identifier + */ + public function getIdentifier() { + return ($this->pid != NULL && $this->dsid != NULL) ? $this->pid . '/'. $this->dsid : FALSE; + } + + + /** + * Dumps the XMLDatastream as an XML String + * + * + * @return string xml + */ + public function dumpXml() { + if ($this->xml == NULL) { + $this->fetchXml(); + } + return $this->xml->saveXml(); + } + + + /** + * Validates the XMLDatastream against the schema location + * defined by the xmlns:schemaLocation attribute of the root + * element. If the xmlns:schemaLocation attribute does not exist, + * then it is assumed to be the old schema and it attempts to convert + * using the convertFromOldSchema method. + * + * TODO: Maybe change it so that it always validates against a known + * schema. This makes more sense because this class assumes the structure + * to be known after it has been validated. + * + * @return boolean $valid + */ + public function validate() { + if ($this->valid === NULL) { + $ret = TRUE; + if ($this->xml == NULL) { + $this->fetchXml(); + } + // figure out if we're dealing with a new or old schema + $rootEl = $this->xml->firstChild; + if (!$rootEl->hasAttributes() || $rootEl->attributes->getNamedItem('schemaLocation') === NULL ) { + //$tmpname = substr($this->pid, strpos($this->pid, ':') + 1); + $tmpname = user_password(10); + $this->convertFromOldSchema(); + drupal_add_js("fedora_repository_print_new_schema_$tmpname = function(tagID) { + var target = document.getElementById(tagID); + var content = target.innerHTML; + var text = 'Title' + + '' + content +''; + printerWindow = window.open('', '', 'toolbar=no,location=no,' + 'status=no,menu=no,scrollbars=yes,width=650,height=400'); + printerWindow.document.open(); +printerWindow.document.write(text); +} ", 'inline'); + + drupal_set_message('Warning: XMLDatastream performed conversion of \''. $this->getIdentifier() .'\' from old schema. Please update the datastream. The new datastream contents are here. '); + $rootEl = $this->xml->firstChild; + } + + $schemaLocation = NULL; + if ($this->forceSchema) { + // hack because you cant easily get the static property value from + // a subclass. + $vars = get_class_vars(get_class($this)); + $schemaLocation = $vars['SCHEMA_URI']; + + } + elseif ($rootEl->attributes->getNamedItem('schemaLocation') !== NULL) { + //figure out where the schema is located and validate. + list(, $schemaLocation) = preg_split('/\s+/', $rootEl->attributes->getNamedItem('schemaLocation')->nodeValue); + } + $schemaLocation = NULL; + return TRUE; + if ($schemaLocation !== NULL) { + if (!$this->xml->schemaValidate($schemaLocation)) { + $ret = FALSE; + $errors=libxml_get_errors(); + foreach ($errors as $err) { + self::$errors[] = 'XML Error: Line '. $err->line .': '. $err->message; + } + } + else { + $this->name=$rootEl->attributes->getNamedItem('name')->nodeValue; + } + } + else { + $ret = FALSE; + self::$errors[] = 'Unable to load schema.'; + } + + $this->valid = $ret; + } + + return $this->valid; + } + + + /** + * Saves the current XML datastream back to fedora. The XML must validate. + * + * @return boolean $success + */ + public function saveToFedora() { + module_load_include('inc', 'Fedora_Repository', 'api/fedora_item'); + if ($this->validate()) { + $item = new Fedora_Item($this->pid); + $item->modify_datastream_by_value($this->dumpXml(), $this->dsid, $this->name, NULL); + return TRUE; + } + return FALSE; + } + + /** + * Purges veersions of the datastream newer than and including the start_date. If + * End date is specified, it can be used to purge a range of versions instead. Date should be in + * DATE_RFC822 format + * + * @param string $start_date + * @param string $end_date + * @return boolean $valid + */ + public function purgeVersions($start_date, $end_date = NULL) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $fedora_item = new Fedora_Item($this->pid); + return $fedora_item->purge_datastream( $this->dsid, $start_date, $end_date); + } + + /** + * Gets the history of the datastream from fedora. + * Returns false on failure. + * + * @return string[] $ret + */ + public function getHistory() { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $fedora_item = new Fedora_Item($this->pid); + $history = $fedora_item->get_datastream_history($this->dsid); + + $ret = FALSE; + if ($history !== FALSE) { + $ret = array(); + foreach ($history as $version) { + if ($version->versionID !== NULL) $ret[] = array('versionID' => $version->versionID, 'createDate' => $version->createDate); + } + } + return $ret; + } + + /** + * Attempts to convert from the old XML schema to the new by + * traversing the XML DOM and building a new DOM. When done + * $this->xml is replaced by the newly created DOM.. + * + * @return void + */ + abstract protected function convertFromOldSchema(); + +} diff --git a/api/dublin_core.inc b/api/dublin_core.inc new file mode 100644 index 00000000..04321677 --- /dev/null +++ b/api/dublin_core.inc @@ -0,0 +1,124 @@ + array(), + 'dc:creator' => array(), + 'dc:subject' => array(), + 'dc:description' => array(), + 'dc:publisher' => array(), + 'dc:contributor' => array(), + 'dc:date' => array(), + 'dc:type' => array(), + 'dc:format' => array(), + 'dc:identifier' => array(), + 'dc:source' => array(), + 'dc:language' => array(), + 'dc:relation' => array(), + 'dc:coverage' => array(), + 'dc:rights' => array(), + ); + public $owner; + + /** + * Constructs a Dublin_Core object from a Fedora_Item object and populates + * the $dc array. + * @param $item + */ + function Dublin_Core($item = NULL) { + if (!empty($item)) { + $this->owner = $item; + $dc_xml = $item->get_datastream_dissemination('DC'); + $this->dc = self::import_from_xml_string($dc_xml)->dc; + } + } + + /** + * + * @param $element_name + * @param $value + */ + function add_element( $element_name, $value ) { + if (is_string($value) && is_array($this->dc[$element_name])) { + $this->dc[$element_name][] = $value; + } + } + +/** + * Replace the given DC element with the values in $values + * @param string $elemnt_name + * @param array $values + */ + function set_element($element_name, $values) { + if (is_array($values)) { + $this->dc[$element_name] = $values; + } + elseif (is_string($values)) { + $this->dc[$element_name] = array($values); + } + } + + /** + * Serialize this object to XML and return it. + */ + function as_xml( $with_preamble = FALSE ) { + $dc_xml = new DomDocument(); + $oai_dc = $dc_xml->createElementNS('http://www.openarchives.org/OAI/2.0/oai_dc/', 'oai_dc:dc'); + $oai_dc->setAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + foreach ($this->dc as $dc_element => $values) { + if (is_array($values) && !empty($values)) { + foreach ($values as $value) { + $new_item = $dc_xml->createElement($dc_element, $value); + $oai_dc->appendChild($new_item); + } + } + else { + $new_item = $dc_xml->createElement($dc_element); + $oai_dc->appendChild($new_item); + } + } + $dc_xml->appendChild($oai_dc); + return $dc_xml->saveXML(); + } + + static function create_dc_from_dict() { + + } + + function save($alt_owner = NULL) { + $item_to_update = (!empty($alt_owner) ? $alt_owner : $this->owner); + // My Java roots showing, trying to do polymorphism in PHP. + if (!empty($item_to_update)) { + $item_to_update->modify_datastream_by_value($this->as_xml(), 'DC', 'Default Dublin Core Metadata', 'text/xml'); + } + } + + /** + * Creates a new instance of the class by parsing dc_xml + * @param string $dc_xml + * @return Dublin_Core + */ + static function import_from_xml_string($dc_xml) { + $dc_doc = new DomDocument(); + if ($dc_doc->loadXML($dc_xml)) { + $oai_dc = $dc_doc->getElementsByTagNameNS('http://purl.org/dc/elements/1.1/', '*'); + $new_dc = new Dublin_Core(); + foreach ($oai_dc as $child) { + array_push($new_dc->dc[$child->nodeName], $child->nodeValue); + } + return $new_dc; + } + else { + return NULL; + } + } + +} + diff --git a/api/fedora_collection.inc b/api/fedora_collection.inc new file mode 100644 index 00000000..c0dce02a --- /dev/null +++ b/api/fedora_collection.inc @@ -0,0 +1,133 @@ + $format + */ +function export_collection($collection_pid, $relationship = 'isMemberOfCollection', $format = 'info:fedora/fedora-system:FOXML-1.1' ) { + $collection_item = new Fedora_Item($collection_pid); + $foxml = $collection_item->export_as_foxml(); + + $file_dir = file_directory_path(); + + // Create a temporary directory to contain the exported FOXML files. + $container = tempnam($file_dir, 'export_'); + file_delete($container); + print $container; + if (mkdir($container) && mkdir($container . '/'. $collection_pid)) { + $foxml_dir = $container . '/'. $collection_pid; + $file = fopen($foxml_dir . '/'. $collection_pid . '.xml', 'w'); + fwrite($file, $foxml); + fclose($file); + + $member_pids = get_related_items_as_array($collection_pid, $relationship); + foreach ($member_pids as $member) { + $file = fopen($foxml_dir . '/'. $member . '.xml', 'w'); + $item = new Fedora_Item($member); + $item_foxml = $item->export_as_foxml(); + fwrite($file, $item_foxml); + fclose($file); + } + if (system("cd $container;zip -r $collection_pid.zip $collection_pid/* >/dev/NULL") == 0) { + header("Content-type: application/zip"); + header('Content-Disposition: attachment; filename="' . $collection_pid . '.zip'. '"'); + $fh = fopen($container . '/'. $collection_pid . '.zip', 'r'); + $the_data = fread($fh, filesize($container . '/'. $collection_pid . '.zip')); + fclose($fh); + echo $the_data; + } + if (file_exists($container . '/'. $collection_pid)) { + system("rm -rf $container"); // I'm sorry. + } + } + else { + drupal_set_message("Error creating temp directory for batch export.", 'error'); + return FALSE; + } + return TRUE; +} + +/** + * Returns an array of pids that match the query contained in teh collection + * object's QUERY datastream or in the suppled $query parameter. + * @param $collection_pid + * @param $query + * @param $query_format R + */ +function get_related_items_as_xml($collection_pid, $relationship = array('isMemberOfCollection'), $limit = 10000, $offset = 0, $active_objects_only = TRUE, $cmodel = NULL) { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + $collection_item = new Fedora_Item($collection_pid); + + global $user; + if (!fedora_repository_access(OBJECTHELPER :: $OBJECT_HELPER_VIEW_FEDORA, $pid, $user)) { + drupal_set_message(t("You do not have access to Fedora objects within the attempted namespace or access to Fedora denied."), 'error'); + return array(); + } + + $query_string = 'select $object $title $content from <#ri> + where ($object $title + and $object $content + and ('; + + if (is_array($relationship)) { + foreach ($relationship as $rel) { + $query_string .= '$object '; + if (next($relationship)) { + $query_string .= ' OR '; + } + } + } + elseif (is_string($relationship)) { + $query_string .= '$object '; + } + else { + return ''; + } + + $query_string .= ') '; + $query_string .= $active_objects_only ? 'and $object ' : ''; + + if ($cmodel) { + $query_string .= ' and $content '; + } + + $query_string .= ') + minus $content + order by $title'; + + $query_string = htmlentities(urlencode($query_string)); + + + $content = ''; + $url = variable_get('fedora_repository_url', 'http://localhost:8080/fedora/risearch'); + $url .= "?type=tuples&flush=TRUE&format=Sparql&limit=$limit&offset=$offset&lang=itql&stream=on&query=". $query_string; + $content .= do_curl($url); + + return $content; +} + +function get_related_items_as_array($collection_pid, $relationship = 'isMemberOfCollection', $limit = 10000, $offset = 0, $active_objects_only = TRUE, $cmodel = NULL) { + $content = get_related_items_as_xml($collection_pid, $relationship, $limit, $offset, $active_objects_only, $cmodel); + if (empty($content)) { + return array(); + } + + $content = new SimpleXMLElement($content); + + $resultsarray = array(); + foreach ($content->results->result as $result) { + $resultsarray[] = substr($result->object->attributes()->uri, 12); // Remove 'info:fedora/'. + } + return $resultsarray; +} diff --git a/api/fedora_export.inc b/api/fedora_export.inc new file mode 100644 index 00000000..d2b08baf --- /dev/null +++ b/api/fedora_export.inc @@ -0,0 +1,179 @@ +get_datastreams_list_as_SimpleXML($pid)) { + $log[] = log_line(t("Failed to get datastream %dsid for pid %pid", array('%dsid' => $ds->ID, '%pid' => $pid)), 'error'); + return FALSE; + } + + // Datastreams added as a result of the ingest process + $ignore_dsids = array('QUERY'); + + $paths = array(); + foreach ($object->datastreamDef as $ds) { + if (!in_array($ds->ID, $ignore_dsids)) { + $file = $dir .'/'. $ds->label .'.'. get_file_extension($ds->MIMEType); + $paths[$ds->ID] = $file; + + //$content = $ob_helper->getDatastreamDissemination($pid, $ds->ID); + if ($content = $ob_helper->getStream($pid, $ds->ID, FALSE)) { + if (!$fp = @fopen($file, 'w')) { + $log[] = log_line(t("Failed to open file %file to write datastream %dsid for pid %pid", array('%file' => $file, '%dsid' => $ds->ID, '%pid' => $pid)), 'error'); + return FALSE; + } + fwrite($fp, $content); + fclose($fp); + } + else { + $log[] = log_line(t("Failed to get datastream %dsid for pid %pid", array('%dsid' => $ds->ID, '%pid' => $pid)), 'error'); + } + } + } + return $paths; +} + +function export_foxml_for_pid($pid, $dir, $paths, &$log, $format = FOXML_11, $remove_islandora = FALSE) { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + $ob_helper = new ObjectHelper(); + if (!$object_xml = $ob_helper->getObject($pid, 'migrate', $format)) { + $log[] = log_line(t("Failed to get foxml for %pid", array('%pid' => $pid)), 'error'); + return FALSE; + } + + $foxml = new DOMDocument(); + $foxml->loadXML($object_xml); + + $xpath = new DOMXpath($foxml); + + // Remove rdf elements added during ingest (if present) + if ($remove_islandora) { + $xpath->registerNamespace('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); + $descNode = $xpath->query("//rdf:RDF/rdf:Description")->item(0); + + if ($model = $descNode->getElementsByTagName('hasModel')->item(0)) { + $descNode->removeChild($model); + } + + if ($member = $descNode->getElementsByTagName('rel:isMemberOfCollection')->item(0)) { + $descNode->removeChild($member); + } + } + + if ($remove_islandora) { + // Update object paths in the foxml for this pid + switch ($format) { + case FOXML_10: + case FOXML_11: + + $disallowed_groups = array('E', 'R'); + + // Update datastream uris + $xpath->registerNamespace('foxml', 'info:fedora/fedora-system:def/foxml#'); + foreach ($xpath->query("//foxml:datastream[@ID]") as $dsNode) { + + // Don't update datastreams having external uris + if (in_array($dsNode->getAttribute('CONTROL_GROUP'), $disallowed_groups)) { + continue; + } + + $dsId = $dsNode->getAttribute('ID'); + + // Remove QUERY datastream + if ($dsId == "QUERY") { + $parentNode = $xpath->query('/foxml:digitalObject')->item(0); + $parentNode->removeChild($dsNode); + } + + foreach ($dsNode->getElementsByTagName('*') as $contentNode) { + if ($str = $contentNode->getAttribute('REF')) { + $contentNode->setAttribute('REF', url($paths[$dsId], array('absolute' => TRUE))); + } + } + } + break; + + case METS_10: + case METS_11: + // Update datastream uris + $xpath->registerNamespace('METS', 'http://www.loc.gov/METS/'); + foreach ($xpath->query('//METS:fileGrp[@ID="DATASTREAMS"]/METS:fileGrp') as $dsNode) { + + $dsId = $dsNode->getAttribute('ID'); + + // Remove QUERY datastream + if ($dsId == "QUERY") { + $parentNode = $xpath->query('//METS:fileGrp[@ID="DATASTREAMS"]')->item(0); + $parentNode->removeChild($dsNode); + } + + $xpath->registerNamespace('xlink', 'http://www.loc.gov/METS/'); + foreach ($xpath->query('METS:file[@OWNERID!="E"][@OWNERID!="R"]/METS:FLocat[@xlink:href]', $dsNode) as $Floc) { + $Floc->setAttribute('xlink:href', url($paths[$dsId], array('absolute' => TRUE))); + } +/* + foreach ($dsNode->getElementsByTagName('METS:file') as $contentNode) { + // Don't update datastreams having external uris + if (in_array($dsNode->getAttribute('OWNERID'), $disallowed_groups)) { + continue; + } + + foreach ($xpath->('METS:FLocat[@xlink:href]', $contentNode) as $Floc) { + $Floc->setAttribute('xlink:href', url($paths[$dsId], array('absolute' => true))); + } + `} +*/ + } + + break; + + default: + $log[] = log_line(t("Unknown or invalid format: ". $format), 'error'); + return FALSE; + } + } //if $remove_islandora + + $file = $dir .'/'. $pid .'.xml'; + if (!$foxml->save($file)) { + $log[] = log_line(t("Failed to write datastream %dsid for pid %pid to %file", array('%dsid' => $ds->ID, '%pid' => $pid, '%file' => $file)), 'error'); + return FALSE; + } + else { + $log[] = log_line(t("Exported %pid to %file", array('%pid' => $pid, '%file' => $file)), 'info'); + } + + return TRUE; +} + +function get_file_extension($mimeType) { + return substr(strstr($mimeType, '/'), 1); +} + +function log_line($msg, $severity = 'info', $sep = "\t") { + return date("Y-m-d H:i:s") . $sep . ucfirst($severity) . $sep . $msg; +} diff --git a/api/fedora_item.inc b/api/fedora_item.inc new file mode 100644 index 00000000..01d71cfa --- /dev/null +++ b/api/fedora_item.inc @@ -0,0 +1,780 @@ +pid = $pid; + if (isset(Fedora_Item::$instantiated_pids[$pid])) { + $this->objectProfile =& Fedora_Item::$instantiated_pids[$pid]->objectProfile; + $this->datastreams =& Fedora_Item::$instantiated_pids[$pid]->datastreams; + $this->datastreams_list =& Fedora_Item::$instantiated_pids[$pid]->datastreams_list; + } else { + if (empty(self::$connection_helper)) { + self::$connection_helper = new ConnectionHelper(); + } + + $raw_objprofile = $this->soap_call('getObjectProfile', array('pid' => $this->pid, 'asOfDateTime' => "")); + + if (!empty($raw_objprofile)) { + $this->objectProfile = $raw_objprofile->objectProfile; + $this->datastreams = $this->get_datastreams_list_as_array(); + } else { + $this->objectProfile = ''; + $this->datastreams = array(); + } + Fedora_Item::$instantiated_pids[$pid]=&$this; + } + } + + function exists() { + return (!empty($this->objectProfile)); + } + + function add_datastream_from_file($datastream_file, $datastream_id, $datastream_label = NULL, $datastream_mimetype = '', $controlGroup = 'M',$logMessage = null) { + module_load_include('inc', 'fedora_repository', 'MimeClass'); + if (empty($datastream_mimetype)) { + // Get mime type from the file extension. + $mimetype_helper = new MimeClass(); + $datastream_mimetype = $mimetype_helper->getType($datastream_file); + } + $original_path = $datastream_file; + // Temporarily move file to a web-accessible location. + file_copy($datastream_file, file_directory_path()); + $datastream_url = drupal_urlencode($datastream_file); + $url = file_create_url($datastream_url); + + $return_value = $this->add_datastream_from_url($url, $datastream_id, $datastream_label, $datastream_mimetype, $controlGroup,$logMessage); + + if ($original_path != $datastream_file) { + file_delete($datastream_file); + } + return $return_value; + } + + function add_datastream_from_url($datastream_url, $datastream_id, $datastream_label = NULL, $datastream_mimetype = '', $controlGroup = 'M',$logMessage = null) { + if (empty( $datastream_label)) { + $datastream_label = $datastream_id; + } + + $params = array( + 'pid' => $this->pid, + 'dsID' => $datastream_id, + 'altIDs' => NULL, + 'dsLabel' => $datastream_label, + 'versionable' => TRUE, + 'MIMEType' => $datastream_mimetype, + 'formatURI' => NULL, + 'dsLocation' => $datastream_url, + 'controlGroup' => $controlGroup, + 'dsState' => 'A', + 'checksumType' => 'DISABLED', + 'checksum' => 'none', + 'logMessage' => ($logMessage != null)?$logMessage: 'Ingested object '. $datastream_id + ); + + return $this->soap_call( 'addDataStream', $params )->datastreamID; + } + + function add_datastream_from_string($str, $datastream_id, $datastream_label = NULL, $datastream_mimetype = 'text/xml', $controlGroup = 'M',$logMessage = null) { + $dir = sys_get_temp_dir(); + $tmpfilename = tempnam($dir, 'fedoratmp'); + $tmpfile = fopen($tmpfilename, 'w'); + fwrite($tmpfile, $str, strlen($str)); + fclose($tmpfile); + $returnvalue = $this->add_datastream_from_file($tmpfilename, $datastream_id, $datastream_label, $datastream_mimetype, $controlGroup,$logMessage); + unlink($tmpfilename); + return $returnvalue; + } + + /** + * Add a relationship string to this object's RELS-EXT. + * does not support rels-int yet. + * @param string $relationship + * @param $object + */ + function add_relationship($relationship, $object, $namespaceURI = RELS_EXT_URI) { + $ds_list = $this->get_datastreams_list_as_array(); + + if (empty($ds_list['RELS-EXT'])) { + $this->add_datastream_from_string(' + + + ', 'RELS-EXT', 'Fedora object-to-object relationship metadata', 'text/xml', 'X'); + } + + $relsext = $this->get_datastream_dissemination('RELS-EXT'); + + if (substr($object, 0, 12) != 'info:fedora/') { + $object = "info:fedora/$object"; + } + + $relsextxml = new DomDocument(); + + $relsextxml->loadXML($relsext); + $description = $relsextxml->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'Description'); + if ($description->length == 0) { + $description = $relsextxml->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'description'); + } + $description=$description->item(0); + + // Create the new relationship node. + $newrel = $relsextxml->createElementNS($namespaceURI, $relationship); + + $newrel->setAttribute('rdf:resource', $object); + + $description->appendChild($newrel); + $this->modify_datastream_by_value( $relsextxml->saveXML(), 'RELS-EXT', "Fedora Object-to-Object Relationship Metadata", 'text/xml'); + //print ($description->dump_node()); + /* + $params = array( 'pid' => $this->pid, + 'relationship' => $relationship, + 'object' => $object, + 'isLiteral' => FALSE, + 'datatype' => '', + ); + + return $this->soap_call( 'addRelationship', $params ); + */ + } + + /** + * Removes the given relationship from the item's RELS-EXT and re-saves it. + * @param string $relationship + * @param string $object + */ + function purge_relationship($relationship, $object) { + $relsext = $this->get_datastream_dissemination('RELS-EXT'); + $namespaceURI = 'info:fedora/fedora-system:def/relations-external#'; + // Pre-pend a namespace prefix to recognized relationships + + switch ($relationship) { + case 'rel:isMemberOf': + case 'fedora:isMemberOf': + $relationship = "isMemberOf"; + $namespaceURI = 'info:fedora/fedora-system:def/relations-external#'; + break; + case "rel:isMemberOfCollection": + case "fedora:isMemberOfCollection": + $relationship = "isMemberOfCollection"; + $namespaceURI = 'info:fedora/fedora-system:def/relations-external#'; + break; + case "fedora:isPartOf": + $relationship = "isPartOf"; + $namespaceURI = 'info:fedora/fedora-system:def/relations-external#'; + break; + } + + if (substr($object, 0, 12) != 'info:fedora/') { + $object = "info:fedora/$object"; + } + + $relsextxml = new DomDocument(); + $relsextxml->loadXML($relsext); + $modified = FALSE; + $rels = $relsextxml->getElementsByTagNameNS($namespaceURI, $relationship); + if (!empty($rels)) { + foreach ($rels as $rel) { + if ($rel->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'resource') == $object) { + $rel->parentNode->removeChild($rel); + $modified = TRUE; + } + } + } + if ($modified) { + $this->modify_datastream_by_value( $relsextxml->saveXML(), 'RELS-EXT', "Fedora Object-to-Object Relationship Metadata", 'text/xml'); + } + return $modified; + //print ($description->dump_node()); + } + + function export_as_foxml() { + $params = array( + 'pid' => $this->pid, + 'format' => 'info:fedora/fedora-system:FOXML-1.1', + 'context' => 'migrate', + ); + $result = self::soap_call('export', $params); + return $result->objectXML; + } + + /** + * Does a search using the "query" format followed by the Fedora REST APi. + * + * @param string $pattern to search for, including wildcards. + * @param string $field The field to search on, e.g. pid, title, cDate. See http://www.fedora-commons.org/confluence/display/FCR30/REST+API#RESTAPI-findObjects for details + * @param int $max_results not used at this time + * @return Array of pid => title pairs that match the results + */ + static function find_objects_by_pattern($pattern = '*', $field = 'pid', $max_results = 100, $resultFields = array()) { + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + + $pattern = drupal_urlencode($pattern); + $done = FALSE; + $cursor = 0; + $session_token = ''; + $i = 0; + $results = array(); + while (!$done && $i < 5) { + $i++; + $url = variable_get('fedora_base_url', 'http://localhost:8080/fedora'); + if ($cursor == 0) { + $url .= "/objects?query=$field~$pattern&pid=true&title=true&resultFormat=xml&maxResults=$max_results"; + } + else { + $url .= "/objects?pid=true&title=truesessionToken=$session_token&resultFormat=xml&maxResults=$max_results"; + } + + if (count($resultFields) > 0) { + $url .= '&'.join('=true&',$resultFields).'=true'; + } + + $resultxml = do_curl($url); + + libxml_use_internal_errors(TRUE); + $resultelements = simplexml_load_string($resultxml); + if ($resultelements === FALSE) { + libxml_clear_errors(); + break; + } + $cursor += count($resultelements->resultList->objectFields); + if (count($resultelements->resultList->objectFields) < $max_results + || count($resultelements->resultList->objectFields) == 0) { + $done = TRUE; + } + foreach ($resultelements->resultList->objectFields as $obj) { + + $ret = (string)$obj->title; + if (count($resultFields) > 0) { + $ret = array('title' => $ret); + foreach ($resultFields as $field) { + $ret[$field]=(string)$obj->$field; + } + } + $results[(string)$obj->pid] = $ret; + $cursor++; + if ($cursor >= $max_results) { + $done = TRUE; + break; + } + } + $session_token = $resultelements->listSession->token; + $done = !empty($session_token); + } + return $results; + } + + function get_datastream_dissemination($dsid, $as_of_date_time = "") { + $params = array( + 'pid' => $this->pid, + 'dsID' => $dsid, + 'asOfDateTime' => $as_of_date_time, + ); + $object = self::soap_call('getDataStreamDissemination', $params); + if (!empty($object)) { + $content = $object->dissemination->stream; + $content = trim($content); + } + else { + $content = ""; + } + return $content; + } + + function get_datastream($dsid, $as_of_date_time = "") { + $params = array( + 'pid' => $this->pid, + 'dsID' => $dsid, + 'asOfDateTime' => $as_of_date_time, + ); + $object = self::soap_call('getDatastream', $params); + + return $object->datastream; + } + + function get_datastream_history($dsid) { + $params = array( + 'pid' => $this->pid, + 'dsID' => $dsid + ); + $object = self::soap_call('getDatastreamHistory', $params); + $ret = FALSE; + if (!empty($object)) { + $ret = $object->datastream; + } + + return $ret; + } + + function get_dissemination($service_definition_pid, $method_name, $parameters = array(), $as_of_date_time = null) { + $params = array( + 'pid' => $this->pid, + 'serviceDefinitionPid' => $service_definition_pid, + 'methodName' => $method_name, + 'parameters' => $parameters, + 'asOfDateTime' => $as_of_date_time, + ); + $object = self::soap_call('getDissemination', $params); + if (!empty($object)) { + $content = $object->dissemination->stream; + $content = trim($content); + } + else { + $content = ""; + } + return $content; + } + + /** + * Retrieves and returns a SimpleXML list of this item's datastreams, and stores them + * as an instance variable for caching purposes. + * + * @return SimpleXMLElement + */ + function get_datastreams_list_as_SimpleXML() { + //if ( empty( $this->datastreams_list ) ) { + $params = array( + 'pid' => $this->pid, + 'asOfDateTime' => "" + ); + + $this->datastreams_list = $this->soap_call('listDataStreams', $params); + //} + return $this->datastreams_list; + } + /** + * * DatastreamControlGroup controlGroup - String restricted to the values of "X", "M", "R", or "E" (InlineXML,Managed Content,Redirect, or External Referenced). + * String ID - The datastream ID (64 characters max). + * String versionID - The ID of the most recent datastream version + * String[] altIDs - Alternative IDs for the datastream, if any. + * String label - The Label of the datastream. + * boolean versionable - Whether the datastream is versionable. + * String MIMEType - The mime-type for the datastream, if set. + * String formatURI - The format uri for the datastream, if set. + * String createDate - The date the first version of the datastream was created. + * long size - The size of the datastream in Fedora. Only valid for inline XML metadata and managed content datastreams. + * String state - The state of the datastream. Will be "A" (active), "I" (inactive) or "D" (deleted). + * String location - If the datastream is an external reference or redirect, the url to the contents. TODO: Managed? + * String checksumType - The algorithm used to compute the checksum. One of "DEFAULT", "DISABLED", "MD5", "SHA-1", "SHA-256", "SHA-385", "SHA-512". + * String checksum - The value of the checksum represented as a hexadecimal string. + + * + * @param string $dsid + * @return datastream object + * get the mimetype size etc. in one shot. instead of iterating throught the datastream list for what we need + */ + function get_datastream_info($dsid,$as_of_date_time = ""){ + $params = array( + 'pid' => $this->pid, + 'dsID' => $dsid, + 'asOfDateTime' => $as_of_date_time + ); + + return $this->soap_call('getDatastream', $params); + + } + + /** + * Returns an associative array of this object's datastreams. Results look like this: + * + * 'DC' => + * array + * 'label' => string 'Dublin Core Record for this object' (length=34) + * 'MIMEType' => string 'text/xml' (length=8) + * 'RELS-EXT' => + * array + * 'label' => string 'RDF Statements about this object' (length=32) + * 'MIMEType' => string 'application/rdf+xml' (length=19) + * + * @return array + */ + function get_datastreams_list_as_array() { + $this->get_datastreams_list_as_SimpleXML(); + $ds_list = array(); + if ($this->datastreams_list != FALSE) { + + // This is a really annoying edge case: if there is only one + // datastream, instead of returning it as an array, only + // the single item will be returned directly. We have to + // check for this. + if (count($this->datastreams_list->datastreamDef) >= 2) { + foreach ($this->datastreams_list->datastreamDef as $ds) { + if (!is_object($ds)) { + print_r($ds); + } + $ds_list[$ds->ID]['label'] = $ds->label; + $ds_list[$ds->ID]['MIMEType'] = $ds->MIMEType; + $ds_list[$ds->ID]['URL'] = $this->url() . '/'. $ds->ID . '/'. drupal_urlencode($ds->label); + } + } + else { + $ds = $this->datastreams_list->datastreamDef; + $ds_list[$ds->ID]['label'] = $ds->label; + $ds_list[$ds->ID]['MIMEType'] = $ds->MIMEType; + $ds_list[$ds->ID]['URL'] = $this->url().'/'.$ds->ID.'/'.drupal_urlencode($ds->label); + } + } + + return $ds_list; + } + + /** + * Returns a MIME type string for the given Datastream ID. + * + * @param string $dsid + * @return string + */ + function get_mimetype_of_datastream($dsid) { + $this->get_datastreams_list_as_SimpleXML(); + + $mimetype = ''; + foreach ($datastream_list as $datastream) { + foreach ($datastream as $datastreamValue) { + if ($datastreamValue->ID == $dsid) { + return $datastreamValue->MIMEType; + } + } + } + + return ''; + } + + /** + * Currently the Fedora API call getRelationships is reporting an uncaught + * exception so we will parse the RELS-EXT ourselves and simulate the + * documented behaviour. + * @param String $relationship - filter the results to match this string. + */ + function get_relationships($relationship = NULL) { + $relationships = array(); + try { + $relsext = $this->get_datastream_dissemination('RELS-EXT'); + } + catch (exception $e) { + drupal_set_message("Error retrieving RELS-EXT of object $pid", 'error'); + return $relationships; + } + + // Parse the RELS-EXT into an associative array. + $relsextxml = new DOMDocument(); + $relsextxml->loadXML($relsext); + $relsextxml->normalizeDocument(); + $rels = $relsextxml->getElementsByTagNameNS('info:fedora/fedora-system:def/relations-external#', '*'); + + foreach ($rels as $child) { + if (empty($relationship) || preg_match("/$relationship/", $child->tagName)) { + $relationships[] = array( + 'subject' => $this->pid, + 'predicate' => $child->tagName, + 'object' => substr($child->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'resource'), 12), + ); + } + } + return $relationships; + //$children = $relsextxml->RDF->description; + //$children = $relsextxml->RDF->description; + //$params = array( 'pid' => $this->pid, + // 'relationship' => 'NULL' ); + //return $this->soap_call( 'getRelationships', $params ); + } + + /** + * Creates a RELS-EXT XML stream from the supplied array and saves it to + * the item on the server. + * @param $relationships + */ + function save_relationships($relationships) { + // Verify the array format and that it isn't empty. + if (!empty($relationships)) { + $relsextxml = '' + . ''; + + foreach ($relationships as $rel) { + if (empty($rel['subject']) || empty($rel['predicate']) || empty($rel['object']) || $rel['subject'] != 'info:fedora/'. $this->pid) { + // drupal_set_message should use parameterized variables, not interpolated. + drupal_set_message("Error with relationship format: ". $rel['subject'] . " - ". $rel['predicate'] . ' - '. $rel['object'], "error"); + return FALSE; + } + } + } + + // Do the messy work constructing the RELS-EXT XML. Because addRelationship is broken. + + return FALSE; + } + + /** + * Removes this object form the repository. + */ + function purge($log_message = 'Purged using Islandora API.', $force = FALSE) { + $params = array( + 'pid' => $this->pid, + 'logMessage' => $log_message, + 'force' => $force + ); + + return $this->soap_call('purgeObject', $params); + } + + function purge_datastream( $dsID, $start_date = NULL, $end_date = NULL, $log_message = 'Purged datastream using Islandora API', $force = FALSE) { + $params = array( + 'pid' => $this->pid, + 'dsID' => $dsID, + 'startDT' => $start_date, + 'endDT' => $end_date, + 'logMessage' => $log_message, + 'force' => $force, + ); + return $this->soap_call('purgeDatastream', $params); + } + + function url() { + global $base_url; + return $base_url . '/fedora/repository/'. $this->pid . (!empty($this->objectProfile) ? '/-/'. drupal_urlencode($this->objectProfile->objLabel) : ''); + } + + static function get_next_PID_in_namespace( $pid_namespace = '') { + if (empty($pid_namespace)) { + // Just get the first one in the config settings. + $allowed_namespaces = explode(" ", variable_get('fedora_pids_allowed', 'default: demo: changeme: Islandora: ilives: ')); + $pid_namespace = $allowed_namespaces[0]; + if (!empty($pid_namespace)) { + $pid_namespace = substr($pid_namespace, 0, strpos($pid_namespace, ":")); + } + else { + $pid_namespace = 'default'; + } + } + + $params = array( + 'numPIDs' => '', + 'pidNamespace' => $pid_namespace, + ); + + $result = self::soap_call('getNextPID', $params); + return $result->pid; + } + + static function ingest_from_FOXML($foxml) { + $params = array('objectXML' => $foxml->saveXML(), 'format' => "info:fedora/fedora-system:FOXML-1.1", 'logMessage' => "Fedora Object Ingested"); + $object = self::soap_call('ingest', $params); + return new Fedora_Item($object->objectPID); + } + + static function ingest_from_FOXML_file($foxml_file) { + $foxml = new DOMDocument(); + $foxml->load( $foxml_file ); + return self::ingest_from_FOXML($foxml); + } + + static function ingest_from_FOXML_files_in_directory($path) { + // Open the directory + $dir_handle = @opendir($path); + // Loop through the files + while ($file = readdir($dir_handle)) { + if ($file == "." || $file == ".." || strtolower(substr($file, strlen($file) - 4)) != '.xml') { + continue; + } + + try { + self::ingest_from_FOXML_file( $path . '/'. $file ); + } + catch (exception $e) { + } + } + // Close + closedir($dir_handle); + } + + function modify_object($label = '', $state = null, $ownerId = null, $logMessage = 'Modified by Islandora API', $quiet=TRUE) { + + $params = array( + 'pid' => $this->pid, + 'ownerId' => $ownerId, + 'state' => $state, + 'label' => $label, + 'logMessage' => $logMessage + ); + + return self::soap_call('modifyObject', $params, $quiet); + } + + function modify_datastream_by_value($content, $dsid, $label, $mime_type, $force = FALSE, $logMessage = 'Modified by Islandora API',$quiet=FALSE) { + $params = array( + 'pid' => $this->pid, + 'dsID' => $dsid, + 'altIDs' => NULL, + 'dsLabel' => $label, + 'MIMEType' => $mime_type, + 'formatURI' => NULL, + 'dsContent' => $content, + 'checksumType' => 'DISABLED', + 'checksum' => 'none', + 'logMessage' => $logMessage, + 'force' => $force + ); + return self::soap_call('modifyDatastreamByValue', $params,$quiet); + } + + static function soap_call( $function_name, $params_array, $quiet = FALSE ) { + if (!self::$connection_helper) { + module_load_include('inc', 'fedora_repository', 'ConnectionHelper'); + self::$connection_helper = new ConnectionHelper(); + } + switch ($function_name) { + case 'ingest': + case 'addDataStream': + case 'addRelationship': + case 'export': + case 'getDatastream': + case 'getDatastreamHistory': + case 'getNextPID': + case 'getRelationships': + case 'modifyDatastreamByValue': + case 'purgeDatastream': + case 'purgeObject': + case 'modifyObject': + $soap_client = self::$connection_helper->getSoapClient(variable_get('fedora_soap_manage_url', 'http://localhost:8080/fedora/services/management?wsdl')); + try { + if (!empty($soap_client)) { + $result = $soap_client->__soapCall($function_name, array('parameters' => $params_array)); + } + else { + watchdog(t("FEDORA_REPOSITORY"), t("Error trying to get SOAP client connection.")); + return NULL; + } + } + catch (exception $e) { + if (!$quiet) { + + if (preg_match('/org\.fcrepo\.server\.security\.xacml\.pep\.AuthzDeniedException/',$e->getMessage())) { + drupal_set_message(t('Error: Insufficient permissions to call SOAP function !fn.', array('!fn' => $function_name) ), 'error'); + } else { + drupal_set_message(t("Error trying to call SOAP function $function_name. Check watchdog logs for more information."), 'error'); + } + + watchdog(t("FEDORA_REPOSITORY"), t("Error Trying to call SOAP function !fn: !e", array('!fn' => $function_name, '!e' => $e)), NULL, WATCHDOG_ERROR); + } + return NULL; + } + break; + + default: + try { + $soap_client = self::$connection_helper->getSoapClient( variable_get('fedora_soap_url', 'http://localhost:8080/fedora/services/access?wsdl')); + if (!empty($soap_client)) { + $result = $soap_client->__soapCall($function_name, array('parameters' => $params_array)); + } + else { + watchdog(t("FEDORA_REPOSITORY"), t("Error trying to get SOAP client connection.")); + return NULL; + } + } + catch (exception $e) { + + if (!$quiet) { + watchdog(t("FEDORA_REPOSITORY"), t("Error trying to call SOAP function !fn: !e", array('!fn' => $function_name, '!e' => $e)), NULL, WATCHDOG_ERROR); + } + return NULL; + } + } + return $result; + } + + + /** + * Creates the minimal FOXML for a new Fedora object, which is then passed to + * ingest_from_FOXML to be added to the repository. + * + * @param string $pid if none given, getnextpid will be called. + * @param string $state The initial state, A - Active, I - Inactive, D - Deleted + */ + static function create_object_FOXML($pid = '', $state = 'A', $label = 'Untitled', $owner = '') { + $foxml = new DOMDocument("1.0", "UTF-8"); + $foxml->formatOutput = TRUE; + if (empty($pid)) { + // Call getNextPid + $pid = self::get_next_PID_in_namespace(); + } + if (empty($owner)) { + if (!empty($user->uid)) { // Default to current Drupal user. + $owner = $user->uid; + } + else { // We are not inside Drupal + $owner = 'fedoraAdmin'; + } + } + + $root_element = $foxml->createElement("foxml:digitalObject"); + $root_element->setAttribute("VERSION", "1.1"); + $root_element->setAttribute("PID", $pid); + $root_element->setAttribute("xmlns:foxml", "info:fedora/fedora-system:def/foxml#"); + $root_element->setAttribute("xmlns:xsl", "http://www.w3.org/2001/XMLSchema-instance"); + $root_element->setAttribute("xsl:schemaLocation", "info:fedora/fedora-system:def/foxml# http://www.fedora.info/definitions/1/0/foxml1-1.xsd"); + $foxml->appendChild($root_element); + + // FOXML object properties section + $object_properties = $foxml->createElement("foxml:objectProperties"); + $state_property = $foxml->createElement("foxml:property"); + $state_property->setAttribute("NAME", "info:fedora/fedora-system:def/model#state"); + $state_property->setAttribute("VALUE", $state); + + $label_property = $foxml->createElement("foxml:property"); + $label_property->setAttribute("NAME", "info:fedora/fedora-system:def/model#label"); + $label_property->setAttribute("VALUE", $label); + + $owner_property = $foxml->createElement("foxml:property"); + $owner_property->setAttribute("NAME", "info:fedora/fedora-system:def/model#ownerId"); + $owner_property->setAttribute("VALUE", $owner ); + + $object_properties->appendChild($state_property); + $object_properties->appendChild($label_property); + $object_properties->appendChild($owner_property); + $root_element->appendChild($object_properties); + $foxml->appendChild($root_element); + + return $foxml; + } + + static function ingest_new_item($pid = '', $state = 'A', $label = '', $owner = '') { + return self::ingest_from_FOXML(self::create_object_FOXML( $pid, $state, $label, $owner)); + } + + static function fedora_item_exists($pid) { + $item = new Fedora_Item($pid); + return $item->exists(); + } + + /******************************************************** + * Relationship Functions + ********************************************************/ + + /** + * Returns an associative array of relationships that this item has + * in its RELS-EXT. + */ +} + diff --git a/api/fedora_utils.inc b/api/fedora_utils.inc new file mode 100644 index 00000000..1d7606b1 --- /dev/null +++ b/api/fedora_utils.inc @@ -0,0 +1,88 @@ +uid == 0) { + $fedora_user = 'anonymous'; + $fedora_pass = 'anonymous'; + } + else { + $fedora_user = $user->name; + $fedora_pass = $user->pass; + } + + if (function_exists("curl_init")) { + $ch = curl_init(); + $user_agent = "Mozilla/4.0 pp(compatible; MSIE 5.01; Windows NT 5.0)"; + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); + curl_setopt($ch, CURLOPT_FAILONERROR, TRUE); // Fail on errors + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // allow redirects + curl_setopt($ch, CURLOPT_TIMEOUT, 90); // times out after 90s + curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, $return_to_variable); // return into a variable + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_USERPWD, "$fedora_user:$fedora_pass"); + //curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + if ($number_of_post_vars>0&&$post) { + curl_setopt($ch, CURLOPT_POST, $number_of_post_vars); + curl_setopt($ch, CURLOPT_POSTFIELDS, "$post"); + } + return curl_exec($ch); + } + else { + if (function_exists(drupal_set_message)) { + drupal_set_message(t('No curl support.'), 'error'); + } + return NULL; + } +} + +function fedora_available() { + $ret = do_curl(variable_get('fedora_soap_url', 'http://localhost:8080/fedora/services/management?wsdl'), 1); + // A bit of a hack but the SOAP parser will cause a fatal error if you give it the wrong URL. + return (strpos($ret, 'wsdl:definitions') != FALSE); +} + +/** + * Returns a UTF-8-encoded transcripiton of the string given in $in_str. + * @param string $in_str + * @return string A UTF-8 encoded string. + */ +function fix_encoding($in_str) { + $cur_encoding = mb_detect_encoding($in_str) ; + if ($cur_encoding == "UTF-8" && mb_check_encoding($in_str, "UTF-8")) { + return $in_str; + } + else { + return utf8_encode($in_str); + } +} + + function validPid($pid) { + $valid = FALSE; + if (strlen(trim($pid)) <= 64 && preg_match('/^([A-Za-z0-9]|-|\.)+:(([A-Za-z0-9])|-|\.|~|_|(%[0-9A-F]{2}))+$/', trim($pid))) { + $valid = TRUE; + } + + return $valid; + } + + function validDsid($dsid) { + $valid = FALSE; + if (strlen(trim($dsid)) <= 64 && preg_match('/^[a-zA-Z0-9\_\-\.]+$/', trim($dsid))) { + $valid = TRUE; + } + + return $valid; + } diff --git a/api/rels-ext.inc b/api/rels-ext.inc new file mode 100644 index 00000000..06aa4cd5 --- /dev/null +++ b/api/rels-ext.inc @@ -0,0 +1,43 @@ +get_datastream_dissemination('RELS-EXT'); + + } + + function modified() { + return !(empty(array_diff($this->relsExtArray, $this->originalRelsExtArray)) && + empty(array_diff($this->originalRelsExtArray, $this->relsExtArray))); + } + + /** + * Save the current state of the RELS-EXT array out to the repository item + * as a datastream. + */ + function save() { + + } +} + diff --git a/api/tagging.inc b/api/tagging.inc new file mode 100644 index 00000000..4156d7d4 --- /dev/null +++ b/api/tagging.inc @@ -0,0 +1,69 @@ +item = $item; + $this->load(); + } + } + + function load() { + $tagsxml = isset($this->item->datastreams[$this->tagsDSID])? $this->item->get_datastream_dissemination($this->tagsDSID) : NULL; + if (empty($tagsxml)) { + $this->tags = array(); + return FALSE; + } + $tagsdoc = new DOMDocument(); + $tagsdoc->loadXML($tagsxml); + $tags = $tagsdoc->getElementsByTagName('tag'); + foreach ($tags as $tag) { + $this->tags[] = array( + 'name' => $tag->nodeValue, + 'creator' => $tag->getAttribute('creator') + ); + } + } + + /** + * Saves an associative array of tags to a datastream. + */ + function save() { + $tagdoc = new DomDocument(); + $e_tags = new DomElement('tags'); + $tagdoc->appendChild($e_tags); + foreach ($this->tags as $tag) { + $e_tag = $tagdoc->createElement('tag', $tag['name']); + $e_tag->setAttribute('creator', (!empty($tag['creator'])) ? $tag['creator'] : ''); + $e_tags->appendChild($e_tag); + } + try { + $datastreams = $this->item->get_datastreams_list_as_array(); + if (empty($datastreams[$this->tagsDSID])) { + $this->item->add_datastream_from_string($tagdoc->saveXML(), $this->tagsDSID, 'Tags', 'text/xml', 'X'); + } + else { + $this->item->modify_datastream_by_value($tagdoc->saveXML(), $this->tagsDSID, 'Tags', 'text/xml', 'X'); + } + } + catch (exception $e) { + drupal_set_message('There was an error saving the tags datastream: !e', array('!e' => $e), 'error'); + return FALSE; + } + return TRUE; + } +} diff --git a/collection_policies/COLLECTION-COLLECTION POLICY.xml b/collection_policies/COLLECTION-COLLECTION POLICY.xml new file mode 100644 index 00000000..5888fd35 --- /dev/null +++ b/collection_policies/COLLECTION-COLLECTION POLICY.xml @@ -0,0 +1,21 @@ + + + + + + dc.title + dc.creator + dc.description + dc.date + dc.identifier + dc.language + dc.publisher + dc.rights + dc.subject + dc.relation + dcterms.temporal + dcterms.spatial + Full Text + + isMemberOfCollection + diff --git a/collection_policies/FLV-COLLECTION POLICY.xml b/collection_policies/FLV-COLLECTION POLICY.xml new file mode 100644 index 00000000..e7ea27a8 --- /dev/null +++ b/collection_policies/FLV-COLLECTION POLICY.xml @@ -0,0 +1,67 @@ + + + + + + vre:test + vre:contentmodel + STANDARD_FLV + + + + + dc.description + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.relation + dc.relation + + + dcterms.temporal + dcterms.temporal + + + dcterms.spatial + dcterms.spatial + + + fgs.DS.first.text + Full Text + + + \ No newline at end of file diff --git a/collection_policies/Image-COLLECTION POLICY.xml b/collection_policies/Image-COLLECTION POLICY.xml new file mode 100644 index 00000000..ec374632 --- /dev/null +++ b/collection_policies/Image-COLLECTION POLICY.xml @@ -0,0 +1,70 @@ + + + + + + vre:spdf + vre:contentmodel + STANDARD_IMAGE + + + + isMemberOfCollection + + + dc.description + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.relation + dc.relation + + + dcterms.temporal + dcterms.temporal + + + dcterms.spatial + dcterms.spatial + + + fgs.DS.first.text + Full Text + + + diff --git a/collection_policies/JPG-COLLECTION POLICY.xml b/collection_policies/JPG-COLLECTION POLICY.xml new file mode 100644 index 00000000..98f3520b --- /dev/null +++ b/collection_policies/JPG-COLLECTION POLICY.xml @@ -0,0 +1,70 @@ + + + + + + demo:Smiley + demo:DualResImage + ISLANDORACM + + + + isMemberOf + + + dc.description + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.relation + dc.relation + + + dcterms.temporal + dcterms.temporal + + + dcterms.spatial + dcterms.spatial + + + fgs.DS.first.text + Full Text + + + diff --git a/collection_policies/PDF-COLLECTION POLICY.xml b/collection_policies/PDF-COLLECTION POLICY.xml new file mode 100644 index 00000000..3f86bf16 --- /dev/null +++ b/collection_policies/PDF-COLLECTION POLICY.xml @@ -0,0 +1 @@ + dc.title dc.creator dc.description dc.date dc.identifier dc.language dc.publisher dc.rights dc.subject dc.relation dcterms.temporal dcterms.spatial Full Text isMemberOfCollection \ No newline at end of file diff --git a/collection_policies/PERSONAL-COLLECTION-POLICY.xml b/collection_policies/PERSONAL-COLLECTION-POLICY.xml new file mode 100644 index 00000000..be51e65b --- /dev/null +++ b/collection_policies/PERSONAL-COLLECTION-POLICY.xml @@ -0,0 +1,79 @@ + + + + + ir:ref + vre:contentmodel + REFWORKS + + + ir:ref + vre:contentmodel + STANDARD_PDF + + + ir:image + vre:contentmodel + STANDARD_IMAGE + + + + isMemberOfCollection + + + dc.description + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.relation + dc.relation + + + dcterms.temporal + dcterms.temporal + + + dcterms.spatial + dcterms.spatial + + + fgs.DS.first.text + Full Text + + + diff --git a/collection_policies/README.txt b/collection_policies/README.txt new file mode 100644 index 00000000..59165662 --- /dev/null +++ b/collection_policies/README.txt @@ -0,0 +1,7 @@ +This folder holds sample collection policy xml files. + +These are not used by the module directly from this location but should +be added as datatreams to objects with a content model property of Collection or +Community. The datastream id should be COLLECTION_POLICY. + +PERSONAL-COLLECTION-POLCIY is referenced from code do not remove \ No newline at end of file diff --git a/collection_policies/REFWORKS_COLLECTION_POLICY.xml b/collection_policies/REFWORKS_COLLECTION_POLICY.xml new file mode 100644 index 00000000..3bf8014e --- /dev/null +++ b/collection_policies/REFWORKS_COLLECTION_POLICY.xml @@ -0,0 +1,11 @@ + + + + + + ir:ref + islandora:refworksCModel + ISLANDORACM + + + diff --git a/collection_policies/RIRI COLLECTION POLICY.xml b/collection_policies/RIRI COLLECTION POLICY.xml new file mode 100644 index 00000000..8424f9e9 --- /dev/null +++ b/collection_policies/RIRI COLLECTION POLICY.xml @@ -0,0 +1,67 @@ + + + + + + vre:riri- + vre:contentmodel + STANDARD_PDF + + + + + dc.description + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.relation + dc.relation + + + dcterms.temporal + dcterms.temporal + + + dcterms.spatial + dcterms.spatial + + + fgs.DS.first.text + Full Text + + + diff --git a/collection_policies/book_collection_policy.xml b/collection_policies/book_collection_policy.xml new file mode 100644 index 00000000..4a6c4a0f --- /dev/null +++ b/collection_policies/book_collection_policy.xml @@ -0,0 +1,69 @@ + + + + + islandora + ilives:bookCModel + ISLANDORACM + + + + isMemberOfCollection + + + dc.description + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.relation + dc.relation + + + dcterms.temporal + dcterms.temporal + + + dcterms.spatial + dcterms.spatial + + + fgs.DS.first.text + Full Text + + + diff --git a/collection_policies/large_image_collection_policy.xml b/collection_policies/large_image_collection_policy.xml new file mode 100644 index 00000000..4f9793a6 --- /dev/null +++ b/collection_policies/large_image_collection_policy.xml @@ -0,0 +1,84 @@ + + + + + islandora:slide + islandora:slideCModel + ISLANDORACM + + + islandora:map + islandora:mapCModel + ISLANDORACM + + + islandora:herb + islandora:herbCModel + ISLANDORACM + + + + isMemberOfCollection + + dc.description + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.relation + dc.relation + + + dcterms.temporal + dcterms.temporal + + + dcterms.spatial + dcterms.spatial + + + fgs.DS.first.text + Full Text + + + diff --git a/collection_policies/slide_collection_policy.xml b/collection_policies/slide_collection_policy.xml new file mode 100644 index 00000000..7cc375b9 --- /dev/null +++ b/collection_policies/slide_collection_policy.xml @@ -0,0 +1,76 @@ + + + + + + + islandora:slide + islandora:slideCModel + ISLANDORACM + + + + isMemberOfCollection + + dc.description + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.relation + dc.relation + + + dcterms.temporal + dcterms.temporal + + + dcterms.spatial + dcterms.spatial + + + fgs.DS.first.text + Full Text + + + diff --git a/collection_policy.xsd b/collection_policy.xsd new file mode 100644 index 00000000..8822f103 --- /dev/null +++ b/collection_policy.xsd @@ -0,0 +1,47 @@ + + + + Islandora Collection Policy Schema + Islandora, Robertson Library, University of Prince Edward Island, 550 University Ave., Charlottetown, Prince Edward Island + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/collection_views/COLLECTION_VIEW.xml b/collection_views/COLLECTION_VIEW.xml new file mode 100644 index 00000000..7b30307d --- /dev/null +++ b/collection_views/COLLECTION_VIEW.xml @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + /fedora/repository/ + /-/ + + + + /fedora/repository/ + / + / + + + + + + + + + /fedora/repository/ + /TN + + +
+ + + + + +
-- + + + /fedora/repository/ + /-/ + + + DETAILS + -- +
+ + + + + + +
+ + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/collection_views/Collection_QUERY.txt b/collection_views/Collection_QUERY.txt new file mode 100644 index 00000000..840d0331 --- /dev/null +++ b/collection_views/Collection_QUERY.txt @@ -0,0 +1,7 @@ +select $object $title from <#ri> + where ($object $title + and $object $content + and $object + and $object ) + + order by $title \ No newline at end of file diff --git a/collection_views/Coverflow_Collection_View.xsl b/collection_views/Coverflow_Collection_View.xsl new file mode 100644 index 00000000..1e67f79f --- /dev/null +++ b/collection_views/Coverflow_Collection_View.xsl @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + +
Testing YUI's CoverFlow version 0.1 (beta)
+
+ + +
+
+ + diff --git a/collection_views/Coverflow_PRE_Collection_View.xsl b/collection_views/Coverflow_PRE_Collection_View.xsl new file mode 100644 index 00000000..e9bae87d --- /dev/null +++ b/collection_views/Coverflow_PRE_Collection_View.xsl @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + +
Testing YUI's CoverFlow version 0.1 (beta)
+
+ + +
+
+ + diff --git a/collection_views/FLV-COLLECTION VIEW(2).xml b/collection_views/FLV-COLLECTION VIEW(2).xml new file mode 100644 index 00000000..e591de97 --- /dev/null +++ b/collection_views/FLV-COLLECTION VIEW(2).xml @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +
+
+ + + + + + + + + + + + + + + + + + + + + /fedora/repository//-/ + + + /fedora/repository//OBJ/ + + + + + + + /fedora/repository//-/ + + + /fedora/repository//TN + + + +
+ + + /fedora/repository//-/ + + + + + + + + + + +
+ + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/collection_views/README.txt b/collection_views/README.txt new file mode 100644 index 00000000..ce9df576 --- /dev/null +++ b/collection_views/README.txt @@ -0,0 +1,11 @@ +This folder holds xslt files that can be used to transform the +display of a collection. These files are not used by the module from +this location but should be added as datastreams to objects that have a +content model of Collection. + +The datastream id should be COLLECTION_VIEW + +NOTE: If you add a invalid xslt to a as a collection view you will +no longer have access to that object or collection. You may have to +fire up the fedora-admin utility and move or modify the Collection_View datastream. This +is a bug but not sure when it will be fixed. \ No newline at end of file diff --git a/collection_views/REFWORKS-COLLECTION_VIEW.xml b/collection_views/REFWORKS-COLLECTION_VIEW.xml new file mode 100644 index 00000000..26d637e4 --- /dev/null +++ b/collection_views/REFWORKS-COLLECTION_VIEW.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + /fedora/repository//-/ + + + /fedora/repository//OBJ/ + + + + + + + +
+ + /fedora/repository//-/ + + + + + + + + + + +
+ + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/collection_views/SIMPLE-COLLECTION_VIEW.xml b/collection_views/SIMPLE-COLLECTION_VIEW.xml new file mode 100644 index 00000000..a01e66e0 --- /dev/null +++ b/collection_views/SIMPLE-COLLECTION_VIEW.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + /fedora/repository//-/ + + + /fedora/repository//OBJ/ + + + + + + + + + + /fedora/repository//TN + + + +
+ +
+ + /fedora/repository//-/ + + + + + + + + + + +
+ + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/collection_views/SmileyStuff-COLLECTION_VIEW.xml b/collection_views/SmileyStuff-COLLECTION_VIEW.xml new file mode 100644 index 00000000..58e28287 --- /dev/null +++ b/collection_views/SmileyStuff-COLLECTION_VIEW.xml @@ -0,0 +1,67 @@ + + + + + + + + +
+ +

+ +
+ + + +

+
+
+
+
+ + + + + + + + +
+
+ + + + /fedora/repository/ + + /FULL_SIZE + + + + + /fedora/repository/ + + /MEDIUM_SIZE + + +
+ ( Full Size ) +
+
+
+ + + + + /fedora/repository/ + /-/ + + + + +
+ +
+
+
+
diff --git a/collection_views/default-sparqltoHtml.xsl b/collection_views/default-sparqltoHtml.xsl new file mode 100644 index 00000000..2f88acb5 --- /dev/null +++ b/collection_views/default-sparqltoHtml.xsl @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + /fedora/repository//TN + + + + + /fedora/repository//-/ + + + +
+ +
+
+
\ No newline at end of file diff --git a/collection_views/simple_list_view.xml b/collection_views/simple_list_view.xml new file mode 100644 index 00000000..e8711651 --- /dev/null +++ b/collection_views/simple_list_view.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/collection_views/yui_coverflow/css/test.css b/collection_views/yui_coverflow/css/test.css new file mode 100644 index 00000000..c6f215a7 --- /dev/null +++ b/collection_views/yui_coverflow/css/test.css @@ -0,0 +1,18 @@ +body { + font-family: Arial; + font-size: 12px; + color: gray; + background: black; +} + +.title { + font-size: 18px; + font-weight: bold; +} + +#coverFlowTest .coverFlowLabel { + margin-top: 10px; + font-size: 14px; + color: #C0C0C0; + font-weight: bold; +} \ No newline at end of file diff --git a/collection_views/yui_coverflow/js/CoverFlow.js b/collection_views/yui_coverflow/js/CoverFlow.js new file mode 100644 index 00000000..3b041592 --- /dev/null +++ b/collection_views/yui_coverflow/js/CoverFlow.js @@ -0,0 +1,936 @@ +/** + * @author elmasse (Maximiliano Fierro) + * @version 0.1 beta + * + * @usage: + * + * var images = [ + * {src: 'images/ardillitaMac.jpg'}, + * {src: 'http://farm2.static.flickr.com/1380/1426855399_b4b8eccbdb.jpg?v=0'}, + * {src: 'http://farm1.static.flickr.com/69/213130158_0d1aa23576_d.jpg'} + * ]; + * var myCoverFlow = new YAHOO.ext.CoverFlow('coverFlowTest', {height: 200, width: 800, images: images, bgColor: '#C0C0C0'}); + * + * + */ + + +YAHOO.namespace("ext"); + +//(function(){ + + /** + * @class CoverFlow + * @namespace YAHOO.ext + * @constructor + * @param el {String|HTMLElement} Reference to element where CoverFlow will be rendered. + * @param config {Object} configuration object + * config.height {Number} Element height. Optional. Default: CoverFlow.DEFAULT_HEIGHT. + * config.width {Number} Element width. Optional. Default: CoverFlow.DEFAULT_WIDTH. + * config.images {Array} Array of Images. [{src:}] + * config.bgColor {String} Background color. Could be in the form #00000 or black. Optional. Default: CoverFlow.DEFAULT_BG_COLOR. + * + */ + YAHOO.ext.CoverFlow = function(el, userConfig){ + if(el) + this.init(el, userConfig || {}); + }; + + //shortcuts + var CoverFlow = YAHOO.ext.CoverFlow; + var Dom = YAHOO.util.Dom; + + + /** + * Defaults + */ + CoverFlow.DEFAULT_HEIGHT = 300; + CoverFlow.DEFAULT_WIDTH = 800; + CoverFlow.DEFAULT_BG_COLOR = '#000000'; + CoverFlow.IMAGE_SEPARATION = 50; + CoverFlow.RIGHT = 'right'; + CoverFlow.LEFT = 'left'; + CoverFlow.LABEL_CLASS = 'coverFlowLabel'; + + CoverFlow.prototype = { + //Images array (it's a sort of transient var) + images: [], + //Items array {CoverFlowItem[]} + coverFlowItems: [], + + remainingImages: 9999, + + element: null, + labelElement: null, + containerHeight: 0, + containerWidth: 0, + + imageHeightRatio: 0.6, + imageWidthRatio: 0.2, + reflectionRatio: 0.6, // this causes: imageTotalHeightRatio = imageHeightRatio + imageHeightRatio*reflectionRatio + topRatio: 0.1, + sideRatio: 0.4, + + perspectiveAngle: 20, + imageZIndex: 1000, + selectedImageZIndex: 9999, + selectedItem: 0, + + moveQueue: [], + animationWorking: false, + + init: function(el, userConfig){ + + this.element = Dom.get(el); + this.applyConfig(userConfig); + + if(userConfig.images) + this.addImages(userConfig.images); + + this.attachEventListeners(); + this.createLabelElement(); + }, + + applyConfig: function(config){ + this.containerHeight = config.height || CoverFlow.DEFAULT_HEIGHT; + this.containerWidth = config.width || CoverFlow.DEFAULT_WIDTH; + this.backgroundColor = config.bgColor || CoverFlow.DEFAULT_BG_COLOR; + + this.element.style.position = 'relative'; + this.element.style.height = this.containerHeight + 'px'; + this.element.style.width = this.containerWidth + 'px'; + this.element.style.background = this.backgroundColor; + this.element.style.overflow = 'hidden'; + }, + + addImages: function(images){ + this.images = []; + this.remainingImages = images.length; + + for(var i=0; i < images.length; i++){ + var img = images[i]; + var image = new Image(); + image.id = Dom.generateId(); + image.index = i; + image.onclick = img.onclick; + image.label = img.label; + + //hide images + image.style.visibility = 'hidden'; + image.style.display = 'none'; + //this is to maintain image order since image.onload will be called randomly + this.element.appendChild(image); + //a shortcut to not create another context to call onload + var me = this; +// image.onload = function(){ +// CoverFlow.preloadImage(me, this); // this = image +// }; + YAHOO.util.Event.on(image, 'load', this.preloadImage, image, this); + image.src = img.src; + + }; + + }, + + /** + * @function preloadImage + * @param event + * @param image + * @return void + */ + preloadImage : function(e, image){ + this.images.push(image); + this.checkAllImagesLoaded(); + }, + + checkAllImagesLoaded: function(){ + this.remainingImages--; + if(!this.remainingImages){ + this.setup(); + } + }, + + setup: function(){ + this.createCoverFlowItems(); + this.sortCoverFlowItems(); + this.initCoverFlow(); + }, + + initCoverFlow: function(){ + + for(var i=0; i < this.coverFlowItems.length; i++){ + var coverFlowItem = this.coverFlowItems[i]; + + var angle = 0; + var direction; + + if(i==0){ + coverFlowItem.setZIndex(this.selectedImageZIndex); + coverFlowItem.setLeft(this.getCenter() - coverFlowItem.element.width/2); + coverFlowItem.isSelected(true); + this.selectedItem = 0; + this.showLabel(coverFlowItem.getLabel()); + }else{ + angle = this.perspectiveAngle; + direction = CoverFlow.LEFT; + coverFlowItem.setZIndex(this.imageZIndex - i); + coverFlowItem.setLeft( this.getRightStart()+ (i - 1)* CoverFlow.IMAGE_SEPARATION); + coverFlowItem.isSelected(false); + } + coverFlowItem.setAngle(angle); + coverFlowItem.drawInPerspective(direction); + } + }, + + createLabelElement: function(){ + var label = document.createElement('div'); + label.id = Dom.generateId(); + label.style.position = 'absolute'; + label.style.top = this.getFooterOffset() + 'px'; + label.innerHTML = ' '; + label.style.textAlign = 'center'; + label.style.width = this.containerWidth + 'px'; + label.style.zIndex = this.selectedImageZIndex + 10; + label.className = CoverFlow.LABEL_CLASS; + this.labelElement = this.element.appendChild(label); + }, + + showLabel: function(text){ + if(text) + this.labelElement.innerHTML = text; + else + this.labelElement.innerHTML = ''; + }, + + attachEventListeners: function(){ + new YAHOO.util.KeyListener(this.element, { keys:39 }, + { fn:this.selectNext, + scope:this, + correctScope:true } ).enable(); + + new YAHOO.util.KeyListener(this.element, { keys:37 }, + { fn:this.selectPrevious, + scope:this, + correctScope:true } ).enable(); + + + }, + + select: function(e,coverFlowItem){ + var distance = this.selectedItem - coverFlowItem.index; + if(distance < 0){ + for(var i=0; i < -distance; i++) + this.selectNext(); + }else{ + for(var i=0; i < distance; i++) + this.selectPrevious(); + } + }, + + + selectNext: function(){ + if(this.animationWorking){ + this.moveQueue.push('moveLeft'); + return; + } + + var animateItems = []; + + for(var i=0; i < this.coverFlowItems.length; i++){ + var coverFlowItem = this.coverFlowItems[i]; + var isLast = (this.selectedItem == this.coverFlowItems.length -1); + if(!isLast){ + var distance = i-this.selectedItem; + + if(distance == 0){// selected + coverFlowItem.setZIndex(this.imageZIndex); + coverFlowItem.isSelected(false); + animateItems.push({item: coverFlowItem, attribute:{angle: {start: 0, end: this.perspectiveAngle} } }); + + coverFlowItem = this.coverFlowItems[++i]; + coverFlowItem.isSelected(true); + this.showLabel(coverFlowItem.getLabel()); + animateItems.push({item: coverFlowItem, attribute:{angle: {start: this.perspectiveAngle, end: 0} } }); + + }else{ + animateItems.push({item: coverFlowItem, attribute: {left: {start:coverFlowItem.getLeft(), end: coverFlowItem.getLeft() - CoverFlow.IMAGE_SEPARATION} }}); + } + } + } + + var animation = new CoverFlowAnimation({ + direction: CoverFlow.LEFT, + center: this.getCenter(), + startLeftPos: this.getLeftStart(), + startRightPos: this.getRightStart() + }, + animateItems, 0.5); + + animation.onStart.subscribe(this.handleAnimationWorking, this); + animation.onComplete.subscribe(this.handleQueuedMove, this); + + animation.animate(); + + if(this.selectedItem + 1 < this.coverFlowItems.length) + this.selectedItem++; + }, + + selectPrevious: function(){ + if(this.animationWorking){ + this.moveQueue.push('moveRight'); + return; + } + + var animateItems = []; + + for(var i=0; i < this.coverFlowItems.length; i++){ + var coverFlowItem = this.coverFlowItems[i]; + var isFirst = (this.selectedItem == 0); + var distance = i-this.selectedItem; + if(!isFirst){ + if(distance == - 1){ + coverFlowItem.setZIndex(this.selectedImageZIndex); + coverFlowItem.isSelected(true); + this.showLabel(coverFlowItem.getLabel()); + animateItems.push({item: coverFlowItem, attribute: {angle: {start: this.perspectiveAngle, end: 0}}}); + + coverFlowItem = this.coverFlowItems[++i]; + coverFlowItem.isSelected(false); + coverFlowItem.setZIndex(this.imageZIndex); + animateItems.push({item: coverFlowItem, attribute: {angle: {start: 0, end: this.perspectiveAngle}}}); + }else{ + coverFlowItem.setZIndex(coverFlowItem.getZIndex() - 1); + animateItems.push({item: coverFlowItem, attribute: {left: {start:coverFlowItem.getLeft(), end: coverFlowItem.getLeft() + CoverFlow.IMAGE_SEPARATION} }}); + } + } + } + var animation = new CoverFlowAnimation({ + direction: CoverFlow.RIGHT, + center: this.getCenter(), + startLeftPos: this.getLeftStart(), + startRightPos: this.getRightStart() + }, + animateItems, 0.5); + + animation.onStart.subscribe(this.handleAnimationWorking, this); + animation.onComplete.subscribe(this.handleQueuedMove, this); + + animation.animate(); + + if(this.selectedItem > 0) + this.selectedItem--; + }, + + handleAnimationWorking: function(a, b, cf){ + cf.animationWorking = true; + }, + + handleQueuedMove: function(msg, data, cf){ + cf.animationWorking = false; + + var next = cf.moveQueue.pop(); + if(next == 'moveLeft') + cf.selectNext(); + if(next == 'moveRight') + cf.selectPrevious(); + }, + + getCenter: function(){ + return this.containerWidth / 2; + }, + + getRightStart: function() { + return this.containerWidth - this.sideRatio * this.containerWidth; + }, + + getLeftStart: function() { + return this.sideRatio * this.containerWidth; + }, + + sortCoverFlowItems: function(){ + function sortFunction(aCoverFlowItem, bCoverFlowItem){ + return aCoverFlowItem.index - bCoverFlowItem.index; + } + + this.coverFlowItems.sort(sortFunction); + }, + + createCoverFlowItems: function(){ + this.coverFlowItems = []; + for(var i=0; i this.getMaxImageHeight() && image.width <= this.getMaxImageWidth()){ + height = ((image.height / this.getMaxImageHeight())) * image.height; + } + if(image.height <= this.getMaxImageHeight() && image.width > this.getMaxImageWidth()){ + height = ((image.width / this.getMaxImageWidth())) * image.height; + } + if(image.height > this.getMaxImageHeight() && image.width > this.getMaxImageWidth()){ + if(image.height > image.width) + height = ((this.getMaxImageHeight() / image.height)) * image.height; + else + height = ((this.getMaxImageWidth() / image.width)) * image.height; + } + return height; + }, + + scaleWidth: function(image){ + var width = 0; + if(image.height <= this.getMaxImageHeight() && image.width <= this.getMaxImageWidth()){ + width = image.width; + } + if(image.height > this.getMaxImageHeight() && image.width <= this.getMaxImageWidth()){ + width = ((image.height / this.getMaxImageHeight())) * image.width; + } + if(image.height <= this.getMaxImageHeight() && image.width > this.getMaxImageWidth()){ + width = ((image.width / this.getMaxImageWidth())) * image.width; + } + if(image.height > this.getMaxImageHeight() && image.width > this.getMaxImageWidth()){ + if(image.height > image.width) + width = ((this.getMaxImageHeight() / image.height)) * image.width; + else + width = ((this.getMaxImageWidth() / image.width)) * image.width; + } + return width; + }, + + + getMaxImageHeight: function(){ + return (this.containerHeight * this.imageHeightRatio); + }, + + getMaxImageWidth: function(){ + return (this.containerWidth * this.imageWidthRatio); + }, + + getTopOffset: function(){ + return this.containerHeight * this.topRatio; + }, + + getFooterOffset: function(){ + return this.containerHeight * (this.topRatio + this.imageHeightRatio); + } + }; + + + /** + * @class CoverFlowItem + * + */ + CoverFlowItem = function(image, config){ + if(image) + this.init(image, config); + }; + + CoverFlowItem.prototype = { + canvas: null, + element: null, + index: null, + id: null, + angle: 0, + selected: false, + onclickFn: null, + selectedOnclickFn: null, + label: null, + + onSelected: null, + + init: function(image, config){ + var scaledWidth = config.scaledWidth; + var scaledHeight = config.scaledHeight; + var reflectionRatio = config.reflectionRatio; + var bgColor = config.bgColor; + + this.id = image.id; + this.index = image.index; + this.onclickFn = config.onclick; + this.selectedOnclickFn = image.onclick; + this.label = image.label; + var parent = image.parentNode; + this.canvas = this.createImageCanvas(image,scaledWidth,scaledHeight,reflectionRatio, bgColor); + this.element = this.canvas.cloneNode(false); + this.element.id = this.id; + parent.replaceChild(this.element, image); + + this.onSelected = new YAHOO.util.CustomEvent('onSelected', this); + this.onSelected.subscribe(this.handleOnclick); + + }, + + getLabel: function(){ + return this.label; + }, + + handleOnclick: function(){ + YAHOO.util.Event.removeListener(this.element, 'click'); + if(!this.selected){ + YAHOO.util.Event.addListener(this.element, 'click', this.onclickFn.fn, this, this.onclickFn.scope); + }else{ + if(this.selectedOnclickFn && this.selectedOnclickFn.fn) + YAHOO.util.Event.addListener(this.element, 'click', this.selectedOnclickFn.fn, this, this.selectedOnclickFn.scope); + else + YAHOO.util.Event.addListener(this.element, 'click', this.selectedOnclickFn); + } + }, + + isSelected: function(selected){ + this.selected = selected; + this.onSelected.fire(); + }, + + setAngle: function(angle){ + this.angle = angle; + }, + + getAngle: function(){ + return this.angle; + }, + + setTop: function(top){ + this.element.style.top = top + 'px'; + }, + + setLeft: function(left){ + this.element.style.left = left + 'px'; + }, + + getLeft: function(){ + var ret = this.element.style.left; + return new Number(ret.replace("px", "")); + }, + + getZIndex: function(){ + return this.element.style.zIndex; + }, + + setZIndex: function(zIndex){ + this.element.style.zIndex = zIndex; + }, + + createImageCanvas: function(image, sWidth, sHeight, reflectionRatio, bgColor){ + + var imageCanvas = document.createElement('canvas'); + + if(imageCanvas.getContext){ + + var scaledWidth = sWidth; + var scaledHeight = sHeight; + var reflectionHeight = scaledHeight * reflectionRatio; + + imageCanvas.height = scaledHeight + reflectionHeight; + imageCanvas.width = scaledWidth; + + var ctx = imageCanvas.getContext('2d'); + + ctx.clearRect(0, 0, imageCanvas.width, imageCanvas.height); + ctx.globalCompositeOperation = 'source-over'; + ctx.fillStyle = 'rgba(0, 0, 0, 1)'; + ctx.fillRect(0, 0, imageCanvas.width, imageCanvas.height); + + //draw the reflection image + ctx.save(); + ctx.translate(0, (2*scaledHeight)); + ctx.scale(1, -1); + ctx.drawImage(image, 0, 0, scaledWidth, scaledHeight); + ctx.restore(); + //create the gradient effect + ctx.save(); + ctx.translate(0, scaledHeight); + ctx.globalCompositeOperation = 'destination-out'; + var grad = ctx.createLinearGradient( 0, 0, 0, scaledHeight); + grad.addColorStop(1, 'rgba(0, 0, 0, 1)'); + grad.addColorStop(0, 'rgba(0, 0, 0, 0.75)'); + ctx.fillStyle = grad; + ctx.fillRect(0, 0, scaledWidth, scaledHeight); + //apply the background color to the gradient + ctx.globalCompositeOperation = 'destination-over'; + ctx.fillStyle = bgColor; '#000'; + ctx.globalAlpha = 0.8; + ctx.fillRect(0, 0 , scaledWidth, scaledHeight); + ctx.restore(); + //draw the image + ctx.save(); + ctx.translate(0, 0); + ctx.globalCompositeOperation = 'source-over'; + ctx.drawImage(image, 0, 0, scaledWidth, scaledHeight); + ctx.restore(); + + return imageCanvas; + } + }, + + drawInPerspective: function(direction, frameSize){ + var canvas = this.element; + var image = this.canvas; + var angle = Math.ceil(this.angle); + var ctx; + var originalWidth = image.width; + var originalHeight = image.height; + var destinationWidth = destinationWidth || originalWidth; // for future use + var destinationHeight = destinationHeight || originalHeight; // for future use + + var perspectiveCanvas = document.createElement('canvas'); + perspectiveCanvas.height = destinationHeight; + perspectiveCanvas.width = destinationWidth; + var perspectiveCtx = perspectiveCanvas.getContext('2d'); + + var alpha = angle * Math.PI/180; // Math uses radian + + if(alpha > 0){ // if we have an angle greater than 0 then apply the perspective + var right = (direction == CoverFlow.RIGHT); + + var initialX=0, finalX=0, initialY=0, finalY=0; + + frameSize = frameSize || 1; + var xDes, yDes; + var heightDes, widthDes; + var perspectiveWidht = destinationWidth; + + var frameFactor = frameSize / originalWidth; + var frames = Math.floor(originalWidth / frameSize); + + var widthSrc = frameSize ; + var heightSrc = originalHeight; + + for(var i=0; i < frames; i++){ + var xSrc = (i) * frameSize; + var ySrc = 0; + var betaTan = 0; + width = destinationWidth * (i) * frameFactor; + horizon = destinationHeight / 2; + + if(right){ + betaTan = horizon/((Math.tan(alpha)*horizon) + width); + xDes = (betaTan*width)/(Math.tan(alpha) + betaTan); + yDes = Math.tan(alpha) * xDes; + + if(i == frames -1){ + finalX=xDes; + finalY=yDes; + } + }else{ + betaTan = horizon/((Math.tan(alpha)*horizon) +(destinationWidth-width)); + xDes = (Math.tan(alpha)*(destinationWidth) + (betaTan * width))/(Math.tan(alpha) + betaTan); + yDes = -Math.tan(alpha)*xDes + (Math.tan(alpha)*(destinationWidth)); + + if(i == 0){ + initialX = xDes; + initialY = yDes; + finalX = destinationWidth; + finalY = 0; + } + } + + heightDes = destinationHeight - (2*yDes); + widthDes = heightDes / destinationHeight * destinationWidth; + + perspectiveCtx.drawImage(image, xSrc, ySrc, widthSrc, heightSrc, xDes, yDes, widthDes, heightDes); + + } + + perspectiveWidth = finalX - initialX; + originalCanvasWidth = destinationWidth; + canvas.width = perspectiveWidth; + + ctx = canvas.getContext('2d'); + + //remove exceeded pixels + ctx.beginPath(); + if(right){ + ctx.moveTo(0, 0); + ctx.lineTo(finalX, finalY); + ctx.lineTo(finalX, finalY + (destinationHeight - 2*finalY)); + ctx.lineTo(0, destinationHeight); + ctx.lineTo(0,0); + }else{ + var initialX1 = initialX - (originalCanvasWidth - perspectiveWidth); + var finalX1 = finalX - (originalCanvasWidth - perspectiveWidth); + ctx.moveTo(0, initialY); + ctx.lineTo(finalX1, finalY); + ctx.lineTo(finalX1, destinationHeight); + ctx.lineTo(initialX1, initialY + (destinationHeight - 2*initialY)); + ctx.lineTo(0, initialY); + } + ctx.closePath(); + ctx.clip(); + + ctx.drawImage(perspectiveCanvas, initialX, 0, perspectiveWidth, destinationHeight, 0, 0, perspectiveWidth, destinationHeight); + + }else{ + + canvas.width = perspectiveCanvas.width; + canvas.height = perspectiveCanvas.height; + perspectiveCtx.drawImage(image, 0, 0, originalWidth, originalHeight, 0, 0, destinationWidth, destinationHeight); + ctx = canvas.getContext('2d'); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(perspectiveCanvas, 0, 0); + } + } + + }; + + /** + * @class CoverFlowAnimation + * @requires YAHOO.util.AnimMgr + */ + CoverFlowAnimation = function(config, animationItems, duration){ + this.init(config, animationItems, duration); + }; + + CoverFlowAnimation.prototype = { + direction: null, + + center: null, + + startLeftPos: null, + + startRightPos: null, + + animationItems: null, + + method : YAHOO.util.Easing.easeNone, + + animated: false, + + startTime: null, + + actualFrames : 0, + + useSeconds : true, // default to seconds + + currentFrame : 0, + + totalFrames : YAHOO.util.AnimMgr.fps, + + init: function(config, animationItems, duration){ + this.direction = config.direction; + this.center = config.center; + this.startLeftPos = config.startLeftPos; + this.startRightPos = config.startRightPos; + this.animationItems = animationItems; + this.duration = duration || 1; + this.registerEvents(); + }, + + registerEvents: function(){ + /** + * Custom event that fires after onStart, useful in subclassing + * @private + */ + this._onStart = new YAHOO.util.CustomEvent('_start', this, true); + + /** + * Custom event that fires when animation begins + * Listen via subscribe method (e.g. myAnim.onStart.subscribe(someFunction) + * @event onStart + */ + this.onStart = new YAHOO.util.CustomEvent('start', this); + + /** + * Custom event that fires between each frame + * Listen via subscribe method (e.g. myAnim.onTween.subscribe(someFunction) + * @event onTween + */ + this.onTween = new YAHOO.util.CustomEvent('tween', this); + + /** + * Custom event that fires after onTween + * @private + */ + this._onTween = new YAHOO.util.CustomEvent('_tween', this, true); + + /** + * Custom event that fires when animation ends + * Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction) + * @event onComplete + */ + this.onComplete = new YAHOO.util.CustomEvent('complete', this); + /** + * Custom event that fires after onComplete + * @private + */ + this._onComplete = new YAHOO.util.CustomEvent('_complete', this, true); + + this._onStart.subscribe(this.doOnStart); + this._onTween.subscribe(this.doOnTween); + this._onComplete.subscribe(this.doOnComplete); + + }, + + isAnimated : function() { + return this.animated; + }, + + getStartTime : function() { + return this.startTime; + }, + + doMethod: function(start, end) { + return this.method(this.currentFrame, start, end - start, this.totalFrames); + }, + + animate : function() { + if ( this.isAnimated() ) { + return false; + } + + this.currentFrame = 0; + + this.totalFrames = ( this.useSeconds ) ? Math.ceil(YAHOO.util.AnimMgr.fps * this.duration) : this.duration; + + if (this.duration === 0 && this.useSeconds) { // jump to last frame if zero second duration + this.totalFrames = 1; + } + YAHOO.util.AnimMgr.registerElement(this); + return true; + }, + + stop : function(finish) { + if (!this.isAnimated()) { // nothing to stop + return false; + } + + if (finish) { + this.currentFrame = this.totalFrames; + this._onTween.fire(); + } + YAHOO.util.AnimMgr.stop(this); + }, + + doOnStart : function() { + this.onStart.fire(); + + this.runtimeItems = []; + for (var i=0; i 0){ + runtimeItem.attribute[attr].perspectiveDirection = this.direction; + runtimeItem.attribute[attr].center = true; + }else{ + runtimeItem.attribute[attr].perspectiveDirection = this.direction == CoverFlow.RIGHT ? CoverFlow.LEFT : CoverFlow.RIGHT; + runtimeItem.attribute[attr].center = false; + } + } + } + this.runtimeItems.push(runtimeItem); + }, + + setItemAttributes: function(item){ + + for(var attr in item.attribute){ + + var value = Math.ceil(this.doMethod(item.attribute[attr].start, item.attribute[attr].end)); + + if(attr == 'angle'){ + item.item.setAngle(value); + var frameSize = Math.ceil(this.doMethod(3, 1)); + item.item.drawInPerspective(item.attribute[attr].perspectiveDirection, frameSize); + var left; + if(item.attribute[attr].center){ + left = this.doMethod(item.item.getLeft(), this.center - item.item.element.width/2); + }else{ + if(this.direction == CoverFlow.LEFT) + left = this.doMethod(item.item.getLeft(), this.startLeftPos - item.item.element.width); + else + left = this.doMethod(item.item.getLeft(), this.startRightPos); + } + item.item.setLeft(Math.ceil(left)); + + }else{ + item.item.setLeft(value); + } + } + } + }; + +//}); \ No newline at end of file diff --git a/collection_views/yui_coverflow/js/test.js b/collection_views/yui_coverflow/js/test.js new file mode 100644 index 00000000..7ba4d637 --- /dev/null +++ b/collection_views/yui_coverflow/js/test.js @@ -0,0 +1,37 @@ + + + +YAHOO.util.Event.onDOMReady(function(){ + + var images = [ + {src: 'images/ardillitaMac.jpg', label: 'Ardileta!', onclick: function(){alert('image1');}}, + {src: 'http://farm2.static.flickr.com/1380/1426855399_b4b8eccbdb.jpg?v=0'}, + {src: 'http://farm1.static.flickr.com/69/213130158_0d1aa23576_d.jpg'}, + {src: 'http://farm1.static.flickr.com/69/213130158_0d1aa23576_d.jpg'}, + {src: 'images/msn2.jpg', label: 'My Mac'}, + {src: 'images/msn2.jpg', label: 'My Mac again...'} + + ]; + var myCoverFlow = new YAHOO.ext.CoverFlow('coverFlowTest', {height: 200, width: 600, images: images}); + + function moveLeft(e, coverFlow){ + coverFlow.selectNext(); + } + function moveRight(e, coverFlow){ + coverFlow.selectPrevious(); + } + var myMoveLeftBtn = new YAHOO.widget.Button('moveLeftButton', {onclick: {fn: moveLeft, obj: myCoverFlow}}); + var myMoveRightBtn = new YAHOO.widget.Button('moveRightButton', {onclick: {fn: moveRight, obj: myCoverFlow}}); + + + var otherImages = [ + {src: 'images/ardillitaMac.jpg', label: 'Ardileta!', onclick: function(){alert('image1');}}, + {src: 'images/msn2.jpg', label: 'My Mac'}, + {src: 'images/msn2.jpg', label: 'My Mac again...'} + + ]; + var anotherCoverFlow = new YAHOO.ext.CoverFlow('anotherCoverFlowTest', {height: 150, width: 500, images: otherImages, bgColor: '#C0C0C0'}); + + + +}); \ No newline at end of file diff --git a/content_modeller/.buildpath b/content_modeller/.buildpath new file mode 100644 index 00000000..606f236d --- /dev/null +++ b/content_modeller/.buildpath @@ -0,0 +1,5 @@ + + + + + diff --git a/content_modeller/.project b/content_modeller/.project new file mode 100644 index 00000000..ddc88b18 --- /dev/null +++ b/content_modeller/.project @@ -0,0 +1,28 @@ + + + Islandora Content Modeler + + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.dltk.core.scriptbuilder + + + + + + org.eclipse.php.core.PHPNature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/content_modeller/.settings/.jsdtscope b/content_modeller/.settings/.jsdtscope new file mode 100644 index 00000000..3c58e917 --- /dev/null +++ b/content_modeller/.settings/.jsdtscope @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/content_modeller/.settings/org.eclipse.php.core.prefs b/content_modeller/.settings/org.eclipse.php.core.prefs new file mode 100644 index 00000000..6ebb55f7 --- /dev/null +++ b/content_modeller/.settings/org.eclipse.php.core.prefs @@ -0,0 +1,3 @@ +#Mon May 17 18:04:49 CDT 2010 +eclipse.preferences.version=1 +include_path=0;/islandora_content_modeler diff --git a/content_modeller/.settings/org.eclipse.wst.jsdt.ui.superType.container b/content_modeller/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 00000000..3bd5d0a4 --- /dev/null +++ b/content_modeller/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/content_modeller/.settings/org.eclipse.wst.jsdt.ui.superType.name b/content_modeller/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 00000000..05bd71b6 --- /dev/null +++ b/content_modeller/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/content_modeller/css/content_modeller.css b/content_modeller/css/content_modeller.css new file mode 100644 index 00000000..e4834b83 --- /dev/null +++ b/content_modeller/css/content_modeller.css @@ -0,0 +1,33 @@ +.contentModeller .collection +{ + width: 400px; + float: left; +} + +.contentModeller .model +{ + width: 475px; + float: right; +} + +.contentModeller img +{ + width: 16px; + padding: 0px; + vertical-align: middle; + cursor: hand; +} + +.contentModeller .ajaxForm +{ + margin-top: 25px; + padding: 10px; + width:300px; + border: 1px dashed black; + display: none; +} + +.contentModeller #ajaxBusy +{ + display: none; +} diff --git a/content_modeller/css/jquery.jnotify.css b/content_modeller/css/jquery.jnotify.css new file mode 100644 index 00000000..e3ab53aa --- /dev/null +++ b/content_modeller/css/jquery.jnotify.css @@ -0,0 +1,16 @@ +.jnotify-item +{ + height: auto; + padding: 4px 4px 4px 4px; + margin: 0 0 5px 0; + display: block; + position: relative; +} + +.jnotify-item-close +{ + float: right; + margin-left: 2px; +} + + diff --git a/content_modeller/css/jquery.treeview.css b/content_modeller/css/jquery.treeview.css new file mode 100644 index 00000000..94de11f8 --- /dev/null +++ b/content_modeller/css/jquery.treeview.css @@ -0,0 +1,68 @@ +.treeview, .treeview ul { + padding: 0; + margin: 0; + list-style: none; +} + +.treeview ul { + + margin-top: 4px; +} + +.treeview .hitarea { + background: url(../images/treeview-default.gif) -64px -25px no-repeat; + height: 16px; + width: 16px; + margin-left: -16px; + float: left; + cursor: pointer; +} +/* fix for IE6 */ +* html .hitarea { + display: inline; + float:none; +} + +.treeview li { + margin: 0; + padding: 3px 0pt 3px 16px; +} + +.treeview a.selected { + background-color: #eee; +} + +#treecontrol { margin: 1em 0; display: none; } + +.treeview .hover { color: red; cursor: pointer; } + +.treeview li { background: url(../images/treeview-default-line.gif) 0 0 no-repeat; } +.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; } + +.treeview .expandable-hitarea { background-position: -80px -3px; } + +.treeview li.last { background-position: 0 -1766px } +.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(../images/treeview-default.gif); } +.treeview li.lastCollapsable { background-position: 0 -111px } +.treeview li.lastExpandable { background-position: -32px -67px } + +.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; } + +.treeview-red li { background-image: url(../images/treeview-red-line.gif); } +.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(../images/treeview-red.gif); } + +.treeview-black li { background-image: url(../images/treeview-black-line.gif); } +.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(../images/treeview-black.gif); } + +.treeview-gray li { background-image: url(../images/treeview-gray-line.gif); } +.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(../images/treeview-gray.gif); } + +.treeview-famfamfam li { background-image: url(../images/treeview-famfamfam-line.gif); } +.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(../images/treeview-famfamfam.gif); } + + +.filetree li { padding: 3px 0 2px 16px; } +.filetree span.folder, .filetree span.file { padding: 1px 0 1px 20px; } +.filetree span.folder { background: url(../images/folder.gif) 0 0 no-repeat; } +.filetree li.expandable span.folder { background: url(../images/folder-closed.gif) 0 0 no-repeat; } +.filetree span.file { background: url(../images/file.gif) 0 0 no-repeat; } diff --git a/content_modeller/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png b/content_modeller/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 00000000..5b5dab2a Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/content_modeller/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png b/content_modeller/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png new file mode 100644 index 00000000..ac8b229a Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png differ diff --git a/content_modeller/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png b/content_modeller/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 00000000..ad3d6346 Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/content_modeller/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png b/content_modeller/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 00000000..42ccba26 Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/content_modeller/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png b/content_modeller/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 00000000..5a46b47c Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/content_modeller/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png b/content_modeller/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100644 index 00000000..86c2baa6 Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/content_modeller/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png b/content_modeller/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 00000000..4443fdc1 Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/content_modeller/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/content_modeller/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 00000000..7c9fa6c6 Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/content_modeller/css/smoothness/images/ui-icons_222222_256x240.png b/content_modeller/css/smoothness/images/ui-icons_222222_256x240.png new file mode 100644 index 00000000..b273ff11 Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-icons_222222_256x240.png differ diff --git a/content_modeller/css/smoothness/images/ui-icons_2e83ff_256x240.png b/content_modeller/css/smoothness/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 00000000..09d1cdc8 Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-icons_2e83ff_256x240.png differ diff --git a/content_modeller/css/smoothness/images/ui-icons_454545_256x240.png b/content_modeller/css/smoothness/images/ui-icons_454545_256x240.png new file mode 100644 index 00000000..59bd45b9 Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-icons_454545_256x240.png differ diff --git a/content_modeller/css/smoothness/images/ui-icons_888888_256x240.png b/content_modeller/css/smoothness/images/ui-icons_888888_256x240.png new file mode 100644 index 00000000..6d02426c Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-icons_888888_256x240.png differ diff --git a/content_modeller/css/smoothness/images/ui-icons_cd0a0a_256x240.png b/content_modeller/css/smoothness/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 00000000..2ab019b7 Binary files /dev/null and b/content_modeller/css/smoothness/images/ui-icons_cd0a0a_256x240.png differ diff --git a/content_modeller/css/smoothness/jquery-ui-1.8.1.custom.css b/content_modeller/css/smoothness/jquery-ui-1.8.1.custom.css new file mode 100644 index 00000000..33d73634 --- /dev/null +++ b/content_modeller/css/smoothness/jquery-ui-1.8.1.custom.css @@ -0,0 +1,486 @@ +/* +* jQuery UI CSS Framework +* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +*/ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + +/* +* jQuery UI CSS Framework +* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +*/ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; } +.ui-widget-content a { color: #222222; } +.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } +.ui-widget-header a { color: #222222; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/* Resizable +----------------------------------*/ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Accordion +----------------------------------*/ +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } +/* IE7-/Win - Fix extra vertical space in lists */ +.ui-accordion a { zoom: 1; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; }/* Autocomplete +----------------------------------*/ +.ui-autocomplete { position: absolute; cursor: default; } +.ui-autocomplete-loading { background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; } + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +/* Menu +----------------------------------*/ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} +/* Button +----------------------------------*/ + +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; } +.ui-button-text-only .ui-button-text { padding: .4em 1em; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button { padding: .4em 1em; } + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 7px; } +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ + + + + + +/* Dialog +----------------------------------*/ +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } +.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* Slider +----------------------------------*/ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs +----------------------------------*/ +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } +/* Datepicker +----------------------------------*/ +.ui-datepicker { width: 17em; padding: .2em .2em 0; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* Progressbar +----------------------------------*/ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/content_modeller/images/add.png b/content_modeller/images/add.png new file mode 100644 index 00000000..306d3d89 Binary files /dev/null and b/content_modeller/images/add.png differ diff --git a/content_modeller/images/ajax-loader.gif b/content_modeller/images/ajax-loader.gif new file mode 100644 index 00000000..c4ab0a24 Binary files /dev/null and b/content_modeller/images/ajax-loader.gif differ diff --git a/content_modeller/images/blue_down.png b/content_modeller/images/blue_down.png new file mode 100644 index 00000000..b81602e6 Binary files /dev/null and b/content_modeller/images/blue_down.png differ diff --git a/content_modeller/images/blue_up.png b/content_modeller/images/blue_up.png new file mode 100644 index 00000000..0d80c322 Binary files /dev/null and b/content_modeller/images/blue_up.png differ diff --git a/content_modeller/images/edit.gif b/content_modeller/images/edit.gif new file mode 100644 index 00000000..0222e1dc Binary files /dev/null and b/content_modeller/images/edit.gif differ diff --git a/content_modeller/images/file.gif b/content_modeller/images/file.gif new file mode 100644 index 00000000..7e621679 Binary files /dev/null and b/content_modeller/images/file.gif differ diff --git a/content_modeller/images/folder-closed.gif b/content_modeller/images/folder-closed.gif new file mode 100644 index 00000000..54110788 Binary files /dev/null and b/content_modeller/images/folder-closed.gif differ diff --git a/content_modeller/images/folder.gif b/content_modeller/images/folder.gif new file mode 100644 index 00000000..2b31631c Binary files /dev/null and b/content_modeller/images/folder.gif differ diff --git a/content_modeller/images/minus.gif b/content_modeller/images/minus.gif new file mode 100644 index 00000000..47fb7b76 Binary files /dev/null and b/content_modeller/images/minus.gif differ diff --git a/content_modeller/images/plus.gif b/content_modeller/images/plus.gif new file mode 100644 index 00000000..69066216 Binary files /dev/null and b/content_modeller/images/plus.gif differ diff --git a/content_modeller/images/purge.gif b/content_modeller/images/purge.gif new file mode 100644 index 00000000..b3037e09 Binary files /dev/null and b/content_modeller/images/purge.gif differ diff --git a/content_modeller/images/red_info.png b/content_modeller/images/red_info.png new file mode 100644 index 00000000..017b5945 Binary files /dev/null and b/content_modeller/images/red_info.png differ diff --git a/content_modeller/images/remove.png b/content_modeller/images/remove.png new file mode 100644 index 00000000..282e4478 Binary files /dev/null and b/content_modeller/images/remove.png differ diff --git a/content_modeller/images/treeview-black-line.gif b/content_modeller/images/treeview-black-line.gif new file mode 100644 index 00000000..e5496877 Binary files /dev/null and b/content_modeller/images/treeview-black-line.gif differ diff --git a/content_modeller/images/treeview-black.gif b/content_modeller/images/treeview-black.gif new file mode 100644 index 00000000..d549b9fc Binary files /dev/null and b/content_modeller/images/treeview-black.gif differ diff --git a/content_modeller/images/treeview-default-line.gif b/content_modeller/images/treeview-default-line.gif new file mode 100644 index 00000000..37114d30 Binary files /dev/null and b/content_modeller/images/treeview-default-line.gif differ diff --git a/content_modeller/images/treeview-default.gif b/content_modeller/images/treeview-default.gif new file mode 100644 index 00000000..a12ac52f Binary files /dev/null and b/content_modeller/images/treeview-default.gif differ diff --git a/content_modeller/images/treeview-famfamfam-line.gif b/content_modeller/images/treeview-famfamfam-line.gif new file mode 100644 index 00000000..6e289cec Binary files /dev/null and b/content_modeller/images/treeview-famfamfam-line.gif differ diff --git a/content_modeller/images/treeview-famfamfam.gif b/content_modeller/images/treeview-famfamfam.gif new file mode 100644 index 00000000..0cb178e8 Binary files /dev/null and b/content_modeller/images/treeview-famfamfam.gif differ diff --git a/content_modeller/images/treeview-gray-line.gif b/content_modeller/images/treeview-gray-line.gif new file mode 100644 index 00000000..37600447 Binary files /dev/null and b/content_modeller/images/treeview-gray-line.gif differ diff --git a/content_modeller/images/treeview-gray.gif b/content_modeller/images/treeview-gray.gif new file mode 100644 index 00000000..cfb8a2f0 Binary files /dev/null and b/content_modeller/images/treeview-gray.gif differ diff --git a/content_modeller/images/treeview-red-line.gif b/content_modeller/images/treeview-red-line.gif new file mode 100644 index 00000000..df9e749a Binary files /dev/null and b/content_modeller/images/treeview-red-line.gif differ diff --git a/content_modeller/images/treeview-red.gif b/content_modeller/images/treeview-red.gif new file mode 100644 index 00000000..3bbb3a15 Binary files /dev/null and b/content_modeller/images/treeview-red.gif differ diff --git a/content_modeller/images/view.gif b/content_modeller/images/view.gif new file mode 100644 index 00000000..eee58178 Binary files /dev/null and b/content_modeller/images/view.gif differ diff --git a/content_modeller/islandora_content_modeller.info b/content_modeller/islandora_content_modeller.info new file mode 100644 index 00000000..1df4ff16 --- /dev/null +++ b/content_modeller/islandora_content_modeller.info @@ -0,0 +1,7 @@ +; $Id$ +name = Islandora Content Modeller +dependencies[] = fedora_repository +description = Allows you to manage and build content models for Islandora/Fedora. +package = Fedora Repository +version = 6.1dev +core = 6.x diff --git a/content_modeller/islandora_content_modeller.module b/content_modeller/islandora_content_modeller.module new file mode 100644 index 00000000..8d64e84e --- /dev/null +++ b/content_modeller/islandora_content_modeller.module @@ -0,0 +1,4376 @@ + 'Islandora Content Modeller', + 'description' => 'Manage Islandora/Fedora Content Models', + 'page callback' => 'islandora_content_modeller_main', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_NORMAL_ITEM + ); + + $items['admin/content/modeller/ajax/listModels'] = array( + 'page callback' => 'icm_ajax_model_list', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK + ); + + $items['admin/content/modeller/ajax/getFiles'] = array( + 'page callback' => 'icm_ajax_pluginFiles', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK + ); + + $items['admin/content/modeller/ajax/getClasses'] = array( + 'page callback' => 'icm_ajax_getClasses', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK + ); + + $items['admin/content/modeller/ajax/getMethods'] = array( + 'page callback' => 'icm_ajax_getMethods', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK + ); + + $items['admin/content/modeller/ajax/button'] = array( + 'page callback' => 'icm_ajax_button', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK + ); + + $items['admin/content/modeller/ajax/processForm/%'] = array( + 'page callback' => 'icm_ajax_processForm', + 'page arguments' => array(5), + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK + ); + + $items['admin/content/modeller/ajax/model'] = array( + 'page callback' => 'icm_ajax_model_tree', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK + ); + + $items['admin/content/modeller/ajax/collection'] = array( + 'page callback' => 'icm_ajax_collection_tree', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK + ); + + return $items; +} + +function icm_get_modules() +{ + $files = module_rebuild_cache(); + + $options=array(''); + foreach ($files as $key=>$val) + { + if ($val->info['package'] == 'Fedora Repository') //only list islandora modules + { + $options[$key]=$key; + } + } + return $options; + +} + +function icm_ajax_pluginFiles() +{ + + echo ''; + $plugin_path = drupal_get_path('module',$_GET['module']); + + if (!$plugin_path) + { + exit(); + } + + $plugin_path.='/plugins'; + + $files = array(''); + + if ( is_dir($plugin_path) && ($dir = opendir($plugin_path)) !== false) + { + while (($file = readdir($dir)) !== false) + { + if (preg_match('/\.inc$/',$file)) + { + echo ''; + } + } + } + exit(); +} + +function icm_ajax_getClasses() +{ + echo ''; + $file = drupal_get_path('module',$_GET['module']); + if (!$file) + { + exit(); + } + + $file.= '/'. $_GET['file']; + + if (file_exists($file)) + { + // hack.. we should really enforce the class name being the same as the file name. + // either that or consider replacing with a plugin register call in each included plugin. + $before_classes = get_declared_classes(); + require_once $file; + $after_classes = get_declared_classes(); + + foreach ($after_classes as $class) + { + if (!in_array($class,$before_classes)) + { + echo ''; + } + } + + } + exit(); +} + +function icm_ajax_getMethods() +{ + echo ''; + $file = drupal_get_path('module',$_GET['module']); + if (!$file) + { + exit(); + } + + $file.= '/'. $_GET['file']; + $class = $_GET['className']; + + if (file_exists($file)) + { + require_once $file; + if (class_exists($class)) + { + $methods = get_class_methods($class); + + foreach ($methods as $method) + { + echo ''; + } + } + + } + exit(); +} + +function icm_ajax_model_list() +{ + global $base_url; + $moduleRoot=drupal_get_path('module','islandora_content_modeller'); + require_once($moduleRoot.'/treeview.inc'); + + $moduleRoot = $base_url.'/'.$moduleRoot; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + module_load_include('inc', 'fedora_repository', 'CollectionClass'); + + $modelTree = new treeview('Installed Content Models','folder',' ','models'); + + $collectionHelper = new CollectionClass(); + $items = new SimpleXMLElement( $collectionHelper->getRelatedItems(variable_get('fedora_content_model_collection_pid','islandora:ContentModelCollection') ,null,null)); + $modelCount = 0; + if (count($items->results->result) > 0) + { + + foreach ($items->results->result as $res) + { + $child_pid=substr($res->object['uri'],strpos($res->object['uri'],'/')+1); + + if (($cm = ContentModel::loadFromModel($child_pid))!==false) + { + $modelTree->addChild(''.$child_pid.'','file',' '); + $modelCount++; + } + } + } + if ($modelCount == 0) + { + $modelTree->addChild(t('No installed content models found.')); + } + + echo $modelTree->buildTree('filetree'); +} + +function icm_ajax_model_tree() +{ + global $base_url; + $ret =false; + $moduleRoot=drupal_get_path('module','islandora_content_modeller'); + require_once($moduleRoot.'/treeview.inc'); + $moduleRoot=$base_url.'/'.$moduleRoot; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (isset($_GET['model_pid'])) + { + $cm = ContentModel::loadFromModel(trim($_GET['model_pid'])); + } else + $cm = ContentModel::loadFromObject(variable_get('fedora_repository_pid', 'islandora:top')); + + if ($cm !== false) + { + $cmValid = $cm->validate(); + + $modelTree = new treeview($cm->pid. ($cmValid?'':'!'),'folder',' ','models'); + + if (!$cmValid) + { + // echo '
'.htmlentities($cm->dumpXml()).'
'; + $errorsEl = $modelTree->addChild('XML Errors','folder'); + + foreach (ContentModel::$errors as $err) + { + $errorsEl->addChild(''.$err.''); + } + + } else + { + $mimeTypesEl = $modelTree->addChild('Mimetypes','folder',' '); + $mimetypes=$cm->getMimeTypes(); + foreach ($mimetypes as $type) + { + $mimeTypesEl->addChild($type,'file', ' '); + } + + $datastreams = $cm->listDatastreams(); + $dstreamsEl = $modelTree->addChild('Datastreams','folder', ' '); + + if (count($datastreams) > 0) + { + foreach ($datastreams as $ds) + { + $dsEl = $dstreamsEl->addChild($ds . ($cm->displayInFieldSet($ds)? '(Display in Fieldset) ':''),'file', + ' '. + ' '); + + $dispMethods = $cm->getDisplayMethods($ds); + $dispMethEl = $dsEl->addChild('Display Methods','folder',' '); + if ($dispMethods !== false && count($dispMethods) > 0) + { + foreach ($dispMethods as $meth) + { + $dispMethEl->addChild(($meth['default']==true?'':'').$meth['file'].'
'.$meth['class'].'->'.$meth['method'],'file', + ' '. + ' '. + ($meth['default']==true?'
':'')); + } + } + + $addMethods = $cm->getAddDsMethod($ds); + $addMethodEl = $dsEl->addChild('Add Datastream Method', 'file',' '); + + + } + } + + $ingestRulesEl = $modelTree->addChild('Ingest Rules','folder', ' '); + $rules = $cm->getIngestRules(); + foreach ($rules as $id=>$rule) + { + $ruleEl = $ingestRulesEl->addChild('Rule '.$id,'folder', ' '); + $applToEl = $ruleEl->addChild('Applies To','folder', ' '); + foreach ($rule['applies_to'] as $type) + { + $applToEl->addChild($type,'file', ' '); + } + + $methodsEl=$ruleEl->addChild('Ingest Methods','folder', ' '); + foreach ($rule['ingest_methods'] as $method) + { + $methodEl = $methodsEl->addChild($method['file'].'
'.$method['class'].'->'.$method['method'],'file',' '); + $paramEl = $methodEl->addChild('Parameters','folder',''); + if (count($method['parameters']) > 0) + { + foreach ($method['parameters'] as $key=>$val) + { + $paramEl->addChild($key.' = '.$val,'file', ' '); + } + } + } + + } + + $attr = $cm->getIngestFormAttributes(); + $ingestFormEl = $modelTree->addChild('Ingest Form
(dsid: '.$attr['dsid'].' page: '.$attr['page'].' file_chooser: '.($attr['hide_file_chooser']?'hidden':'visible').' )','folder', + ' '); + + $builderMethod = $cm->getIngestFormBuilderMethod(); + $ingestFormEl->addChild($builderMethod['file'].'
Builder: '.$builderMethod['class'].'->'.$builderMethod['method'].'
Handler: '.$builderMethod['class'].'->'.$builderMethod['handler'],'file'); + + $elementsEl = $ingestFormEl->addChild('Form Elements','folder',' '); + + if (($elements = $cm->getIngestFormElements())!==false) + { + $j=0; + foreach ($elements as $element) + { + + $icons = ' '; + + if ($j > 0) + { + $icons.=' '; + } + + if ($j < count($elements) - 1) + { + $icons.=' '; + } + + $icons .= ' '; + + $elementEl = $elementsEl->addChild(''.$element['label'] .' ' . $element['name'].' ('.$element['type'].')','file',$icons); + $params = $cm->getIngestFormElementParams($element['name']); + $paramEl = $elementEl->addChild('Parameters','folder',''); + if (count($params) > 0) + { + foreach ($params as $key=>$val) + { + $paramEl->addChild($key.' = '.$val,'file', ' '); + } + } + + + if ($element['type'] == 'select' || $element['type'] == 'radio' || $element['type'] == 'other_select') + { + $authListEl = $elementEl->addChild(t('Authoritative List'),'folder',' '); + $i=0; + foreach ($element['authoritative_list'] as $value=>$label) + { + $icons = ' '; + if ($i > 0) + { + $icons .= ' '; + } + + if ($i < count($element['authoritative_list']) - 1) + { + $icons .= ' '; + } + $authListEl->addChild(''.$label.' '.$value,'file',$icons); + $i++; + } + } + + $j++; + } + } + + $addIcon = ''; + $metadataMethod = $cm->getEditMetadataMethod(); + if ($metadataMethod == false) + { + $addIcon = ' '; + } + $metaDataEl = $modelTree->addChild('Edit Metadata Method','folder',$addIcon); + + if ($metadataMethod !== false) + { + $icons = ' '; + $icons .= ' '; + $metaDataEl->addChild('DSID: '.$metadataMethod['dsid'].'
'.$metadataMethod['file'].'
Builder: '.$metadataMethod['class'].'->'.$metadataMethod['method'].'
Handler: '.$metadataMethod['class'].'->'.$metadataMethod['handler'],'file',$icons); + } + + + $modelTree->addChild('Services','folder',' '); + + } + + + $ret = $modelTree->buildTree('filetree'); + } + + if ($ret !== false) + { + echo $ret; + } else + echo t('Error: Unable to load content model'); + + exit(); +} + +function icm_ajax_collection_tree() +{ + global $base_url; + $ret =false; + $moduleRoot=drupal_get_path('module','islandora_content_modeller'); + require_once($moduleRoot.'/treeview.inc'); + $moduleRoot=$base_url.'/'.$moduleRoot; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + module_load_include('inc', 'fedora_repository', 'CollectionClass'); + + $collectionHelper = new CollectionClass(); + + $pid=(!isset($_GET['collection_pid']) || strtolower($_GET['collection_pid']) == 'false')?variable_get('fedora_repository_pid', 'islandora:top'):trim($_GET['collection_pid']); + $cm=ContentModel::loadFromObject($pid); + $cp=CollectionPolicy::loadFromCollection($pid); + + $cssPid = $pid;//str_replace(':','_',$pid); + + if ($cm !== false && $cp !== false) + { + $cmValid = $cm->validate(); + $cpValid = $cp->validate(); + + $collectionTree = new treeview($pid .($cpValid?'':'!').' ('.$cm->pid. ($cmValid?'':'!').')','folder',' ','collections'); + + if (!$cmValid || !$cpValid) + { + // echo '
'.htmlentities($cm->dumpXml()).'
'; + $errorsEl = $collectionTree->addChild('XML Errors','folder'); + + foreach (ContentModel::$errors as $err) + { + $errorsEl->addChild(''.$err.''); + } + foreach (CollectionPolicy::$errors as $err) + { + $errorsEl->addChild(''.$err.''); + } + } else + { + + $childrenAllowed = false; + $contentModels = $cp->getContentModels(); + $cm_tree = $collectionTree->addChild('Allowed Content Models','folder',' ',$cssPid.'-cmodels'); + foreach ($contentModels as $ccm) + { + if ($ccm->pid == variable_get('fedora_collection_model_pid','islandora:collectionCModel') ) + { + $childrenAllowed = true; + } + + $cm_tree->addChild($ccm->name.' ('.$ccm->pid.')', 'file', ' '); + } + + $dstreams=$cm->listDatastreams(); + if (count($dstreams) > 0) + { + $ds_tree = $collectionTree->addChild('Datastreams','folder',null,$cssPid.'-dstreams'); + foreach ($dstreams as $ds) + $ds_tree->addChild($ds); + } + + $terms=$cp->getSearchTerms(true); + $search_tree = $collectionTree->addChild('Search Terms','folder',' ', $cssPid.'-terms'); + if (count($terms) > 0) + { + foreach ($terms as $term) + { + $search_tree->addChild(($term['default']?'':'').$term['value'].' ('.$term['field'].')'.($term['default']?'':''), 'file', ' Remove Set as Default '); + } + } + + if ($childrenAllowed) + { + $items = new SimpleXMLElement( $collectionHelper->getRelatedItems($pid,null,null)); + $child_tree= new TreeView('Child Collections','folder',' ',$cssPid.'-children'); + + if (count($items->results->result) > 0) + { + foreach ($items->results->result as $res) + { + $child_pid=substr($res->object['uri'],strpos($res->object['uri'],'/')+1); + $model_pid=substr($res->content['uri'] ,strpos($res->content['uri'],'/')+1); + + $child_cp=CollectionPolicy::loadFromCollection($child_pid); + if ($child_cp !== false) + { + $child_tree->addChild(''.$child_pid.' ('.$model_pid.')','file',' '); + } + } + } + $collectionTree->addChild($child_tree); + } + } + $ret = $collectionTree->buildTree('filetree'); + } + + if ($ret !== false) + { + echo $ret; + } else + echo t('Error: Missing content model and/or collection policy datastream(s) for '. $pid); + + exit(); +} + + +function islandora_content_modeller_main() +{ + global $base_url; + $moduleRoot=drupal_get_path('module','islandora_content_modeller'); + drupal_add_css($moduleRoot.'/css/jquery.treeview.css'); + drupal_add_css($moduleRoot.'/css/content_modeller.css'); + drupal_add_css($moduleRoot.'/css/jquery.jnotify.css'); + drupal_add_css($moduleRoot.'/css/smoothness/jquery-ui-1.8.1.custom.css'); + + drupal_add_js($moduleRoot.'/js/jquery.cookie.js'); + drupal_add_js($moduleRoot.'/js/jquery.treeview.min.js'); + drupal_add_js($moduleRoot.'/js/content_modeller.js'); + drupal_add_js($moduleRoot.'/js/jquery.jnotify.js'); + + $moduleRoot = $base_url.'/'.$moduleRoot; + + $content = '
'; + $content .= 'Refresh Loading
'; + $content .= '

'.t('Collections').'

'; + $content .= '
'; + $content .= '
'; + $content .= '

'.t('Models').'

'; + $content .= 'List Installed Models'; + $content .= '
'; + $content .= '
'; + $content .= '
'; + $content .= '
'; + $content .= '
'; + + return $content; +} + +function icm_ajax_formExists($formName) +{ + $validForms = array('icm_collection_new','icm_collection_edit','icm_collection_purge','icm_model_new','icm_model_purge','icm_model_edit_ingestForm','icm_model_add_mime','icm_collection_add_term','icm_collection_add_cmodel','icm_model_add_ingestMethodParam','icm_model_add_ingestMethod','icm_model_add_ingestRule','icm_model_add_appliesTo', + 'icm_model_add_ds','icm_model_add_dispmeth','icm_model_add_ingestFormElement','icm_model_edit_ingestFormElement','icm_model_add_authListItem','icm_model_update_editMetadataMethod','icm_model_rollback','icm_collection_rollback','icm_display_rawXml','icm_model_add_ingestElementParam', + 'icm_model_edit_adddsmeth','icm_model_service_add'); + return in_array($formName,$validForms); +} + +function icm_ajax_processForm($formName) +{ + $params=null; + if (isset($_GET['formReq'])) + { + $params=preg_split('/\s+/',trim($_GET['formReq'])); + } + + // require_once(drupal_get_path('module','islandora_content_modeller').'/ajaxForms.inc'); + if (icm_ajax_formExists($formName)) + { + + $formContent = drupal_get_form($formName,$params); + echo theme_status_messages('error'); + echo $formContent; + } +} + +function icm_ajax_button() +{ + + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + $params=null; + if (isset($_GET['formReq'])) + { + $params=preg_split('/\s+/',trim($_GET['formReq'])); + } + + switch (strtolower($params[0])) + { + case 'icm_model_remove_editmetadatamethod': + if (count($params) == 2) + { + $model_pid = $params[1]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->removeEditMetadataMethod() || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove edit metadata method from model %cm_pid.',array('%cm_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully removed edit metadata method from model %cm_pid.',array('%cm_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + } else + { + echo t('Error: Missing parameters to remove edit metadata method. Please try again.'); + } + break; + + case 'icm_model_remove_authlistitem': + if (count($params) == 4) + { + $model_pid = $params[1]; + $elementName = $params[2]; + $authValue = $params[3]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->removeAuthListItem($elementName,$authValue) || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove authoritative list item %value in model %m_pid.',array('%value'=>$authValue,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully removed authoritative list item %value in model %m_pid.',array('%value'=>$authValue,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + } else + { + echo t('Error: Missing parameters to remove authoritative list item. Please try again.'); + } + break; + + case 'icm_model_inc_authlistitem': + if (count($params) == 4) + { + $model_pid = $params[1]; + $elementName = $params[2]; + $authValue = $params[3]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->incAuthListItem($elementName,$authValue) || !$cm->saveToFedora()) + { + echo t('Error: Unable to increment authoritative list item %value in model %m_pid.',array('%value'=>$authValue,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully incremented authoritative list item %value in model %m_pid.',array('%value'=>$authValue,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + } else + { + echo t('Error: Missing parameters to increment authoritative list item. Please try again.'); + } + break; + + case 'icm_model_dec_authlistitem': + if (count($params) == 4) + { + $model_pid = $params[1]; + $elementName = $params[2]; + $authValue = $params[3]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->decAuthListItem($elementName,$authValue) || !$cm->saveToFedora()) + { + echo t('Error: Unable to decrement authoritative list item %value in model %m_pid.',array('%value'=>$authValue,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully decremented authoritative list item %value in model %m_pid.',array('%value'=>$authValue,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + } else + { + echo t('Error: Missing parameters to decrement authoritative list item. Please try again.'); + } + break; + + case 'icm_model_remove_ingestformelement': + if (count($params) == 3) + { + $model_pid = $params[1]; + $name = $params[2]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->removeIngestFormElement($name) || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove ingest form element %name from model %m_pid.',array('%name'=>$name,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully removed ingest form element %name from model %m_pid.',array('%name'=>$name,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters to remove ingest form element. Please try again.'); + } + break; + + case 'icm_model_inc_ingestformelement': + if (count($params) == 3) + { + $model_pid = $params[1]; + $name = $params[2]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->incIngestFormElement($name) || !$cm->saveToFedora()) + { + echo t('Error: Unable to increment ingest form element %name from model %m_pid.',array('%name'=>$name,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully incremented ingest form element %name from model %m_pid.',array('%name'=>$name,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters to increment ingest form element. Please try again.'); + } + break; + + case 'icm_model_dec_ingestformelement': + if (count($params) == 3) + { + $model_pid = $params[1]; + $name = $params[2]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->decIngestFormElement($name) || !$cm->saveToFedora()) + { + echo t('Error: Unable to decrement ingest form element %name from model %m_pid.',array('%name'=>$name,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully decremented ingest form element %name from model %m_pid.',array('%name'=>$name,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters to decrement ingest form element. Please try again.'); + } + break; + + + case 'icm_model_remove_dispmeth': + if (count($params) == 7) + { + $model_pid = $params[1]; + $dsid = $params[2]; + $module = $params[3]; + $file = $params[4]; + $class = $params[5]; + $method = $params[6]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->removeDispMeth($dsid, $module, $file,$class,$method) || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove display method for datastream %dsid of model %m_pid.',array('%dsid'=>$dsid,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully remove display method for datastream %dsid of model %m_pid.',array('%dsid'=>$dsid, '%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters to remove display method of datastream.'); + } + break; + + case 'icm_model_default_dispmeth': + if (count($params) == 7) + { + $model_pid = $params[1]; + $dsid = $params[2]; + $module = $params[3]; + $file = $params[4]; + $class = $params[5]; + $method = $params[6]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->setDefaultDispMeth($dsid,$module,$file,$class,$method) || !$cm->saveToFedora()) + { + echo t('Error: Unable to set default display method for datastream %dsid of model %m_pid.',array('%dsid'=>$dsid,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully set default display method for datastream %dsid of model %m_pid.',array('%dsid'=>$dsid, '%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters to set default display method of datastream.'); + } + break; + + case 'icm_model_remove_ds': + if (count($params) == 3) + { + + $model_pid = $params[1]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->removeDs($params[2]) || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove datastream from model %m_pid.',array('%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully removed datastream model %m_pid.',array('%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters for removal of application mimetype.'); + } + break; + case 'icm_model_remove_appliesto': + if (count($params) == 4) + { + + $model_pid = $params[1]; + $rule_id = $params[2]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->removeAppliesTo($rule_id,$params[3] ) || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove application mimetype from Rule %rule_id in model %m_pid.',array('%rule_id'=>$rule_id,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully removed application mimetype from Rule %rule_id in model %m_pid.',array('%rule_id'=>$rule_id,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters for removal of application mimetype.'); + } + break; + + + case 'icm_model_remove_ingestrule': + + if (count($params) == 3) + { + + $model_pid = $params[1]; + $rule_id = $params[2]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->removeIngestRule($rule_id ) || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove ingest Rule %rule_id in model %m_pid.',array('%rule_id'=>$rule_id,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully removed ingest Rule %rule_id in model %m_pid.',array('%rule_id'=>$rule_id,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters for removal of ingest rule.'); + } + break; + + case 'icm_model_remove_ingestmethod': + if (count($params) == 7) + { + + $model_pid = $params[1]; + $rule_id = $params[2]; + $module = $params[3]; + $file = $params[4]; + $class = $params[5]; + $method = $params[6]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->removeIngestMethod($rule_id, $module, $file, $class, $method) || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove ingest method of Rule %rule_id in model %m_pid.',array('%rule_id'=>$rule_id,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully removed ingest method of Rule %rule_id in model %m_pid.',array('%rule_id'=>$rule_id,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters for removal of ingest method.'); + } + break; + + case 'icm_model_remove_ingestmethodparam': + + if (count($params) == 8) + { + + $model_pid = $params[1]; + $rule_id = $params[2]; + $module = $params[3]; + $file = $params[4]; + $class = $params[5]; + $method = $params[6]; + $name = $params[7]; + + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->removeIngestMethodParam($rule_id, $module, $file, $class, $method, $name) || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove parameter of Rule %rule_id in model %m_pid.',array('%rule_id'=>$rule_id,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully removed parameter of Rule %rule_id in model %m_pid.',array('%rule_id'=>$rule_id,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters for removal of ingest method parameter.'); + } + + break; + + case 'icm_model_remove_ingestelementparam': + + if (count($params) == 4) + { + + $model_pid = $params[1]; + $element_name = $params[2]; + $name = $params[3]; + + if (($cm=ContentModel::loadFromModel($model_pid))!==FALSE) + { + if (!$cm->setIngestFormElementParam($element_name, $name, FALSE) || !$cm->saveToFedora()) + { + echo t('Error: Unable to remove parameter of element %element in model %m_pid.',array('%element'=>$element_name,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'. t('Successfully removed parameter of element %element in model %m_pid.',array('%element'=>$element_name,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + + } else + { + echo t('Error: Missing parameters for removal of form element parameter.'); + } + + break; + + case 'icm_model_toggle_dsdisplay': + if (isset($params[1]) && isset($params[2])) + { + if (($cm=ContentModel::loadFromModel($params[1]))!==FALSE) + { + $dsid = trim($params[2]); + if ($dsid == '') + { + echo t('Error: Datastream missing or not specified. Please try again.'); + } else if (!$cm->setDisplayInFieldset($dsid, !$cm->displayInFieldset($dsid)) || !$cm->saveToFedora()) + { + echo t('Error: Unable to update datastream %dsid in model %m_pid.',array('%dsid'=>$dsid,'%m_pid'=>$cm->pid)); + } else + { + echo 'success:'.t('Successfully updated datastream %dsid in model %m_pid',array('%dsid'=>$dsid,'%m_pid'=>$cm->pid)); + exit(); + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + } else + { + echo t('Error: Missing parameters for toggle datastream display in fieldset.'); + } + break; + + case 'icm_collection_remove_cmodel': + + if (isset($params[1]) && isset($params[2])) + { + $cp = CollectionPolicy::loadFromCollection($params[1]); + $cm = ContentModel::loadFromModel($params[2]); + if ($cm !== false && $cp !== false) + { + if (!$cp->removeModel($cm) || !$cp->saveToFedora()) + { + echo t('Error: Unable to remove content model %m_pid from collection policy of %c_pid.',array('%m_pid'=>$cm->pid,'%c_pid'=>$cp->pid)); + } else + { + echo 'success:'.t('Successfully removed content model %m_pid from collection policy of %c_pid.',array('%m_pid'=>$cm->pid,'%c_pid'=>$cp->pid)); + exit(); + } + } else + echo t('Error: Unknown collection policy or content model. Please try again.'); + } else + echo t('Error: Unknown collection policy or content model. Please try again.'); + break; + + case 'icm_collection_default_term': + $c_pid=$params[1]; + if (($cp = CollectionPolicy::loadFromCollection(trim($c_pid)))!== FALSE) + { + $field=isset($params[2])?$params[2]:''; + if (trim($field) != '') + { + if (!$cp->setDefaultTerm(htmlentities($field)) || !$cp->saveToFedora()) + { + echo t('Error: Unable to set default search term to %field in collection policy %cp_id.',array('%field'=>htmlentities($field),'%pc_pid'=>$cp->pid)); + } else + { + echo 'success:'.t('Successfully set default search term %field in collection policy %cp_id.',array('%field'=>htmlentities($field),'%cp_pid'=>$cp->pid)); + exit(); + } + } else + { + echo t('Error: Unknown search term %field selected. Please try again.',array('%field'=>htmlentities($field))); + } + } else + { + echo t('Error: Unknown collection policy. Please try again.'); + } + break; + + + case 'icm_collection_remove_term': + $c_pid=$params[1]; + if (($cp = CollectionPolicy::loadFromCollection(trim($c_pid)))!== FALSE) + { + $field=isset($params[2])?$params[2]:''; + if (trim($field) != '') + { + if (!$cp->removeTerm(htmlentities($field)) || !$cp->saveToFedora()) + { + echo t('Error: Unable to remove search term %field from collection policy %cp_id.',array('%field'=>htmlentities($field),'%c_pid'=>$cp->pid)); + } else + { + echo 'success:'.t('Successfully removed search term %field from collection policy %cp_id.',array('%field'=>htmlentities($field),'%c_pid'=>$cp->pid)); + exit(); + } + } else + { + echo t('Error: Unknown search term %field selected for removal. Please try again.',array('%field'=>htmlentities($field))); + } + } else + { + echo t('Error: Unknown collection policy. Please try again.'); + } + break; + + case 'icm_model_remove_mime': + $m_pid =$params[1]; + if (($cm = ContentModel::loadFromModel(trim($m_pid))) !== FALSE) + { + $type = isset($params[2])?trim($params[2]):''; + if ($type == '') + { + echo t('Error: You must specify a mimetype to remove. Please try again.'); + } else + { + if ($cm->removeMimetype($type) && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully removed mime type %type from content model %m_pid.',array('%type'=>htmlentities($type),'%m_pid'=>htmlentities($m_pid))); + exit(); + } else + { + echo t('Error: Unable to remove mime type %type from content model %m_pid. Please make sure that it isnt the only term left in the content model.',array('%type'=>htmlentities($type),'%m_pid'=>htmlentities($m_pid))); + } + } + } else + { + echo t('Error: Unknown content model. Please try again.'); + } + break; + + default: + echo t('Error: Unknown action %action Please try again',array('%action'=>$params[0])); + } + +} + + + +function icm_model_add_mime_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (trim($form_state['values']['addMime']['model_pid'])=='' || ($cm = ContentModel::loadFromModel(trim($form_state['values']['addMime']['model_pid']))) === FALSE) + { + form_set_error('',t('Error: Specified model could not be found.')); + } else if ($cm->addMimetype(trim($form_state['values']['addMime']['type'])) === FALSE || $cm->saveToFedora() === FALSE) + { + form_set_error('',t('Error: Unable to add mimetype to specified model. Please make sure that the mimetype is not already listed in the model.')); + } else + { + echo 'success:'.t('Successfully added mimetype %mimetype to model %model_name',array('%model_name'=>$cm->name,'%mimetype'=>trim($form_state['values']['addMime']['type']))); + exit(); + } +} + +function icm_model_add_mime(&$form_state,$params=null) +{ + + if (is_array($params) && isset($params[0])) + { + $model_pid = $params[0]; + } else if (isset($form_state['post']['addMime']['model_pid'])) + { + $model_pid = $form_state['post']['addMime']['model_pid']; + } + + + $form['addMime'] = array( + '#type'=>'fieldset', + '#title'=> t('Add Mimetype to Model %model_pid', array('%model_pid'=>$model_pid)), + '#tree'=>TRUE + ); + + $form['addMime']['type'] = array( + '#type' => 'textfield', + '#title' => t('Mimetype'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('A content mimetype that can be ingested using this model.'), + ); + + $form['addMime']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['addMime']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['addMime']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; + +} + +function icm_collection_add_cmodel_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc','fedora_repository','CollectionPolicy'); + module_load_include('inc','fedora_repository','ContentModel'); + + if (!ContentModel::validPid($form_state['values']['form']['namespace'])) + { + form_set_error('form][namespace',t('Error: Invalid namespace format.')); + } else + { + $c_pid = $form_state['values']['form']['collection_pid']; + $m_pid = $form_state['values']['form']['model_pid']; + + + if (($cm = ContentModel::loadFromModel($m_pid))!== FALSE && + ($cp = CollectionPolicy::loadFromCollection($c_pid)) !== FALSE) + { + if ($cp->addModel($cm,trim($form_state['values']['form']['namespace'])) && $cp->saveToFedora()) + { + echo 'success:'.t('Successfully added content model %cm_pid% to collection policy of %cp_pid%.',array('%cm_pid%'=>$cm->pid,'%cp_pid%'=>$cp->pid)); + exit(); + + } else + { + form_set_error('form][model_pid',t('Error: Unable to add content model %cm_pid% to collection policy of %cp_pid%. Please make sure that the model is not already listed in the collection policy.',array('%cm_pid%'=>$cm->pid,'%cp_pid%'=>$cp->pid))); + } + + } else + { + form_set_error('',t('Error: Unable to load specified content model or collection policy. Please try again.')); + } + } +} + +function icm_collection_add_cmodel(&$form_state,$params=null) +{ + + if (is_array($params) && isset($params[0])) + { + $collection_pid = $params[0]; + } else if (isset($form_state['post']['form']['collection_pid'])) + { + $collection_pid = $form_state['post']['form']['collection_pid']; + } + + module_load_include('inc','fedora_repository','CollectionClass'); + module_load_include('inc','fedora_repository','ContentModel'); + $collectionHelper = new CollectionClass(); + + $options=array(); + $items = new SimpleXMLElement( $collectionHelper->getRelatedItems(variable_get('fedora_content_model_collection_pid','islandora:ContentModelCollection') ,null,null)); + for ($i = 0; $i < count($items->results->result); $i++) + { + list(,$pid)=preg_split('/\//',$items->results->result[$i]->object['uri']); + + $cm = ContentModel::loadFromModel($pid); + if ($cm !== false) + { + $options[$pid] = $items->results->result[$i]->title .' ('.$pid.')'; + } + } + + $form['form'] = array( + '#type'=>'fieldset', + '#title'=> t('Add content model to collection %collection_pid', array('%collection_pid'=>$collection_pid)), + '#tree'=>TRUE + ); + + $form['form']['model_pid'] = array( + '#type' => 'select', + '#title' => t('Content Model'), + '#required' => TRUE, + '#options' => $options, + '#description' => t('A descriptive label for the field displayed on the search form.'), + ); + + $form['form']['namespace'] = array( + '#type'=> 'textfield', + '#title'=> t('Namespace'), + '#description' => t('The base namespace for objects of this type injested into the collection. eg islandora:collection '), + '#size' => 30, + '#maxSize' => 60, + '#required' => TRUE + ); + + $form['form']['collection_pid'] = array('#type' => 'hidden', '#value'=> $collection_pid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; + +} + +function icm_collection_add_term_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + if (trim($form_state['values']['form']['collection_pid'])=='' || ($cp = CollectionPolicy::loadFromCollection(trim($form_state['values']['form']['collection_pid']))) === FALSE) + { + form_set_error('',t('Error: Specified collection policy could not be found.')); + } else if ($cp->addTerm(trim($form_state['values']['form']['field']),trim($form_state['values']['form']['value'])) === FALSE || $cp->saveToFedora() === FALSE) + { + form_set_error('',t('Error: Unable to add search term to specified collection policy. Please make sure that the field is not already listed in the search terms.')); + } else + { + echo 'success:'.t('Successfully added term %field to collection policy %cp_pid',array('%cp_pid'=>$cp->pid,'%field'=>trim($form_state['values']['form']['field']))); + exit(); + } +} + +function icm_collection_add_term(&$form_state,$params=null) +{ + + if (is_array($params) && isset($params[0])) + { + $collection_pid = $params[0]; + } else if (isset($form_state['post']['collection_pid'])) + { + $collection_pid = $form_state['post']['collection_pid']; + } + + + $form['form'] = array( + '#type'=>'fieldset', + '#title'=> t('Add search term to collection %collection_pid', array('%collection_pid'=>$collection_pid)), + '#tree'=>TRUE + ); + + $form['form']['field'] = array( + '#type' => 'textfield', + '#title' => t('Field'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The name of the field in the DC to search.'), + ); + + $form['form']['value'] = array( + '#type' => 'textfield', + '#title' => t('Label'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('A descriptive label for the field displayed on the search form.'), + ); + + $form['form']['collection_pid'] = array('#type' => 'hidden', '#value'=> $collection_pid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; + +} + + +function icm_collection_rollback_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + + if (($cp = CollectionPolicy::loadFromCollection($form_state['values']['form']['c_pid']))!==FALSE) + { + + $history = $cp->getHistory(); + $found = false; + foreach ($history as $key=>$ver) + { + if ($ver['versionID'] == $form_state['values']['form']['version']) + { + $found = $key; + break; + } + } + + if ($found === false) + { + form_set_error('',t('Error: Selected version was not found. Please try again.')); + } else if ($found == 0 && $form_state['values']['form']['removeOlder'] == 0) + { + form_set_error('',t('Error: Selected version is the current version. Nothing changed.')); + } else + { + $success=true; + if ($found > 0) + { + $startDate = $history[$found-1]['createDate']; + $success = $cp->purgeVersions($history[$found-1]['createDate'],null); + } + + if ($form_state['values']['form']['removeOlder'] == 1 && isset($history[$found+1])) + { + $endDate = $history[$found+1]['createDate']; + $success = $success && $cp->purgeVersions(null,$endDate); + } + + if ($success) + { + echo 'success:'.t('Successfully rolled back version of collection policy %c_pid.',array('%c_pid'=>$cp->pid)); + exit(); + + } else + { + form_set_error('',t('Error: Unable to roll back version. Check watchdog logs.')); + } + } + + } else + { + form_set_error('',t('Error: Unable to load collection policy %c_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['c_pid'])))); + + } +} + +function icm_collection_rollback(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $c_pid = $params[0]; + } else + { + $c_pid = $form_state['post']['form']['model_pid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Rollback Collection Policy %$c_pid',array('%$c_pid'=>$c_pid)), + '#tree' => TRUE, + ); + + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + + if (($cp = CollectionPolicy::loadFromCollection($c_pid))!==false) + { + + $history = $cp->getHistory(); + + $options = array(); + foreach ($history as $ver) + { + $options[$ver['versionID']] = date(DATE_RFC822,strtotime($ver['createDate'])); + } + + if ($history !== false && count($history) > 0) + { + + + $form['form']['warning'] = array('#value' => 'Warning: Rolling back a datastream will purge all versions up-to the selected datastream.'); + + + $form['form']['cur'] = array( + '#type'=> 'item', + '#title'=> t('Current Version:'), + '#value'=> date(DATE_RFC822,strtotime($history[0]['createDate'])) + ); + + $form['form']['version'] = array( + '#type' => 'select', + '#title' => t('Version'), + '#options' => $options + ); + + $form['form']['removeOlder'] = array( + '#type' => 'checkbox', + '#title' => 'Purge Older Versions', + '#description' => 'If enabled, also purges versions of the datastream that are OLDER than the selected, effectively leaving only the selected version.' + ); + + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + + } else + { + $form['form']['version'] = array( + '#type'=> 'item', + '#title'=> t('Rollback to Version:'), + '#value'=> t('only one version available.') + ); + } + + + + } else + { + form_set_error('',t('Error: Unable to load collection policy %c_pid.',array('%c_pid'=>$c_pid))); + } + + $form['form']['c_pid'] = array('#type' => 'hidden', '#value'=> $c_pid); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + +function icm_model_add_ingestMethodParam_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->addIngestMethodParam($form_state['values']['form']['rule_id'], + $form_state['values']['form']['module'], + $form_state['values']['form']['file'], + $form_state['values']['form']['class'], + $form_state['values']['form']['method'], + $form_state['values']['form']['name'], + $form_state['values']['form']['value']) && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully added parameter to ingest method of Rule %rule_id for model %model_pid.',array('%rule_id'=>htmlentities($form_state['values']['form']['rule_id']),'%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to add parameter to ingest method of Rule %rule_id for model %model_pid. Please make sure that the parameter is not already listed.',array('%rule_id'=>htmlentities($form_state['values']['form']['rule_id']),'%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } + +} + + +function icm_model_add_ingestMethodParam(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + $rule_id = $params[1]; + $module = $params[2]; + $file = $params[3]; + $class = $params[4]; + $method = $params[5]; + } else + { + $model_pid = $form_state['post']['model_id']; + $rule_id = $form_state['post']['rule_id']; + $module = $form_state['post']['module']; + $file = $form_state['post']['file']; + $class = $form_state['post']['class']; + $method = $form_state['post']['method']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add Ingest Method Parameter to ingest Rule %rule_id of model %model_pid.',array('%rule_id'=>$rule_id,'%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['module_label'] = array( + '#type'=> 'item', + '#title'=> t('Module'), + '#value' => $module + ); + + $form['form']['file_label'] = array( + '#type'=> 'item', + '#title'=> t('Filename'), + '#value' => $file + ); + + $form['form']['class_label'] = array( + '#type'=> 'item', + '#title'=> t('Class'), + '#value' => $class + ); + + $form['form']['method_label'] = array( + '#type'=> 'item', + '#title'=> t('Method'), + '#value' => $method + ); + + $form['form']['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The name of the parameter to pass along to the ingest method above.'), + ); + + $form['form']['value'] = array( + '#type' => 'textfield', + '#title' => t('Value'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The value of the parameter to pass along to the ingest method above'), + ); + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['rule_id'] = array('#type' => 'hidden', '#value'=> $rule_id); + $form['form']['module'] = array('#type' => 'hidden', '#value'=> $module); + $form['form']['file'] = array('#type' => 'hidden', '#value'=> $file); + $form['form']['class'] = array('#type' => 'hidden', '#value' => $class); + $form['form']['method'] = array('#type' => 'hidden', '#value'=> $method); + + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + + return $form; +} + + +function icm_model_add_ingestElementParam_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->setIngestFormElementParam($form_state['values']['form']['element_name'], + $form_state['values']['form']['name'], + $form_state['values']['form']['value']) && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully added parameter to form element %element_name for model %model_pid.',array('%element_name'=>htmlentities($form_state['values']['form']['element_name']),'%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to add parameter to form element %element_name for model %model_pid. Please make sure that the parameter is not already listed.',array('%element_name'=>htmlentities($form_state['values']['form']['element_name']),'%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } + +} + + +function icm_model_add_ingestElementParam(&$form_state,$params=null) +{ + if (is_array($params)) + { + $model_pid = $params[0]; + $element_name = $params[1]; + } else + { + $model_pid = $form_state['post']['model_id']; + $element_name = $form_state['post']['element_name']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add Ingest Form Element Parameter to element %element_name of model %model_pid.',array('%element_name'=>$element_name,'%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The name of the parameter to pass along to the form element above.'), + ); + + $form['form']['value'] = array( + '#type' => 'textarea', + '#title' => t('Value'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The value of the parameter to pass along to the form element above'), + ); + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['element_name'] = array('#type' => 'hidden', '#value'=> $element_name); + + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + + return $form; +} + +function icm_model_add_ingestMethod_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + + $module = $form_state['values']['form']['module']; + $file = $form_state['values']['form']['filename']; + $class= $form_state['values']['form']['class']; + $method=$form_state['values']['form']['method']; + + $path = drupal_get_path('module',$module); + + if (empty($path) || !file_exists($path.'/'.$file)) + { + form_set_error('form][filename',t('Error: Selected plugin file not found. Please try again.')); + } else + { + require_once ($path.'/'.$file); + if (!class_exists($class)) + { + form_set_error('form][class',t('Error: Specified class does not exist in the plugin. Please try again.')); + } else + { + $obj = new $class; + if (!method_exists($obj,$method)) + { + form_set_error('form][method',t('Error: Specified method does not exist in the specified class/plugin. Please try again.')); + } + } + } + + if (!ContentModel::validDsid($form_state['values']['form']['dsid'])) + { + form_set_error('form][dsid',t('Error: Invalid datastream identifier. Please try again.')); + } + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->addIngestMethod($form_state['values']['form']['rule_id'],$module,$module,$file,$class,$method,$form_state['values']['form']['dsid'],$form_state['values']['form']['modified_files_ext']) && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully added ingest method to Rule %rule_id for model %model_pid.',array('%rule_id'=>htmlentities($form_state['values']['form']['rule_id']),'%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to add ingest method to Rule %rule_id for model %model_pid.',array('%rule_id'=>htmlentities($form_state['values']['form']['rule_id']),'%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } + +} + +function icm_model_add_ingestMethod(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + $rule_id = $params[1]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + $rule_id = $form_state['post']['form']['rule_id']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add Ingest Method to ingest Rule %rule_id of model %model_pid',array('%rule_id'=>$rule_id,'%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['module'] = array( + '#type' => 'select', + '#title' => t('Module'), + '#element_validate' => array('icm_module_validate'), + '#options'=>icm_get_modules(), + '#required' => TRUE, + '#description' => t('The name of the module containing the plugin file.'), + ); + + $form['form']['filename'] = array( + '#type' => 'textfield', + '#title' => t('File'), + '#element_validate' => array('icm_filename_validate'), + '#required' => TRUE, + '#description' => t('The relative path of the file containing the ingest method class/method.'), + ); + $form['form']['class'] = array( + '#type' => 'textfield', + '#title' => t('Class'), + '#element_validate' => array('icm_class_validate'), + '#required' => TRUE, + '#size'=>30, + '#description' => t('The name of the ingest method class.'), + ); + $form['form']['method'] = array( + '#type' => 'textfield', + '#title' => t('Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#description' => t('The name of the class method to call when ingesting a file.'), + ); + + $form['form']['dsid'] = array( + '#type' => 'textfield', + '#title' => t('Datastream Identifier'), + '#size' => 30, + '#maxlength' => 64, + '#required' => TRUE, + '#description' => t('The datastream ID that will store the output from this method.'), + ); + + $form['form']['modified_files_ext'] = array( + '#type' => 'textfield', + '#title' => t('Modified Files Extension'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The file extension that will be appended to the modified file.'), + ); + + + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['rule_id'] = array('#type' => 'hidden', '#value'=> $rule_id); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + +function icm_model_add_appliesTo_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->addAppliesTo($form_state['values']['form']['rule_id'],$form_state['values']['form']['appliesTo']) && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully added application mimetype to Rule %rule_id for model %model_pid.',array('%rule_id'=>htmlentities($form_state['values']['form']['rule_id']),'%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to add application mimetype to Rule %rule_id for model %model_pid.',array('%rule_id'=>htmlentities($form_state['values']['form']['rule_id']),'%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } +} + +function icm_model_add_appliesTo(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + $rule_id = $params[1]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + $rule_id = $form_state['post']['form']['rule_id']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add application mimetype to ingest Rule %rule_id of model %model_pid',array('%rule_id'=>$rule_id,'%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['appliesTo'] = array( + '#type' => 'textfield', + '#title' => t('Applies To'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('A content mimetype that this ingest rule will be applied to.'), + ); + + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['rule_id'] = array('#type' => 'hidden', '#value'=> $rule_id); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + + +function icm_model_add_ingestRule_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + $module = $form_state['values']['form']['module']; + $file = $form_state['values']['form']['filename']; + $class= $form_state['values']['form']['class']; + $method=$form_state['values']['form']['method']; + $path = drupal_get_path('module',$module); + + if (empty($path) || !file_exists($path.'/'.$file)) + { + form_set_error('form][filename',t('Error: Selected plugin file not found. Please try again.')); + } else + { + require_once ($path.'/'.$file); + if (!class_exists($class)) + { + form_set_error('form][class',t('Error: Specified class does not exist in the plugin. Please try again.')); + } else + { + $obj = new $class; + if (!method_exists($obj,$method)) + { + form_set_error('form][method',t('Error: Specified method does not exist in the specified class/plugin. Please try again.')); + } + } + } + + if (!ContentModel::validDsid($form_state['values']['form']['dsid'])) + { + form_set_error('form][dsid',t('Error: Invalid datastream identifier. Please try again.')); + } + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->addIngestRule($form_state['values']['form']['appliesTo'],$module,$file,$class,$method,$form_state['values']['form']['dsid'],$form_state['values']['form']['modified_files_ext']) && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully added ingest method to Rule %rule_id for model %model_pid.',array('%rule_id'=>htmlentities($form_state['values']['form']['rule_id']),'%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to add ingest rule for model %model_pid.',array('%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } + +} + + + +function icm_model_add_ingestRule(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add Ingest Rule to model %model_pid',array('%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['appliesTo'] = array( + '#type' => 'textfield', + '#title' => t('Applies To'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('A content mimetype that this ingest rule will be applied to.'), + ); + + $form['form']['module'] = array( + '#type' => 'select', + '#title' => t('Module'), + '#element_validate' => array('icm_module_validate'), + '#options'=>icm_get_modules(), + '#required' => TRUE, + '#description' => t('The name of the module containing the plugin file.'), + ); + + $form['form']['filename'] = array( + '#type' => 'textfield', + '#title' => t('File'), + '#element_validate' => array('icm_filename_validate'), + '#required' => TRUE, + '#description' => t('The relative path of the file containing the ingest method class/method.'), + ); + + $form['form']['class'] = array( + '#type' => 'textfield', + '#title' => t('Class'), + '#element_validate' => array('icm_class_validate'), + '#required' => TRUE, + '#size'=>30, + '#description' => t('The name of the ingest method class.'), + ); + $form['form']['method'] = array( + '#type' => 'textfield', + '#title' => t('Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#description' => t('The name of the class method to call when ingesting a file.'), + ); + + $form['form']['dsid'] = array( + '#type' => 'textfield', + '#title' => t('Datastream Identifier'), + '#size' => 30, + '#maxlength' => 64, + '#required' => TRUE, + '#description' => t('The datastream ID that will store the output from this method.'), + ); + + $form['form']['modified_files_ext'] = array( + '#type' => 'textfield', + '#title' => t('Modified Files Extension'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The file extension that will be appended to the modified file.'), + ); + + + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + + +function icm_model_add_ds_validate($form,&$form_state) +{ + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (!ContentModel::validDsid($form_state['values']['form']['dsid'])) + { + form_set_error('form][dsid',t('Error: Invalid datastream identifier. Please try again.')); + } + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->addDs($form_state['values']['form']['dsid'],$form_state['values']['form']['display_in_fieldset']==1) && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully added datastream to model %model_pid.',array('%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to add datastream to model %model_pid.',array('%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } + +} + +function icm_model_add_ds(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add Datastream to model %model_pid',array('%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['dsid'] = array( + '#type' => 'textfield', + '#title' => t('Datastream Identifier'), + '#size' => 30, + '#maxlength' => 64, + '#required' => TRUE, + '#description' => t('The datastream ID that will store the output from this method.'), + ); + + $form['form']['display_in_fieldset'] = array( + '#type' => 'checkbox', + '#title' => t('Display in Fieldset'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('Display this datastream in the fieldset for this model?'), + ); + + + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + + +function icm_model_add_dispmeth_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + $module = $form_state['values']['form']['module']; + $file = $form_state['values']['form']['filename']; + $class= $form_state['values']['form']['class']; + $method=$form_state['values']['form']['method']; + $path = drupal_get_path('module',$module); + + if (empty($path) || !file_exists($path.'/'.$file)) + { + form_set_error('form][filename',t('Error: Selected plugin file not found. Please try again.')); + } else + { + require_once ($path.'/'.$file); + if (!class_exists($class)) + { + form_set_error('form][class',t('Error: Specified class does not exist in the plugin. Please try again.')); + } else + { + $obj = @new $class; + if (!method_exists($obj,$method)) + { + form_set_error('form][method',t('Error: Specified method does not exist in the specified class/plugin. Please try again.')); + } + } + } + + if (!ContentModel::validDsid($form_state['values']['form']['dsid'])) + { + form_set_error('form][dsid',t('Error: Invalid datastream identifier. Please try again.')); + } + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->addDispMeth($form_state['values']['form']['dsid'],$module,$file,$class,$method) && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully added display method to datastream %dsid of model %model_pid.',array('%dsid'=>htmlentities($form_state['values']['form']['dsid']),'%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to add display method to datastream %dsid of model %model_pid.',array('%dsid'=>htmlentities($form_state['values']['form']['dsid']),'%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } +} + +function icm_model_add_dispmeth(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + $dsid = $params[1]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + $dsid = $form_state['post']['form']['dsid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add Display Method to datastream %dsid of model %model_pid',array('%dsid'=>$dsid,'%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['module'] = array( + '#type' => 'select', + '#title' => t('Module'), + '#element_validate' => array('icm_module_validate'), + '#options'=>icm_get_modules(), + '#required' => TRUE, + '#description' => t('The name of the module containing the plugin file.'), + ); + + $form['form']['filename'] = array( + '#type' => 'textfield', + '#title' => t('File'), + '#element_validate' => array('icm_filename_validate'), + '#required' => TRUE, + '#description' => t('The relative path of the file containing the ingest method class/method.'), + ); + + $form['form']['class'] = array( + '#type' => 'textfield', + '#title' => t('Class'), + '#element_validate' => array('icm_class_validate'), + '#required' => TRUE, + '#size'=>30, + '#description' => t('The name of the ingest method class.'), + ); + $form['form']['method'] = array( + '#type' => 'textfield', + '#title' => t('Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#description' => t('The name of the class method to call when displaying the datastream.'), + ); + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['dsid'] = array('#type' => 'hidden', '#value'=> $dsid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + + +function icm_model_edit_ingestForm_validate($form,&$form_state) +{ + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (!ContentModel::validDsid($form_state['values']['form']['dsid'])) + { + form_set_error('form][dsid',t('Error: Invalid datastream identifier. Please try again.')); + } + + $module=$form_state['values']['form']['module']; + $file = $form_state['values']['form']['filename']; + $class= $form_state['values']['form']['class']; + $method=$form_state['values']['form']['method']; + $handler=$form_state['values']['form']['handler']; + $path = drupal_get_path('module',$module); + + if (empty($path) || !file_exists($path.'/'.$file)) + { + form_set_error('form][filename',t('Error: Selected plugin file not found. Please try again.')); + } else + { + require_once ($path.'/'.$file); + if (!class_exists($class)) + { + form_set_error('form][class',t('Error: Specified class does not exist in the plugin. Please try again.')); + } else + { + $obj = @new $class; + if (!method_exists($obj,$method)) + { + form_set_error('form][method',t('Error: Specified builder method does not exist in the specified class/plugin. Please try again.')); + } + if (!method_exists($obj,$handler)) + { + form_set_error('form][handler',t('Error: Specified handler method does not exist in the specified class/plugin. Please try again.')); + } + } + } + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->editIngestFormAttributes(htmlentities($form_state['values']['form']['dsid']),htmlentities($form_state['values']['form']['page']),$form_state['values']['form']['hide_file_chooser']==1,$form_state['values']['form']['redirect']==1) + && $cm->editIngestFormBuilderMethod($module,$file,$class,$method,$handler) + && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully updated ingest form of model %model_pid.',array('%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to update ingest form of model %model_pid.',array('%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } +} + +function icm_model_edit_ingestForm(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[1]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Edit Ingest Form of model %model_pid',array('%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (($cm = ContentModel::loadFromModel($model_pid))!==false) + { + + $attr = $cm->getIngestFormAttributes(); + $builderMethod = $cm->getIngestFormBuilderMethod(); + + $form['form']['dsid'] = array( + '#type' => 'textfield', + '#title' => t('Datastream Identifier'), + '#size' => 30, + '#maxlength' => 64, + '#default_value'=>$attr['dsid'], + '#required' => TRUE, + + '#description' => t('The datastream ID that stores the collected metadata from the form.'), + ); + + $form['form']['page'] = array( + '#type' => 'textfield', + '#title' => t('Page'), + '#size' => 3, + '#required' => TRUE, + '#default_value' => $attr['page'], + '#description' => t('??? not sure what this field is for. Cant find a reference to it, candidate for removal. '), + ); + + $form['form']['hide_file_chooser'] = array( + '#type' => 'checkbox', + '#title' => t('Hide File Chooser'), + '#size' => 3, + '#required' => TRUE, + '#default_value' => $attr['hide_file_chooser']?1:0, + '#description' => t('If enabled, the file choose will not be displayed in the ingest form for this model.'), + ); + + $form['form']['redirect'] = array( + '#type' => 'checkbox', + '#title' => t('Redirect on Ingest'), + '#size' => 3, + '#required' => TRUE, + '#default_value' => $attr['redirect']?1:0, + '#description' => t('If enabled, the user will be redirected to the collection view on successful ingest.'), + ); + + $form['form']['module'] = array( + '#type' => 'select', + '#title' => t('Module'), + '#element_validate' => array('icm_module_validate'), + '#options'=>icm_get_modules(), + '#required' => TRUE, + '#default_value'=> ($builderMethod['module']==''?'fedora_repository':$builderMethod['module']), + '#description' => t('The name of the module containing the plugin file.'), + ); + + $form['form']['filename'] = array( + '#type' => 'textfield', + '#title' => t('File'), + '#element_validate' => array('icm_filename_validate'), + '#required' => TRUE, + '#default_value'=> $builderMethod['file'], + '#description' => t('The relative path of the file containing the builder/handler method class/method.'), + ); + + $form['form']['class'] = array( + '#type' => 'textfield', + '#title' => t('Class'), + '#element_validate' => array('icm_class_validate'), + '#required' => TRUE, + '#default_value'=> $builderMethod['class'], + '#size'=>30, + '#description' => t('The name of the builder/handler class.'), + ); + $form['form']['method'] = array( + '#type' => 'textfield', + '#title' => t('Form Builder Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#default_value'=> $builderMethod['method'], + '#description' => t('The name of the class method to build the ingest form.'), + ); + + $form['form']['handler'] = array( + '#type' => 'textfield', + '#title' => t('Form Handler Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#default_value'=> $builderMethod['handler'], + '#description' => t('The name of the class method to handle the ingest form.'), + ); + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + + } else + { + form_set_error('',t('Error: Unable to load content model %model_pid.',array('%model_pid'=>$model_pid))); + } + + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; +} + + +function icm_model_edit_adddsmeth_validate($form,&$form_state) +{ + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (!ContentModel::validDsid($form_state['values']['form']['dsid'])) + { + form_set_error('form][dsid',t('Error: Invalid datastream identifier. Please try again.')); + } + + $module = $form_state['values']['form']['module']; + $file = $form_state['values']['form']['filename']; + $class= $form_state['values']['form']['class']; + $method=$form_state['values']['form']['method']; + $handler=$form_state['values']['form']['handler']; + $path = drupal_get_path('module',$module); + + if (empty($path) || !file_exists($path.'/'.$file)) + { + form_set_error('form][filename',t('Error: Selected plugin file not found. Please try again.')); + } else + { + require_once ($path.'/'.$file); + if (!class_exists($class)) + { + form_set_error('form][class',t('Error: Specified class does not exist in the plugin. Please try again.')); + } else + { + $obj = @new $class; + if (!method_exists($obj,$method)) + { + form_set_error('form][method',t('Error: Specified builder method does not exist in the specified class/plugin. Please try again.')); + } + if (!method_exists($obj,$handler)) + { + form_set_error('form][handler',t('Error: Specified handler method does not exist in the specified class/plugin. Please try again.')); + } + } + } + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->editIngestFormAttributes(htmlentities($form_state['values']['form']['dsid']),htmlentities($form_state['values']['form']['page']),$form_state['values']['form']['hide_file_chooser']==1,$form_state['values']['form']['redirect']==1) + && $cm->editIngestFormBuilderMethod($module,$file,$class,$method,$handler) + && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully updated ingest form of model %model_pid.',array('%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to update ingest form of model %model_pid.',array('%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } +} + +function icm_model_edit_adddsmeth(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + $dsid = $params[1]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + $dsid = $form_state['post']['form']['dsid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Edit Add DataStream Method of model %model_pid datastream %dsid',array('%model_pid'=>$model_pid,'%dsid'=>$dsid)), + '#tree' => TRUE, + ); + + $form['form']['label'] = array('#value'=> t('This method will be called when a datastream is ingested into %dsid. The resulting file generated by the method is then ingested into the specified datastream.')); + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (($cm = ContentModel::loadFromModel($model_pid))!==false) + { + + $method = $cm->getIngestFormBuilderMethod(); + + + $form['form']['module'] = array( + '#type' => 'select', + '#title' => t('Module'), + '#element_validate' => array('icm_module_validate'), + '#options'=>icm_get_modules(), + '#default_value'=>($method['module']==''?'fedora_repository':$method['module']), + '#required' => TRUE, + '#description' => t('The name of the module containing the plugin file.'), + ); + + $form['form']['filename'] = array( + '#type' => 'textfield', + '#title' => t('File'), + '#element_validate' => array('icm_filename_validate'), + '#default_value' =>$method['file'], + '#required' => TRUE, + '#description' => t('The relative path of the file containing the ingest method class/method.'), + ); + + $form['form']['class'] = array( + '#type' => 'textfield', + '#title' => t('Class'), + '#element_validate' => array('icm_class_validate'), + '#required' => TRUE, + '#default_value'=> $method['class'], + '#size'=>30, + '#description' => t('The name of the class.'), + ); + $form['form']['method'] = array( + '#type' => 'textfield', + '#title' => t('Form Builder Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#default_value'=> $method['method'], + '#description' => t('The name of the class method called.'), + ); + + + $form['form']['out_dsid'] = array( + '#type' => 'textfield', + '#title' => t('Datastream Identifier'), + '#size' => 30, + '#maxlength' => 64, + '#default_value'=>$attr['dsid'], + '#required' => TRUE, + '#description' => t('The datastream ID that stores the resulting file from the specified method.'), + ); + + $form['form']['modified_files_ext'] = array( + '#type' => 'textfield', + '#title' => t('Modified Files Extension'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The file extension that will be appended to the modified file.'), + ); + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['dsid'] = array('#type' => 'hidden', '#value'=> $dsid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + + } else + { + form_set_error('',t('Error: Unable to load content model %model_pid.',array('%model_pid'=>$model_pid))); + } + + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; +} + + +function icm_model_add_ingestFormElement_validate($form,&$form_state) +{ + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + + $elements = $cm->getIngestFormElements(); + $found = false; + foreach ($elements as $el) + { + if ($el['name']==$form_state['values']['form']['name']) + { + $found=true; + break; + } + } + + if ($found) + { + form_set_error('form][name',t('Error: The specified form element name is already listed in the ingest form. Please edit or delete the existing form element instead.')); + } + else if ($cm->addIngestFormElement(htmlentities($form_state['values']['form']['name']), + htmlentities($form_state['values']['form']['label']), + $form_state['values']['form']['type'], + $form_state['values']['form']['required']==1, + htmlentities($form_state['values']['form']['description'])) && + + $cm->setIngestFormElementParam(htmlentities($form_state['values']['form']['name']), + '#sticky', + $form_state['values']['form']['sticky']==1?'TRUE':false) && + + $cm->setIngestFormElementParam(htmlentities($form_state['values']['form']['name']), + '#autocomplete_path', + trim($form_state['values']['form']['autocomplete'])!=''?trim($form_state['values']['form']['autocomplete']):false) + && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully added ingest form element to model %model_pid.',array('%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to add ingest form element to model %model_pid.',array('%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } +} + +function icm_model_add_ingestFormElement(&$form_state,$params=null) +{ + if (is_array($params)) + { + $model_pid = $params[0]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add element to ingest form of %model_pid',array('%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The name of the form element.'), + ); + + $form['form']['label'] = array( + '#type' => 'textfield', + '#title' => t('Label'), + '#size' => 30, + '#description' => t('The label that will be displayed for the form element. If left blank, defaults to the element name.'), + ); + + $form['form']['type'] = array( + '#type' => 'select', + '#title' => t('Type'), + '#required'=> TRUE, + '#options'=> array('textfield'=>t('Textfield'), + 'select'=>t('Select'), + 'checkbox'=>t('Checkbox'), + 'radio'=>t('Radio'), + 'textarea'=>t('Textarea'), + 'filechooser'=>t('Ingest File Chooser'), + 'list'=>t('List/Tag Editor'), + 'fieldset'=>t('Fieldset'), + 'people'=>t('People List (incl. name, title, organization, conference, role)'), + 'other_select'=>t('Select (with \'other\' option)'), + 'datepicker'=>t('Datepicker'), + 'copyright'=>t('Creative-Commons Copyright Chooser'), + 'hidden'=>t('Hidden'), + 'file'=>t('File Upload (browse)'), + ), + '#description'=> t('The type of form element to display.') + ); + + $form['form']['required'] = array( + '#type' => 'checkbox', + '#title' => t('Required'), + '#description' => t('If enabled, the form element will be required.'), + ); + + $form['form']['sticky'] = array( + '#type' => 'checkbox', + '#title' => t('Sticky'), + '#description' => t('If enabled, the entered value will be carried over to the next ingest.'), + ); + + + $form['form']['autocomplete'] = array( + '#type' => 'textfield', + '#title' => t('Autocomplete Path'), + '#description' => t('Filled in, the field will suggest values from the current collection as the user types as listed by the specified drupal path. Only available for textfields.'), + ); + + $form['form']['description'] = array( + '#type' => 'textarea', + '#title' => t('Description'), + '#size'=>30, + '#description' => t('A brief description that will appear next to the form element.'), + ); + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; +} + + +function icm_model_edit_ingestFormElement_validate($form,&$form_state) +{ + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + + $elements = $cm->getIngestFormElements(); + $found = false; + foreach ($elements as $el) + { + if ($el['name']==$form_state['values']['form']['name']) + { + $found=true; + break; + } + } + + if (!$found) + { + form_set_error('form][name',t('Error: The specified form element was not found in the ingest form.')); + } + else if ($cm->editIngestFormElement(htmlentities($form_state['values']['form']['name']), + htmlentities($form_state['values']['form']['label']), + $form_state['values']['form']['type'], + $form_state['values']['form']['required']==1, + htmlentities($form_state['values']['form']['description'])) && + + $cm->setIngestFormElementParam(htmlentities($form_state['values']['form']['name']), + '#sticky', + $form_state['values']['form']['sticky']==1?'TRUE':false) && + + $cm->setIngestFormElementParam(htmlentities($form_state['values']['form']['name']), + '#autocomplete_path', + trim($form_state['values']['form']['autocomplete'])!=''?trim($form_state['values']['form']['autocomplete']):false) && + + $cm->saveToFedora()) + { + echo 'success:'.t('Successfully updated ingest form element to model %model_pid.',array('%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to updated ingest form element to model %model_pid.',array('%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } +} + +function icm_model_edit_ingestFormElement(&$form_state,$params=null) +{ + if (is_array($params)) + { + $model_pid = array_shift($params); + $name = join(' ',$params); + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + $name = $form_state['post']['form']['name']; + } + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (($cm = ContentModel::loadFromModel($model_pid))!==false) + { + $elements = $cm->getIngestFormElements(); + $element = false; + foreach ($elements as $el) + { + if ($el['name'] == $name) + { + $element=$el; + break; + } + } + + if ($element === false) + { + form_set_error('',t('Error: Specified ingest form element "%name" does not exist. Please try again.',array('%name'=>$name))); + } else + { + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Edit element "%name" in ingest form of %model_pid',array('%name'=>$name,'%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['nameDisp'] = array( + '#type' => 'item', + '#title' => t('Name'), + '#description' => t('The name of the form element.'), + '#value'=>$name + ); + + $form['form']['label'] = array( + '#type' => 'textfield', + '#title' => t('Label'), + '#size' => 30, + '#default_value' => ($element['label']==$name)?'':$element['label'], + '#description' => t('The label that will be displayed for the form element. If left blank, defaults to the element name.'), + ); + + $form['form']['type'] = array( + '#type' => 'select', + '#title' => t('Type'), + '#required'=> TRUE, + '#default_value'=>$element['type'], + '#options'=> array('textfield'=>t('Textfield'), + 'select'=>t('Select'), + 'checkbox'=>t('Checkbox'), + 'radio'=>t('Radio'), + 'textarea'=>t('Textarea'), + 'filechooser'=>t('Ingest File Chooser'), + 'list'=>t('List/Tag Editor'), + 'fieldset'=>t('Fieldset'), + 'people'=>t('People List (incl. name, title, organization, conference, role)'), + 'other_select'=>t('Select (with \'other\' option)'), + 'datepicker'=>t('Datepicker'), + 'copyright'=>t('Creative-Commons Copyright Chooser'), + 'hidden'=>t('Hidden'), + 'file'=>t('File Upload (browse)'), + ), + '#description'=> t('The type of form element to display.
Warning: Changing the type from "Select" or "Radio" to anything else will cause any authoritative list to be permanently removed.') + ); + + $form['form']['required'] = array( + '#type' => 'checkbox', + '#title' => t('Required'), + '#default_value'=> $element['required']?1:0, + '#description' => t('If enabled, the form element will be required.'), + ); + + $form['form']['sticky'] = array( + '#type' => 'checkbox', + '#title' => t('Sticky'), + '#default_value'=> isset($element['parameters']['#sticky']) && $element['parameters']['#sticky']?1:0, + '#description' => t('If enabled, the entered value will be carried over to the next ingest.'), + ); + + $form['form']['autocomplete'] = array( + '#type' => 'textfield', + '#title' => t('Autocomplete Path'), + '#default_value'=> isset($element['parameters']['#autocomplete_path'])?$element['parameters']['#autocomplete_path']:'', + '#description' => t('Filled in, the field will suggest values from the current collection as the user types as listed by the specified drupal path. Only available for textfields.'), + ); + + + $form['form']['description'] = array( + '#type' => 'textarea', + '#title' => t('Description'), + '#default_value' => $element['description'], + '#description' => t('A brief description that will appear next to the form element.'), + ); + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['name'] = array('#type' => 'hidden', '#value'=> $name); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + } + } else { + form_set_error('',t('Error: Unable to load content model %model_pid.',array('%model_pid'=>$model_pid))); + } + + + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; +} + + +function icm_model_add_authListItem_validate($form,&$form_state) +{ + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + + $elements = $cm->getIngestFormElements(); + $found = false; + foreach ($elements as $el) + { + if ($el['name']==$form_state['values']['form']['name']) + { + $found=true; + break; + } + } + + if (!$found) + { + form_set_error('form][name',t('Error: The specified form element was not found in the ingest form.')); + } + else if ($cm->addAuthListItem($form_state['values']['form']['name'],htmlentities($form_state['values']['form']['authValue']),htmlentities($form_state['values']['form']['authLabel'])) + && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully added authoritative list item to ingest form element to model %model_pid.',array('%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to add authoritative list item to ingest form of model %model_pid.',array('%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } +} + + + +function icm_model_add_authListItem(&$form_state,$params=null) +{ + if (is_array($params)) + { + $model_pid = array_shift($params); + $name = join(' ',$params); + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + $name = $form_state['post']['form']['name']; + } + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (($cm = ContentModel::loadFromModel($model_pid))!==false) + { + $elements = $cm->getIngestFormElements(); + $element = false; + foreach ($elements as $el) + { + if ($el['name'] == $name) + { + $element=$el; + break; + } + } + + if ($element === false) + { + form_set_error('',t('Error: Specified ingest form element "%name" does not exist. Please try again.',array('%name'=>$name))); + } else + { + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add item to the authoritative list of element "%name" of ingest form for %model_pid',array('%name'=>$name,'%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + $form['form']['nameDisp'] = array( + '#type' => 'item', + '#title' => t('Element Name'), + '#description' => t('The name of the form element.'), + '#value'=>$name + ); + + $form['form']['labelDisp'] = array( + '#type' => 'item', + '#title' => t('Element Label'), + '#value' => $element['label'], + '#description' => t('The label that will be displayed for the form element.'), + ); + + + $form['form']['authValue'] = array( + '#type' => 'textfield', + '#title' => t('Value'), + '#size'=> 30, + '#required' => TRUE, + '#description' => t('Authoritative list value.'), + ); + + $form['form']['authLabel'] = array( + '#type' => 'textfield', + '#title' => t('Label'), + '#size'=> 30, + '#description' => t('Authoritative list label. If left blank the item\'s value will also be used as the label.'), + ); + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['name'] = array('#type' => 'hidden', '#value'=> $name); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + } + } else { + form_set_error('',t('Error: Unable to load content model %model_pid.',array('%model_pid'=>$model_pid))); + } + + + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; +} + + + +function icm_model_update_editMetadataMethod_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + $module = $form_state['values']['form']['module']; + $file = $form_state['values']['form']['filename']; + $class= $form_state['values']['form']['class']; + $method=$form_state['values']['form']['method']; + $handler=$form_state['values']['form']['handler']; + $path = drupal_get_path('module',$module); + + if (empty($path) || !file_exists($path.'/'.$file)) + { + form_set_error('form][filename',t('Error: Selected plugin file not found. Please try again.')); + } else + { + require_once ($path.'/'.$file); + if (!class_exists($class)) + { + form_set_error('form][class',t('Error: Specified class does not exist in the plugin. Please try again.')); + } else + { + $obj = new $class; + if (!method_exists($obj,$method)) + { + form_set_error('form][method',t('Error: Specified builder method does not exist in the specified class/plugin. Please try again.')); + } + if (!method_exists($obj,$handler)) + { + form_set_error('form][handler',t('Error: Specified handler method does not exist in the specified class/plugin. Please try again.')); + } + } + } + + if (!ContentModel::validDsid($form_state['values']['form']['dsid'])) + { + form_set_error('form][dsid',t('Error: Invalid datastream identifier. Please try again.')); + } + + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + if ($cm->updateEditMetadataMethod($module,$file,$class,$method,$handler,$form_state['values']['form']['dsid']) && $cm->saveToFedora()) + { + echo 'success:'.t('Successfully updated edit metadata method to model %model_pid.',array('%model_pid'=>$cm->pid)); + exit(); + } else + { + form_set_error('form][name',t('Error: Unable to update edit metadata method to model %model_pid.',array('%model_pid'=>$cm->pid))); + } + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + } + +} + +function icm_model_update_editMetadataMethod(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Update Edit Metadata Method to model %model_pid',array('%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (($cm = ContentModel::loadFromModel($model_pid))!==false) + { + + $method = $cm->getEditMetadataMethod(); + + $form['form']['dsid'] = array( + '#type' => 'textfield', + '#title' => t('Datastream Identifier'), + '#size' => 30, + '#maxlength' => 64, + '#default_value'=>isset($method['dsid'])?$method['dsid']:'', + '#required' => TRUE, + '#description' => t('The datastream ID that stores the collected metadata from the form.'), + ); + + $form['form']['module'] = array( + '#type' => 'select', + '#title' => t('Module'), + '#element_validate' => array('icm_module_validate'), + '#options'=>icm_get_modules(), + '#required' => TRUE, + '#default_value'=>isset($method['module'])?$method['module']:'', + '#description' => t('The name of the module containing the plugin file.'), + ); + + $form['form']['filename'] = array( + '#type' => 'textfield', + '#title' => t('File'), + '#element_validate' => array('icm_filename_validate'), + '#default_value'=>isset($method['file'])?$method['file']:'', + '#required' => TRUE, + '#description' => t('The relative path of the file containing the ingest method class/method.'), + ); + + $form['form']['class'] = array( + '#type' => 'textfield', + '#title' => t('Class'), + '#element_validate' => array('icm_class_validate'), + '#required' => TRUE, + '#size'=>30, + '#default_value'=>isset($method['class'])?$method['class']:'', + '#description' => t('The name of the ingest method class.'), + ); + $form['form']['method'] = array( + '#type' => 'textfield', + '#title' => t('Builder Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#default_value'=>isset($method['method'])?$method['method']:'', + '#description' => t('The name of the class method to call when building the edit metadata form.'), + ); + + $form['form']['handler'] = array( + '#type' => 'textfield', + '#title' => t('Handler Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#default_value'=>isset($method['handler'])?$method['handler']:'', + '#description' => t('The name of the class method to call to handle the edit metadata form.'), + ); + + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + } else + { + form_set_error('',t('Error: Unable to load content model %model_pid.',array('%model_pid'=>$model_pid))); + } + + + + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + + +function icm_model_rollback_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($form_state['values']['form']['model_pid']))!==FALSE) + { + + $history = $cm->getHistory(); + $found = false; + foreach ($history as $key=>$ver) + { + if ($ver['versionID'] == $form_state['values']['form']['version']) + { + $found = $key; + break; + } + } + + if ($found === false) + { + form_set_error('',t('Error: Selected version was not found. Please try again.')); + } else if ($found == 0 && $form_state['values']['form']['removeOlder'] == 0) + { + form_set_error('',t('Error: Selected version is the current version. Nothing changed.')); + } else + { + $success=true; + if ($found > 0) + { + $startDate = $history[$found-1]['createDate']; + $success = $cm->purgeVersions($history[$found-1]['createDate'],null); + } + + if ($form_state['values']['form']['removeOlder'] == 1 && isset($history[$found+1])) + { + $endDate = $history[$found+1]['createDate']; + $success = $success && $cm->purgeVersions(null,$endDate); + } + + if ($success) + { + echo 'success:'.t('Successfully rolled back version of content model %cm_pid',array('%cm_pid'=>$cm->pid)); + exit(); + + } else + { + form_set_error('',t('Error: Unable to roll back version. Check watchdog logs.')); + } + } + + } else + { + form_set_error('',t('Error: Unable to load content model %cm_pid.',array('%cm_pid'=>htmlentities($form_state['values']['form']['model_pid'])))); + + } +} + +function icm_model_rollback(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Rollback Content Model %model_pid',array('%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($model_pid))!==false) + { + + $history = $cm->getHistory(); + + $options = array(); + foreach ($history as $ver) + { + $options[$ver['versionID']] = date(DATE_RFC822,strtotime($ver['createDate'])); + } + + if ($history !== false && count($history) > 0) + { + + + $form['form']['warning'] = array('#value' => 'Warning: Rolling back a datastream will purge all versions up-to the selected datastream.'); + + + $form['form']['cur'] = array( + '#type'=> 'item', + '#title'=> t('Current Version:'), + '#value'=> date(DATE_RFC822,strtotime($history[0]['createDate'])) + ); + + $form['form']['version'] = array( + '#type' => 'select', + '#title' => t('Version'), + '#options' => $options + ); + + $form['form']['removeOlder'] = array( + '#type' => 'checkbox', + '#title' => 'Purge Older Versions', + '#description' => 'If enabled, also purges versions of the datastream that are OLDER than the selected, effectively leaving only the selected version.' + ); + + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + + } else + { + $form['form']['version'] = array( + '#type'=> 'item', + '#title'=> t('Rollback to Version:'), + '#value'=> t('only one version available.') + ); + } + + + + } else + { + form_set_error('',t('Error: Unable to load content model %model_pid.',array('%model_pid'=>$model_pid))); + } + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + +function icm_model_purge_validate($form,&$form_state) +{ + + if ($form_state['values']['form']['confirm'] == 0) + { + form_set_error('form][confirm',t('If you would like to purge the selected content model, please check the confirmation checkbox and try again.')); + } else + { + $model_pid = $form_state['values']['form']['model_pid']; + + module_load_include('inc','fedora_repository','api/fedora_item'); + module_load_include('inc','fedora_repository','ContentModel'); + + if (($cm = ContentModel::loadFromModel($model_pid))!==FALSE) + { + $fedoraItem = new Fedora_Item($model_pid); + + if ($fedoraItem->purge(t('Purged using Islandora Content Modeller.'))) + { + echo 'success:'.t('Successfully purged content model %model_pid.',array('%model_pid'=>$model_pid)); + exit(); + + } else + { + form_set_error('',t('Error: Purge failed. Please contact an administrator for assistance.')); + } + + } else + { + form_set_error('',t('Error: Unable to load specified content model.')); + } + + } +} + +function icm_model_purge(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $model_pid = $params[0]; + } else + { + $model_pid = $form_state['post']['form']['model_pid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Purge Content Model %model_pid',array('%model_pid'=>$model_pid)), + '#tree' => TRUE, + ); + + module_load_include('inc', 'fedora_repository', 'ContentModel'); + + if (($cm = ContentModel::loadFromModel($model_pid))!==false) + { + $form['form']['warning'] = array('#value' => 'Warning: Purging a content model will affect any objects and collections that reference the model. Once purged, the entire model will be permanently deleted.'); + + $form['form']['confirm'] = array('#type' => 'checkbox', + '#title' => t('Confirm purge of model %model_pid',array('%model_pid'=>$model_pid)), + '#default_vale' => 0, + '#required' => TRUE); + + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + + } else + { + form_set_error('',t('Error: Unable to load content model %model_pid.',array('%model_pid'=>$model_pid))); + } + + $form['form']['model_pid'] = array('#type' => 'hidden', '#value'=> $model_pid); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + +function icm_model_new_submit($form,&$form_state) +{ + + //save the values for the current step into the storage array + $form_state['storage']['values'][$form_state['storage']['step']] = $form_state['values']; + + + if ($form_state['storage']['step'] == 2) + { + + module_load_include('inc','fedora_repository','api/fedora_item'); + module_load_include('inc','fedora_repository','ContentModel'); + + $item = Fedora_Item::ingest_new_item($form_state['storage']['values'][1]['form']['pid'],'A',$form_state['storage']['values'][1]['form']['name']); + $item->add_relationship('fedora-model:hasModel','info:fedora/fedora-system:ContentModel-3.0',FEDORA_MODEL_URI); + + switch ($form_state['storage']['values'][1]['form']['initialize']) + { + case 'blank': + //($pid,$name,$modelDsid, $defaultMimetype, $ingestFormDsid, $ingestFormPage, $ingestFormHideChooser, $ingestFormFile, $ingestFormClass, $ingestFormMethod, $ingestFormHandler) + $cm = ContentModel::ingestBlankModel($form_state['storage']['values'][1]['form']['pid'], + $form_state['storage']['values'][1]['form']['name'], + ContentModel::getDefaultDSID(), + $form_state['storage']['values'][2]['form']['type'], + $form_state['storage']['values'][2]['form']['dsid'], + $form_state['storage']['values'][2]['form']['page'], + $form_state['storage']['values'][2]['form']['hide_file_chooser']==1, + $form_state['storage']['values'][2]['from']['module'], + $form_state['storage']['values'][2]['form']['filename'], + $form_state['storage']['values'][2]['form']['class'], + $form_state['storage']['values'][2]['form']['method'], + $form_state['storage']['values'][2]['form']['handler']); + break; + + case 'model': + $cm = ContentModel::ingestFromModel($form_state['storage']['values'][1]['form']['pid'], + $form_state['storage']['values'][1]['form']['name'], + ContentModel::getDefaultDSID(), + $form_state['storage']['values'][2]['form']['model_pid']); + break; + + case 'file': + $cm = ContentModel::ingestFromFile($form_state['storage']['values'][1]['form']['pid'], + $form_state['storage']['values'][1]['form']['name'], + ContentModel::getDefaultDSID(), + drupal_get_path('module','fedora_repository').'/'.$form_state['storage']['values'][2]['form']['xml_filename']); + + + break; + } + + + + if ($cm !== false) + { + echo 'success:'.t('Successfully ingested new content model.'); + exit(); + }else + { + echo t('Error: Unable to ingest new content model. Please try again or contact an administrator.'); + + } + + } else + { + // check the button that was clicked and action the step chagne + $form_state['storage']['step']++; + + //tell Drupal we are redrawing the same form + $form_state['rebuild'] = TRUE; + + } +} + +function icm_model_new_validate($form, &$form_state) +{ + module_load_include('inc', 'fedora_repository', 'ContentModel'); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + + switch ($form_state['storage']['step']) + { + case 1: + if (!ContentModel::validPid($form_state['values']['form']['pid'])) + { + form_set_error('form][pid', t('Error: Invalid persistant identifier. Please try again.')); + } else if (Fedora_Item::fedora_item_exists($form_state['values']['form']['pid'])) + { + form_set_error('form][pid', t('Error: Specified PID already exists. Please choose a different PID and try again.')); + } + break; + + + case 2: + if ($form_state['storage']['values'][1]['form']['initialize'] == 'blank') + { + if (!ContentModel::validDsid($form_state['values']['form']['dsid'])) + { + form_set_error('form][dsid', t('Error: Invalid datastream identifier. Please try again.')); + } + if (intval($form_state['values']['form']['page']) <= 0) + { + form_set_error('form][page', t('Error: Page must be a positive integer. Please try again.')); + } + + $module=$form_state['values']['form']['module']; + $file = $form_state['values']['form']['filename']; + $class= $form_state['values']['form']['class']; + $method=$form_state['values']['form']['method']; + $handler=$form_state['values']['form']['handler']; + $path = drupal_get_path('module',$module); + + if (empty($path) || !file_exists($path.'/'.$file)) + { + form_set_error('form][filename',t('Error: Selected plugin file not found. Please try again.')); + } else + { + require_once ($path.'/'.$file); + if (!class_exists($class)) + { + form_set_error('form][class',t('Error: Specified class does not exist in the plugin. Please try again.')); + } else + { + $obj = @new $class; + if (!method_exists($obj,$method)) + { + form_set_error('form][method',t('Error: Specified builder method does not exist in the specified class/plugin. Please try again.')); + } + if (!method_exists($obj,$handler)) + { + form_set_error('form][handler',t('Error: Specified handler method does not exist in the specified class/plugin. Please try again.')); + } + } + } + } + break; + + } + +} + +function icm_model_new(&$form_state,$params=null) +{ + $form['#multistep']= TRUE; + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Create/Install New Content Model'), + '#tree' => TRUE, + ); + + if (empty($form_state['storage']['step'])) + { + // we are coming in without a step, so default to step 1 + $form_state['storage']['step'] = 1; + } + + switch ($form_state['storage']['step']) + { + case 1: + $form['form']['pid'] = array( + '#type' => 'textfield', + '#title' => t('Persistent Identifier'), + '#size' => 30, + '#required' => TRUE, + '#maxsize' => 64, + '#description' => t('The persistent identifier that will be used to identify the new content model. Make sure to choose a namespace that you will have access to from islandora.'), + ); + + $form['form']['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('A short human readable name for the content model.'), + ); + + $form['form']['initialize'] = array( + '#type' => 'select', + '#title' => t('Initialize Content Model'), + '#options' => array('blank'=>t('Start with a blank model'), + 'model'=>t('Clone an existing installed model'), + 'file'=>t('Load from a content model XML file')), + '#description' => t('Determines how the new content model is initialized.') + ); + + break; + + case 2: + + + $form['form']['#description'] = 'PID: '.$form_state['storage']['values'][1]['form']['pid'].'
'. + 'Name: '.$form_state['storage']['values'][1]['form']['name'].'

'; + + switch ($form_state['storage']['values'][1]['form']['initialize']) + { + case 'model': + $form['form']['#description'] .= t('Please select an content model below that will be used as the base for this new content model. The model name will be updated to the value entered in the previous step.'); + module_load_include('inc','fedora_repository','CollectionClass'); + module_load_include('inc','fedora_repository','ContentModel'); + $collectionHelper = new CollectionClass(); + + $options=array(); + $items = new SimpleXMLElement( $collectionHelper->getRelatedItems(variable_get('fedora_content_model_collection_pid','islandora:ContentModelCollection') ,null,null)); + for ($i = 0; $i < count($items->results->result); $i++) + { + list(,$pid)=preg_split('/\//',$items->results->result[$i]->object['uri']); + + $cm = ContentModel::loadFromModel($pid); + if ($cm !== false) + { + $options[$pid] = $items->results->result[$i]->title .' ('.$pid.')'; + } + } + + $form['form']['model_pid'] = array( + '#type' => 'select', + '#title' => t('Content Model'), + '#required' => TRUE, + '#options' => $options, + '#description' => t('The currently installed content model to clone.'), + ); + break; + + case 'file': + $form['form']['#description'] .= t('Please select an ISLANDORACM XML file that will be used as the base for this new content model.'); + + $plugin_path = drupal_get_path('module','fedora_repository').'/content_models'; + + $files = array(''); + if ( ($dir = opendir($plugin_path)) !== false) + { + while (($file = readdir($dir)) !== false) + { + if (preg_match('/\.xml$/',$file)) + { + $files['content_models/'.$file]='content_models/'.$file; + } + } + } + + $form['form']['xml_filename'] = array( + '#type' => 'select', + '#title' => t('File'), + '#options'=>$files, + '#required' => TRUE, + '#description' => t('The relative path of the file containing the desired content model datastream.'), + ); + + break; + + case 'blank': + default: + + $form['form']['#description'] .= t('The only additional required information that a model must have is the ingest form method/handler. Once the model has been added, please go in and add any additional mimetypes, datastreams and ingest rules and ingest form elements that are neccessary. '); + + + $form['form']['type'] = array( + '#type' => 'textfield', + '#title' => t('Mimetype'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('A content mimetype that can be ingested using this model.'), + ); + + $form['form']['dsid'] = array( + '#type' => 'textfield', + '#title' => t('Datastream Identifier'), + '#size' => 30, + '#maxlength' => 64, + '#default_value'=>$attr['dsid'], + '#required' => TRUE, + + '#description' => t('The datastream ID that stores the collected metadata from the form.'), + ); + + $form['form']['page'] = array( + '#type' => 'textfield', + '#title' => t('Page'), + '#size' => 3, + '#required' => TRUE, + '#default_value' => $attr['page'], + '#description' => t('??? not sure what this field is for. Cant find a reference to it, candidate for removal. '), + ); + + $form['form']['hide_file_chooser'] = array( + '#type' => 'checkbox', + '#title' => t('Hide File Chooser'), + '#size' => 3, + '#required' => TRUE, + '#default_value' => $attr['hide_file_chooser']?1:0, + '#description' => t('If enabled, the file choose will not be displayed in the ingest form for this model.'), + ); + + $form['form']['redirect'] = array( + '#type' => 'checkbox', + '#title' => t('Redirect on Ingest'), + '#size' => 3, + '#required' => TRUE, + '#default_value' => $attr['redirect']?1:0, + '#description' => t('If enabled, the user will be redirected to the collection view on successful ingest.'), + ); + + $form['form']['module'] = array( + '#type' => 'select', + '#title' => t('Module'), + '#element_validate' => array('icm_module_validate'), + '#options'=>icm_get_modules(), + '#required' => TRUE, + '#default_value'=>$builderMethod['module'], + '#description' => t('The name of the module containing the form builder plugin file.'), + ); + + $form['form']['filename'] = array( + '#type' => 'textfield', + '#title' => t('File'), + '#element_validate' => array('icm_filename_validate'), + '#required' => TRUE, + '#default_value'=>$builderMethod['file'], + '#description' => t('The relative path of the file containing the form builder/handler class/method.'), + ); + + $form['form']['class'] = array( + '#type' => 'textfield', + '#title' => t('Class'), + '#element_validate' => array('icm_class_validate'), + '#required' => TRUE, + '#default_value'=> $builderMethod['class'], + '#size'=>30, + '#description' => t('The name of the builder/handler class.'), + ); + $form['form']['method'] = array( + '#type' => 'textfield', + '#title' => t('Form Builder Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#default_value'=> $builderMethod['method'], + '#description' => t('The name of the class method to build the ingest form.'), + ); + + $form['form']['handler'] = array( + '#type' => 'textfield', + '#title' => t('Form Handler Method'), + '#element_validate' => array('icm_method_validate'), + '#size'=>30, + '#required' => TRUE, + '#default_value'=> $builderMethod['handler'], + '#description' => t('The name of the class method to handle the ingest form.'), + ); + + break; + } + + break; + + } + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; +} + + + +function icm_collection_purge_validate($form,&$form_state) +{ + + if ($form_state['values']['form']['confirm'] == 0) + { + form_set_error('form][confirm',t('If you would like to purge the selected collection, please check the confirmation checkbox and try again.')); + } else + { + $cp_pid = $form_state['values']['form']['cp_pid']; + + module_load_include('inc','fedora_repository','api/fedora_item'); + module_load_include('inc','fedora_repository','CollectionPolicy'); + + if (($cp = CollectionPolicy::loadFromCollection($cp_pid))!==FALSE) + { + $fedoraItem = new Fedora_Item($cp_pid); + + if ($fedoraItem->purge(t('Purged using Islandora Content Modeller.'))) + { + echo 'success:'.t('Successfully purged collection %cp_pid.',array('%cp_pid'=>$cp_pid)); + exit(); + } else + { + form_set_error('',t('Error: Purge failed. Please contact an administrator for assistance.')); + } + + } else + { + form_set_error('',t('Error: Unable to load specified collection policy.')); + } + + } +} + +function icm_collection_purge(&$form_state,$params=null) +{ + + if (is_array($params)) + { + $cp_pid = $params[0]; + } else + { + $cp_pid = $form_state['post']['form']['cp_pid']; + } + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Purge Collection %cp_pid',array('%cp_pid'=>$cp_pid)), + '#tree' => TRUE, + ); + + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + + if (($cm = CollectionPolicy::loadFromCollection($cp_pid))!==false) + { + $form['form']['warning'] = array('#value' => 'Warning: Purging a collection will orphan any objects contained in the collection. This can not be undone.'); + + $form['form']['confirm'] = array('#type' => 'checkbox', + '#title' => t('Confirm purge of collection %cp_pid',array('%cp_pid'=>$cp_pid)), + '#default_vale' => 0, + '#required' => TRUE); + + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + + } else + { + form_set_error('',t('Error: Unable to load collection %cp_pid.',array('%cp_pid'=>$cp_pid))); + } + + $form['form']['cp_pid'] = array('#type' => 'hidden', '#value'=> $cp_pid); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + return $form; +} + +function icm_collection_new_submit($form,&$form_state) +{ + + //save the values for the current step into the storage array + $form_state['storage']['values'][$form_state['storage']['step']] = $form_state['values']; + + + + if ($form_state['storage']['step'] == 2) + { + + module_load_include('inc','fedora_repository','api/fedora_item'); + module_load_include('inc','fedora_repository','CollectionPolicy'); + + $cp = false; + if (($parent_cp = CollectionPolicy::loadFromCollection($form_state['storage']['parent'])) !== FALSE) + { + $item = Fedora_Item::ingest_new_item($form_state['storage']['values'][1]['form']['pid'],'A',$form_state['storage']['values'][1]['form']['name']); + $item->add_relationship('fedora-model:hasModel','info:fedora/'.variable_get('fedora_collection_model_pid','islandora:collectionCModel') ,FEDORA_MODEL_URI); + $item->add_relationship($parent_cp->getRelationship(),$parent_cp->pid,RELS_EXT_URI); + + switch ($form_state['storage']['values'][1]['form']['initialize']) + { + case 'blank': + //($pid,$name,$modelDsid, $defaultMimetype, $ingestFormDsid, $ingestFormPage, $ingestFormHideChooser, $ingestFormFile, $ingestFormClass, $ingestFormMethod, $ingestFormHandler) + $cp = CollectionPolicy::ingestBlankPolicy($form_state['storage']['values'][1]['form']['pid'], + $form_state['storage']['values'][1]['form']['name'], + CollectionPolicy::getDefaultDSID(), + $form_state['storage']['values'][2]['form']['model']['pid'], + $form_state['storage']['values'][2]['form']['model']['namespace'], + $form_state['storage']['values'][2]['form']['relationship'], + $form_state['storage']['values'][2]['form']['term']['field'], + $form_state['storage']['values'][2]['form']['term']['value']); + break; + + case 'collection': + $cp = CollectionPolicy::ingestFromCollection($form_state['storage']['values'][1]['form']['pid'], + $form_state['storage']['values'][1]['form']['name'], + CollectionPolicy::getDefaultDSID(), + $form_state['storage']['values'][2]['form']['collection_pid']); + break; + + case 'file': + $cp = CollectionPolicy::ingestFromFile($form_state['storage']['values'][1]['form']['pid'], + $form_state['storage']['values'][1]['form']['name'], + CollectionPolicy::getDefaultDSID(), + drupal_get_path('module','fedora_repository').'/'.$form_state['storage']['values'][2]['form']['policy_filename']); + + + break; + } + } + + + if ($cp !== false) + { + echo 'success:'.t('Successfully ingested new collection.'); + exit(); + }else + { + echo t('Error: Unable to ingest new collection. Please try again or contact an administrator.'); + + } + + } else + { + // check the button that was clicked and action the step chagne + $form_state['storage']['step']++; + + //tell Drupal we are redrawing the same form + $form_state['rebuild'] = TRUE; + + } +} + +function icm_collection_new_validate($form, &$form_state) +{ + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + module_load_include('inc', 'fedora_repository', 'ContentModel'); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + + if ($cp = CollectionPolicy::loadFromCollection($form_state['storage']['parent']) === FALSE) + { + form_set_error('',t('Error: Unable to load parent collection %cp_pid. Please try adding to a different collection or contact an administrator.',array('%cp_pid',$form_state['storage']['parent']))); + } + + switch ($form_state['storage']['step']) + { + case 1: + if (!CollectionPolicy::validPid($form_state['values']['form']['pid'])) + { + form_set_error('form][pid', t('Error: Invalid persistant identifier. Please try again.')); + } else if (Fedora_Item::fedora_item_exists($form_state['values']['form']['pid'])) + { + form_set_error('form][pid', t('Error: Specified PID already exists. Please choose a different PID and try again.')); + } + break; + + + case 2: + switch ($form_state['storage']['values'][1]['form']['initialize'] ) + { + case 'blank': + if ($form_state['values']['form']['model']['pid'] != $form_state['storage']['values'][1]['form']['pid'] && ($cm = ContentModel::loadFromModel($form_state['values']['form']['model']['pid'])) === FALSE) + { + form_set_error('form][model][pid', t('Error: Specified content model could not be loaded. Please choose a different model or contact an administrator.')); + } + if (!ContentModel::validPid($form_state['values']['form']['model']['namespace'])) + { + form_set_error('form][model][namespace',t('Error: Invalid namespace format.')); + } + break; + + case 'collection': + if (!CollectionPolicy::validPid($form_state['values']['form']['collection_pid']) || ($cp = CollectionPolicy::loadFromCollection($form_state['values']['form']['collection_pid'])) === FALSE) + { + form_set_error('form][collection_pid', t('Error: Specified collection could not be loaded. Please choose a different collection or contact an administrator.')); + } + break; + + } + break; + + } + +} + +function icm_collection_new(&$form_state,$params=null) +{ + $form['#multistep']= TRUE; + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Create/Install New Collection'), + '#tree' => TRUE, + ); + + if (empty($form_state['storage']['step'])) + { + // we are coming in without a step, so default to step 1 + $form_state['storage']['step'] = 1; + $form_state['storage']['parent'] = $params[0]; + } + + switch ($form_state['storage']['step']) + { + case 1: + $form['form']['pid'] = array( + '#type' => 'textfield', + '#title' => t('Persistent Identifier'), + '#size' => 30, + '#required' => TRUE, + '#maxsize' => 64, + '#description' => t('The persistent identifier that will be used to identify the new collection. Make sure to choose a namespace that you will have access to from islandora.'), + ); + + $form['form']['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('A short human readable name for the collection.'), + ); + + $form['form']['initialize'] = array( + '#type' => 'select', + '#title' => t('Initialize Collection Policy'), + '#options' => array('blank'=>t('Start with a blank policy'), + 'collection'=>t('Clone the policy from an existing collection'), + 'file'=>t('Load from a collection policy XML file')), + '#description' => t('Determines how the new collection policy is initialized.') + ); + + break; + + case 2: + + + $form['form']['#description'] = 'PID: '.$form_state['storage']['values'][1]['form']['pid'].'
'. + 'Name: '.$form_state['storage']['values'][1]['form']['name'].'

'; + + switch ($form_state['storage']['values'][1]['form']['initialize']) + { + case 'collection': + $form['form']['#description'] .= t('Please select a collection below whose collection policy will be used as the basis for the new collection. The collections name will be updated to the value entered in the previous step.'); + module_load_include('inc','fedora_repository','CollectionClass'); + module_load_include('inc','fedora_repository','ContentModel'); + + $form['form']['collection_pid'] = array( + '#type' => 'textfield', + '#title' => t('Collection'), + '#required' => TRUE, + '#size' => 30, + '#maxsize' => 64, + '#description' => t('The currently installed collection to clone.'), + ); + break; + + case 'file': + $form['form']['#description'] .= t('Please select an COLLECTION_POLICY XML file that will be used as the base for this new collection.'); + + $plugin_path = drupal_get_path('module','fedora_repository').'/collection_policies'; + $files = array(''); + if ( ($dir = opendir($plugin_path)) !== false) + { + while (($file = readdir($dir)) !== false) + { + if (preg_match('/\.xml$/',$file)) + { + $files['collection_policies/'.$file]='collection_policies/'.$file; + } + } + } + + $form['form']['policy_filename'] = array( + '#type' => 'select', + '#title' => t('File'), + '#options'=>$files, + '#required' => TRUE, + '#description' => t('The relative path of the file containing the desired collection policy datastream.'), + ); + + break; + + case 'blank': + default: + + $form['form']['#description'] .= t('The only additional required information that a collection must have is an allowed content model, relationship and default search term. Once the collection has been added, please go in and add any content models and search terms that are neccessary. '); + + module_load_include('inc','fedora_repository','CollectionClass'); + module_load_include('inc','fedora_repository','ContentModel'); + $collectionHelper = new CollectionClass(); + + $options=array($form_state['storage']['values'][1]['form']['pid']=> 'Self ('.$form_state['storage']['values'][1]['form']['pid'].')'); + $items = new SimpleXMLElement( $collectionHelper->getRelatedItems(variable_get('icm_model_collection_pid','islandora:ContentModelCollection') ,null,null)); + for ($i = 0; $i < count($items->results->result); $i++) + { + list(,$pid)=preg_split('/\//',$items->results->result[$i]->object['uri']); + + $cm = ContentModel::loadFromModel($pid); + if ($cm !== false) + { + $options[$pid] = $items->results->result[$i]->title .' ('.$pid.')'; + } + } + + $form['form']['relationship'] = array( + '#type' => 'textfield', + '#title'=> t('Relationship'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The relationship to use for objects in this collection.'), + '#default_value' => 'isMemberOfCollection' + ); + + $form['form']['model'] = array( + '#type' => 'fieldset', + '#title' => t('Initial Content Model'), + '#tree' => TRUE, + ); + + $form['form']['model']['pid'] = array( + '#type' => 'select', + '#title' => t('Persistent Identifier'), + '#required' => TRUE, + '#options' => $options, + '#description' => t('The PID of the content model that can be ingested into this collection.'), + ); + + + $form['form']['model']['namespace'] = array( + '#type'=> 'textfield', + '#title'=> t('Namespace'), + '#description' => t('The base namespace for objects of this type injested into the collection. eg islandora:collection '), + '#size' => 30, + '#maxSize' => 60, + '#required' => TRUE + ); + + $form['form']['term'] = array( + '#type' => 'fieldset', + '#title' => t('Search Term'), + '#tree' => TRUE, + ); + + $form['form']['term']['field'] = array( + '#type' => 'textfield', + '#title' => t('Field'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('The name of the field in the DC to search.'), + ); + + $form['form']['term']['value'] = array( + '#type' => 'textfield', + '#title' => t('Label'), + '#size' => 30, + '#required' => TRUE, + '#description' => t('A descriptive label for the field displayed on the search form.'), + ); + + + break; + } + + break; + + } + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; +} + + +function icm_collection_edit_validate($form,&$form_state) +{ + //only proceed if no errors have been found. + if (form_get_errors() !== NULL) + return; + + module_load_include('inc','fedora_repository','CollectionPolicy'); + + $c_pid = $form_state['values']['form']['collection_pid']; + + if (($cp = CollectionPolicy::loadFromCollection($c_pid)) !== FALSE) + { + if ($cp->setRelationship(trim($form_state['values']['form']['relationship'])) && $cp->setStagingArea(trim($form_state['values']['form']['staging_area'])) && $cp->saveToFedora()) + { + echo 'success:'.t('Successfully updated collection policy of %cp_pid%.',array('%cp_pid%'=>$cp->pid)); + exit(); + + } else + { + form_set_error('',t('Error: Unable to update collection policy of %cp_pid%.',array('%cp_pid%'=>$cp->pid))); + } + } +} + + +function icm_collection_edit(&$form_state,$params=null) +{ + + if (is_array($params) && isset($params[0])) + { + $collection_pid = $params[0]; + } else if (isset($form_state['post']['form']['collection_pid'])) + { + $collection_pid = $form_state['post']['form']['collection_pid']; + } + + $form['form'] = array( + '#type'=>'fieldset', + '#title'=> t('Edit collection %collection_pid', array('%collection_pid'=>$collection_pid)), + '#tree'=>TRUE + ); + + module_load_include('inc','fedora_repository','CollectionPolicy'); + if (($cp = CollectionPolicy::loadFromCollection($collection_pid))!==FALSE) + { + + $staging_area = $cp->getStagingArea(false); + if ($staging_area == false) + { + $staging_area = ''; + } + + $form['form']['relationship'] = array( + '#type' => 'textfield', + '#title' => t('Relationship'), + '#required' => TRUE, + '#default_value' => $cp->getRelationship(), + '#size' => 30, + '#maxSize' => 60, + '#description' => t('The relationship to use for members of this collection.'), + ); + + $form['form']['staging_area'] = array( + '#type'=> 'textfield', + '#title'=> t('Staging Area'), + '#default_value'=> $staging_area, + '#description' => t('The path to the staging area to use when ingesting files into this collection. If left blank, the staging area of the parent collection will be used. Please do not include a trailing slash.'), + '#size' => 30, + '#maxSize' => 60 + ); + + $form['form']['collection_pid'] = array('#type' => 'hidden', '#value'=> $collection_pid); + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + } else + { + form_set_error('',t('Error: Unable to load requested collection_policy.')); + } + + + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; +} + +function /*icm*/_model_service_add(&$form_state,$params=null) +{ + + if (empty($form_state['storage']['step'])) + { + // we are coming in without a step, so default to step 1 + $form_state['storage']['step'] = 1; + $form_state['storage']['cm_pid'] = $params[0]; + } + + $cm_pid = $form_state['storage']['cm_pid']; + + $form['#multistep']= TRUE; + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Add Service to Content Model %cm_pid.',array('%cm_pid'=>$cm_pid)), + '#tree' => TRUE, + ); + + + switch ($form_state['storage']['step']) + { + case 1: + + module_load_include('inc','fedora_repository','CollectionClass'); + $collectionHelper = new CollectionClass(); + + $options=array(); + $items = new SimpleXMLElement( $collectionHelper->getRelatedItems(variable_get('fedora_service_def_collection_pid','uofm:serviceDefCollection') ,null,null)); + for ($i = 0; $i < count($items->results->result); $i++) + { + list(,$pid)=preg_split('/\//',$items->results->result[$i]->object['uri']); + + $cm = ContentModel::loadFromModel($pid); + if ($cm !== false) + { + $options[$pid] = $items->results->result[$i]->title .' ('.$pid.')'; + } + } + + $form['form'] = array( + '#type'=>'fieldset', + '#title'=> t('Add content model to collection %collection_pid', array('%collection_pid'=>$collection_pid)), + '#tree'=>TRUE + ); + + $form['form']['model_pid'] = array( + '#type' => 'select', + '#title' => t('Content Model'), + '#required' => TRUE, + '#options' => $options, + '#description' => t('A descriptive label for the field displayed on the search form.'), + ); + + $form['form']['namespace'] = array( + '#type'=> 'textfield', + '#title'=> t('Namespace'), + '#description' => t('The base namespace for objects of this type injested into the collection. eg islandora:collection '), + '#size' => 30, + '#maxSize' => 60, + '#required' => TRUE + ); + break; + + } + $form['form']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Cancel'), '#id'=>'cancel'); + + return $form; +} + +function icm_display_rawXml(&$form_state,$params=null) +{ + + $form['form'] = array( + '#type' => 'fieldset', + '#title' => t('Display Raw XML'), + '#tree' => TRUE, + ); + + if (is_array($params)) + { + $type = $params[0]; + $pid = $params[1]; + + switch (strtolower($type)) + { + case 'model': + module_load_include('inc', 'fedora_repository', 'ContentModel'); + if (($cm = ContentModel::loadFromModel($pid))!==false) + { + $form['form']['pid'] = array( + '#type'=>'item', + '#title'=>t('PID'), + '#value'=>$pid + ); + $form['form']['pre'] = array( + '#value'=>'
'.htmlentities($cm->dumpXml()).'
' + ); + } else + { + form_set_error('',t('Error: Unable to load requested content model.')); + } + break; + + case 'collection': + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + if (($cp = CollectionPolicy::loadFromCollection($pid))!==false) + { + $form['form']['pid'] = array( + '#type'=>'item', + '#title'=>t('PID'), + '#value'=>$pid + ); + $form['form']['pre'] = array( + '#value'=>'
'.htmlentities($cp->dumpXml()).'
' + ); + } else + { + form_set_error('',t('Error: Unable to load requested collection policy.')); + } + break; + } + + } else + { + form_set_error('',t('Error: Unknown XML Datastream Specified.')); + } + $form['form']['cancel'] = array('#type' => 'button', '#value' => t('Close'), '#id'=>'cancel'); + + return $form; +} + diff --git a/content_modeller/js/content_modeller.js b/content_modeller/js/content_modeller.js new file mode 100644 index 00000000..3d815111 --- /dev/null +++ b/content_modeller/js/content_modeller.js @@ -0,0 +1,271 @@ + var collection = new Array('Root'); + var model = false; + +$(document).ready(function () { + + $(document).ajaxStart(function(){ + $('#ajaxBusy').show(); + }).ajaxStop(function(){ + $('#ajaxBusy').hide(); + }); + + $('#Notification').jnotifyInizialize({ + oneAtTime: false, + appendType: 'append' + }) + .css({ + 'marginTop': '20px', + 'left': '20px', + 'width': '500px', + 'z-index': '9999' + }); + + updateCollectionTree(); + updateModelList(); + + $('.refresh').click(function () { + $('#Notification').jnotifyAddMessage({text: 'Refreshed collection '+collection[collection.length-1]+' and model '+(model==false?'list':model)+'.', permanent: false}); + updateCollectionTree(); + if (model == false) + updateModelList(); + else + updateModelTree(); + return false; + }); + + $('.list').click(function () { + $('#Notification').jnotifyAddMessage({text: 'Refreshed model list.', permanent: false}); + model = false; + updateModelList(); + return false; + }); + + + function updateBreadcrumbs() + { + var content = ''; + for (var i = 0; i < collection.length; i++) + { + content += ''+collection[i]+' /'; + } + $('#collection_crumbs').html(content); + } + + function handleForm() + { + $('#edit-form-module').change(function () { + $.get('modeller/ajax/getFiles/', { module: $('#edit-form-module').val() }, function (data) { + $('#edit-form-filename-select').html(data); + }); + $('#edit-form-class-select, #edit-form-method-select, #edit-form-handler-select').html(''); + }); + + $('.form-item #edit-form-filename').hide(); + $('.form-item #edit-form-filename').before(''); + $('#edit-form-filename-select').change(function () { + $('#edit-form-filename').val($('#edit-form-filename-select').val()); + $.get('modeller/ajax/getClasses/', { module: $('#edit-form-module').val(), + file: $('#edit-form-filename').val(), + className: $('#edit-form-class').val() }, + function (data) { $('#edit-form-class-select').html(data); }); + }); + + + $('.form-item #edit-form-class').hide(); + $('.form-item #edit-form-class').before(''); + $('#edit-form-class-select').change(function () { + $('#edit-form-class').val($('#edit-form-class-select').val()); + $.get('modeller/ajax/getMethods/', { module: $('#edit-form-module').val(), + file: $('#edit-form-filename').val(), + className: $('#edit-form-class').val() }, + function (data) { + $('#edit-form-method-select').html(data); + $('#edit-form-handler-select').html(data); + }); + }); + + if ($('#edit-form-file').val() || $('#edit-form-class').val() || $('#edit-form-filename').val()) + { + $.get('modeller/ajax/getFiles/', { module: $('#edit-form-module').val(), file: $('#edit-form-filename').val() }, function (data) { + $('#edit-form-filename-select').html(data); + }); + $.get('modeller/ajax/getClasses/', { module: $('#edit-form-module').val(), file: $('#edit-form-filename').val(), className: $('#edit-form-class').val() }, function (data) { + $('#edit-form-class-select').html(data); + }); + } + + $('.form-item #edit-form-method, .form-item #edit-form-handler').hide(); + $('.form-item #edit-form-method').before(''); + $('.form-item #edit-form-handler').before(''); + $('#edit-form-method-select').change(function () { + $('#edit-form-method').val($('#edit-form-method-select').val()); + }); + $('#edit-form-handler-select').change(function () { + $('#edit-form-handler').val($('#edit-form-handler-select').val()); + }); + + + if ( $('#edit-form-class').val()) + { + $.get('modeller/ajax/getMethods/', { module: $('#edit-form-module').val(), file: $('#edit-form-filename').val(), className: $('#edit-form-class').val(), method: $('#edit-form-method').val() }, function (data) { + $('#edit-form-method-select').html(data); + }); + $.get('modeller/ajax/getMethods/', { module: $('#edit-form-module').val(), file: $('#edit-form-filename').val(), className: $('#edit-form-class').val(), method: $('#edit-form-handler').val() }, function (data) { + $('#edit-form-handler-select').html(data); + }); + } + + $('#ajaxForm #cancel').click(function (d) { + $('#ajaxForm').fadeOut(); + return false; + }); + + $('#ajaxForm form').submit(function (d) { + $.post(d.target.action, + $('#'+d.target.id).serialize()+'&op=Save', + function (data) + { + lines = data.split(':'); + if (lines.shift() == 'success') + { + $('#Notification').jnotifyAddMessage({text: lines.join(':'), permanent: false}); + $('#ajaxForm').fadeOut(); + if (model == false) + updateModelList(); + else + updateModelTree(); + updateCollectionTree(); + } else + { + $('#ajaxForm').html(data); + handleForm(); + } + }); + return false; + }); + } + + function buttonIcons() + { + $('.ajaxButtonIcon').unbind(); + $('.ajaxButtonIcon').click(function () { + $.get('modeller/ajax/button', { formReq: this.id}, function (data) { + lines = data.split(':'); + if (lines.shift() == 'success') + { + $('#Notification').jnotifyAddMessage({text: lines.join(':'), permanent: false}); + if (model == false) + updateModelList(); + else + updateModelTree(); + updateCollectionTree(); + } else + { + $('#Notification').jnotifyAddMessage({text: data, permanent: false, type: 'error'}); + } + }); + + }); + } + + function formIcons() + { + $('.ajaxFormIcon').unbind(); + $('.ajaxFormIcon').click(function () { + var params=this.id.split(' '); + var formName=params.shift(); + $.get('modeller/ajax/processForm/'+formName, { formReq: params.join(' ')}, function (data) { + if (data == '') + { + $('#Notification').jnotifyAddMessage({text: 'Error: Unable to load requested form \''+formName+'\'.', permanent: false, type: 'error'}); + } else + { + $('#ajaxForm').html(data).fadeIn(); + handleForm(); + } + }); + + return false; + }); + } + + function updateModelList() { + $.get('modeller/ajax/listModels' , function (j) { + $('#model_tree').html(j); + $('#model_tree ul').treeview({ animated: "fast", + collapsed: true, + unique: false, + persist: "cookie", + cookieId: "modelTree"}); + + $(".list_model").click( function () { + model = this.id; + updateModelTree(); + $('#Notification').jnotifyAddMessage({text: 'Displayed model '+this.id, permanent: false}); + return false; + }); + + buttonIcons(); + formIcons(); + + }); + } + + function updateModelTree() { + $.get('modeller/ajax/model', { model_pid: model} , function (j) { + $('#model_tree').html(j); + $('#model_tree ul').treeview({ animated: "fast", + collapsed: true, + unique: false, + persist: "cookie", + cookieId: "modelTree"}); + + buttonIcons(); + formIcons(); + + }); + } + + function updateCollectionTree() { + collection_pid = collection[collection.length-1]; + if (collection_pid == 'Root') + collection_pid = false; + + $.get('modeller/ajax/collection', { collection_pid: collection_pid} , function (j) { + updateBreadcrumbs(); + + $('#collection_tree').html(j); + $('#collection_tree ul').treeview({ animated: "fast", + collapsed: true, + unique: false, + persist: "cookie", + cookieId: "collectionTree" }); + + buttonIcons(); + formIcons(); + + $(".collection_model").click( function () { + model = this.id; + updateModelTree(); + $('#Notification').jnotifyAddMessage({text: 'Displayed model '+this.id, permanent: false}); + return false; + }); + + $(".collection_child").click( function () { + collection.push(this.id); + updateCollectionTree(); + $('#Notification').jnotifyAddMessage({text: 'Switched to collection '+this.id, permanent: false}); + return false; + }); + + $(".collection_crumb").click( function () { + var pop_no = collection.length-this.id-1; + for (var i =0; i < pop_no; i++) + collection.pop(); + updateCollectionTree(); + $('#Notification').jnotifyAddMessage({text: 'Switched to collection '+collection[collection.length-1], permanent: false}); + return false; + }); + }); + } + }); diff --git a/content_modeller/js/jquery.cookie.js b/content_modeller/js/jquery.cookie.js new file mode 100644 index 00000000..8e8e1d9e --- /dev/null +++ b/content_modeller/js/jquery.cookie.js @@ -0,0 +1,92 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', {expires: 7, path: '/', domain: 'jquery.com', secure: true}); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + var path = options.path ? '; path=' + options.path : ''; + var domain = options.domain ? '; domain=' + options.domain : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; \ No newline at end of file diff --git a/content_modeller/js/jquery.jnotify.js b/content_modeller/js/jquery.jnotify.js new file mode 100644 index 00000000..0366e791 --- /dev/null +++ b/content_modeller/js/jquery.jnotify.js @@ -0,0 +1,143 @@ +/** +* jQuery.jNotify +* jQuery Notification Engine +* +* Copyright (c) 2010 Fabio Franzini +* +* 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 notify and this permission notify 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. +* +* @author Fabio Franzini +* @copyright 2010 www.fabiofranzini.com +* @version 1 +**/ + +(function(jQuery) { + jQuery.fn.jnotifyInizialize = function(options) { + var element = this; + + var defaults = { + oneAtTime: false, + appendType: 'append' + }; + + var options = jQuery.extend({}, defaults, options); + + this.addClass('notify-wrapper'); + + if (options.oneAtTime) + this.addClass('notify-wrapper-oneattime'); + + if (options.appendType == 'prepend' && options.oneAtTime == false) + this.addClass('notify-wrapper-prepend'); + + return this; + }; + jQuery.fn.jnotifyAddMessage = function(options) { + + var notifyWrapper = this; + + if (notifyWrapper.hasClass('notify-wrapper')) { + + var defaults = { + text: '', + type: 'message', + showIcon: true, + permanent: false, + disappearTime: 3000 + }; + + var options = jQuery.extend({}, defaults, options); + var styleClass; + var iconClass; + + switch (options.type) { + case 'message': + { + styleClass = 'ui-state-highlight'; + iconClass = 'ui-icon-info'; + } + break; + case 'error': + { + styleClass = 'ui-state-error'; + iconClass = 'ui-icon-alert'; + } + break; + default: + { + styleClass = 'ui-state-highlight'; + iconClass = 'ui-icon-info'; + } + break; + } + + if (notifyWrapper.hasClass('notify-wrapper-oneattime')) { + this.children().remove(); + } + + var notifyItemWrapper = jQuery('
'); + var notifyItem = jQuery('
') + .addClass(styleClass); + + if (notifyWrapper.hasClass('notify-wrapper-prepend')) + notifyItem.prependTo(notifyWrapper); + else + notifyItem.appendTo(notifyWrapper); + + notifyItem.wrap(notifyItemWrapper); + + if (options.showIcon) + jQuery('') + .addClass(iconClass) + .appendTo(notifyItem); + + jQuery('').html(options.text).appendTo(notifyItem); + jQuery('
') + .prependTo(notifyItem) + .click(function() { remove(notifyItem) }); + + // IEsucks + if (navigator.userAgent.match(/MSIE (\d+\.\d+);/)) { + notifyWrapper.css({ top: document.documentElement.scrollTop }); + //http://groups.google.com/group/jquery-dev/browse_thread/thread/ba38e6474e3e9a41 + notifyWrapper.removeClass('IEsucks'); + } + // ------ + + if (!options.permanent) { + setTimeout(function() { remove(notifyItem); }, options.disappearTime); + } + } + + function remove(obj) { + obj.animate({ opacity: '0' }, 600, function() { + obj.parent().animate({ height: '0px' }, 300, + function() { + obj.parent().remove(); + // IEsucks + if (navigator.userAgent.match(/MSIE (\d+\.\d+);/)) { + //http://groups.google.com/group/jquery-dev/browse_thread/thread/ba38e6474e3e9a41 + obj.parent().parent().removeClass('IEsucks'); + } + // ------- + }); + }); + } + }; +})(jQuery); \ No newline at end of file diff --git a/content_modeller/js/jquery.treeview.min.js b/content_modeller/js/jquery.treeview.min.js new file mode 100644 index 00000000..be38dfee --- /dev/null +++ b/content_modeller/js/jquery.treeview.min.js @@ -0,0 +1,254 @@ +/* +* Treeview 1.4 - jQuery plugin to hide and show branches of a tree +* +* http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ +* http://docs.jquery.com/Plugins/Treeview +* +* Copyright (c) 2007 Jörn Zaefferer +* +* Dual licensed under the MIT and GPL licenses: +* http://www.opensource.org/licenses/mit-license.php +* http://www.gnu.org/licenses/gpl.html +* +* Revision: $Id: jquery.treeview.js 4684 2008-02-07 19:08:06Z joern.zaefferer $ +* +*/ + +;(function($) { + + $.extend($.fn, { + swapClass: function(c1, c2) { + var c1Elements = this.filter('.' + c1); + this.filter('.' + c2).removeClass(c2).addClass(c1); + c1Elements.removeClass(c1).addClass(c2); + return this; + }, + replaceClass: function(c1, c2) { + return this.filter('.' + c1).removeClass(c1).addClass(c2).end(); + }, + hoverClass: function(className) { + className = className || "hover"; + return this.hover(function() { + $(this).addClass(className); + }, function() { + $(this).removeClass(className); + }); + }, + heightToggle: function(animated, callback) { + animated ? + this.animate({ height: "toggle" }, animated, callback) : + this.each(function(){ + jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ](); + if(callback) + callback.apply(this, arguments); + }); + }, + heightHide: function(animated, callback) { + if (animated) { + this.animate({ height: "hide" }, animated, callback); + } else { + this.hide(); + if (callback) + this.each(callback); + } + }, + prepareBranches: function(settings) { + if (!settings.prerendered) { + // mark last tree items + this.filter(":last-child:not(ul)").addClass(CLASSES.last); + // collapse whole tree, or only those marked as closed, anyway except those marked as open + this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide(); + } + // return all items with sublists + return this.filter(":has(>ul)"); + }, + applyClasses: function(settings, toggler) { + + this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event) { + toggler.apply($(this).next()); + }).add( $("a", this) ).hoverClass(); + + if (!settings.prerendered) { + // handle closed ones first + this.filter(":has(>ul:hidden)") + .addClass(CLASSES.expandable) + .replaceClass(CLASSES.last, CLASSES.lastExpandable); + + // handle open ones + this.not(":has(>ul:hidden)") + .addClass(CLASSES.collapsable) + .replaceClass(CLASSES.last, CLASSES.lastCollapsable); + + // create hitarea + this.prepend("
").find("div." + CLASSES.hitarea).each(function() { + var classes = ""; + $.each($(this).parent().attr("class").split(" "), function() { + classes += this + "-hitarea "; + }); + $(this).addClass( classes ); + }); + } + + // apply event to hitarea + this.find("div." + CLASSES.hitarea).click( toggler ); + }, + treeview: function(settings) { + + if (!settings.cookieId) { + settings = $.extend({ + cookieId: "treeview" + }, settings); + } + + if (settings.add) { + return this.trigger("add", [settings.add]); + } + + if ( settings.toggle ) { + var callback = settings.toggle; + settings.toggle = function() { + return callback.apply($(this).parent()[0], arguments); + }; + } + + // factory for treecontroller + function treeController(tree, control) { + // factory for click handlers + function handler(filter) { + return function() { + // reuse toggle event handler, applying the elements to toggle + // start searching for all hitareas + toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() { + // for plain toggle, no filter is provided, otherwise we need to check the parent element + return filter ? $(this).parent("." + filter).length : true; + }) ); + return false; + }; + } + // click on first element to collapse tree + $("a:eq(0)", control).click( handler(CLASSES.collapsable) ); + // click on second to expand tree + $("a:eq(1)", control).click( handler(CLASSES.expandable) ); + // click on third to toggle tree + $("a:eq(2)", control).click( handler() ); + } + + // handle toggle event + function toggler() { + $(this) + .parent() + // swap classes for hitarea + .find(">.hitarea") + .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) + .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) + .end() + // swap classes for parent li + .swapClass( CLASSES.collapsable, CLASSES.expandable ) + .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) + // find child lists + .find( ">ul" ) + // toggle them + .heightToggle( settings.animated, settings.toggle ); + if ( settings.unique ) { + $(this).parent() + .siblings() + // swap classes for hitarea + .find(">.hitarea") + .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) + .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) + .end() + .replaceClass( CLASSES.collapsable, CLASSES.expandable ) + .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) + .find( ">ul" ) + .heightHide( settings.animated, settings.toggle ); + } + } + + function serialize() { + function binary(arg) { + return arg ? 1 : 0; + } + var data = []; + branches.each(function(i, e) { + data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0; + }); + $.cookie(settings.cookieId, data.join("") ); + } + + function deserialize() { + var stored = $.cookie(settings.cookieId); + if ( stored ) { + var data = stored.split(""); + branches.each(function(i, e) { + $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ](); + }); + } + } + + // add treeview class to activate styles + this.addClass("treeview"); + + // prepare branches and find all tree items with child lists + var branches = this.find("li").prepareBranches(settings); + + switch(settings.persist) { + case "cookie": + var toggleCallback = settings.toggle; + settings.toggle = function() { + serialize(); + if (toggleCallback) { + toggleCallback.apply(this, arguments); + } + }; + deserialize(); + break; + case "location": + var current = this.find("a").filter(function() { return this.href.toLowerCase() == location.href.toLowerCase(); }); + if ( current.length ) { + current.addClass("selected").parents("ul, li").add( current.next() ).show(); + } + break; + } + + branches.applyClasses(settings, toggler); + + // if control option is set, create the treecontroller and show it + if ( settings.control ) { + treeController(this, settings.control); + $(settings.control).show(); + } + + return this.bind("add", function(event, branches) { + $(branches).prev() + .removeClass(CLASSES.last) + .removeClass(CLASSES.lastCollapsable) + .removeClass(CLASSES.lastExpandable) + .find(">.hitarea") + .removeClass(CLASSES.lastCollapsableHitarea) + .removeClass(CLASSES.lastExpandableHitarea); + $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, toggler); + }); + } + }); + + // classes used by the plugin + // need to be styled via external stylesheet, see first example + var CLASSES = $.fn.treeview.classes = { + open: "open", + closed: "closed", + expandable: "expandable", + expandableHitarea: "expandable-hitarea", + lastExpandableHitarea: "lastExpandable-hitarea", + collapsable: "collapsable", + collapsableHitarea: "collapsable-hitarea", + lastCollapsableHitarea: "lastCollapsable-hitarea", + lastCollapsable: "lastCollapsable", + lastExpandable: "lastExpandable", + last: "last", + hitarea: "hitarea" + }; + + // provide backwards compability + $.fn.Treeview = $.fn.treeview; + +})(jQuery); \ No newline at end of file diff --git a/content_modeller/treeview.inc b/content_modeller/treeview.inc new file mode 100644 index 00000000..f5fa751b --- /dev/null +++ b/content_modeller/treeview.inc @@ -0,0 +1,56 @@ +type = $type; + $this->content = $content; + $this->id = $id; + $this->icons = $icons; + } + + function buildTree($class = NULL, $includeul = TRUE) { + $ret = ''; + if ($includeul) + $ret .= '
    id != NULL ? 'id="'. $this->id .'"' : '') . ($class != NULL ? 'class="'. $class .'"' : '') .'>'; + $ret .= '
  • '; + if ($this->type != NULL) { + $ret .=''; + } + $ret .= $this->content; + if ($this->type != NULL) { + $ret .= ''; + } + + $ret .= $this->icons; + + if (count($this->children) > 0) { + if ($includeul) + $ret .= '
      '; + else + $ret .= '
        id != NULL ? 'id="' . $this->id .'"' : '') .'>'; + foreach ($this->children as $tree) { + $ret .= $tree->buildTree(NULL, FALSE); + } + $ret .= '
      '; + } + $ret .= ''; + if ($includeul) + $ret .= '
    '; + + return $ret; + } + + function addChild($content, $type = 'file', $icons = NULL, $id = NULL) { + $tree = (is_object($content) && get_class($content) == 'treeview') ? $content : new treeview($content, $type, $icons, $id); + $this->children[] = $tree; + return $tree; + } +} diff --git a/content_modeller/treeview/changelog.txt b/content_modeller/treeview/changelog.txt new file mode 100644 index 00000000..44a94e82 --- /dev/null +++ b/content_modeller/treeview/changelog.txt @@ -0,0 +1,29 @@ +1.4 +--- + +* Added changelog (this file) +* Fixed tree control to search only for anchors, allowing images or other elements inside the controls, while keeping the control usable with the keyboard +* Restructured folder layout: root contains plugin resources, lib contains script dependencies, demo contains demos and related files +* Added prerendered option: If set to true, assumes all hitarea divs and classes already rendered, speeding up initialization for big trees, but more obtrusive +* Added jquery.treeview.async.js for ajax-lazy-loading trees, see async.html demo +* Exposed $.fn.treeview.classes for custom classes if necessary +* Show treecontrol only when JavaScript is enabled +* Completely reworked themeing via CSS sprites, resulting in only two files per theme + * updated dotted, black, gray and red theme + * added famfamfam theme (no lines) +* Improved cookie persistence to allow multiple persisted trees per page via cookieId option +* Improved location persistence by making it case-insensitive +* Improved swapClass and replaceClass plugin implementations +* Added folder-closed.gif to filetree example + +1.3 +--- + +* Fixes for all outstanding bugs +* Added persistence features + * location based: click on a link in the treeview and reopen that link after the page loaded + * cookie based: save the state of the tree in a cookie on each click and load that on reload +* smoothed animations, fixing flickering in both IE and Opera +* Tested in Firefox 2, IE 6 & 7, Opera 9, Safari 3 +* Moved documentation to jQuery wiki +* Requires jQuery 1.2+ diff --git a/content_modeller/treeview/images/add.png b/content_modeller/treeview/images/add.png new file mode 100644 index 00000000..306d3d89 Binary files /dev/null and b/content_modeller/treeview/images/add.png differ diff --git a/content_modeller/treeview/images/file.gif b/content_modeller/treeview/images/file.gif new file mode 100644 index 00000000..7e621679 Binary files /dev/null and b/content_modeller/treeview/images/file.gif differ diff --git a/content_modeller/treeview/images/folder-closed.gif b/content_modeller/treeview/images/folder-closed.gif new file mode 100644 index 00000000..54110788 Binary files /dev/null and b/content_modeller/treeview/images/folder-closed.gif differ diff --git a/content_modeller/treeview/images/folder.gif b/content_modeller/treeview/images/folder.gif new file mode 100644 index 00000000..2b31631c Binary files /dev/null and b/content_modeller/treeview/images/folder.gif differ diff --git a/content_modeller/treeview/images/minus.gif b/content_modeller/treeview/images/minus.gif new file mode 100644 index 00000000..47fb7b76 Binary files /dev/null and b/content_modeller/treeview/images/minus.gif differ diff --git a/content_modeller/treeview/images/plus.gif b/content_modeller/treeview/images/plus.gif new file mode 100644 index 00000000..69066216 Binary files /dev/null and b/content_modeller/treeview/images/plus.gif differ diff --git a/content_modeller/treeview/images/purge.gif b/content_modeller/treeview/images/purge.gif new file mode 100644 index 00000000..b3037e09 Binary files /dev/null and b/content_modeller/treeview/images/purge.gif differ diff --git a/content_modeller/treeview/images/remove.png b/content_modeller/treeview/images/remove.png new file mode 100644 index 00000000..282e4478 Binary files /dev/null and b/content_modeller/treeview/images/remove.png differ diff --git a/content_modeller/treeview/images/treeview-black-line.gif b/content_modeller/treeview/images/treeview-black-line.gif new file mode 100644 index 00000000..e5496877 Binary files /dev/null and b/content_modeller/treeview/images/treeview-black-line.gif differ diff --git a/content_modeller/treeview/images/treeview-black.gif b/content_modeller/treeview/images/treeview-black.gif new file mode 100644 index 00000000..d549b9fc Binary files /dev/null and b/content_modeller/treeview/images/treeview-black.gif differ diff --git a/content_modeller/treeview/images/treeview-default-line.gif b/content_modeller/treeview/images/treeview-default-line.gif new file mode 100644 index 00000000..37114d30 Binary files /dev/null and b/content_modeller/treeview/images/treeview-default-line.gif differ diff --git a/content_modeller/treeview/images/treeview-default.gif b/content_modeller/treeview/images/treeview-default.gif new file mode 100644 index 00000000..a12ac52f Binary files /dev/null and b/content_modeller/treeview/images/treeview-default.gif differ diff --git a/content_modeller/treeview/images/treeview-famfamfam-line.gif b/content_modeller/treeview/images/treeview-famfamfam-line.gif new file mode 100644 index 00000000..6e289cec Binary files /dev/null and b/content_modeller/treeview/images/treeview-famfamfam-line.gif differ diff --git a/content_modeller/treeview/images/treeview-famfamfam.gif b/content_modeller/treeview/images/treeview-famfamfam.gif new file mode 100644 index 00000000..0cb178e8 Binary files /dev/null and b/content_modeller/treeview/images/treeview-famfamfam.gif differ diff --git a/content_modeller/treeview/images/treeview-gray-line.gif b/content_modeller/treeview/images/treeview-gray-line.gif new file mode 100644 index 00000000..37600447 Binary files /dev/null and b/content_modeller/treeview/images/treeview-gray-line.gif differ diff --git a/content_modeller/treeview/images/treeview-gray.gif b/content_modeller/treeview/images/treeview-gray.gif new file mode 100644 index 00000000..cfb8a2f0 Binary files /dev/null and b/content_modeller/treeview/images/treeview-gray.gif differ diff --git a/content_modeller/treeview/images/treeview-red-line.gif b/content_modeller/treeview/images/treeview-red-line.gif new file mode 100644 index 00000000..df9e749a Binary files /dev/null and b/content_modeller/treeview/images/treeview-red-line.gif differ diff --git a/content_modeller/treeview/images/treeview-red.gif b/content_modeller/treeview/images/treeview-red.gif new file mode 100644 index 00000000..3bbb3a15 Binary files /dev/null and b/content_modeller/treeview/images/treeview-red.gif differ diff --git a/content_modeller/treeview/images/view.gif b/content_modeller/treeview/images/view.gif new file mode 100644 index 00000000..eee58178 Binary files /dev/null and b/content_modeller/treeview/images/view.gif differ diff --git a/content_modeller/treeview/jquery.treeview.async.js b/content_modeller/treeview/jquery.treeview.async.js new file mode 100644 index 00000000..2597dde1 --- /dev/null +++ b/content_modeller/treeview/jquery.treeview.async.js @@ -0,0 +1,72 @@ +/* + * Async Treeview 0.1 - Lazy-loading extension for Treeview + * + * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ + * + * Copyright (c) 2007 Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id$ + * + */ + +;(function($) { + +function load(settings, root, child, container) { + $.getJSON(settings.url, {root: root}, function(response) { + function createNode(parent) { + var current = $("
  • ").attr("id", this.id || "").html("" + this.text + "").appendTo(parent); + if (this.classes) { + current.children("span").addClass(this.classes); + } + if (this.expanded) { + current.addClass("open"); + } + if (this.hasChildren || this.children && this.children.length) { + var branch = $("
      ").appendTo(current); + if (this.hasChildren) { + current.addClass("hasChildren"); + createNode.call({ + text:"placeholder", + id:"placeholder", + children:[] + }, branch); + } + if (this.children && this.children.length) { + $.each(this.children, createNode, [branch]) + } + } + } + $.each(response, createNode, [child]); + $(container).treeview({add: child}); + }); +} + +var proxied = $.fn.treeview; +$.fn.treeview = function(settings) { + if (!settings.url) { + return proxied.apply(this, arguments); + } + var container = this; + load(settings, "source", this, container); + var userToggle = settings.toggle; + return proxied.call(this, $.extend({}, settings, { + collapsed: true, + toggle: function() { + var $this = $(this); + if ($this.hasClass("hasChildren")) { + var childList = $this.removeClass("hasChildren").find("ul"); + childList.empty(); + load(settings, this.id, childList, container); + } + if (userToggle) { + userToggle.apply(this, arguments); + } + } + })); +}; + +})(jQuery); \ No newline at end of file diff --git a/content_modeller/treeview/jquery.treeview.css b/content_modeller/treeview/jquery.treeview.css new file mode 100644 index 00000000..4a910965 --- /dev/null +++ b/content_modeller/treeview/jquery.treeview.css @@ -0,0 +1,68 @@ +.treeview, .treeview ul { + padding: 0; + margin: 0; + list-style: none; +} + +.treeview ul { + background-color: white; + margin-top: 4px; +} + +.treeview .hitarea { + background: url(images/treeview-default.gif) -64px -25px no-repeat; + height: 16px; + width: 16px; + margin-left: -16px; + float: left; + cursor: pointer; +} +/* fix for IE6 */ +* html .hitarea { + display: inline; + float:none; +} + +.treeview li { + margin: 0; + padding: 3px 0pt 3px 16px; +} + +.treeview a.selected { + background-color: #eee; +} + +#treecontrol { margin: 1em 0; display: none; } + +.treeview .hover { color: red; cursor: pointer; } + +.treeview li { background: url(images/treeview-default-line.gif) 0 0 no-repeat; } +.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; } + +.treeview .expandable-hitarea { background-position: -80px -3px; } + +.treeview li.last { background-position: 0 -1766px } +.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(images/treeview-default.gif); } +.treeview li.lastCollapsable { background-position: 0 -111px } +.treeview li.lastExpandable { background-position: -32px -67px } + +.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; } + +.treeview-red li { background-image: url(images/treeview-red-line.gif); } +.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(images/treeview-red.gif); } + +.treeview-black li { background-image: url(images/treeview-black-line.gif); } +.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(images/treeview-black.gif); } + +.treeview-gray li { background-image: url(images/treeview-gray-line.gif); } +.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(images/treeview-gray.gif); } + +.treeview-famfamfam li { background-image: url(images/treeview-famfamfam-line.gif); } +.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(images/treeview-famfamfam.gif); } + + +.filetree li { padding: 3px 0 2px 16px; } +.filetree span.folder, .filetree span.file { padding: 1px 0 1px 16px; display: block; } +.filetree span.folder { background: url(images/folder.gif) 0 0 no-repeat; } +.filetree li.expandable span.folder { background: url(images/folder-closed.gif) 0 0 no-repeat; } +.filetree span.file { background: url(images/file.gif) 0 0 no-repeat; } diff --git a/content_modeller/treeview/jquery.treeview.js b/content_modeller/treeview/jquery.treeview.js new file mode 100644 index 00000000..bc5d9e46 --- /dev/null +++ b/content_modeller/treeview/jquery.treeview.js @@ -0,0 +1,251 @@ +/* + * Treeview 1.4 - jQuery plugin to hide and show branches of a tree + * + * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ + * http://docs.jquery.com/Plugins/Treeview + * + * Copyright (c) 2007 Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id: jquery.treeview.js 4684 2008-02-07 19:08:06Z joern.zaefferer $ + * + */ + +;(function($) { + + $.extend($.fn, { + swapClass: function(c1, c2) { + var c1Elements = this.filter('.' + c1); + this.filter('.' + c2).removeClass(c2).addClass(c1); + c1Elements.removeClass(c1).addClass(c2); + return this; + }, + replaceClass: function(c1, c2) { + return this.filter('.' + c1).removeClass(c1).addClass(c2).end(); + }, + hoverClass: function(className) { + className = className || "hover"; + return this.hover(function() { + $(this).addClass(className); + }, function() { + $(this).removeClass(className); + }); + }, + heightToggle: function(animated, callback) { + animated ? + this.animate({ height: "toggle" }, animated, callback) : + this.each(function(){ + jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ](); + if(callback) + callback.apply(this, arguments); + }); + }, + heightHide: function(animated, callback) { + if (animated) { + this.animate({ height: "hide" }, animated, callback); + } else { + this.hide(); + if (callback) + this.each(callback); + } + }, + prepareBranches: function(settings) { + if (!settings.prerendered) { + // mark last tree items + this.filter(":last-child:not(ul)").addClass(CLASSES.last); + // collapse whole tree, or only those marked as closed, anyway except those marked as open + this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide(); + } + // return all items with sublists + return this.filter(":has(>ul)"); + }, + applyClasses: function(settings, toggler) { + this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event) { + toggler.apply($(this).next()); + }).add( $("a", this) ).hoverClass(); + + if (!settings.prerendered) { + // handle closed ones first + this.filter(":has(>ul:hidden)") + .addClass(CLASSES.expandable) + .replaceClass(CLASSES.last, CLASSES.lastExpandable); + + // handle open ones + this.not(":has(>ul:hidden)") + .addClass(CLASSES.collapsable) + .replaceClass(CLASSES.last, CLASSES.lastCollapsable); + + // create hitarea + this.prepend("
      ").find("div." + CLASSES.hitarea).each(function() { + var classes = ""; + $.each($(this).parent().attr("class").split(" "), function() { + classes += this + "-hitarea "; + }); + $(this).addClass( classes ); + }); + } + + // apply event to hitarea + this.find("div." + CLASSES.hitarea).click( toggler ); + }, + treeview: function(settings) { + + settings = $.extend({ + cookieId: "treeview" + }, settings); + + if (settings.add) { + return this.trigger("add", [settings.add]); + } + + if ( settings.toggle ) { + var callback = settings.toggle; + settings.toggle = function() { + return callback.apply($(this).parent()[0], arguments); + }; + } + + // factory for treecontroller + function treeController(tree, control) { + // factory for click handlers + function handler(filter) { + return function() { + // reuse toggle event handler, applying the elements to toggle + // start searching for all hitareas + toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() { + // for plain toggle, no filter is provided, otherwise we need to check the parent element + return filter ? $(this).parent("." + filter).length : true; + }) ); + return false; + }; + } + // click on first element to collapse tree + $("a:eq(0)", control).click( handler(CLASSES.collapsable) ); + // click on second to expand tree + $("a:eq(1)", control).click( handler(CLASSES.expandable) ); + // click on third to toggle tree + $("a:eq(2)", control).click( handler() ); + } + + // handle toggle event + function toggler() { + $(this) + .parent() + // swap classes for hitarea + .find(">.hitarea") + .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) + .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) + .end() + // swap classes for parent li + .swapClass( CLASSES.collapsable, CLASSES.expandable ) + .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) + // find child lists + .find( ">ul" ) + // toggle them + .heightToggle( settings.animated, settings.toggle ); + if ( settings.unique ) { + $(this).parent() + .siblings() + // swap classes for hitarea + .find(">.hitarea") + .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) + .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) + .end() + .replaceClass( CLASSES.collapsable, CLASSES.expandable ) + .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) + .find( ">ul" ) + .heightHide( settings.animated, settings.toggle ); + } + } + + function serialize() { + function binary(arg) { + return arg ? 1 : 0; + } + var data = []; + branches.each(function(i, e) { + data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0; + }); + $.cookie(settings.cookieId, data.join("") ); + } + + function deserialize() { + var stored = $.cookie(settings.cookieId); + if ( stored ) { + var data = stored.split(""); + branches.each(function(i, e) { + $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ](); + }); + } + } + + // add treeview class to activate styles + this.addClass("treeview"); + + // prepare branches and find all tree items with child lists + var branches = this.find("li").prepareBranches(settings); + + switch(settings.persist) { + case "cookie": + var toggleCallback = settings.toggle; + settings.toggle = function() { + serialize(); + if (toggleCallback) { + toggleCallback.apply(this, arguments); + } + }; + deserialize(); + break; + case "location": + var current = this.find("a").filter(function() { return this.href.toLowerCase() == location.href.toLowerCase(); }); + if ( current.length ) { + current.addClass("selected").parents("ul, li").add( current.next() ).show(); + } + break; + } + + branches.applyClasses(settings, toggler); + + // if control option is set, create the treecontroller and show it + if ( settings.control ) { + treeController(this, settings.control); + $(settings.control).show(); + } + + return this.bind("add", function(event, branches) { + $(branches).prev() + .removeClass(CLASSES.last) + .removeClass(CLASSES.lastCollapsable) + .removeClass(CLASSES.lastExpandable) + .find(">.hitarea") + .removeClass(CLASSES.lastCollapsableHitarea) + .removeClass(CLASSES.lastExpandableHitarea); + $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, toggler); + }); + } + }); + + // classes used by the plugin + // need to be styled via external stylesheet, see first example + var CLASSES = $.fn.treeview.classes = { + open: "open", + closed: "closed", + expandable: "expandable", + expandableHitarea: "expandable-hitarea", + lastExpandableHitarea: "lastExpandable-hitarea", + collapsable: "collapsable", + collapsableHitarea: "collapsable-hitarea", + lastCollapsableHitarea: "lastCollapsable-hitarea", + lastCollapsable: "lastCollapsable", + lastExpandable: "lastExpandable", + last: "last", + hitarea: "hitarea" + }; + + // provide backwards compability + $.fn.Treeview = $.fn.treeview; + +})(jQuery); \ No newline at end of file diff --git a/content_modeller/treeview/jquery.treeview.min.js b/content_modeller/treeview/jquery.treeview.min.js new file mode 100644 index 00000000..96202d9c --- /dev/null +++ b/content_modeller/treeview/jquery.treeview.min.js @@ -0,0 +1,15 @@ +/* + * Treeview 1.4 - jQuery plugin to hide and show branches of a tree + * + * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ + * http://docs.jquery.com/Plugins/Treeview + * + * Copyright (c) 2007 Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id: jquery.treeview.js 4684 2008-02-07 19:08:06Z joern.zaefferer $ + * + */;(function($){$.extend($.fn,{swapClass:function(c1,c2){var c1Elements=this.filter('.'+c1);this.filter('.'+c2).removeClass(c2).addClass(c1);c1Elements.removeClass(c1).addClass(c2);return this;},replaceClass:function(c1,c2){return this.filter('.'+c1).removeClass(c1).addClass(c2).end();},hoverClass:function(className){className=className||"hover";return this.hover(function(){$(this).addClass(className);},function(){$(this).removeClass(className);});},heightToggle:function(animated,callback){animated?this.animate({height:"toggle"},animated,callback):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();if(callback)callback.apply(this,arguments);});},heightHide:function(animated,callback){if(animated){this.animate({height:"hide"},animated,callback);}else{this.hide();if(callback)this.each(callback);}},prepareBranches:function(settings){if(!settings.prerendered){this.filter(":last-child:not(ul)").addClass(CLASSES.last);this.filter((settings.collapsed?"":"."+CLASSES.closed)+":not(."+CLASSES.open+")").find(">ul").hide();}return this.filter(":has(>ul)");},applyClasses:function(settings,toggler){this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event){toggler.apply($(this).next());}).add($("a",this)).hoverClass();if(!settings.prerendered){this.filter(":has(>ul:hidden)").addClass(CLASSES.expandable).replaceClass(CLASSES.last,CLASSES.lastExpandable);this.not(":has(>ul:hidden)").addClass(CLASSES.collapsable).replaceClass(CLASSES.last,CLASSES.lastCollapsable);this.prepend("
      ").find("div."+CLASSES.hitarea).each(function(){var classes="";$.each($(this).parent().attr("class").split(" "),function(){classes+=this+"-hitarea ";});$(this).addClass(classes);});}this.find("div."+CLASSES.hitarea).click(toggler);},treeview:function(settings){settings=$.extend({cookieId:"treeview"},settings);if(settings.add){return this.trigger("add",[settings.add]);}if(settings.toggle){var callback=settings.toggle;settings.toggle=function(){return callback.apply($(this).parent()[0],arguments);};}function treeController(tree,control){function handler(filter){return function(){toggler.apply($("div."+CLASSES.hitarea,tree).filter(function(){return filter?$(this).parent("."+filter).length:true;}));return false;};}$("a:eq(0)",control).click(handler(CLASSES.collapsable));$("a:eq(1)",control).click(handler(CLASSES.expandable));$("a:eq(2)",control).click(handler());}function toggler(){$(this).parent().find(">.hitarea").swapClass(CLASSES.collapsableHitarea,CLASSES.expandableHitarea).swapClass(CLASSES.lastCollapsableHitarea,CLASSES.lastExpandableHitarea).end().swapClass(CLASSES.collapsable,CLASSES.expandable).swapClass(CLASSES.lastCollapsable,CLASSES.lastExpandable).find(">ul").heightToggle(settings.animated,settings.toggle);if(settings.unique){$(this).parent().siblings().find(">.hitarea").replaceClass(CLASSES.collapsableHitarea,CLASSES.expandableHitarea).replaceClass(CLASSES.lastCollapsableHitarea,CLASSES.lastExpandableHitarea).end().replaceClass(CLASSES.collapsable,CLASSES.expandable).replaceClass(CLASSES.lastCollapsable,CLASSES.lastExpandable).find(">ul").heightHide(settings.animated,settings.toggle);}}function serialize(){function binary(arg){return arg?1:0;}var data=[];branches.each(function(i,e){data[i]=$(e).is(":has(>ul:visible)")?1:0;});$.cookie(settings.cookieId,data.join(""));}function deserialize(){var stored=$.cookie(settings.cookieId);if(stored){var data=stored.split("");branches.each(function(i,e){$(e).find(">ul")[parseInt(data[i])?"show":"hide"]();});}}this.addClass("treeview");var branches=this.find("li").prepareBranches(settings);switch(settings.persist){case"cookie":var toggleCallback=settings.toggle;settings.toggle=function(){serialize();if(toggleCallback){toggleCallback.apply(this,arguments);}};deserialize();break;case"location":var current=this.find("a").filter(function(){return this.href.toLowerCase()==location.href.toLowerCase();});if(current.length){current.addClass("selected").parents("ul, li").add(current.next()).show();}break;}branches.applyClasses(settings,toggler);if(settings.control){treeController(this,settings.control);$(settings.control).show();}return this.bind("add",function(event,branches){$(branches).prev().removeClass(CLASSES.last).removeClass(CLASSES.lastCollapsable).removeClass(CLASSES.lastExpandable).find(">.hitarea").removeClass(CLASSES.lastCollapsableHitarea).removeClass(CLASSES.lastExpandableHitarea);$(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings,toggler);});}});var CLASSES=$.fn.treeview.classes={open:"open",closed:"closed",expandable:"expandable",expandableHitarea:"expandable-hitarea",lastExpandableHitarea:"lastExpandable-hitarea",collapsable:"collapsable",collapsableHitarea:"collapsable-hitarea",lastCollapsableHitarea:"lastCollapsable-hitarea",lastCollapsable:"lastCollapsable",lastExpandable:"lastExpandable",last:"last",hitarea:"hitarea"};$.fn.Treeview=$.fn.treeview;})(jQuery); \ No newline at end of file diff --git a/content_modeller/treeview/jquery.treeview.pack.js b/content_modeller/treeview/jquery.treeview.pack.js new file mode 100644 index 00000000..eddac491 --- /dev/null +++ b/content_modeller/treeview/jquery.treeview.pack.js @@ -0,0 +1,16 @@ +/* + * Treeview 1.4 - jQuery plugin to hide and show branches of a tree + * + * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ + * http://docs.jquery.com/Plugins/Treeview + * + * Copyright (c) 2007 Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id: jquery.treeview.js 4684 2008-02-07 19:08:06Z joern.zaefferer $ + * + */ +eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(4($){$.1l($.F,{E:4(b,c){l a=3.n(\'.\'+b);3.n(\'.\'+c).o(c).m(b);a.o(b).m(c);8 3},s:4(a,b){8 3.n(\'.\'+a).o(a).m(b).P()},1n:4(a){a=a||"1j";8 3.1j(4(){$(3).m(a)},4(){$(3).o(a)})},1h:4(b,a){b?3.1g({1e:"p"},b,a):3.x(4(){T(3)[T(3).1a(":U")?"H":"D"]();7(a)a.A(3,O)})},12:4(b,a){7(b){3.1g({1e:"D"},b,a)}1L{3.D();7(a)3.x(a)}},11:4(a){7(!a.1k){3.n(":r-1H:G(9)").m(k.r);3.n((a.1F?"":"."+k.X)+":G(."+k.W+")").6(">9").D()}8 3.n(":y(>9)")},S:4(b,c){3.n(":y(>9):G(:y(>a))").6(">1z").C(4(a){c.A($(3).19())}).w($("a",3)).1n();7(!b.1k){3.n(":y(>9:U)").m(k.q).s(k.r,k.t);3.G(":y(>9:U)").m(k.u).s(k.r,k.v);3.1r("").6("J."+k.5).x(4(){l a="";$.x($(3).B().1o("14").13(" "),4(){a+=3+"-5 "});$(3).m(a)})}3.6("J."+k.5).C(c)},z:4(g){g=$.1l({N:"z"},g);7(g.w){8 3.1K("w",[g.w])}7(g.p){l d=g.p;g.p=4(){8 d.A($(3).B()[0],O)}}4 1m(b,c){4 L(a){8 4(){K.A($("J."+k.5,b).n(4(){8 a?$(3).B("."+a).1i:1I}));8 1G}}$("a:10(0)",c).C(L(k.u));$("a:10(1)",c).C(L(k.q));$("a:10(2)",c).C(L())}4 K(){$(3).B().6(">.5").E(k.Z,k.Y).E(k.I,k.M).P().E(k.u,k.q).E(k.v,k.t).6(">9").1h(g.1f,g.p);7(g.1E){$(3).B().1D().6(">.5").s(k.Z,k.Y).s(k.I,k.M).P().s(k.u,k.q).s(k.v,k.t).6(">9").12(g.1f,g.p)}}4 1d(){4 1C(a){8 a?1:0}l b=[];j.x(4(i,e){b[i]=$(e).1a(":y(>9:1B)")?1:0});$.V(g.N,b.1A(""))}4 1c(){l b=$.V(g.N);7(b){l a=b.13("");j.x(4(i,e){$(e).6(">9")[1y(a[i])?"H":"D"]()})}}3.m("z");l j=3.6("Q").11(g);1x(g.1w){18"V":l h=g.p;g.p=4(){1d();7(h){h.A(3,O)}};1c();17;18"1b":l f=3.6("a").n(4(){8 3.16.15()==1b.16.15()});7(f.1i){f.m("1v").1u("9, Q").w(f.19()).H()}17}j.S(g,K);7(g.R){1m(3,g.R);$(g.R).H()}8 3.1t("w",4(a,b){$(b).1s().o(k.r).o(k.v).o(k.t).6(">.5").o(k.I).o(k.M);$(b).6("Q").1q().11(g).S(g,K)})}});l k=$.F.z.1J={W:"W",X:"X",q:"q",Y:"q-5",M:"t-5",u:"u",Z:"u-5",I:"v-5",v:"v",t:"t",r:"r",5:"5"};$.F.1p=$.F.z})(T);',62,110,'|||this|function|hitarea|find|if|return|ul||||||||||||var|addClass|filter|removeClass|toggle|expandable|last|replaceClass|lastExpandable|collapsable|lastCollapsable|add|each|has|treeview|apply|parent|click|hide|swapClass|fn|not|show|lastCollapsableHitarea|div|toggler|handler|lastExpandableHitarea|cookieId|arguments|end|li|control|applyClasses|jQuery|hidden|cookie|open|closed|expandableHitarea|collapsableHitarea|eq|prepareBranches|heightHide|split|class|toLowerCase|href|break|case|next|is|location|deserialize|serialize|height|animated|animate|heightToggle|length|hover|prerendered|extend|treeController|hoverClass|attr|Treeview|andSelf|prepend|prev|bind|parents|selected|persist|switch|parseInt|span|join|visible|binary|siblings|unique|collapsed|false|child|true|classes|trigger|else'.split('|'),0,{})) \ No newline at end of file diff --git a/content_modeller/treeview/jquery.treeview.zip b/content_modeller/treeview/jquery.treeview.zip new file mode 100644 index 00000000..1eaa5612 Binary files /dev/null and b/content_modeller/treeview/jquery.treeview.zip differ diff --git a/content_modeller/treeview/lib/jquery.cookie.js b/content_modeller/treeview/lib/jquery.cookie.js new file mode 100644 index 00000000..8e8e1d9e --- /dev/null +++ b/content_modeller/treeview/lib/jquery.cookie.js @@ -0,0 +1,92 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', {expires: 7, path: '/', domain: 'jquery.com', secure: true}); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + var path = options.path ? '; path=' + options.path : ''; + var domain = options.domain ? '; domain=' + options.domain : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; \ No newline at end of file diff --git a/content_modeller/treeview/lib/jquery.js b/content_modeller/treeview/lib/jquery.js new file mode 100644 index 00000000..b660baab --- /dev/null +++ b/content_modeller/treeview/lib/jquery.js @@ -0,0 +1,3363 @@ +(function(){ +/* + * jQuery 1.2.2b2 - New Wave Javascript + * + * Copyright (c) 2007 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2007-12-20 14:36:56 +0100 (Don, 20 Dez 2007) $ + * $Rev: 4251 $ + */ + +// Map over jQuery in case of overwrite +if ( window.jQuery ) + var _jQuery = window.jQuery; + +var jQuery = window.jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.prototype.init( selector, context ); +}; + +// Map over the $ in case of overwrite +if ( window.$ ) + var _$ = window.$; + +// Map the jQuery namespace to the '$' one +window.$ = jQuery; + +// A simple way to check for HTML strings or ID strings +// (both of which we optimize for) +var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; + +// Is it a simple selector +var isSimple = /^.[^:#\[\.]*$/; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + // Make sure that a selection was provided + selector = selector || document; + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this[0] = selector; + this.length = 1; + return this; + + // Handle HTML strings + } else if ( typeof selector == "string" ) { + // Are we dealing with HTML string or an ID? + var match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) + selector = jQuery.clean( [ match[1] ], context ); + + // HANDLE: $("#id") + else { + var elem = document.getElementById( match[3] ); + + // Make sure an element was located + if ( elem ) + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id != match[3] ) + return jQuery().find( selector ); + + // Otherwise, we inject the element directly into the jQuery object + else { + this[0] = elem; + this.length = 1; + return this; + } + + else + selector = []; + } + + // HANDLE: $(expr, [context]) + // (which is just equivalent to: $(content).find(expr) + } else + return new jQuery( context ).find( selector ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) + return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector ); + + return this.setArray( + // HANDLE: $(array) + selector.constructor == Array && selector || + + // HANDLE: $(arraylike) + // Watch for when an array-like object, contains DOM nodes, is passed in as the selector + (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) || + + // HANDLE: $(*) + [ selector ] ); + }, + + // The current version of jQuery being used + jquery: "@VERSION", + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + // The number of elements contained in the matched element set + length: 0, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == undefined ? + + // Return a 'clean' array + jQuery.makeArray( this ) : + + // Return just the object + this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + // Build a new jQuery matched element set + var ret = jQuery( elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Force the current matched set of elements to become + // the specified array of elements (destroying the stack in the process) + // You should use pushStack() in order to do this, but maintain the stack + setArray: function( elems ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + this.length = 0; + Array.prototype.push.apply( this, elems ); + + return this; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + var ret = -1; + + // Locate the position of the desired element + this.each(function(i){ + if ( this == elem ) + ret = i; + }); + + return ret; + }, + + attr: function( name, value, type ) { + var options = name; + + // Look for the case where we're accessing a style value + if ( name.constructor == String ) + if ( value == undefined ) + return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined; + + else { + options = {}; + options[ name ] = value; + } + + // Check to see if we're setting style values + return this.each(function(i){ + // Set all the styles + for ( name in options ) + jQuery.attr( + type ? + this.style : + this, + name, jQuery.prop( this, options[ name ], type, i, name ) + ); + }); + }, + + css: function( key, value ) { + // ignore negative width and height values + if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) + value = undefined; + return this.attr( key, value, "curCSS" ); + }, + + text: function( text ) { + if ( typeof text != "object" && text != null ) + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); + + var ret = ""; + + jQuery.each( text || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + ret += this.nodeType != 1 ? + this.nodeValue : + jQuery.fn.text( [ this ] ); + }); + }); + + return ret; + }, + + wrapAll: function( html ) { + if ( this[0] ) + // The elements to wrap the target around + jQuery( html, this[0].ownerDocument ) + .clone() + .insertBefore( this[0] ) + .map(function(){ + var elem = this; + + while ( elem.firstChild ) + elem = elem.firstChild; + + return elem; + }) + .append(this); + + return this; + }, + + wrapInner: function( html ) { + return this.each(function(){ + jQuery( this ).contents().wrapAll( html ); + }); + }, + + wrap: function( html ) { + return this.each(function(){ + jQuery( this ).wrapAll( html ); + }); + }, + + append: function() { + return this.domManip(arguments, true, false, function(elem){ + if (this.nodeType == 1) + this.appendChild( elem ); + }); + }, + + prepend: function() { + return this.domManip(arguments, true, true, function(elem){ + if (this.nodeType == 1) + this.insertBefore( elem, this.firstChild ); + }); + }, + + before: function() { + return this.domManip(arguments, false, false, function(elem){ + this.parentNode.insertBefore( elem, this ); + }); + }, + + after: function() { + return this.domManip(arguments, false, true, function(elem){ + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + }, + + end: function() { + return this.prevObject || jQuery( [] ); + }, + + find: function( selector ) { + var elems = jQuery.map(this, function(elem){ + return jQuery.find( selector, elem ); + }); + + return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ? + jQuery.unique( elems ) : + elems ); + }, + + clone: function( events ) { + // Do the clone + var ret = this.map(function(){ + if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) { + // IE copies events bound via attachEvent when + // using cloneNode. Calling detachEvent on the + // clone will also remove the events from the orignal + // In order to get around this, we use innerHTML. + // Unfortunately, this means some modifications to + // attributes in IE that are actually only stored + // as properties will not be copied (such as the + // the name attribute on an input). + var clone = this.cloneNode(true), + container = document.createElement("div"), + container2 = document.createElement("div"); + container.appendChild(clone); + container2.innerHTML = container.innerHTML; + return container2.firstChild; + } else + return this.cloneNode(true); + }); + + // Need to set the expando to null on the cloned set if it exists + // removeData doesn't work here, IE removes it from the original as well + // this is primarily for IE but the data expando shouldn't be copied over in any browser + var clone = ret.find("*").andSelf().each(function(){ + if ( this[ expando ] != undefined ) + this[ expando ] = null; + }); + + // Copy the events from the original to the clone + if ( events === true ) + this.find("*").andSelf().each(function(i){ + var events = jQuery.data( this, "events" ); + + for ( var type in events ) + for ( var handler in events[ type ] ) + jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data ); + }); + + // Return the cloned set + return ret; + }, + + filter: function( selector ) { + return this.pushStack( + jQuery.isFunction( selector ) && + jQuery.grep(this, function(elem, i){ + return selector.call( elem, i ); + }) || + + jQuery.multiFilter( selector, this ) ); + }, + + not: function( selector ) { + if ( selector.constructor == String ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ) ); + else + selector = jQuery.multiFilter( selector, this ); + + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; + return this.filter(function() { + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; + }); + }, + + add: function( selector ) { + return !selector ? this : this.pushStack( jQuery.merge( + this.get(), + selector.constructor == String ? + jQuery( selector ).get() : + selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ? + selector : [selector] ) ); + }, + + is: function( selector ) { + return selector ? + jQuery.multiFilter( selector, this ).length > 0 : + false; + }, + + hasClass: function( selector ) { + return this.is( "." + selector ); + }, + + val: function( value ) { + if ( value == undefined ) { + + if ( this.length ) { + var elem = this[0]; + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value; + + // We don't need an array for one selects + if ( one ) + return value; + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + + // Everything else, we just grab the value + } else + return (this[0].value || "").replace(/\r/g, ""); + + } + + return undefined; + } + + return this.each(function(){ + if ( this.nodeType != 1 ) + return; + + if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) + this.checked = (jQuery.inArray(this.value, value) >= 0 || + jQuery.inArray(this.name, value) >= 0); + + else if ( jQuery.nodeName( this, "select" ) ) { + var values = value.constructor == Array ? + value : + [ value ]; + + jQuery( "option", this ).each(function(){ + this.selected = (jQuery.inArray( this.value, values ) >= 0 || + jQuery.inArray( this.text, values ) >= 0); + }); + + if ( !values.length ) + this.selectedIndex = -1; + + } else + this.value = value; + }); + }, + + html: function( value ) { + return value == undefined ? + (this.length ? + this[0].innerHTML : + null) : + this.empty().append( value ); + }, + + replaceWith: function( value ) { + return this.after( value ).remove(); + }, + + eq: function( i ) { + return this.slice( i, i + 1 ); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function(elem, i){ + return callback.call( elem, i, elem ); + })); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + domManip: function( args, table, reverse, callback ) { + var clone = this.length > 1, elems; + + return this.each(function(){ + if ( !elems ) { + elems = jQuery.clean( args, this.ownerDocument ); + + if ( reverse ) + elems.reverse(); + } + + var obj = this; + + if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) ) + obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") ); + + var scripts = jQuery( [] ); + + jQuery.each(elems, function(){ + var elem = clone ? + jQuery( this ).clone( true )[0] : + this; + + // execute all scripts after the elements have been injected + if ( jQuery.nodeName( elem, "script" ) ) { + scripts = scripts.add( elem ); + } else { + // Remove any inner scripts for later evaluation + if ( elem.nodeType == 1 ) + scripts = scripts.add( jQuery( "script", elem ).remove() ); + + // Inject the elements into the document + callback.call( obj, elem ); + } + }); + + scripts.each( evalScript ); + }); + } +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.prototype.init.prototype = jQuery.prototype; + +function evalScript( i, elem ) { + if ( elem.src ) + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild( elem ); +} + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; + + // Handle a deep copy situation + if ( target.constructor == Boolean ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target != "object" && typeof target != "function" ) + target = {}; + + // extend jQuery itself if only one argument is passed + if ( length == 1 ) { + target = this; + i = 0; + } + + for ( ; i < length; i++ ) + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) + // Extend the base object + for ( var name in options ) { + // Prevent never-ending loop + if ( target === options[ name ] ) + continue; + + // Recurse if we're merging object values + if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType ) + target[ name ] = jQuery.extend( target[ name ], options[ name ] ); + + // Don't bring in undefined values + else if ( options[ name ] != undefined ) + target[ name ] = options[ name ]; + + } + + // Return the modified object + return target; +}; + +var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {}; + +// exclude the following css properties to add px +var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; + +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) + window.jQuery = _jQuery; + + return jQuery; + }, + + // This may seem like some crazy code, but trust me when I say that this + // is the only cross-browser way to do this. --John + isFunction: function( fn ) { + return !!fn && typeof fn != "string" && !fn.nodeName && + fn.constructor != Array && /function/i.test( fn + "" ); + }, + + // check if an element is in a (or is an) XML document + isXMLDoc: function( elem ) { + return elem.documentElement && !elem.body || + elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; + }, + + // Evalulates a script in a global context + globalEval: function( data ) { + data = jQuery.trim( data ); + + if ( data ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + if ( jQuery.browser.msie ) + script.text = data; + else + script.appendChild( document.createTextNode( data ) ); + + head.appendChild( script ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + cache: {}, + + data: function( elem, name, data ) { + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ]; + + // Compute a unique ID for the element + if ( !id ) + id = elem[ expando ] = ++uuid; + + // Only generate the data cache if we're + // trying to access or manipulate it + if ( name && !jQuery.cache[ id ] ) + jQuery.cache[ id ] = {}; + + // Prevent overriding the named cache with undefined values + if ( data != undefined ) + jQuery.cache[ id ][ name ] = data; + + // Return the named cache data, or the ID for the element + return name ? + jQuery.cache[ id ][ name ] : + id; + }, + + removeData: function( elem, name ) { + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( jQuery.cache[ id ] ) { + // Remove the section of cache data + delete jQuery.cache[ id ][ name ]; + + // If we've removed all the data, remove the element's cache + name = ""; + + for ( name in jQuery.cache[ id ] ) + break; + + if ( !name ) + jQuery.removeData( elem ); + } + + // Otherwise, we want to remove all of the element's data + } else { + // Clean up the element expando + try { + delete elem[ expando ]; + } catch(e){ + // IE has trouble directly removing the expando + // but it's ok with using removeAttribute + if ( elem.removeAttribute ) + elem.removeAttribute( expando ); + } + + // Completely remove the data cache + delete jQuery.cache[ id ]; + } + }, + + // args is for internal usage only + each: function( object, callback, args ) { + if ( args ) { + if ( object.length == undefined ) + for ( var name in object ) + callback.apply( object[ name ], args ); + else + for ( var i = 0, length = object.length; i < length; i++ ) + if ( callback.apply( object[ i ], args ) === false ) + break; + + // A special, fast, case for the most common use of each + } else { + if ( object.length == undefined ) + for ( var name in object ) + callback.call( object[ name ], name, object[ name ] ); + else + for ( var i = 0, length = object.length, value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} + } + + return object; + }, + + prop: function( elem, value, type, i, name ) { + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, i ); + + // Handle passing in a number to a CSS property + return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, classNames ) { + jQuery.each((classNames || "").split(/\s+/), function(i, className){ + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) + elem.className += (elem.className ? " " : "") + className; + }); + }, + + // internal only, use removeClass("class") + remove: function( elem, classNames ) { + if (elem.nodeType == 1) + elem.className = classNames != undefined ? + jQuery.grep(elem.className.split(/\s+/), function(className){ + return !jQuery.className.has( classNames, className ); + }).join(" ") : + ""; + }, + + // internal only, use is(".class") + has: function( elem, className ) { + return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; + } + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = {}; + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + callback.call( elem ); + + // Revert the old values + for ( var name in options ) + elem.style[ name ] = old[ name ]; + }, + + css: function( elem, name, force ) { + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; + + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; + var padding = 0, border = 0; + jQuery.each( which, function() { + padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; + border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; + }); + val -= Math.round(padding + border); + } + + if ( jQuery(elem).is(":visible") ) + getWH(); + else + jQuery.swap( elem, props, getWH ); + + return Math.max(0, val); + } + + return jQuery.curCSS( elem, name, force ); + }, + + curCSS: function( elem, name, force ) { + var ret; + + // A helper method for determining if an element's values are broken + function color( elem ) { + if ( !jQuery.browser.safari ) + return false; + + var ret = document.defaultView.getComputedStyle( elem, null ); + return !ret || ret.getPropertyValue("color") == ""; + } + + // We need to handle opacity special in IE + if ( name == "opacity" && jQuery.browser.msie ) { + ret = jQuery.attr( elem.style, "opacity" ); + + return ret == "" ? + "1" : + ret; + } + // Opera sometimes will give the wrong display answer, this fixes it, see #2037 + if ( jQuery.browser.opera && name == "display" ) { + var save = elem.style.display; + elem.style.display = "block"; + elem.style.display = save; + } + + // Make sure we're using the right name for getting the float value + if ( name.match( /float/i ) ) + name = styleFloat; + + if ( !force && elem.style[ name ] ) + ret = elem.style[ name ]; + + else if ( document.defaultView && document.defaultView.getComputedStyle ) { + + // Only "float" is needed here + if ( name.match( /float/i ) ) + name = "float"; + + name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); + + var getComputedStyle = document.defaultView.getComputedStyle( elem, null ); + + if ( getComputedStyle && !color( elem ) ) + ret = getComputedStyle.getPropertyValue( name ); + + // If the element isn't reporting its values properly in Safari + // then some display: none elements are involved + else { + var swap = [], stack = []; + + // Locate all of the parent display: none elements + for ( var a = elem; a && color(a); a = a.parentNode ) + stack.unshift(a); + + // Go through and make them visible, but in reverse + // (It would be better if we knew the exact display type that they had) + for ( var i = 0; i < stack.length; i++ ) + if ( color( stack[ i ] ) ) { + swap[ i ] = stack[ i ].style.display; + stack[ i ].style.display = "block"; + } + + // Since we flip the display style, we have to handle that + // one special, otherwise get the value + ret = name == "display" && swap[ stack.length - 1 ] != null ? + "none" : + ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || ""; + + // Finally, revert the display styles back + for ( var i = 0; i < swap.length; i++ ) + if ( swap[ i ] != null ) + stack[ i ].style.display = swap[ i ]; + } + + // We should always get a number back from opacity + if ( name == "opacity" && ret == "" ) + ret = "1"; + + } else if ( elem.currentStyle ) { + var camelCase = name.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); + + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + elem.style.left = ret || 0; + ret = elem.style.pixelLeft + "px"; + + // Revert the changed values + elem.style.left = style; + elem.runtimeStyle.left = runtimeStyle; + } + } + + return ret; + }, + + clean: function( elems, context ) { + var ret = []; + context = context || document; + // !context.createElement fails in IE with an error but returns typeof 'object' + if (typeof context.createElement == 'undefined') + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + + jQuery.each(elems, function(i, elem){ + if ( !elem ) + return; + + if ( elem.constructor == Number ) + elem = elem.toString(); + + // Convert html string into DOM nodes + if ( typeof elem == "string" ) { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area)$/i) ? + all : + front + ">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div"); + + var wrap = + // option or optgroup + !tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "", "
      " ] || + + !tags.indexOf("", "" ] || + + // matched above + (!tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + // IE can't serialize and '; + $output.='
      '; + + if ($element['#autocomplete_path'] && menu_valid_path(array('link_path' => $element['#autocomplete_path']))) { + drupal_add_js('misc/autocomplete.js'); + $class[] = 'form-autocomplete'; + $extra = ''; + } + _form_set_class($element, $class); + + if (isset($element['#field_prefix'])) { + $output .= ''. $element['#field_prefix'] .' '; + } + + $output .= ''; + + if (isset($element['#field_suffix'])) { + $output .= ' '. $element['#field_suffix'] .''; + } + + $stickyName = preg_replace('/\]/','',array_pop(preg_split('/\[/',$element['#name']))).'-sticky'; + $output .= (isset($element['#sticky']) && $element['#sticky'] == TRUE?' Sticky?':'') . '
      '; + + + return theme('form_element', $element, $output ) . $extra; + +} + + + +/** + * Theme function to format the output. + * + * We use the container-inline class so that all three of the HTML elements + * are placed next to each other, rather than on separate lines. + */ +function theme_sticky_textfield($element) { + + //echo '
      '; var_dump($element); echo '
      '; + + //return theme('theme_form_element', $element, '
      ' . $element['#children'] . '
      '); + $size = empty($element['#size']) ? '' : ' size="'. $element['#size'] .'"'; + $maxlength = empty($element['#maxlength']) ? '' : ' maxlength="'. $element['#maxlength'] .'"'; + $class = array('form-text'); + $extra = ''; + $output='
      '; + + if ($element['#autocomplete_path'] && menu_valid_path(array('link_path' => $element['#autocomplete_path']))) { + drupal_add_js('misc/autocomplete.js'); + $class[] = 'form-autocomplete'; + $extra = ''; + } + _form_set_class($element, $class); + + if (isset($element['#field_prefix'])) { + $output .= ''. $element['#field_prefix'] .' '; + } + + $output .= ''; + + if (isset($element['#field_suffix'])) { + $output .= ' '. $element['#field_suffix'] .''; + } + + $stickyName = preg_replace('/\]/','',array_pop(preg_split('/\[/',$element['#name']))).'-sticky'; + $output .= (isset($element['#sticky']) && $element['#sticky'] == TRUE?' Sticky?':'') . '
      '; + + + return theme('form_element', $element, $output ) . $extra; + +} + +function ife_filechooser_validate($element,&$form_state) +{ + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + $cp = CollectionPolicy::loadFromCollection($form_state['storage']['collection_pid']); + if ($cp !== false) + { + $form_state['values'][$element['#name']] =$cp->getStagingArea().'/'.$element['#value']; + } +} + +function ife_filechooser_process($element, $edit, &$form_state) +{ + $element['#model_pid']=$form_state['values']['models']; + + return $element; +} + +function islandora_form_elements_menu() +{ + + module_load_include('inc','fedora_repository','ObjectHelper'); + + $items=array(); + + $items['ife/people_ahah'] = array( + 'page callback' => 'ife_people_ahah', + 'type' => MENU_CALLBACK, + 'access arguments' => array(ObjectHelper::$INGEST_FEDORA_OBJECTS), + 'file' => 'includes/people.inc', + ); + + $items['autocomplete_marcrelator/%'] = array( + 'title' => 'autocomplete', + 'page callback' => 'ife_autocomplete_marcrelator', + 'page arguments'=> array(1), + 'type' => MENU_CALLBACK, + 'access arguments' => array(ObjectHelper::$INGEST_FEDORA_OBJECTS), + 'file'=> 'includes/autocomplete.inc' + ); + + $items['autocomplete_gacs/%'] = array( + 'title' => 'autocomplete', + 'page callback' => 'ife_autocomplete_gacs', + 'page arguments'=> array(1), + 'type' => MENU_CALLBACK, + 'access arguments' => array(ObjectHelper::$INGEST_FEDORA_OBJECTS), + 'file'=> 'includes/autocomplete.inc' + ); + + $items['autocomplete_language/%'] = array( + 'title' => 'autocomplete', + 'page callback' => 'ife_autocomplete_language', + 'page arguments'=> array(1), + 'type' => MENU_CALLBACK, + 'access arguments' => array(ObjectHelper::$INGEST_FEDORA_OBJECTS), + 'file'=> 'includes/autocomplete.inc' + ); + + $items['autocomplete_person/%'] = array( + 'title' => 'autocomplete', + 'page callback' => 'ife_autocomplete_person', + 'page arguments'=> array(1), + 'type' => MENU_CALLBACK, + 'access arguments' => array(ObjectHelper::$INGEST_FEDORA_OBJECTS), + 'file'=> 'includes/autocomplete.inc' + ); + + $items['autocomplete/%/%'] = array( + 'title' => 'autocomplete', + 'page callback' => 'ife_autocomplete', + 'page arguments'=> array(1,2), + 'type' => MENU_CALLBACK, + 'access arguments' => array(ObjectHelper::$INGEST_FEDORA_OBJECTS), + 'file'=> 'includes/autocomplete.inc', + ); + + + $items['filechooser/getThumbnail/%/%/%'] = array( + 'title' => 'getThumbnail', + 'page callback' => 'ife_filechooser_get_thumbnail', + 'page arguments'=> array(2,3,4), + 'type' => MENU_CALLBACK, + 'access arguments' => array(ObjectHelper::$INGEST_FEDORA_OBJECTS), + 'file' => 'includes/filechooser.inc' + ); + + $items['filechooser/generatePreview/%/%'] = array( + 'title' => 'generatePreview', + 'page callback' => 'ife_filechooser_generate_thumbnails', + 'page arguments'=> array(2,3), + 'type' => MENU_CALLBACK, + 'access arguments' => array(ObjectHelper::$INGEST_FEDORA_OBJECTS), + 'file' => 'includes/filechooser.inc' + ); + + + + return $items; +} + diff --git a/form_elements/js/copyright.js b/form_elements/js/copyright.js new file mode 100644 index 00000000..6c9ed082 --- /dev/null +++ b/form_elements/js/copyright.js @@ -0,0 +1,48 @@ +$(document).ready(function () { + + var cc_versions = new Array(); cc_versions[""]="3.0"; cc_versions["ar"]="2.5"; cc_versions["au"]="3.0"; cc_versions["at"]="3.0"; cc_versions["be"]="2.0"; cc_versions["br"]="3.0"; cc_versions["bg"]="2.5"; cc_versions["ca"]="2.5"; cc_versions["cl"]="2.0"; cc_versions["cn"]="2.5"; cc_versions["co"]="2.5"; cc_versions["hr"]="3.0"; cc_versions["cz"]="3.0"; cc_versions["dk"]="2.5"; cc_versions["ec"]="3.0"; cc_versions["fi"]="1.0"; cc_versions["fr"]="2.0"; cc_versions["de"]="3.0"; cc_versions["gr"]="3.0"; cc_versions["gt"]="3.0"; cc_versions["hk"]="3.0"; cc_versions["hu"]="2.5"; cc_versions["in"]="2.5"; cc_versions["il"]="2.5"; cc_versions["it"]="2.5"; cc_versions["jp"]="2.0"; cc_versions["kr"]="2.0"; cc_versions["lu"]="3.0"; cc_versions["mk"]="2.5"; cc_versions["my"]="2.5"; cc_versions["mt"]="2.5"; cc_versions["mx"]="2.5"; cc_versions["nl"]="3.0"; cc_versions["nz"]="3.0"; cc_versions["no"]="3.0"; cc_versions["pe"]="2.5"; cc_versions["ph"]="3.0"; cc_versions["pl"]="3.0"; cc_versions["pt"]="2.5"; cc_versions["pr"]="3.0"; cc_versions["ro"]="3.0"; cc_versions["rs"]="3.0"; cc_versions["sg"]="3.0"; cc_versions["si"]="2.5"; cc_versions["za"]="2.5"; cc_versions["es"]="3.0"; cc_versions["se"]="2.5"; cc_versions["ch"]="2.5"; cc_versions["tw"]="3.0"; cc_versions["th"]="3.0"; cc_versions["uk"]="2.0"; cc_versions["scotland"]="2.5"; cc_versions["us"]="3.0"; cc_versions["vn"]="3.0"; + + function updateCCPreview() + { + + var commercial = $('.cc_commercial').val(); + var modification = $('.cc_modifications').val(); + var jurisdiction= $('.cc_jurisdiction').val(); + var jurisdiction_name = jurisdiction; + var version = cc_versions[jurisdiction_name]; + + var params=""; + + if (commercial != '') + params+="-"+commercial; + if (modification != '') + params+="-"+modification; + + + if (jurisdiction != null) + jurisdiction+="/"; + else + { + jurisdiction = ""; + jurisdiction_name = ""; + } + + var html = "\"Creative
      This work is licensed under a Creative Commons License."; + + $('.cc_preview').html(html); + } + + $('.cc_enable').change(function () { + $('.cc_field').attr('disabled', !$(this).attr('checked')); + if ($(this).attr('checked')) + updateCCPreview(); + else + $('.cc_preview').html(''); + }); + + $('.cc_field').change(function () { + updateCCPreview(); + }); + + updateCCPreview(); +}); \ No newline at end of file diff --git a/form_elements/js/filechooser.js b/form_elements/js/filechooser.js new file mode 100644 index 00000000..ac81ec47 --- /dev/null +++ b/form_elements/js/filechooser.js @@ -0,0 +1,90 @@ +var files = new Array(); +var selectedFile = null; +var visibleFiles=4; + +$(document).ready(function () { + + var selectedValue = false; + var selectedIndex = 0; + var cp_pid; + var cm_pid; + var start=0; + var end = 50; + + if ($('#fileField').attr('value') != '') + { + selectedValue = $('#fileField').attr('value'); + } + + cp_pid = $('#edit-collection-pid').attr('value'); + cm_pid = $('#model_pid').attr('value'); + $.getJSON("/filechooser/generatePreview/"+cp_pid+"/"+cm_pid+"?start="+start+"&end="+end,function (data) + { + + $('#fileList').html(''); + if (data.length == 0) + { + $('#fileList').append('
      No files found in staging area.
      '); + + } else + { + $.each(data, function(i, item) + { + var html; + files[i]=item.name; + var selected= ""; + if (selectedValue == item.name) + { + selected='class="selected"'; + selectedFile='file'+i; + selectedIndex=i - (i%visibleFiles); + } + + if (item.thumb) + { + html='
    • '+item.name+'
      '+item.mime+'
      '+item.size+'  '+item.resolution+'
    • '; + } else + { + var type=item.mime.split('/',1).shift(); + html='
    •  
      '+item.name+'
      '+item.mime+'
      '+item.size+'
    • '; + } + + $('#fileList').append(html); + }); + + $('#fileList li div').breakly(15); + + } + + + $(".carousel .jCarouselLite").jCarouselLite({ + btnNext: ".carousel .next", + btnPrev: ".carousel .prev", + mouseWheel: true, + circular: false, + speed: 750, + easing: "bounceout", + visible: visibleFiles, + scroll: visibleFiles, + initial: selectedIndex + }); + + $(".carousel li").click(function() { + + if (selectedFile != this.id) + { + $('#fileField').attr('value',files[this.id.split('file',2).pop()]); + $("#"+(this.id)).addClass('selected'); + if (selectedFile != null) + { + $("#"+selectedFile).removeClass('selected'); + } + selectedFile=this.id; + } + }) + + }); + +}); + + diff --git a/form_elements/js/jcarousellite_1.0.1.js b/form_elements/js/jcarousellite_1.0.1.js new file mode 100644 index 00000000..d51bca66 --- /dev/null +++ b/form_elements/js/jcarousellite_1.0.1.js @@ -0,0 +1,343 @@ +/** + * jCarouselLite - jQuery plugin to navigate images/any content in a carousel style widget. + * @requires jQuery v1.2 or above + * + * http://gmarwaha.com/jquery/jcarousellite/ + * + * Copyright (c) 2007 Ganeshji Marwaha (gmarwaha.com) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Version: 1.0.1 + * Note: Requires jquery 1.2 or above from version 1.0.1 + */ + +/** + * Creates a carousel-style navigation widget for images/any-content from a simple HTML markup. + * + * The HTML markup that is used to build the carousel can be as simple as... + * + * + * + * As you can see, this snippet is nothing but a simple div containing an unordered list of images. + * You don't need any special "class" attribute, or a special "css" file for this plugin. + * I am using a class attribute just for the sake of explanation here. + * + * To navigate the elements of the carousel, you need some kind of navigation buttons. + * For example, you will need a "previous" button to go backward, and a "next" button to go forward. + * This need not be part of the carousel "div" itself. It can be any element in your page. + * Lets assume that the following elements in your document can be used as next, and prev buttons... + * + * + * + * + * Now, all you need to do is call the carousel component on the div element that represents it, and pass in the + * navigation buttons as options. + * + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev" + * }); + * + * That's it, you would have now converted your raw div, into a magnificient carousel. + * + * There are quite a few other options that you can use to customize it though. + * Each will be explained with an example below. + * + * @param an options object - You can specify all the options shown below as an options object param. + * + * @option btnPrev, btnNext : string - no defaults + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev" + * }); + * @desc Creates a basic carousel. Clicking "btnPrev" navigates backwards and "btnNext" navigates forward. + * + * @option btnGo - array - no defaults + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * btnGo: [".0", ".1", ".2"] + * }); + * @desc If you don't want next and previous buttons for navigation, instead you prefer custom navigation based on + * the item number within the carousel, you can use this option. Just supply an array of selectors for each element + * in the carousel. The index of the array represents the index of the element. What i mean is, if the + * first element in the array is ".0", it means that when the element represented by ".0" is clicked, the carousel + * will slide to the first element and so on and so forth. This feature is very powerful. For example, i made a tabbed + * interface out of it by making my navigation elements styled like tabs in css. As the carousel is capable of holding + * any content, not just images, you can have a very simple tabbed navigation in minutes without using any other plugin. + * The best part is that, the tab will "slide" based on the provided effect. :-) + * + * @option mouseWheel : boolean - default is false + * @example + * $(".carousel").jCarouselLite({ + * mouseWheel: true + * }); + * @desc The carousel can also be navigated using the mouse wheel interface of a scroll mouse instead of using buttons. + * To get this feature working, you have to do 2 things. First, you have to include the mouse-wheel plugin from brandon. + * Second, you will have to set the option "mouseWheel" to true. That's it, now you will be able to navigate your carousel + * using the mouse wheel. Using buttons and mouseWheel or not mutually exclusive. You can still have buttons for navigation + * as well. They complement each other. To use both together, just supply the options required for both as shown below. + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * mouseWheel: true + * }); + * + * @option auto : number - default is null, meaning autoscroll is disabled by default + * @example + * $(".carousel").jCarouselLite({ + * auto: 800, + * speed: 500 + * }); + * @desc You can make your carousel auto-navigate itself by specfying a millisecond value in this option. + * The value you specify is the amount of time between 2 slides. The default is null, and that disables auto scrolling. + * Specify this value and magically your carousel will start auto scrolling. + * + * @option speed : number - 200 is default + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * speed: 800 + * }); + * @desc Specifying a speed will slow-down or speed-up the sliding speed of your carousel. Try it out with + * different speeds like 800, 600, 1500 etc. Providing 0, will remove the slide effect. + * + * @option easing : string - no easing effects by default. + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * easing: "bounceout" + * }); + * @desc You can specify any easing effect. Note: You need easing plugin for that. Once specified, + * the carousel will slide based on the provided easing effect. + * + * @option vertical : boolean - default is false + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * vertical: true + * }); + * @desc Determines the direction of the carousel. true, means the carousel will display vertically. The next and + * prev buttons will slide the items vertically as well. The default is false, which means that the carousel will + * display horizontally. The next and prev items will slide the items from left-right in this case. + * + * @option circular : boolean - default is true + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * circular: false + * }); + * @desc Setting it to true enables circular navigation. This means, if you click "next" after you reach the last + * element, you will automatically slide to the first element and vice versa. If you set circular to false, then + * if you click on the "next" button after you reach the last element, you will stay in the last element itself + * and similarly for "previous" button and first element. + * + * @option visible : number - default is 3 + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * visible: 4 + * }); + * @desc This specifies the number of items visible at all times within the carousel. The default is 3. + * You are even free to experiment with real numbers. Eg: "3.5" will have 3 items fully visible and the + * last item half visible. This gives you the effect of showing the user that there are more images to the right. + * + * @option start : number - default is 0 + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * start: 2 + * }); + * @desc You can specify from which item the carousel should start. Remember, the first item in the carousel + * has a start of 0, and so on. + * + * @option scrool : number - default is 1 + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * scroll: 2 + * }); + * @desc The number of items that should scroll/slide when you click the next/prev navigation buttons. By + * default, only one item is scrolled, but you may set it to any number. Eg: setting it to "2" will scroll + * 2 items when you click the next or previous buttons. + * + * @option beforeStart, afterEnd : function - callbacks + * @example + * $(".carousel").jCarouselLite({ + * btnNext: ".next", + * btnPrev: ".prev", + * beforeStart: function(a) { + * alert("Before animation starts:" + a); + * }, + * afterEnd: function(a) { + * alert("After animation ends:" + a); + * } + * }); + * @desc If you wanted to do some logic in your page before the slide starts and after the slide ends, you can + * register these 2 callbacks. The functions will be passed an argument that represents an array of elements that + * are visible at the time of callback. + * + * + * @cat Plugins/Image Gallery + * @author Ganeshji Marwaha/ganeshread@gmail.com + */ + +(function($) { // Compliant with jquery.noConflict() +$.fn.jCarouselLite = function(o) { + o = $.extend({ + btnPrev: null, + btnNext: null, + btnGo: null, + mouseWheel: false, + auto: null, + + speed: 200, + easing: null, + + vertical: false, + circular: true, + visible: 3, + start: 0, + scroll: 1, + + beforeStart: null, + afterEnd: null + }, o || {}); + + return this.each(function() { // Returns the element collection. Chainable. + + var running = false, animCss=o.vertical?"top":"left", sizeCss=o.vertical?"height":"width"; + var div = $(this), ul = $("ul", div), tLi = $("li", ul), tl = tLi.size(), v = o.visible; + + if(o.circular) { + ul.prepend(tLi.slice(tl-v-1+1).clone()) + .append(tLi.slice(0,v).clone()); + o.start += v; + } + + var li = $("li", ul), itemLength = li.size(), curr = o.start; + div.css("visibility", "visible"); + + li.css({overflow: "hidden", float: o.vertical ? "none" : "left"}); + ul.css({margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1"}); + div.css({overflow: "hidden", position: "relative", "z-index": "2", left: "0px"}); + + var liSize = o.vertical ? height(li) : width(li); // Full li size(incl margin)-Used for animation + var ulSize = liSize * itemLength; // size of full ul(total length, not just for the visible items) + var divSize = liSize * v; // size of entire div(total length for just the visible items) + + li.css({width: li.width(), height: li.height()}); + ul.css(sizeCss, ulSize+"px").css(animCss, -(curr*liSize)); + + div.css(sizeCss, divSize+"px"); // Width of the DIV. length of visible images + + if(o.btnPrev) + $(o.btnPrev).click(function() { + return go(curr-o.scroll); + }); + + if(o.btnNext) + $(o.btnNext).click(function() { + return go(curr+o.scroll); + }); + + if(o.btnGo) + $.each(o.btnGo, function(i, val) { + $(val).click(function() { + return go(o.circular ? o.visible+i : i); + }); + }); + if(o.initial && o.initial >= o.visible) + go(o.circular ? o.visible+o.initial : o.initial); + + if(o.mouseWheel && div.mousewheel) + div.mousewheel(function(e, d) { + return d>0 ? go(curr-o.scroll) : go(curr+o.scroll); + }); + + if(o.auto) + setInterval(function() { + go(curr+o.scroll); + }, o.auto+o.speed); + + function vis() { + return li.slice(curr).slice(0,v); + }; + + function go(to) { + if(!running) { + + if(o.beforeStart) + o.beforeStart.call(this, vis()); + + if(o.circular) { // If circular we are in first or last, then goto the other end + if(to<=o.start-v-1) { // If first, then goto last + ul.css(animCss, -((itemLength-(v*2))*liSize)+"px"); + // If "scroll" > 1, then the "to" might not be equal to the condition; it can be lesser depending on the number of elements. + curr = to==o.start-v-1 ? itemLength-(v*2)-1 : itemLength-(v*2)-o.scroll; + } else if(to>=itemLength-v+1) { // If last, then goto first + ul.css(animCss, -( (v) * liSize ) + "px" ); + // If "scroll" > 1, then the "to" might not be equal to the condition; it can be greater depending on the number of elements. + curr = to==itemLength-v+1 ? v+1 : v+o.scroll; + } else curr = to; + } else { // If non-circular and to points to first or last, we just return. + if(to<0 || to>itemLength-v) return; + else curr = to; + } // If neither overrides it, the curr will still be "to" and we can proceed. + + running = true; + + ul.animate( + animCss == "left" ? { left: -(curr*liSize) } : { top: -(curr*liSize) } , o.speed, o.easing, + function() { + if(o.afterEnd) + o.afterEnd.call(this, vis()); + running = false; + } + ); + // Disable buttons when the carousel reaches the last/first, and enable when not + if(!o.circular) { + $(o.btnPrev + "," + o.btnNext).removeClass("disabled"); + $( (curr-o.scroll<0 && o.btnPrev) + || + (curr+o.scroll > itemLength-v && o.btnNext) + || + [] + ).addClass("disabled"); + } + + } + return false; + }; + }); +}; + +function css(el, prop) { + return parseInt($.css(el[0], prop)) || 0; +}; +function width(el) { + return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight'); +}; +function height(el) { + return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom'); +}; + +})(jQuery); \ No newline at end of file diff --git a/form_elements/js/jquery.breakly-1.0.js b/form_elements/js/jquery.breakly-1.0.js new file mode 100644 index 00000000..e025a34d --- /dev/null +++ b/form_elements/js/jquery.breakly-1.0.js @@ -0,0 +1,58 @@ +/** + * jQuery Breakly plugin - Breaks your texts. Gently. + * This plugin can be used to give the browser an "hint" on when (and eventually how) break + * some long texts that are wrapped in a container with an explicitely defined width. + * It works adding a "special" unicode character after the given number of characters. + * By default the plugin inserts U+200B (the zero width space), but you can specify any + * other character as the second parameter + * + * @name jquery-breakly-1.0.js + * @author Claudio Cicali - http://claudio.cicali.name + * @version 1.0 + * @date December 22, 2009 + * @category jQuery plugin + * @copyright (c) 2009 Claudio Cicali ( http://claudio.cicali.name ) + * @license CC Attribution-No Derivative Works 2.5 Brazil - http://creativecommons.org/licenses/by-nd/2.5/br/deed.en_US + * @examples + * $('h3').breakly(3); // "breaks" any h3 text (and any h3's children text too) inserting a \U+200B after every 3 characters + * $('h3').breakly(3, 0x202f); // Same as above, but inserts a "NARROW NO-BREAK SPACE" (just for the fun of it) + + * Visit http://lab.web20.it/breakly/example.html + * List of Unicode spaces: http://www.cs.tut.fi/~jkorpela/chars/spaces.html + */ +$.fn.breakly = function(chopAt, spaceCode) { + spaceCode |= 8203; // U+200B ZERO WIDTH SPACE + var zw = String.fromCharCode(spaceCode), re = new RegExp(/\B/), orig, idx, chopped, ch; + function breakly(node) { + if (3 == node.nodeType && (orig = node.nodeValue).length > chopAt) { + idx = 0; + chopped=[]; + for (var i=0; i < orig.length; i++) { + ch = orig.substr(i,1); + chopped.push(ch); + if (null != ch.match(re)) { + idx=0; + continue; + } + if (++idx == chopAt) { + ch = orig.substr(i+1,1); // look ahead + if (ch && null == ch.match(re)) { + chopped.push(zw); + idx=0; + } + } + } + node.nodeValue = chopped.join(''); + } else { + for (var i=0; i < node.childNodes.length; i++) { + breakly(node.childNodes[i]); + } + } + } + + return this.each(function() { + breakly(this); + }) +} + + diff --git a/form_elements/js/jquery.easing.1.1.js b/form_elements/js/jquery.easing.1.1.js new file mode 100644 index 00000000..f2ae8730 --- /dev/null +++ b/form_elements/js/jquery.easing.1.1.js @@ -0,0 +1,105 @@ +/* + * jQuery Easing v1.1 - http://gsgd.co.uk/sandbox/jquery.easing.php + * + * Uses the built in easing capabilities added in jQuery 1.1 + * to offer multiple easing options + * + * Copyright (c) 2007 George Smith + * Licensed under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + */ + +jQuery.easing = { + easein: function(x, t, b, c, d) { + return c*(t/=d)*t + b; // in + }, + easeinout: function(x, t, b, c, d) { + if (t < d/2) return 2*c*t*t/(d*d) + b; + var ts = t - d/2; + return -2*c*ts*ts/(d*d) + 2*c*ts/d + c/2 + b; + }, + easeout: function(x, t, b, c, d) { + return -c*t*t/(d*d) + 2*c*t/d + b; + }, + expoin: function(x, t, b, c, d) { + var flip = 1; + if (c < 0) { + flip *= -1; + c *= -1; + } + return flip * (Math.exp(Math.log(c)/d * t)) + b; + }, + expoout: function(x, t, b, c, d) { + var flip = 1; + if (c < 0) { + flip *= -1; + c *= -1; + } + return flip * (-Math.exp(-Math.log(c)/d * (t-d)) + c + 1) + b; + }, + expoinout: function(x, t, b, c, d) { + var flip = 1; + if (c < 0) { + flip *= -1; + c *= -1; + } + if (t < d/2) return flip * (Math.exp(Math.log(c/2)/(d/2) * t)) + b; + return flip * (-Math.exp(-2*Math.log(c/2)/d * (t-d)) + c + 1) + b; + }, + bouncein: function(x, t, b, c, d) { + return c - jQuery.easing['bounceout'](x, d-t, 0, c, d) + b; + }, + bounceout: function(x, t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + bounceinout: function(x, t, b, c, d) { + if (t < d/2) return jQuery.easing['bouncein'] (x, t*2, 0, c, d) * .5 + b; + return jQuery.easing['bounceout'] (x, t*2-d,0, c, d) * .5 + c*.5 + b; + }, + elasin: function(x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + elasout: function(x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + elasinout: function(x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + backin: function(x, t, b, c, d) { + var s=1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + backout: function(x, t, b, c, d) { + var s=1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + backinout: function(x, t, b, c, d) { + var s=1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + linear: function(x, t, b, c, d) { + return c*t/d + b; //linear + } +}; \ No newline at end of file diff --git a/form_elements/js/jquery.loadImages.1.0.1.js b/form_elements/js/jquery.loadImages.1.0.1.js new file mode 100644 index 00000000..b2594ba3 --- /dev/null +++ b/form_elements/js/jquery.loadImages.1.0.1.js @@ -0,0 +1,33 @@ +(function($){ + //cache needed for overagressive garbage collectors. + var cache = []; + //images can either be an array of paths to images or a single image. + $.loadImages = function(images, ids, callback){ + + //convert to array if needed so rest of script works + if (!(images instanceof Array)) { + images = [images]; + } + + if (!(images instanceof Array)) { + ids = [ids]; + } + + var imagesLength = images.length; + var loadedCounter = 0; + + for (var i=0; i < imagesLength; i++) { + var cacheImage = document.createElement('img'); + //set the onload method before the src is called otherwise will fail to be called in IE + cacheImage.onload = function(){ + loadedCounter++; + if ($.isFunction(callback)) { + callback(this); + } + } + cacheImage.src = images[i]; + cacheImage.id = '#'+ids[i]; + cache.push(cacheImage); + } + } +})(jQuery) diff --git a/form_elements/js/jquery.loadImages.1.0.1.min.js b/form_elements/js/jquery.loadImages.1.0.1.min.js new file mode 100644 index 00000000..b697758e --- /dev/null +++ b/form_elements/js/jquery.loadImages.1.0.1.min.js @@ -0,0 +1 @@ +(function(c){var h=[];c.loadImages=function(a,d){a instanceof Array||(a=[a]);for(var e=a.length,f=0,g=e;g--;){var b=document.createElement("img");b.onload=function(){f++;f>=e&&c.isFunction(d)&&d()};b.src=a[g];h.push(b)}}})(jQuery); \ No newline at end of file diff --git a/form_elements/js/jquery.loadImages.1.0.1.zip b/form_elements/js/jquery.loadImages.1.0.1.zip new file mode 100644 index 00000000..1444833d Binary files /dev/null and b/form_elements/js/jquery.loadImages.1.0.1.zip differ diff --git a/form_elements/js/jquery.mousewheel.min.js b/form_elements/js/jquery.mousewheel.min.js new file mode 100644 index 00000000..05ebb0a9 --- /dev/null +++ b/form_elements/js/jquery.mousewheel.min.js @@ -0,0 +1,11 @@ +/* Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * + * Version: 3.0.2 + * + * Requires: 1.2.2+ + */ +(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery); \ No newline at end of file diff --git a/form_elements/js/jquery.tag.editor-min.js b/form_elements/js/jquery.tag.editor-min.js new file mode 100644 index 00000000..b111631d --- /dev/null +++ b/form_elements/js/jquery.tag.editor-min.js @@ -0,0 +1,8 @@ +/* +@inital author: Karl-Johan Sjögren / http://blog.crazybeavers.se/ +@contributor: Joost Elfering / http://yopefonic.wordpress.com/ +@url: http://blog.crazybeavers.se/wp-content/demos/jquery.tag.editor/ +@license: Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/ +@version: 1.4.1 +*/ +(function(jQuery) { jQuery.fn.tagEditor = function(options) { var defaults = { separator: ",", items: [], className: "tagEditor", confirmRemoval: false, confirmRemovalText: "Do you really want to remove the tag?", completeOnSeparator: false, completeOnBlur: false, tagsBeforeField: false, initialParse: true, imageTag: false, imageTagUrl: "", continuousOutputBuild: false }; options = jQuery.extend(defaults, options); var listBase, textBase = this, hiddenText; var itemBase = []; return this.each(function() { function addTag(tag) { tag = jQuery.trim(tag); for (var i = 0; i < itemBase.length; i++) { if (itemBase[i].toLowerCase() == tag.toLowerCase()) { return false; } } var item = jQuery(document.createElement("li")); item.text(tag); item.attr("title", "Remove tag"); if (options.imageTag) { item.append(''); } item.click(function() { if (options.confirmRemoval) { if (!confirm(options.confirmRemovalText)) { return; } } item.remove(); parse(); }); listBase.append(item); return true; } function resetTags() { itemBase = []; listBase.html(""); textBase.val(""); hiddenText.val(""); for (var i = 0; i < options.items.length; i++) { addTag(jQuery.trim(options.items[i])); } parse(); } function buildArray() { itemBase = []; var items = jQuery("li", listBase); for (var i = 0; i < items.length; i++) { itemBase.push(jQuery.trim(jQuery(items[i]).text())); } if (options.continuousOutputBuild) { hiddenText.val(itemBase.join(options.separator)); } } function parse() { var items = textBase.val().split(options.separator); for (var i = 0; i < items.length; i++) { var trimmedItem = jQuery.trim(items[i]); if (trimmedItem.length > 0) { addTag(trimmedItem); } } textBase.val(""); buildArray(); } function handleKeys(ev) { var keyCode = (ev.which) ? ev.which : ev.keyCode; if (options.completeOnSeparator) { if (String.fromCharCode(keyCode) == options.separator) { parse(); return false; } } switch (keyCode) { case 13: if (jQuery.trim(textBase.val()) != "") { parse(); return false; } return true; default: return true; } } jQuery.fn.extend({ tagEditorGetTags: function() { return itemBase.join(options.separator); }, tagEditorResetTags: function() { resetTags(); }, tagEditorAddTag: function(tag) { return addTag(tag); } }); hiddenText = jQuery(document.createElement("input")); hiddenText.attr("type", "hidden"); if (options.continuousOutputBuild) { hiddenText.attr("name", textBase.attr("name")); textBase.attr("name", textBase.attr("name") + "_old"); } textBase.after(hiddenText); listBase = jQuery(document.createElement("ul")); listBase.attr("class", options.className); if (options.tagsBeforeField) { jQuery(this).before(listBase); } else { jQuery(this).after(listBase); } for (var i = 0; i < options.items.length; i++) { addTag(jQuery.trim(options.items[i])); } if (options.initialParse) { parse(); } if (options.completeOnBlur) { jQuery(this).blur(parse); } buildArray(); jQuery(this).keypress(handleKeys); var form = jQuery(this).parents("form"); if (!options.continuousOutputBuild) { form.submit(function() { parse(); hiddenText.val(itemBase.join(options.separator)); hiddenText.attr("id", textBase.attr("id")); hiddenText.attr("name", textBase.attr("name")); textBase.attr("id", textBase.attr("id") + "_old"); textBase.attr("name", textBase.attr("name") + "_old"); }); } }); }; })(jQuery); \ No newline at end of file diff --git a/form_elements/js/jquery.tag.editor.js b/form_elements/js/jquery.tag.editor.js new file mode 100644 index 00000000..d34837ae --- /dev/null +++ b/form_elements/js/jquery.tag.editor.js @@ -0,0 +1,214 @@ +/* +@inital author: Karl-Johan Sjögren / http://blog.crazybeavers.se/ +@contributor: Joost Elfering / http://yopefonic.wordpress.com/ +@url: http://blog.crazybeavers.se/wp-content/demos/jquery.tag.editor/ +@license: Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/ +@version: 1.4.1 +@changelog +1.4.1 +Karl-Johan Sjögren +-Removed all references to $ to make sure that it is compatible even when using other libraries that bind to $ +-Reorganized the code and cleaned it up to pass the JSLint-test to make sure that it works when minified +-Switched minifier to YUI Compressor since Packer broke the script (even though it passes JSLint) +1.4 +Karl-Johan Sjögren +-Normalized the string chars in the script to ' +-Added a minified version of the script to the package using http://base2.googlecode.com/svn/trunk/src/apps/packer/packer.html +Joost Elfering +-Major change in extension of the object +-Moved getTags to tagEditorGetTags for naming convention +-Changed tagEditor so that it can be called without arguments +-Changed call for getTags to $(object).tagEditorGetTags() +-Changed addTag to return a true or false value as a success indicator +-Added resetTags method to clear the input and set the default given tags as start +-Added tagEditorResetTags as API for resetTags: $(object).tagEditorResetTags() +-Added tagEditorAddTag as API for addTag: $(object).tagEditorAddTag('string') +-Added continuousOutputBuild option to allow continuous building for dynamic forms +-Added tagsBeforeField option to switch places between tags added and the input field +-Added imageTag option to add and image to the list for styling purposes +-Added imageTagUrl option to define custom image for styling purposes +1.3 +-Any string already in the textbox when enabling the tag editor is now parsed as tags +-Added initialParse to stop the initial parsing +-Added confirmRemovalText as an option to better support different localizations +-Added the getTags method. +-Fixed completeOnBlur that wasn't working +1.2 +-Fixed bug with completeOnSeparator for Firefox +-Fixed so that pressing return on an empty editor would submit the form +1.1 +-Initial public release +-Added the completeOnSeparator and completeOnBlur options +*/ +(function(jQuery) { + jQuery.fn.tagEditor = function(options) { + var defaults = { + separator: ',', + items: [], + className: 'tagEditor', + confirmRemoval: false, + confirmRemovalText: 'Do you really want to remove the tag?', + completeOnSeparator: false, + completeOnBlur: false, + tagsBeforeField: false, + initialParse: true, + imageTag: false, + imageTagUrl: '', + continuousOutputBuild: false + }; + + options = jQuery.extend(defaults, options); + + var listBase, textBase = this, hiddenText; + var itemBase = []; + + return this.each(function() { + function addTag(tag) { + tag = jQuery.trim(tag); + for (var i = 0; i < itemBase.length; i++) { + if (itemBase[i].toLowerCase() == tag.toLowerCase()) { + return false; + } + } + + var item = jQuery(document.createElement('li')); + item.text(tag); + item.attr('title', 'Remove tag'); + if (options.imageTag) { + item.append(''); + } + + item.click(function() { + if (options.confirmRemoval) { + if (!confirm(options.confirmRemovalText)) { + return; + } + } + + item.remove(); + parse(); + }); + + listBase.append(item); + return true; + } + + function resetTags() { + itemBase = []; + listBase.html(''); + textBase.val(''); + hiddenText.val(''); + for (var i = 0; i < options.items.length; i++) { + addTag(jQuery.trim(options.items[i])); + } + parse(); + } + + function buildArray() { + itemBase = []; + var items = jQuery('li', listBase); + + for (var i = 0; i < items.length; i++) { + itemBase.push(jQuery.trim(jQuery(items[i]).text())); + } + + if (options.continuousOutputBuild) { + hiddenText.val(itemBase.join(options.separator)); + } + } + + function parse() { + var items = textBase.val().split(options.separator); + + for (var i = 0; i < items.length; i++) { + var trimmedItem = jQuery.trim(items[i]); + if (trimmedItem.length > 0) { + addTag(trimmedItem); + } + } + + textBase.val(''); + buildArray(); + } + + function handleKeys(ev) { + var keyCode = (ev.which) ? ev.which : ev.keyCode; + + if (options.completeOnSeparator) { + if (String.fromCharCode(keyCode) == options.separator) { + parse(); + return false; + } + } + + switch (keyCode) { + case 13: + if (jQuery.trim(textBase.val()) != '') { + parse(); + return false; + } + return true; + default: + return true; + } + } + + jQuery.fn.extend({ + tagEditorGetTags: function() { + return itemBase.join(options.separator); + }, + tagEditorResetTags: function() { + resetTags(); + }, + tagEditorAddTag: function(tag) { + return addTag(tag); + } + }); + + hiddenText = jQuery(document.createElement('input')); + hiddenText.attr('type', 'hidden'); + if (options.continuousOutputBuild) { + hiddenText.attr('name', textBase.attr('name')); + textBase.attr('name', textBase.attr('name') + '_old'); + } + textBase.after(hiddenText); + + listBase = jQuery(document.createElement('ul')); + listBase.attr('class', options.className); + if (options.tagsBeforeField) { + jQuery(this).before(listBase); + } else { + jQuery(this).after(listBase); + } + + for (var i = 0; i < options.items.length; i++) { + addTag(jQuery.trim(options.items[i])); + } + + if (options.initialParse) { + parse(); + } + + if (options.completeOnBlur) { + jQuery(this).blur(parse); + } + + buildArray(); + jQuery(this).keypress(handleKeys); + + var form = jQuery(this).parents('form'); + + if (!options.continuousOutputBuild) { + form.submit(function() { + parse(); + hiddenText.val(itemBase.join(options.separator)); + hiddenText.attr('id', textBase.attr('id')); + hiddenText.attr("name", textBase.attr('name')); + textBase.attr('id', textBase.attr('id') + '_old'); + textBase.attr('name', textBase.attr('name') + '_old'); + + }); + } + }); + }; +})(jQuery); \ No newline at end of file diff --git a/form_elements/js/jquery.ui.core.js b/form_elements/js/jquery.ui.core.js new file mode 100644 index 00000000..7067cddf --- /dev/null +++ b/form_elements/js/jquery.ui.core.js @@ -0,0 +1,281 @@ +/*! + * jQuery UI 1.8.4 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function( $, undefined ) { + +// prevent duplicate loading +// this is only a problem because we proxy existing functions +// and we don't want to double proxy them +$.ui = $.ui || {}; +if ( $.ui.version ) { + return; +} + +//Helper functions and ui object +$.extend( $.ui, { + version: "1.8.4", + + // $.ui.plugin is deprecated. Use the proxy pattern instead. + plugin: { + add: function( module, option, set ) { + var proto = $.ui[ module ].prototype; + for ( var i in set ) { + proto.plugins[ i ] = proto.plugins[ i ] || []; + proto.plugins[ i ].push( [ option, set[ i ] ] ); + } + }, + call: function( instance, name, args ) { + var set = instance.plugins[ name ]; + if ( !set || !instance.element[ 0 ].parentNode ) { + return; + } + + for ( var i = 0; i < set.length; i++ ) { + if ( instance.options[ set[ i ][ 0 ] ] ) { + set[ i ][ 1 ].apply( instance.element, args ); + } + } + } + }, + + contains: function( a, b ) { + return document.compareDocumentPosition ? + a.compareDocumentPosition( b ) & 16 : + a !== b && a.contains( b ); + }, + + hasScroll: function( el, a ) { + + //If overflow is hidden, the element might have extra content, but the user wants to hide it + if ( $( el ).css( "overflow" ) === "hidden") { + return false; + } + + var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", + has = false; + + if ( el[ scroll ] > 0 ) { + return true; + } + + // TODO: determine which cases actually cause this to happen + // if the element doesn't have the scroll set, see if it's possible to + // set the scroll + el[ scroll ] = 1; + has = ( el[ scroll ] > 0 ); + el[ scroll ] = 0; + return has; + }, + + isOverAxis: function( x, reference, size ) { + //Determines when x coordinate is over "b" element axis + return ( x > reference ) && ( x < ( reference + size ) ); + }, + + isOver: function( y, x, top, left, height, width ) { + //Determines when x, y coordinates is over "b" element + return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width ); + }, + + keyCode: { + ALT: 18, + BACKSPACE: 8, + CAPS_LOCK: 20, + COMMA: 188, + COMMAND: 91, + COMMAND_LEFT: 91, // COMMAND + COMMAND_RIGHT: 93, + CONTROL: 17, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + INSERT: 45, + LEFT: 37, + MENU: 93, // COMMAND_RIGHT + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SHIFT: 16, + SPACE: 32, + TAB: 9, + UP: 38, + WINDOWS: 91 // COMMAND + } +}); + +//jQuery plugins +$.fn.extend({ + _focus: $.fn.focus, + focus: function( delay, fn ) { + return typeof delay === "number" ? + this.each(function() { + var elem = this; + setTimeout(function() { + $( elem ).focus(); + if ( fn ) { + fn.call( elem ); + } + }, delay ); + }) : + this._focus.apply( this, arguments ); + }, + + enableSelection: function() { + return this + .attr( "unselectable", "off" ) + .css( "MozUserSelect", "" ); + }, + + disableSelection: function() { + return this + .attr( "unselectable", "on" ) + .css( "MozUserSelect", "none" ); + }, + + scrollParent: function() { + var scrollParent; + if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { + scrollParent = this.parents().filter(function() { + return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + }).eq(0); + } else { + scrollParent = this.parents().filter(function() { + return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + }).eq(0); + } + + return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; + }, + + zIndex: function( zIndex ) { + if ( zIndex !== undefined ) { + return this.css( "zIndex", zIndex ); + } + + if ( this.length ) { + var elem = $( this[ 0 ] ), position, value; + while ( elem.length && elem[ 0 ] !== document ) { + // Ignore z-index if position is set to a value where z-index is ignored by the browser + // This makes behavior of this function consistent across browsers + // WebKit always returns auto if the element is positioned + position = elem.css( "position" ); + if ( position === "absolute" || position === "relative" || position === "fixed" ) { + // IE returns 0 when zIndex is not specified + // other browsers return a string + // we ignore the case of nested elements with an explicit value of 0 + //
      + value = parseInt( elem.css( "zIndex" ) ); + if ( !isNaN( value ) && value != 0 ) { + return value; + } + } + elem = elem.parent(); + } + } + + return 0; + } +}); + +$.each( [ "Width", "Height" ], function( i, name ) { + var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], + type = name.toLowerCase(), + orig = { + innerWidth: $.fn.innerWidth, + innerHeight: $.fn.innerHeight, + outerWidth: $.fn.outerWidth, + outerHeight: $.fn.outerHeight + }; + + function reduce( elem, size, border, margin ) { + $.each( side, function() { + size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0; + if ( border ) { + size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0; + } + if ( margin ) { + size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0; + } + }); + return size; + } + + $.fn[ "inner" + name ] = function( size ) { + if ( size === undefined ) { + return orig[ "inner" + name ].call( this ); + } + + return this.each(function() { + $.style( this, type, reduce( this, size ) + "px" ); + }); + }; + + $.fn[ "outer" + name] = function( size, margin ) { + if ( typeof size !== "number" ) { + return orig[ "outer" + name ].call( this, size ); + } + + return this.each(function() { + $.style( this, type, reduce( this, size, true, margin ) + "px" ); + }); + }; +}); + +//Additional selectors +function visible( element ) { + return !$( element ).parents().andSelf().filter(function() { + return $.curCSS( this, "visibility" ) === "hidden" || + $.expr.filters.hidden( this ); + }).length; +} + +$.extend( $.expr[ ":" ], { + data: function( elem, i, match ) { + return !!$.data( elem, match[ 3 ] ); + }, + + focusable: function( element ) { + var nodeName = element.nodeName.toLowerCase(), + tabIndex = $.attr( element, "tabindex" ); + if ( "area" === nodeName ) { + var map = element.parentNode, + mapName = map.name, + img; + if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { + return false; + } + img = $( "img[usemap=#" + mapName + "]" )[0]; + return !!img && visible( img ); + } + return ( /input|select|textarea|button|object/.test( nodeName ) + ? !element.disabled + : "a" == nodeName + ? element.href || !isNaN( tabIndex ) + : !isNaN( tabIndex )) + // the element and all of its ancestors must be visible + && visible( element ); + }, + + tabbable: function( element ) { + var tabIndex = $.attr( element, "tabindex" ); + return ( isNaN( tabIndex ) || tabIndex >= 0 ) && $( element ).is( ":focusable" ); + } +}); + +})( jQuery ); diff --git a/form_elements/js/jquery.ui.datepicker.js b/form_elements/js/jquery.ui.datepicker.js new file mode 100644 index 00000000..8937b0f3 --- /dev/null +++ b/form_elements/js/jquery.ui.datepicker.js @@ -0,0 +1,1732 @@ +/* + * jQuery UI Datepicker 1.8.4 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Datepicker + * + * Depends: + * jquery.ui.core.js + */ +(function( $, undefined ) { + +$.extend($.ui, { datepicker: { version: "1.8.4" } }); + +var PROP_NAME = 'datepicker'; +var dpuuid = new Date().getTime(); + +/* Date picker manager. + Use the singleton instance of this class, $.datepicker, to interact with the date picker. + Settings for (groups of) date pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Datepicker() { + this.debug = false; // Change this to true to start debugging + this._curInst = null; // The current instance in use + this._keyEvent = false; // If the last event was a key event + this._disabledInputs = []; // List of date picker inputs that have been disabled + this._datepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division + this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class + this._appendClass = 'ui-datepicker-append'; // The name of the append marker class + this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class + this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class + this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class + this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class + this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class + this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class + this.regional = []; // Available regional settings, indexed by language code + this.regional[''] = { // Default regional settings + closeText: 'Done', // Display text for close link + prevText: 'Prev', // Display text for previous month link + nextText: 'Next', // Display text for next month link + currentText: 'Today', // Display text for current month link + monthNames: ['January','February','March','April','May','June', + 'July','August','September','October','November','December'], // Names of months for drop-down and formatting + monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting + dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting + dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting + dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday + weekHeader: 'Wk', // Column header for week of the year + dateFormat: 'mm/dd/yy', // See format options on parseDate + firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... + isRTL: false, // True if right-to-left language, false if left-to-right + showMonthAfterYear: false, // True if the year select precedes month, false for month then year + yearSuffix: '' // Additional text to append to the year in the month headers + }; + this._defaults = { // Global defaults for all the date picker instances + showOn: 'focus', // 'focus' for popup on focus, + // 'button' for trigger button, or 'both' for either + showAnim: 'fadeIn', // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + defaultDate: null, // Used when field is blank: actual date, + // +/-number for offset from today, null for today + appendText: '', // Display text following the input box, e.g. showing the format + buttonText: '...', // Text for trigger button + buttonImage: '', // URL for trigger button image + buttonImageOnly: false, // True if the image appears alone, false if it appears on a button + hideIfNoPrevNext: false, // True to hide next/previous month links + // if not applicable, false to just disable them + navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links + gotoCurrent: false, // True if today link goes back to current selection instead + changeMonth: false, // True if month can be selected directly, false if only prev/next + changeYear: false, // True if year can be selected directly, false if only prev/next + yearRange: 'c-10:c+10', // Range of years to display in drop-down, + // either relative to today's year (-nn:+nn), relative to currently displayed year + // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) + showOtherMonths: false, // True to show dates in other months, false to leave blank + selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable + showWeek: false, // True to show week of the year, false to not show it + calculateWeek: this.iso8601Week, // How to calculate the week of the year, + // takes a Date and returns the number of the week for it + shortYearCutoff: '+10', // Short year values < this are in the current century, + // > this are in the previous century, + // string value starting with '+' for current year + value + minDate: null, // The earliest selectable date, or null for no limit + maxDate: null, // The latest selectable date, or null for no limit + duration: 'fast', // Duration of display/closure + beforeShowDay: null, // Function that takes a date and returns an array with + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', + // [2] = cell title (optional), e.g. $.datepicker.noWeekends + beforeShow: null, // Function that takes an input field and + // returns a set of custom settings for the date picker + onSelect: null, // Define a callback function when a date is selected + onChangeMonthYear: null, // Define a callback function when the month or year is changed + onClose: null, // Define a callback function when the datepicker is closed + numberOfMonths: 1, // Number of months to show at a time + showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) + stepMonths: 1, // Number of months to step back/forward + stepBigMonths: 12, // Number of months to step back/forward for the big links + altField: '', // Selector for an alternate field to store selected dates into + altFormat: '', // The date format to use for the alternate field + constrainInput: true, // The input is constrained by the current date format + showButtonPanel: false, // True to show button panel, false to not show it + autoSize: false // True to size the input for the date format, false to leave as is + }; + $.extend(this._defaults, this.regional['']); + this.dpDiv = $('
      '); +} + +$.extend(Datepicker.prototype, { + /* Class name added to elements to indicate already configured with a date picker. */ + markerClassName: 'hasDatepicker', + + /* Debug logging (if enabled). */ + log: function () { + if (this.debug) + console.log.apply('', arguments); + }, + + // TODO rename to "widget" when switching to widget factory + _widgetDatepicker: function() { + return this.dpDiv; + }, + + /* Override the default settings for all instances of the date picker. + @param settings object - the new settings to use as defaults (anonymous object) + @return the manager object */ + setDefaults: function(settings) { + extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the date picker to a jQuery selection. + @param target element - the target input field or division or span + @param settings object - the new settings to use for this date picker instance (anonymous) */ + _attachDatepicker: function(target, settings) { + // check for settings on the control itself - in namespace 'date:' + var inlineSettings = null; + for (var attrName in this._defaults) { + var attrValue = target.getAttribute('date:' + attrName); + if (attrValue) { + inlineSettings = inlineSettings || {}; + try { + inlineSettings[attrName] = eval(attrValue); + } catch (err) { + inlineSettings[attrName] = attrValue; + } + } + } + var nodeName = target.nodeName.toLowerCase(); + var inline = (nodeName == 'div' || nodeName == 'span'); + if (!target.id) { + this.uuid += 1; + target.id = 'dp' + this.uuid; + } + var inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}, inlineSettings || {}); + if (nodeName == 'input') { + this._connectDatepicker(target, inst); + } else if (inline) { + this._inlineDatepicker(target, inst); + } + }, + + /* Create a new instance object. */ + _newInst: function(target, inline) { + var id = target[0].id.replace(/([^A-Za-z0-9_])/g, '\\\\$1'); // escape jQuery meta chars + return {id: id, input: target, // associated target + selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection + drawMonth: 0, drawYear: 0, // month being drawn + inline: inline, // is datepicker inline or not + dpDiv: (!inline ? this.dpDiv : // presentation div + $('
      '))}; + }, + + /* Attach the date picker to an input field. */ + _connectDatepicker: function(target, inst) { + var input = $(target); + inst.append = $([]); + inst.trigger = $([]); + if (input.hasClass(this.markerClassName)) + return; + this._attachments(input, inst); + input.addClass(this.markerClassName).keydown(this._doKeyDown). + keypress(this._doKeyPress).keyup(this._doKeyUp). + bind("setData.datepicker", function(event, key, value) { + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key) { + return this._get(inst, key); + }); + this._autoSize(inst); + $.data(target, PROP_NAME, inst); + }, + + /* Make attachments based on settings. */ + _attachments: function(input, inst) { + var appendText = this._get(inst, 'appendText'); + var isRTL = this._get(inst, 'isRTL'); + if (inst.append) + inst.append.remove(); + if (appendText) { + inst.append = $('' + appendText + ''); + input[isRTL ? 'before' : 'after'](inst.append); + } + input.unbind('focus', this._showDatepicker); + if (inst.trigger) + inst.trigger.remove(); + var showOn = this._get(inst, 'showOn'); + if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field + input.focus(this._showDatepicker); + if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked + var buttonText = this._get(inst, 'buttonText'); + var buttonImage = this._get(inst, 'buttonImage'); + inst.trigger = $(this._get(inst, 'buttonImageOnly') ? + $('').addClass(this._triggerClass). + attr({ src: buttonImage, alt: buttonText, title: buttonText }) : + $('').addClass(this._triggerClass). + html(buttonImage == '' ? buttonText : $('').attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? 'before' : 'after'](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) + $.datepicker._hideDatepicker(); + else + $.datepicker._showDatepicker(input[0]); + return false; + }); + } + }, + + /* Apply the maximum length for the date format. */ + _autoSize: function(inst) { + if (this._get(inst, 'autoSize') && !inst.inline) { + var date = new Date(2009, 12 - 1, 20); // Ensure double digits + var dateFormat = this._get(inst, 'dateFormat'); + if (dateFormat.match(/[DM]/)) { + var findMax = function(names) { + var max = 0; + var maxI = 0; + for (var i = 0; i < names.length; i++) { + if (names[i].length > max) { + max = names[i].length; + maxI = i; + } + } + return maxI; + }; + date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? + 'monthNames' : 'monthNamesShort')))); + date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? + 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay()); + } + inst.input.attr('size', this._formatDate(inst, date).length); + } + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) + return; + divSpan.addClass(this.markerClassName).append(inst.dpDiv). + bind("setData.datepicker", function(event, key, value){ + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key){ + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + this._setDate(inst, this._getDefaultDate(inst), true); + this._updateDatepicker(inst); + this._updateAlternate(inst); + }, + + /* Pop-up the date picker in a "dialog" box. + @param input element - ignored + @param date string or Date - the initial date to display + @param onSelect function - the function to call when a date is selected + @param settings object - update the dialog date picker instance's settings (anonymous object) + @param pos int[2] - coordinates for the dialog's position within the screen or + event - with x/y coordinates or + leave empty for default (screen centre) + @return the manager object */ + _dialogDatepicker: function(input, date, onSelect, settings, pos) { + var inst = this._dialogInst; // internal instance + if (!inst) { + this.uuid += 1; + var id = 'dp' + this.uuid; + this._dialogInput = $(''); + this._dialogInput.keydown(this._doKeyDown); + $('body').append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], PROP_NAME, inst); + } + extendRemove(inst.settings, settings || {}); + date = (date && date.constructor == Date ? this._formatDate(inst, date) : date); + this._dialogInput.val(date); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + var browserWidth = document.documentElement.clientWidth; + var browserHeight = document.documentElement.clientHeight; + var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + var scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px'); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) + $.blockUI(this.dpDiv); + $.data(this._dialogInput[0], PROP_NAME, inst); + return this; + }, + + /* Detach a datepicker from its control. + @param target element - the target input field or division or span */ + _destroyDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName == 'input') { + inst.append.remove(); + inst.trigger.remove(); + $target.removeClass(this.markerClassName). + unbind('focus', this._showDatepicker). + unbind('keydown', this._doKeyDown). + unbind('keypress', this._doKeyPress). + unbind('keyup', this._doKeyUp); + } else if (nodeName == 'div' || nodeName == 'span') + $target.removeClass(this.markerClassName).empty(); + }, + + /* Enable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _enableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = false; + inst.trigger.filter('button'). + each(function() { this.disabled = false; }).end(). + filter('img').css({opacity: '1.0', cursor: ''}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().removeClass('ui-state-disabled'); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _disableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = true; + inst.trigger.filter('button'). + each(function() { this.disabled = true; }).end(). + filter('img').css({opacity: '0.5', cursor: 'default'}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().addClass('ui-state-disabled'); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + @param target element - the target input field or division or span + @return boolean - true if disabled, false if enabled */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] == target) + return true; + } + return false; + }, + + /* Retrieve the instance data for the target control. + @param target element - the target input field or division or span + @return object - the associated instance data + @throws error if a jQuery problem getting data */ + _getInst: function(target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw 'Missing instance data for this datepicker'; + } + }, + + /* Update or retrieve the settings for a date picker attached to an input field or division. + @param target element - the target input field or division or span + @param name object - the new settings to update or + string - the name of the setting to change or retrieve, + when retrieving also 'all' for all instance settings or + 'defaults' for all global defaults + @param value any - the new value for the setting + (omit if above is an object or to retrieve a value) */ + _optionDatepicker: function(target, name, value) { + var inst = this._getInst(target); + if (arguments.length == 2 && typeof name == 'string') { + return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) : + (inst ? (name == 'all' ? $.extend({}, inst.settings) : + this._get(inst, name)) : null)); + } + var settings = name || {}; + if (typeof name == 'string') { + settings = {}; + settings[name] = value; + } + if (inst) { + if (this._curInst == inst) { + this._hideDatepicker(); + } + var date = this._getDateDatepicker(target, true); + extendRemove(inst.settings, settings); + this._attachments($(target), inst); + this._autoSize(inst); + this._setDateDatepicker(target, date); + this._updateDatepicker(inst); + } + }, + + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, + + /* Redraw the date picker attached to an input field or division. + @param target element - the target input field or division or span */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + @param target element - the target input field or division or span + @param date Date - the new date */ + _setDateDatepicker: function(target, date) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + @param target element - the target input field or division or span + @param noDefault boolean - true if no default date is to be used + @return Date - the current date */ + _getDateDatepicker: function(target, noDefault) { + var inst = this._getInst(target); + if (inst && !inst.inline) + this._setDateFromField(inst, noDefault); + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var inst = $.datepicker._getInst(event.target); + var handled = true; + var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(); + handled = false; + break; // hide on tab out + case 13: var sel = $('td.' + $.datepicker._dayOverClass, inst.dpDiv). + add($('td.' + $.datepicker._currentClass, inst.dpDiv)); + if (sel[0]) + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + else + $.datepicker._hideDatepicker(); + return false; // don't submit the form + break; // select the value on enter + case 27: $.datepicker._hideDatepicker(); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + else { + handled = false; + } + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var inst = $.datepicker._getInst(event.target); + if ($.datepicker._get(inst, 'constrainInput')) { + var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); + var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); + return event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); + } + }, + + /* Synchronise manual entry and field/alternate field. */ + _doKeyUp: function(event) { + var inst = $.datepicker._getInst(event.target); + if (inst.input.val() != inst.lastVal) { + try { + var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), + (inst.input ? inst.input.val() : null), + $.datepicker._getFormatConfig(inst)); + if (date) { // only if valid + $.datepicker._setDateFromField(inst); + $.datepicker._updateAlternate(inst); + $.datepicker._updateDatepicker(inst); + } + } + catch (event) { + $.datepicker.log(event); + } + } + return true; + }, + + /* Pop-up the date picker for a given input field. + @param input element - the input field attached to the date picker or + event - if triggered by focus */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger + input = $('input', input.parentNode)[0]; + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here + return; + var inst = $.datepicker._getInst(input); + if ($.datepicker._curInst && $.datepicker._curInst != inst) { + $.datepicker._curInst.dpDiv.stop(true, true); + } + var beforeShow = $.datepicker._get(inst, 'beforeShow'); + extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {})); + inst.lastVal = null; + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + if ($.datepicker._inDialog) // hide cursor + input.value = ''; + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + var isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css('position') == 'fixed'; + return !isFixed; + }); + if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled + $.datepicker._pos[0] -= document.documentElement.scrollLeft; + $.datepicker._pos[1] -= document.documentElement.scrollTop; + } + var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + // determine sizing offscreen + inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', + left: offset.left + 'px', top: offset.top + 'px'}); + if (!inst.inline) { + var showAnim = $.datepicker._get(inst, 'showAnim'); + var duration = $.datepicker._get(inst, 'duration'); + var postProcess = function() { + $.datepicker._datepickerShowing = true; + var borders = $.datepicker._getBorders(inst.dpDiv); + inst.dpDiv.find('iframe.ui-datepicker-cover'). // IE6- only + css({left: -borders[0], top: -borders[1], + width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); + }; + inst.dpDiv.zIndex($(input).zIndex()+1); + if ($.effects && $.effects[showAnim]) + inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + else + inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); + if (!showAnim || !duration) + postProcess(); + if (inst.input.is(':visible') && !inst.input.is(':disabled')) + inst.input.focus(); + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + var self = this; + var borders = $.datepicker._getBorders(inst.dpDiv); + inst.dpDiv.empty().append(this._generateHTML(inst)) + .find('iframe.ui-datepicker-cover') // IE6- only + .css({left: -borders[0], top: -borders[1], + width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) + .end() + .find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a') + .bind('mouseout', function(){ + $(this).removeClass('ui-state-hover'); + if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover'); + if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover'); + }) + .bind('mouseover', function(){ + if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) { + $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); + $(this).addClass('ui-state-hover'); + if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover'); + if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover'); + } + }) + .end() + .find('.' + this._dayOverClass + ' a') + .trigger('mouseover') + .end(); + var numMonths = this._getNumberOfMonths(inst); + var cols = numMonths[1]; + var width = 17; + if (cols > 1) + inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); + else + inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); + inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + + 'Class']('ui-datepicker-multi'); + inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + + 'Class']('ui-datepicker-rtl'); + if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && + inst.input.is(':visible') && !inst.input.is(':disabled')) + inst.input.focus(); + }, + + /* Retrieve the size of left and top borders for an element. + @param elem (jQuery object) the element of interest + @return (number[2]) the left and top borders */ + _getBorders: function(elem) { + var convert = function(value) { + return {thin: 1, medium: 2, thick: 3}[value] || value; + }; + return [parseFloat(convert(elem.css('border-left-width'))), + parseFloat(convert(elem.css('border-top-width')))]; + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(); + var dpHeight = inst.dpDiv.outerHeight(); + var inputWidth = inst.input ? inst.input.outerWidth() : 0; + var inputHeight = inst.input ? inst.input.outerHeight() : 0; + var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft(); + var viewHeight = document.documentElement.clientHeight + $(document).scrollTop(); + + offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight) : 0); + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + var inst = this._getInst(obj); + var isRTL = this._get(inst, 'isRTL'); + while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) { + obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; + } + var position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + @param input element - the input field attached to the date picker */ + _hideDatepicker: function(input) { + var inst = this._curInst; + if (!inst || (input && inst != $.data(input, PROP_NAME))) + return; + if (this._datepickerShowing) { + var showAnim = this._get(inst, 'showAnim'); + var duration = this._get(inst, 'duration'); + var postProcess = function() { + $.datepicker._tidyDialog(inst); + this._curInst = null; + }; + if ($.effects && $.effects[showAnim]) + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + else + inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' : + (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); + if (!showAnim) + postProcess(); + var onClose = this._get(inst, 'onClose'); + if (onClose) + onClose.apply((inst.input ? inst.input[0] : null), + [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback + this._datepickerShowing = false; + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); + if ($.blockUI) { + $.unblockUI(); + $('body').append(this.dpDiv); + } + } + this._inDialog = false; + } + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) + return; + var $target = $(event.target); + if ($target[0].id != $.datepicker._mainDivId && + $target.parents('#' + $.datepicker._mainDivId).length == 0 && + !$target.hasClass($.datepicker.markerClassName) && + !$target.hasClass($.datepicker._triggerClass) && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) + $.datepicker._hideDatepicker(); + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._isDisabledDatepicker(target[0])) { + return; + } + this._adjustInstDate(inst, offset + + (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._get(inst, 'gotoCurrent') && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } + else { + var date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id); + var inst = this._getInst(target[0]); + inst._selectingMonthYear = false; + inst['selected' + (period == 'M' ? 'Month' : 'Year')] = + inst['draw' + (period == 'M' ? 'Month' : 'Year')] = + parseInt(select.options[select.selectedIndex].value,10); + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Restore input focus after not changing month/year. */ + _clickMonthYear: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (inst.input && inst._selectingMonthYear) { + setTimeout(function() { + inst.input.focus(); + }, 0); + } + inst._selectingMonthYear = !inst._selectingMonthYear; + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var target = $(id); + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + var inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $('a', td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + this._selectDate(target, ''); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var target = $(id); + var inst = this._getInst(target[0]); + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) + inst.input.val(inst.input.val()+dateStr); + this._updateAlternate(inst); + var onSelect = this._get(inst, 'onSelect'); + if (onSelect) + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + else if (inst.input) + inst.input.trigger('change'); // fire the change event + if (inst.inline) + this._updateDatepicker(inst); + else { + this._hideDatepicker(); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) != 'object') + inst.input.focus(); // restore focus + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altField = this._get(inst, 'altField'); + if (altField) { // update alternate field too + var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); + var date = this._getDate(inst); + var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + @param date Date - the date to customise + @return [boolean, string] - is this date selectable?, what is its CSS class? */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), '']; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + @param date Date - the date to get the week for + @return number - the number of the week within the year that contains this date */ + iso8601Week: function(date) { + var checkDate = new Date(date.getTime()); + // Find Thursday of this week starting on Monday + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); + var time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + }, + + /* Parse a string value into a date object. + See formatDate below for the possible formats. + + @param format string - the expected format of the date + @param value string - the date in the above format + @param settings Object - attributes include: + shortYearCutoff number - the cutoff year for determining the century (optional) + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return Date - the extracted date value or null if value is blank */ + parseDate: function (format, value, settings) { + if (format == null || value == null) + throw 'Invalid arguments'; + value = (typeof value == 'object' ? value.toString() : value + ''); + if (value == '') + return null; + var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + var year = -1; + var month = -1; + var day = -1; + var doy = -1; + var literal = false; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Extract a number from the string value + var getNumber = function(match) { + lookAhead(match); + var size = (match == '@' ? 14 : (match == '!' ? 20 : + (match == 'y' ? 4 : (match == 'o' ? 3 : 2)))); + var digits = new RegExp('^\\d{1,' + size + '}'); + var num = value.substring(iValue).match(digits); + if (!num) + throw 'Missing number at position ' + iValue; + iValue += num[0].length; + return parseInt(num[0], 10); + }; + // Extract a name from the string value and convert to an index + var getName = function(match, shortNames, longNames) { + var names = (lookAhead(match) ? longNames : shortNames); + for (var i = 0; i < names.length; i++) { + if (value.substr(iValue, names[i].length) == names[i]) { + iValue += names[i].length; + return i + 1; + } + } + throw 'Unknown name at position ' + iValue; + }; + // Confirm that a literal character matches the string value + var checkLiteral = function() { + if (value.charAt(iValue) != format.charAt(iFormat)) + throw 'Unexpected literal at position ' + iValue; + iValue++; + }; + var iValue = 0; + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + checkLiteral(); + else + switch (format.charAt(iFormat)) { + case 'd': + day = getNumber('d'); + break; + case 'D': + getName('D', dayNamesShort, dayNames); + break; + case 'o': + doy = getNumber('o'); + break; + case 'm': + month = getNumber('m'); + break; + case 'M': + month = getName('M', monthNamesShort, monthNames); + break; + case 'y': + year = getNumber('y'); + break; + case '@': + var date = new Date(getNumber('@')); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case '!': + var date = new Date((getNumber('!') - this._ticksTo1970) / 10000); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")) + checkLiteral(); + else + literal = true; + break; + default: + checkLiteral(); + } + } + if (year == -1) + year = new Date().getFullYear(); + else if (year < 100) + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + if (doy > -1) { + month = 1; + day = doy; + do { + var dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) + break; + month++; + day -= dim; + } while (true); + } + var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) + throw 'Invalid date'; // E.g. 31/02/* + return date; + }, + + /* Standard date formats. */ + ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) + COOKIE: 'D, dd M yy', + ISO_8601: 'yy-mm-dd', + RFC_822: 'D, d M y', + RFC_850: 'DD, dd-M-y', + RFC_1036: 'D, d M y', + RFC_1123: 'D, d M yy', + RFC_2822: 'D, d M yy', + RSS: 'D, d M y', // RFC 822 + TICKS: '!', + TIMESTAMP: '@', + W3C: 'yy-mm-dd', // ISO 8601 + + _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), + + /* Format a date object into a string value. + The format can be combinations of the following: + d - day of month (no leading zero) + dd - day of month (two digit) + o - day of year (no leading zeros) + oo - day of year (three digit) + D - day name short + DD - day name long + m - month of year (no leading zero) + mm - month of year (two digit) + M - month name short + MM - month name long + y - year (two digit) + yy - year (four digit) + @ - Unix timestamp (ms since 01/01/1970) + ! - Windows ticks (100ns since 01/01/0001) + '...' - literal text + '' - single quote + + @param format string - the desired format of the date + @param date Date - the date value to format + @param settings Object - attributes include: + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return string - the date in the above format */ + formatDate: function (format, date, settings) { + if (!date) + return ''; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Format a number, with leading zero if necessary + var formatNumber = function(match, value, len) { + var num = '' + value; + if (lookAhead(match)) + while (num.length < len) + num = '0' + num; + return num; + }; + // Format a name, short or long as requested + var formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }; + var output = ''; + var literal = false; + if (date) + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + output += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': + output += formatNumber('d', date.getDate(), 2); + break; + case 'D': + output += formatName('D', date.getDay(), dayNamesShort, dayNames); + break; + case 'o': + output += formatNumber('o', + (date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000, 3); + break; + case 'm': + output += formatNumber('m', date.getMonth() + 1, 2); + break; + case 'M': + output += formatName('M', date.getMonth(), monthNamesShort, monthNames); + break; + case 'y': + output += (lookAhead('y') ? date.getFullYear() : + (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); + break; + case '@': + output += date.getTime(); + break; + case '!': + output += date.getTime() * 10000 + this._ticksTo1970; + break; + case "'": + if (lookAhead("'")) + output += "'"; + else + literal = true; + break; + default: + output += format.charAt(iFormat); + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var chars = ''; + var literal = false; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + for (var iFormat = 0; iFormat < format.length; iFormat++) + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + chars += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': case 'm': case 'y': case '@': + chars += '0123456789'; + break; + case 'D': case 'M': + return null; // Accept anything + case "'": + if (lookAhead("'")) + chars += "'"; + else + literal = true; + break; + default: + chars += format.charAt(iFormat); + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst, noDefault) { + if (inst.input.val() == inst.lastVal) { + return; + } + var dateFormat = this._get(inst, 'dateFormat'); + var dates = inst.lastVal = inst.input ? inst.input.val() : null; + var date, defaultDate; + date = defaultDate = this._getDefaultDate(inst); + var settings = this._getFormatConfig(inst); + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + this.log(event); + dates = (noDefault ? '' : dates); + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + return this._restrictMinMax(inst, + this._determineDate(inst, this._get(inst, 'defaultDate'), new Date())); + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(inst, date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }; + var offsetString = function(offset) { + try { + return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), + offset, $.datepicker._getFormatConfig(inst)); + } + catch (e) { + // Ignore + } + var date = (offset.toLowerCase().match(/^c/) ? + $.datepicker._getDate(inst) : null) || new Date(); + var year = date.getFullYear(); + var month = date.getMonth(); + var day = date.getDate(); + var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; + var matches = pattern.exec(offset); + while (matches) { + switch (matches[2] || 'd') { + case 'd' : case 'D' : + day += parseInt(matches[1],10); break; + case 'w' : case 'W' : + day += parseInt(matches[1],10) * 7; break; + case 'm' : case 'M' : + month += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + case 'y': case 'Y' : + year += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }; + date = (date == null ? defaultDate : (typeof date == 'string' ? offsetString(date) : + (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date))); + date = (date && date.toString() == 'Invalid Date' ? defaultDate : date); + if (date) { + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + return this._daylightSavingAdjust(date); + }, + + /* Handle switch to/from daylight saving. + Hours may be non-zero on daylight saving cut-over: + > 12 when midnight changeover, but then cannot generate + midnight datetime, so jump to 1AM, otherwise reset. + @param date (Date) the date to check + @return (Date) the corrected date */ + _daylightSavingAdjust: function(date) { + if (!date) return null; + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, noChange) { + var clear = !(date); + var origMonth = inst.selectedMonth; + var origYear = inst.selectedYear; + date = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + inst.selectedDay = inst.currentDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear(); + if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange) + this._notifyChange(inst); + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? '' : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var today = new Date(); + today = this._daylightSavingAdjust( + new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time + var isRTL = this._get(inst, 'isRTL'); + var showButtonPanel = this._get(inst, 'showButtonPanel'); + var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); + var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); + var numMonths = this._getNumberOfMonths(inst); + var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); + var stepMonths = this._get(inst, 'stepMonths'); + var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); + var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + var drawMonth = inst.drawMonth - showCurrentAtPos; + var drawYear = inst.drawYear; + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + var prevText = this._get(inst, 'prevText'); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + '' + prevText + '' : + (hideIfNoPrevNext ? '' : '' + prevText + '')); + var nextText = this._get(inst, 'nextText'); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + '' + nextText + '' : + (hideIfNoPrevNext ? '' : '' + nextText + '')); + var currentText = this._get(inst, 'currentText'); + var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + var controls = (!inst.inline ? '' : ''); + var buttonPanel = (showButtonPanel) ? '
      ' + (isRTL ? controls : '') + + (this._isInRange(inst, gotoDate) ? '' : '') + (isRTL ? '' : controls) + '
      ' : ''; + var firstDay = parseInt(this._get(inst, 'firstDay'),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + var showWeek = this._get(inst, 'showWeek'); + var dayNames = this._get(inst, 'dayNames'); + var dayNamesShort = this._get(inst, 'dayNamesShort'); + var dayNamesMin = this._get(inst, 'dayNamesMin'); + var monthNames = this._get(inst, 'monthNames'); + var monthNamesShort = this._get(inst, 'monthNamesShort'); + var beforeShowDay = this._get(inst, 'beforeShowDay'); + var showOtherMonths = this._get(inst, 'showOtherMonths'); + var selectOtherMonths = this._get(inst, 'selectOtherMonths'); + var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; + var defaultDate = this._getDefaultDate(inst); + var html = ''; + for (var row = 0; row < numMonths[0]; row++) { + var group = ''; + for (var col = 0; col < numMonths[1]; col++) { + var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + var cornerClass = ' ui-corner-all'; + var calender = ''; + if (isMultiMonth) { + calender += '
      '; + } + calender += '
      ' + + (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + + (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + '
      ' + + ''; + var thead = (showWeek ? '' : ''); + for (var dow = 0; dow < 7; dow++) { // days of the week + var day = (dow + firstDay) % 7; + thead += '= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + + '' + dayNamesMin[day] + ''; + } + calender += thead + ''; + var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate + var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += ''; + var tbody = (!showWeek ? '' : ''); + for (var dow = 0; dow < 7; dow++) { // create date picker days + var daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); + var otherMonth = (printDate.getMonth() != drawMonth); + var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += ''; // display selectable date + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + ''; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += '
      ' + this._get(inst, 'weekHeader') + '
      ' + + this._get(inst, 'calculateWeek')(printDate) + '' + // actions + (otherMonth && !showOtherMonths ? ' ' : // display for other months + (unselectable ? '' + printDate.getDate() + '' : '' + printDate.getDate() + '')) + '
      ' + (isMultiMonth ? '
      ' + + ((numMonths[0] > 0 && col == numMonths[1]-1) ? '
      ' : '') : ''); + group += calender; + } + html += group; + } + html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ? + '' : ''); + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + var changeMonth = this._get(inst, 'changeMonth'); + var changeYear = this._get(inst, 'changeYear'); + var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); + var html = '
      '; + var monthHtml = ''; + // month selection + if (secondary || !changeMonth) + monthHtml += '' + monthNames[drawMonth] + ''; + else { + var inMinYear = (minDate && minDate.getFullYear() == drawYear); + var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); + monthHtml += ''; + } + if (!showMonthAfterYear) + html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); + // year selection + if (secondary || !changeYear) + html += '' + drawYear + ''; + else { + // determine range of years to display + var years = this._get(inst, 'yearRange').split(':'); + var thisYear = new Date().getFullYear(); + var determineYear = function(value) { + var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + var year = determineYear(years[0]); + var endYear = Math.max(year, determineYear(years[1] || '')); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + html += ''; + } + html += this._get(inst, 'yearSuffix'); + if (showMonthAfterYear) + html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; + html += '
      '; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period == 'Y' ? offset : 0); + var month = inst.drawMonth + (period == 'M' ? offset : 0); + var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + + (period == 'D' ? offset : 0); + var date = this._restrictMinMax(inst, + this._daylightSavingAdjust(new Date(year, month, day))); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period == 'M' || period == 'Y') + this._notifyChange(inst); + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + date = (minDate && date < minDate ? minDate : date); + date = (maxDate && date > maxDate ? maxDate : date); + return date; + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, 'onChangeMonthYear'); + if (onChange) + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, 'numberOfMonths'); + return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - new Date(year, month, 32).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst); + var date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + if (offset < 0) + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime())); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, 'shortYearCutoff'); + shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), + monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day == 'object' ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); + } +}); + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) + if (props[name] == null || props[name] == undefined) + target[name] = props[name]; + return target; +}; + +/* Determine whether an object is an array. */ +function isArray(a) { + return (a && (($.browser.safari && typeof a == 'object' && a.length) || + (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); +}; + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick). + find('body').append($.datepicker.dpDiv); + $.datepicker.initialized = true; + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + return this.each(function() { + typeof options == 'string' ? + $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.8.4"; + +// Workaround for #4055 +// Add another global to avoid noConflict issues with inline event handlers +window['DP_jQuery_' + dpuuid] = $; + +})(jQuery); diff --git a/form_elements/js/jquery.ui.widget.js b/form_elements/js/jquery.ui.widget.js new file mode 100644 index 00000000..85e9293b --- /dev/null +++ b/form_elements/js/jquery.ui.widget.js @@ -0,0 +1,237 @@ +/*! + * jQuery UI Widget 1.8.4 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Widget + */ +(function( $, undefined ) { + +var _remove = $.fn.remove; + +$.fn.remove = function( selector, keepData ) { + return this.each(function() { + if ( !keepData ) { + if ( !selector || $.filter( selector, [ this ] ).length ) { + $( "*", this ).add( [ this ] ).each(function() { + $( this ).triggerHandler( "remove" ); + }); + } + } + return _remove.call( $(this), selector, keepData ); + }); +}; + +$.widget = function( name, base, prototype ) { + var namespace = name.split( "." )[ 0 ], + fullName; + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName ] = function( elem ) { + return !!$.data( elem, name ); + }; + + $[ namespace ] = $[ namespace ] || {}; + $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without initializing for simple inheritance + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + + var basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from +// $.each( basePrototype, function( key, val ) { +// if ( $.isPlainObject(val) ) { +// basePrototype[ key ] = $.extend( {}, val ); +// } +// }); + basePrototype.options = $.extend( true, {}, basePrototype.options ); + $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { + namespace: namespace, + widgetName: name, + widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, + widgetBaseClass: fullName + }, prototype ); + + $.widget.bridge( name, $[ namespace ][ name ] ); +}; + +$.widget.bridge = function( name, object ) { + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = Array.prototype.slice.call( arguments, 1 ), + returnValue = this; + + // allow multiple hashes to be passed on init + options = !isMethodCall && args.length ? + $.extend.apply( null, [ true, options ].concat(args) ) : + options; + + // prevent calls to internal methods + if ( isMethodCall && options.substring( 0, 1 ) === "_" ) { + return returnValue; + } + + if ( isMethodCall ) { + this.each(function() { + var instance = $.data( this, name ), + methodValue = instance && $.isFunction( instance[options] ) ? + instance[ options ].apply( instance, args ) : + instance; + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue; + return false; + } + }); + } else { + this.each(function() { + var instance = $.data( this, name ); + if ( instance ) { + if ( options ) { + instance.option( options ); + } + instance._init(); + } else { + $.data( this, name, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( options, element ) { + // allow instantiation without initializing for simple inheritance + if ( arguments.length ) { + this._createWidget( options, element ); + } +}; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + options: { + disabled: false + }, + _createWidget: function( options, element ) { + // $.widget.bridge stores the plugin instance, but we do it anyway + // so that it's stored even before the _create function runs + $.data( element, this.widgetName, this ); + this.element = $( element ); + this.options = $.extend( true, {}, + this.options, + $.metadata && $.metadata.get( element )[ this.widgetName ], + options ); + + var self = this; + this.element.bind( "remove." + this.widgetName, function() { + self.destroy(); + }); + + this._create(); + this._init(); + }, + _create: function() {}, + _init: function() {}, + + destroy: function() { + this.element + .unbind( "." + this.widgetName ) + .removeData( this.widgetName ); + this.widget() + .unbind( "." + this.widgetName ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetBaseClass + "-disabled " + + "ui-state-disabled" ); + }, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + self = this; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.extend( {}, self.options ); + } + + if (typeof key === "string" ) { + if ( value === undefined ) { + return this.options[ key ]; + } + options = {}; + options[ key ] = value; + } + + $.each( options, function( key, value ) { + self._setOption( key, value ); + }); + + return self; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + [ value ? "addClass" : "removeClass"]( + this.widgetBaseClass + "-disabled" + " " + + "ui-state-disabled" ) + .attr( "aria-disabled", value ); + } + + return this; + }, + + enable: function() { + return this._setOption( "disabled", false ); + }, + disable: function() { + return this._setOption( "disabled", true ); + }, + + _trigger: function( type, event, data ) { + var callback = this.options[ type ]; + + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + data = data || {}; + + // copy original event properties over to the new event + // this would happen if we could call $.event.fix instead of $.Event + // but we don't have a way to force an event to be fixed multiple times + if ( event.originalEvent ) { + for ( var i = $.event.props.length, prop; i; ) { + prop = $.event.props[ --i ]; + event[ prop ] = event.originalEvent[ prop ]; + } + } + + this.element.trigger( event, data ); + + return !( $.isFunction(callback) && + callback.call( this.element[0], event, data ) === false || + event.isDefaultPrevented() ); + } +}; + +})( jQuery ); diff --git a/form_elements/js/otherselect.js b/form_elements/js/otherselect.js new file mode 100644 index 00000000..a138aba7 --- /dev/null +++ b/form_elements/js/otherselect.js @@ -0,0 +1,30 @@ +$(document).ready(function () { + $('.otherSelect').each(function (index) + { + var name = $(this).attr('name').replace(/[\[\]]+/g,'-'); + $(this).attr('id',name); + + $('#'+name+' option:last').after(''); + $(this).after(''); + + $(this).removeAttr('name'); + + + $(this).change(function () + { + + if ($(this).val() == 'other') + { + $('#'+$(this).attr('id')+'_field').val(''); + $('#'+$(this).attr('id')+'_other').show('fast'); + } else + { + $('#'+$(this).attr('id')+'_field').val($(this).val()); + $('#'+$(this).attr('id')+'_other').hide('fast'); + } + }); + + }); + }); + + \ No newline at end of file diff --git a/form_elements/js/people_ahah.js b/form_elements/js/people_ahah.js new file mode 100755 index 00000000..9b89b0bb --- /dev/null +++ b/form_elements/js/people_ahah.js @@ -0,0 +1,90 @@ + +(function($) { + +if (Drupal.jsEnabled) { + $(document).ready(function() { + if (Drupal.ahah != undefined) { + + $('#edit-mods-people-add-from-repository').change(function () { + $('#edit-mods-people-add-person').mousedown(); + }); + +/** + * Override of Drupal.ahah.prototype.success. The only difference is that we + * allow for new Drupal.settings. + */ +Drupal.ahah.prototype.success = function (response, status) { + $('#edit-mods-people-add-from-repository').val(''); + + var wrapper = $(this.wrapper); + var form = $(this.element).parents('form'); + // Manually insert HTML into the jQuery object, using $() directly crashes + // Safari with long string lengths. http://dev.jquery.com/ticket/1152 + var new_content = $('
      ').html(response.data); + + // Restore the previous action and target to the form. + form.attr('action', this.form_action); + this.form_target ? form.attr('target', this.form_target) : form.removeAttr('target'); + this.form_encattr ? form.attr('target', this.form_encattr) : form.removeAttr('encattr'); + + // Remove the progress element. + if (this.progress.element) { + $(this.progress.element).remove(); + } + if (this.progress.object) { + this.progress.object.stopMonitoring(); + } + $(this.element).removeClass('progress-disabled').attr('disabled', false); + + // Add the new content to the page. + Drupal.freezeHeight(); + if (this.method == 'replace') { + wrapper.empty().append(new_content); + } + else { + wrapper[this.method](new_content); + } + + $('.datepicker').datepicker({ buttonImage: '/misc/date.png', constrainInput: false, showOn: 'button', changeMonth: true, changeYear: true }); + + // Immediately hide the new content if we're using any effects. + if (this.showEffect != 'show') { + new_content.hide(); + } + + // Determine what effect use and what content will receive the effect, then + // show the new content. For browser compatibility, Safari is excluded from + // using effects on table rows. + if (($.browser.safari && $("tr.ahah-new-content", new_content).size() > 0)) { + new_content.show(); + } + else if ($('.ahah-new-content', new_content).size() > 0) { + $('.ahah-new-content', new_content).hide(); + new_content.show(); + $(".ahah-new-content", new_content)[this.showEffect](this.showSpeed); + } + else if (this.showEffect != 'show') { + new_content[this.showEffect](this.showSpeed); + } + + // Merge in new and changed settings, if any. + if (response.settings) { + $.extend(Drupal.settings, response.settings); + } + + // Attach all javascript behaviors to the new content, if it was successfully + // added to the page, this if statement allows #ahah[wrapper] to be optional. + if (new_content.parents('html').length > 0) { + Drupal.attachBehaviors(new_content); + } + + Drupal.unfreezeHeight(); +}; + + } + + + }); +} + +})(jQuery); \ No newline at end of file diff --git a/form_elements/js/tageditor_1-4-1.zip b/form_elements/js/tageditor_1-4-1.zip new file mode 100644 index 00000000..6264ff55 Binary files /dev/null and b/form_elements/js/tageditor_1-4-1.zip differ diff --git a/form_elements/xml/gacs.xml b/form_elements/xml/gacs.xml new file mode 100644 index 00000000..dc9f4db7 --- /dev/null +++ b/form_elements/xml/gacs.xml @@ -0,0 +1,5562 @@ + + + + + + + + marcgac + MARC Code List for Geographic Areas + Network Development and MARC Standards Office + info:lc/vocabulary/gacs + + + info:lc/vocabulary/gacs/a-af + Afghanistan + a-af + + + info:lc/vocabulary/gacs/f + Africa + f + + Islamic countries + + + Sahel + + + + info:lc/vocabulary/gacs/fc + Africa, Central + fc + + Central Africa + + + + info:lc/vocabulary/gacs/fe + Africa, Eastern + fe + + Africa, East + + British East Africa + + + East Africa + + + + Eastern Africa + + + + info:lc/vocabulary/gacs/fq + Africa, French-speaking Equatorial + fq + + Chad, Lake + + + Africa, Equatorial + + + French Equatorial Africa + + + French-speaking Equatorial Africa + + + + info:lc/vocabulary/gacs/ff + Africa, North + ff + + Africa, Northwest + + Northwest Africa + + + + Islamic Empire + + + Rome + + Roman Empire + + + + North Africa + + + + info:lc/vocabulary/gacs/fh + Africa, Northeast + fh + + Africa, Italian East + + + East African Horn + + + Italian East Africa + + + Northeast Africa + + + + info:lc/vocabulary/gacs/fs + Africa, Southern + fs + + Southern Africa + + + + info:lc/vocabulary/gacs/fb + Africa, Sub-Saharan + fb + + Sub-Saharan Africa + + + + info:lc/vocabulary/gacs/fw + Africa, West + fw + + Africa, French-speaking West + + French-speaking West Africa + + + French West Africa + + + + Africa, Northwest + + Northwest Africa + + + + Ghana (Empire) + + + Mali (Empire) + + + British West Africa + + + West Africa + + + + info:lc/vocabulary/gacs/n-us-al + Alabama + n-us-al + + + info:lc/vocabulary/gacs/n-us-ak + Alaska + n-us-ak + + + info:lc/vocabulary/gacs/e-aa + Albania + e-aa + + People's Socialist Republic of Albania + + + + info:lc/vocabulary/gacs/n-cn-ab + Alberta + n-cn-ab + + + info:lc/vocabulary/gacs/f-ae + Algeria + f-ae + + People's Democratic Republic of Algeria + + + + info:lc/vocabulary/gacs/ea + Alps + ea + + + info:lc/vocabulary/gacs/sa + Amazon River + sa + + + info:lc/vocabulary/gacs/poas + American Samoa + poas + + Samoa, American + + + + info:lc/vocabulary/gacs/aa + Amur River (China and Russia) + aa + + Hei Ho (China and Russia) + + + Heilong Jiang (China and Russia) + + + Reka Amur (China and Russia) + + + Sakhalin Ula (China and Russia) + + + + info:lc/vocabulary/gacs/sn + Andes + sn + + Andean Area + + + + info:lc/vocabulary/gacs/e-an + Andorra + e-an + + + info:lc/vocabulary/gacs/f-ao + Angola + f-ao + + Kongo Kingdom + + Congo (Kingdom) + + + + People's Republic of Angola + + + Portuguese West Africa + + + West Africa, Portuguese + + + + info:lc/vocabulary/gacs/nwxa + Anguilla + nwxa + + Coded [nwxi] (Saint Kitts and Nevis) before Mar. 1988 + + + Saint Kitts-Nevis-Anguilla + + St. Christopher-Nevis-Anguilla + + + + + info:lc/vocabulary/gacs/a-cc-an + Anhui Sheng (China) + a-cc-an + + Anhwei Province (China) + + + + info:lc/vocabulary/gacs/t + Antarctic Ocean + t + + + info:lc/vocabulary/gacs/t + Antarctica + t + + Coded also [t-ay] (Antarctica) before Mar. 1988 + + + Polar regions + + + South Shetland Islands (Antarctica) + + Coded [lsfk] (Falkland Islands) before Mar. 1998 + + + + Antarctic regions + + + South Pole + + + + info:lc/vocabulary/gacs/nwaq + Antigua and Barbuda + nwaq + + Antigua + + + Barbuda + + Coded [nwbc] (Barbuda) before Mar. 1988 + + + + + info:lc/vocabulary/gacs/nwla + Antilles, Lesser + nwla + + West Indies, French + + French West Indies + + + + Lesser Antilles + + + + info:lc/vocabulary/gacs/n-usa + Appalachian Mountains + n-usa + + Appalachian Mountains, Southern + + + Appalachian Region + + + Blue Ridge Mountains + + + + info:lc/vocabulary/gacs/ma + Arab countries + ma + + Arabic countries + + + + info:lc/vocabulary/gacs/ar + Arabian Peninsula + ar + + Persian Gulf States + + + Arabia + + + + info:lc/vocabulary/gacs/au + Arabian Sea + au + + Oman, Gulf of + + Gulf of Oman + + + + + info:lc/vocabulary/gacs/r + Arctic Ocean + r + + Barents Sea + + + Beaufort Sea + + + + info:lc/vocabulary/gacs/r + Arctic regions + r + + Polar regions + + + Northeast Passage + + + Northwest Passage + + + North Pole + + + + info:lc/vocabulary/gacs/s-ag + Argentina + s-ag + + + info:lc/vocabulary/gacs/n-us-az + Arizona + n-us-az + + + info:lc/vocabulary/gacs/n-us-ar + Arkansas + n-us-ar + + Ozark Mountains + + + + info:lc/vocabulary/gacs/a-ai + Armenia (Republic) + a-ai + + Coded [e-ur-ai] (Armenia (Republic)) before June 1998 + + + Armenia + + + Transcaucasia + + Coded [e-ur-ai] (Armenia (Republic)), [e-ur-aj] (Azerbaijan), [e-ur-gs] (Georgia + (Republic)) before June 1998] + + + + Armenian S.S.R. + + + + info:lc/vocabulary/gacs/nwaw + Aruba + nwaw + + Coded [nwco] (Curaçao) before Sept. 2002 + + + + info:lc/vocabulary/gacs/lsai + Ascension Island (Atlantic Ocean) + lsai + + + info:lc/vocabulary/gacs/u-ac + Ashmore and Cartier Islands + u-ac + + + info:lc/vocabulary/gacs/a + Asia + a + + Islamic countries + + + Orient + + East + + + + + info:lc/vocabulary/gacs/ac + Asia, Central + ac + + Central Asia + + + Soviet Central Asia + + + + info:lc/vocabulary/gacs/l + Atlantic Ocean + l + + Islands of the Atlantic + + + + info:lc/vocabulary/gacs/fa + Atlas Mountains + fa + + + info:lc/vocabulary/gacs/u + Australasia + u + + + info:lc/vocabulary/gacs/u-at + Australia + u-at + + Norfolk Island + + + + info:lc/vocabulary/gacs/u-at-ac + Australian Capital Territory + u-at-ac + + Coded [u-at-ne] (New South Wales) before Sept. 2002 + + + A.C.T. + + + Federal Capital Territory + + + + info:lc/vocabulary/gacs/e-au + Austria + e-au + + Pannonia + + + + info:lc/vocabulary/gacs/a-aj + Azerbaijan + a-aj + + Coded [e-ur-aj] (Azerbaijan) before June 1998 + + + Transcaucasia + + Coded [e-ur-ai] (Armenia (Republic)), [e-ur-aj] (Azerbaijan), [e-ur-gs] (Georgia + (Republic)) before June 1998] + + + + Azerbaijan S.S.R. + + + + info:lc/vocabulary/gacs/lnaz + Azores + lnaz + + Açores + + + + info:lc/vocabulary/gacs/nwbf + Bahamas + nwbf + + + info:lc/vocabulary/gacs/a-ba + Bahrain + a-ba + + Bahrein + + + + info:lc/vocabulary/gacs/ed + Balkan Peninsula + ed + + Europe, Southeastern + + + Southeastern Europe + + + + info:lc/vocabulary/gacs/eb + Baltic States + eb + + + info:lc/vocabulary/gacs/a-bg + Bangladesh + a-bg + + East Pakistan (Pakistan) + + + + info:lc/vocabulary/gacs/nwbb + Barbados + nwbb + + + info:lc/vocabulary/gacs/a-cc-pe + Beijing (China) + a-cc-pe + + Peiping (China) + + + Peking (China) + + + + info:lc/vocabulary/gacs/e-bw + Belarus + e-bw + + Coded [e-ur-bw] (Belarus) before June 1998 + + + Kievan Rus + + Coded [e-ur] (Soviet Union) before June 1998 + + + + Belorussian S.S.R. + + + Byelorussian S.S.R. + + + White Russia + + + + info:lc/vocabulary/gacs/e-be + Belgium + e-be + + + info:lc/vocabulary/gacs/ncbh + Belize + ncbh + + British Honduras + + + + info:lc/vocabulary/gacs/el + Benelux countries + el + + Low countries + + + + info:lc/vocabulary/gacs/ab + Bengal, Bay of + ab + + Bay of Bengal + + + + info:lc/vocabulary/gacs/f-dm + Benin + f-dm + + Dahomey + + + People's Republic of Benin + + + + info:lc/vocabulary/gacs/lnbm + Bermuda Islands + lnbm + + + info:lc/vocabulary/gacs/a-bt + Bhutan + a-bt + + + info:lc/vocabulary/gacs/mb + Black Sea + mb + + + info:lc/vocabulary/gacs/a-ccp + Bo Hai (China) + a-ccp + + Bohai (China : Gulf) + + + Chihli, Gulf of (China) + + + Po Gulf (China) + + + Po Hai (China) + + + + info:lc/vocabulary/gacs/s-bo + Bolivia + s-bo + + + info:lc/vocabulary/gacs/nwbn + Bonaire (Netherlands Antilles) + nwbn + + Coded [nwco] (Curaçao) before Sept. 200 + + + + info:lc/vocabulary/gacs/a-bn + Borneo + a-bn + + + info:lc/vocabulary/gacs/e-bn + Bosnia and Hercegovina + e-bn + + Coded [e-yu] (Yugoslavia) before Oct. 1992 + + + + info:lc/vocabulary/gacs/f-bs + Botswana + f-bs + + Bechuanaland + + + + info:lc/vocabulary/gacs/lsbv + Bouvet Island + lsbv + + + info:lc/vocabulary/gacs/s-bl + Brazil + s-bl + + + info:lc/vocabulary/gacs/n-cn-bc + British Columbia + n-cn-bc + + Canada, Western + + Western Canada + + + + Northwest, Pacific + + Northwest (U.S.) + + + Pacific Northwest + + + + + info:lc/vocabulary/gacs/i-bi + British Indian Ocean Territory + i-bi + + Diego Garcia (British Indian Ocean Territory) + + + Chagos Islands + + + Indian Ocean Territory, British + + + + info:lc/vocabulary/gacs/nwvb + British Virgin Islands + nwvb + + Virgin Islands + + Coded [nwvr] (Virgin Islands) before Mar. 1988 + + + + Virgin Islands, British + + + Virgin Islands (Great Britain) + + + Virgin Islands (Presidency) + + + + info:lc/vocabulary/gacs/a-bx + Brunei + a-bx + + + info:lc/vocabulary/gacs/e-bu + Bulgaria + e-bu + + Macedonia + + + Macedonia (Bulgaria) + + + People's Republic of Bulgaria + + + + info:lc/vocabulary/gacs/f-uv + Burkina Faso + f-uv + + Upper Volta + + + + info:lc/vocabulary/gacs/a-br + Burma + a-br + + Shan States + + + Myanmar + + + + info:lc/vocabulary/gacs/f-bd + Burundi + f-bd + + Ruanda-Urundi + + + German East Africa + + + + info:lc/vocabulary/gacs/n-us-ca + California + n-us-ca + + Pacific States + + + + info:lc/vocabulary/gacs/a-cb + Cambodia + a-cb + + Kampuchea + + + Khmer Republic + + + + info:lc/vocabulary/gacs/f-cm + Cameroon + f-cm + + Adamawa (Emirate) + + + Cameroons, French + + + Cameroons, Southern + + + Cameroun + + + French Cameroons + + + Southern Cameroons + + + + info:lc/vocabulary/gacs/n-cn + Canada + n-cn + + Canada, Eastern + + Eastern Canada + + + + Canada, Northern + + Northern Canada + + + + Northwest, Canadian + + Canadian Northwest + + + West (Canada) + + + + Saint Lawrence River + + + + info:lc/vocabulary/gacs/nccz + Canal Zone + nccz + + Panama Canal Zone + + + + info:lc/vocabulary/gacs/lnca + Canary Islands + lnca + + + info:lc/vocabulary/gacs/lncv + Cape Verde + lncv + + Cabo Verde + + + Republic of Cape Verde + + + + info:lc/vocabulary/gacs/cc + Caribbean Area + cc + + Spanish Main + + + Caribbean Sea Region + + + Circumcaribbean + + Coded [cr] (Circumcaribbean) before Mar. 1988 + + + + + info:lc/vocabulary/gacs/cc + Caribbean Sea + cc + + + info:lc/vocabulary/gacs/poci + Caroline Islands + poci + + + info:lc/vocabulary/gacs/ak + Caspian Sea + ak + + + info:lc/vocabulary/gacs/e-urk + Caucasus + e-urk + + + info:lc/vocabulary/gacs/e-urr + Caucasus, Northern (Russia) + e-urr + + North Caucasus (Russia) + + + Northern Caucasus (Russia) + + + + info:lc/vocabulary/gacs/nwcj + Cayman Islands + nwcj + + + info:lc/vocabulary/gacs/f-cx + Central African Republic + f-cx + + Central African Empire + + + Ubangi Shari + + + + info:lc/vocabulary/gacs/nc + Central America + nc + + America, Central + + + Middle America + + Coded [cm] (Middle America) before Mar. 1988 + + + + + info:lc/vocabulary/gacs/u-atc + Central Australia + u-atc + + Coded [u-at] (Australia) before September 2005 + + + Australia, Central + + + + info:lc/vocabulary/gacs/e-urc + Central Chernozem Region (Russia) + e-urc + + Central Black Earth Region (Russia) + + + Central Black Soil Region (Russia) + + + + info:lc/vocabulary/gacs/f-cd + Chad + f-cd + + Tibesti Mountains + + + + info:lc/vocabulary/gacs/s-cl + Chile + s-cl + + + info:lc/vocabulary/gacs/a-cc + China + a-cc + + Manchuria (China) + + + Mainland China + + + People's Republic of China + + + + info:lc/vocabulary/gacs/a-cc-cq + Chongqing (China) + a-cc-cq + + Coded [a-cc-sz] (Szechuan Province (China)) before Sept. 2000 + + + Ch'ung-ch'ing shih (China) + + + Chungking (China) + + + + info:lc/vocabulary/gacs/i-xa + Christmas Island (Indian Ocean) + i-xa + + + info:lc/vocabulary/gacs/i-xb + Cocos (Keeling) Islands + i-xb + + Keeling Islands + + + + info:lc/vocabulary/gacs/q + Cold regions + q + + + info:lc/vocabulary/gacs/s-ck + Colombia + s-ck + + + info:lc/vocabulary/gacs/n-us-co + Colorado + n-us-co + + + info:lc/vocabulary/gacs/b + Commonwealth countries + b + + British Commonwealth countries + + + British Dominions + + + Commonwealth nations + + + + info:lc/vocabulary/gacs/i-cq + Comoros + i-cq + + Comoro Islands + + + Îles Comores + + + + info:lc/vocabulary/gacs/f-cf + Congo (Brazzaville) + f-cf + + Kongo Kingdom + + Congo (Kingdom) + + + + Brazzaville + + + French Congo + + + Middle Congo + + + + info:lc/vocabulary/gacs/f-cg + Congo (Democratic Republic) + f-cg + + Kongo Kingdom + + Congo (Kingdom) + + + + Belgian Congo + + + Congo (Kinshasa) + + + Congo (Leopoldville) + + + Zaire + + + + info:lc/vocabulary/gacs/fg + Congo River + fg + + + info:lc/vocabulary/gacs/n-us-ct + Connecticut + n-us-ct + + + info:lc/vocabulary/gacs/pocw + Cook Islands + pocw + + + info:lc/vocabulary/gacs/u-cs + Coral Sea Islands + u-cs + + + info:lc/vocabulary/gacs/nccr + Costa Rica + nccr + + + info:lc/vocabulary/gacs/f-iv + Côte d'Ivoire + f-iv + + Ivory Coast + + + + info:lc/vocabulary/gacs/e-ci + Croatia + e-ci + + Coded [e-yu] (Yugoslavia) before Oct. 1992] + + + People's Republic of Croatia + + + + info:lc/vocabulary/gacs/nwcu + Cuba + nwcu + + + info:lc/vocabulary/gacs/nwco + Curaçao (Netherlands Antilles) + nwco + + + info:lc/vocabulary/gacs/a-cy + Cyprus + a-cy + + + info:lc/vocabulary/gacs/e-xr + Czech Republic [e-xr] + e-xr + + Coded [e-cs] (Czechoslovakia) before May 1993 + + + Czech Socialist Republic (Czechoslovakia) + + + + info:lc/vocabulary/gacs/e-cs + Czechoslovakia + e-cs + + Includes the Czech Republic and Slovakia treated collectively + + + + info:lc/vocabulary/gacs/eo + Danube River + eo + + + info:lc/vocabulary/gacs/zd + Deep space + zd + + + info:lc/vocabulary/gacs/n-us-de + Delaware + n-us-de + + + info:lc/vocabulary/gacs/e-dk + Denmark + e-dk + + + info:lc/vocabulary/gacs/dd + Developed countries + dd + + Advanced countries + + + Economically advanced countries + + + First World + + + Industrialized countries + + + + info:lc/vocabulary/gacs/d + Developing countries + d + + Emerging nations + + + Third World + + + Underdeveloped areas + + + + info:lc/vocabulary/gacs/f-ft + Djibouti + f-ft + + Afars and Issas, French Territory of the + + + French Somaliland + + + French Territory of the Afars and Issas + + + Somaliland, French + + + + info:lc/vocabulary/gacs/nwdq + Dominica + nwdq + + + info:lc/vocabulary/gacs/nwdr + Dominican Republic + nwdr + + + info:lc/vocabulary/gacs/x + Earth + x + + + info:lc/vocabulary/gacs/n-usr + East (U.S.) + n-usr + + + info:lc/vocabulary/gacs/ae + East Asia + ae + + Asia, East + + + East (Far East) + + + Far East + + + + info:lc/vocabulary/gacs/an + East China Sea + an + + + info:lc/vocabulary/gacs/a-em + East Timor + a-em + + Coded [a-pt] (Portuguese Timor) before April 21, 1980; coded [a-io] (Indonesia) from + 1980-Sept. 2002] + + + Lesser Sunda Islands (Indonesia and East Timor) + + Sunda Islands, Lesser (Indonesia and East Timor) + + + + Timor Island + + + Portuguese Timor + + + Timor, East + + + Timor, Portuguese + + + Timor Timur + + + + info:lc/vocabulary/gacs/poea + Easter Island + poea + + Isla de Pascua + + + Pascua Island + + + + info:lc/vocabulary/gacs/u-ate + Eastern Australia + u-ate + + Coded [u-at] (Australia) before September 2005 + + + Australia, Eastern + + + + info:lc/vocabulary/gacs/xa + Eastern Hemisphere + xa + + + info:lc/vocabulary/gacs/s-ec + Ecuador + s-ec + + + info:lc/vocabulary/gacs/f-ua + Egypt + f-ua + + United Arab Republic + + + + info:lc/vocabulary/gacs/nces + El Salvador + nces + + Salvador + + + + info:lc/vocabulary/gacs/e-uk-en + England + e-uk-en + + Brownsea Island (England) + + + Isle of Wight (England) + + Wight, Isle of + + + + + info:lc/vocabulary/gacs/f-eg + Equatorial Guinea + f-eg + + Fernando Po (Equatorial Guinea) + + Bioco (Equatorial Guinea) + + + Bioko (Equatorial Guinea) + + + Macias Nguema (Equatorial Guinea) + + + + Guinea, Equatorial + + + Guinea, Spanish + + + Río Muni + + + Spanish Guinea + + + + info:lc/vocabulary/gacs/f-ea + Eritrea + f-ea + + Coded [f-et] (Ethiopia) before Nov. 1993 + + + + info:lc/vocabulary/gacs/e-er + Estonia + e-er + + Coded [e-ur-er] (Estonia) before June 1998 + + + + info:lc/vocabulary/gacs/f-et + Ethiopia + f-et + + Abyssinia + + + + info:lc/vocabulary/gacs/me + Eurasia + me + + Asia and Europe (treated collectively) + + + Europe and Asia (treated collectively) + + + + info:lc/vocabulary/gacs/e + Europe + e + + European Economic Community countries + + + European Union countries + + + Holy Roman Empire + + + Rome + + Roman Empire + + + + + info:lc/vocabulary/gacs/ec + Europe, Central + ec + + Central Europe + + + Europe, East Central + + Coded [et] (Europe, East Central) before Mar. 1988 + + + + + info:lc/vocabulary/gacs/ee + Europe, Eastern + ee + + Carpathian Mountains + + + Communist countries + + Coded [v] (Communist countries) before June 1998 + + + + Eastern Europe + + + Europe, East Central + + Coded [et] (Europe, East Central) before Mar. 1988 + + + + + info:lc/vocabulary/gacs/en + Europe, Northern + en + + Northern Europe + + + + info:lc/vocabulary/gacs/es + Europe, Southern + es + + Southern Europe + + + + info:lc/vocabulary/gacs/ew + Europe, Western + ew + + Western Europe + + + + info:lc/vocabulary/gacs/lsfk + Falkland Islands + lsfk + + South Orkney Islands + + + Malvinas Islands + + + + info:lc/vocabulary/gacs/lnfa + Faroe Islands + lnfa + + Faeroe Islands + + + + info:lc/vocabulary/gacs/pofj + Fiji + pofj + + + info:lc/vocabulary/gacs/e-fi + Finland + e-fi + + Lapland + + + + info:lc/vocabulary/gacs/e-fr + France + e-fr + + Corsica (France) + + + + info:lc/vocabulary/gacs/h + French Community + h + + Communauté francaise + + + French Union + + + + info:lc/vocabulary/gacs/s-fg + French Guiana + s-fg + + Guiana, French + + + + info:lc/vocabulary/gacs/pofp + French Polynesia + pofp + + Austral Islands (French Polynesia) + + Tubuai Islands (French Polynesia) + + + + Gambier Islands (French Polynesia) + + + Marquesas Islands (French Polynesia) + + Archipel des Marquises (French Polynesia) + + + Îles Marquises de Mendoça (French Polynesia) + + + Islas Marquesas de Mendoza (French Polynesia) + + + Mendaña (French Polynesia) + + + + Society Islands (French Polynesia) + + + Tuamotu Archipelago (French Polynesia) + + + Oceania, French + + + Polynesia, French + + + + info:lc/vocabulary/gacs/a-cc-fu + Fujian Sheng (China) + a-cc-fu + + Fukien Province (China) + + + + info:lc/vocabulary/gacs/f-go + Gabon + f-go + + + info:lc/vocabulary/gacs/pogg + Galapagos Islands + pogg + + + info:lc/vocabulary/gacs/f-gm + Gambia + f-gm + + + info:lc/vocabulary/gacs/a-cc-ka + Gansu Sheng (China) [a-cc-ka] + a-cc-ka + + Kansu Province (China) + + + + info:lc/vocabulary/gacs/awgz + Gaza Strip + awgz + + Palestine + + + + info:lc/vocabulary/gacs/n-us-ga + Georgia + n-us-ga + + + info:lc/vocabulary/gacs/a-gs + Georgia (Republic) + a-gs + + Coded [e-ur-gs] (Georgia (Republic)) before June 1998 + + + Transcaucasia + + Coded [e-ur-ai] (Armenia (Republic)), [e-ur-aj] (Azerbaijan), [e-ur-gs] (Georgia + (Republic)) before June 1998] + + + + Georgia (Soviet Union) + + + Georgian S.S.R. + + + + info:lc/vocabulary/gacs/e-gx + Germany + e-gx + + For Germany as a whole regardless of time period; includes Germany (East) and Germany + (West) as a whole between 1949 and 1990] + + + Berlin (Germany) + + Coded [e-gx] (Germany) for Berlin as a whole; [e-ge] (Germany (East)) for East + Berlin; or [e-gw] (Germany (West)) for West Berlin before Jan. 1991] + + + East Berlin + + + West Berlin + + + + Germany, Northern + + Northern Germany + + + + Prussia (Germany) + + + Germany, Southern + + Southern Germany + + + + + info:lc/vocabulary/gacs/e-ge + Germany (East) + e-ge + + For the eastern part of Germany before 1949 or after 1990 and for the German + Democratic Republic between 1949-1990] + + + Democratic German Republic + + + East Germany + + + German Democratic Republic + + + Germany, Eastern + + + + info:lc/vocabulary/gacs/e-gw + Germany (West) + e-gw + + For the western part of Germany before 1949 or after 1990 and for the Federal Republic + of Germany between 1949-1990 + + + Federal German Republic + + + German Federal Republic + + + Germany, Western + + + West Germany + + + + info:lc/vocabulary/gacs/f-gh + Ghana + f-gh + + Togoland + + + Togoland (British) + + British Togoland + + + + Ashanti + + + Gold Coast + + + + info:lc/vocabulary/gacs/e-gi + Gibraltar + e-gi + + Gibraltar, Strait of + + Strait of Gibraltar + + + + + info:lc/vocabulary/gacs/e-uk + Great Britain + e-uk + + British Isles + + + United Kingdom + + + + info:lc/vocabulary/gacs/e-uk-ui + Great Britain Miscellaneous Island Dependencies + e-uk-ui + + Alderney (Channel Islands) + + + Calf of Man (Isle of Man) + + + Channel Islands + + + Guernsey (Channel Islands) + + + Isle of Man + + Man, Isle of + + + + Jersey (Channel Islands) + + + Island Dependencies of Great Britain + + + United Kingdom Miscellaneous Island Dependencies + + + + info:lc/vocabulary/gacs/nl + Great Lakes (North America) + nl + + + info:lc/vocabulary/gacs/np + Great Plains + np + + + info:lc/vocabulary/gacs/fr + Great Rift Valley + fr + + Rift Valley + + + + info:lc/vocabulary/gacs/e-gr + Greece + e-gr + + Aegean Islands (Greece and Turkey) + + Islands of the Aegean + + + + Aegean Sea + + + Crete (Greece) + + + Dodekanesos (Greece) + + + Macedonia + + + Macedonia (Greece) + + + + info:lc/vocabulary/gacs/n-gl + Greenland + n-gl + + + info:lc/vocabulary/gacs/nwgd + Grenada + nwgd + + Grenadines (Saint Vincent and the Grenadines and Grenada) + + + + info:lc/vocabulary/gacs/nwgp + Guadeloupe + nwgp + + Marie-Galante (Guadeloupe) + + + Saint-Barthélemy + + Coded [nwsb] (Saint-Barthelemy) before Mar. 1988 + + + Saint Bartholomew + + + Saint Barts + + + St. Barthélémy + + + + + info:lc/vocabulary/gacs/pogu + Guam + pogu + + + info:lc/vocabulary/gacs/a-cc-kn + Guangdong Sheng (China) + a-cc-kn + + Kwangtung Province (China) + + + + info:lc/vocabulary/gacs/a-cc-kc + Guangxi Zhuangzu Zizhiqu (China) + a-cc-kc + + Kuang-hsi Chuang tsu tzu chih ch'ü (China) + + + Kwangsi Chuang Autonomous Region + + + + info:lc/vocabulary/gacs/ncgt + Guatemala + ncgt + + + info:lc/vocabulary/gacs/f-gv + Guinea + f-gv + + French Guinea + + + Guinea, French + + + Guinée + + + Republique de Guinée + + + + info:lc/vocabulary/gacs/f-pg + Guinea-Bissau + f-pg + + Guinea, Portuguese + + + Portuguese Guinea + + + + info:lc/vocabulary/gacs/a-cc-kw + Guizhou Sheng (China) + a-cc-kw + + Kweichow Province (China) + + + + info:lc/vocabulary/gacs/s-gy + Guyana + s-gy + + British Guiana + + + Guiana, British + + + + info:lc/vocabulary/gacs/a-cc-ha + Hainan Sheng (China) + a-cc-ha + + Coded [a-cc-kn] (Kwangtung Province (China)) before June 1998 + + + Hainan Island (China) + + + Hainan Province (China) + + + + info:lc/vocabulary/gacs/nwht + Haiti + nwht + + + info:lc/vocabulary/gacs/n-us-hi + Hawaii + n-us-hi + + Sunbelt States + + + + info:lc/vocabulary/gacs/i-hm + Heard and McDonald Islands + i-hm + + Heard Island (Heard and McDonald Islands) + + + McDonald Island (Heard and McDonald Islands) + + + + info:lc/vocabulary/gacs/a-cc-hp + Hebei Sheng (China) + a-cc-hp + + Ho-pei sheng (China) + + + Hopeh Province (China) + + + + info:lc/vocabulary/gacs/a-cc-he + Heilongjiang Sheng (China) + a-cc-he + + Heilungkiang Province (China) + + + + info:lc/vocabulary/gacs/a-cc-ho + Henan Sheng (China) + a-cc-ho + + Honan Province (China) + + + + info:lc/vocabulary/gacs/ah + Himalaya Mountains + ah + + + info:lc/vocabulary/gacs/nwhi + Hispaniola + nwhi + + + info:lc/vocabulary/gacs/ncho + Honduras + ncho + + + info:lc/vocabulary/gacs/a-cc-hk + Hong Kong (China) + a-cc-hk + + Coded [a-hk] (Hong Kong) before June 1998 + + + Hong Kong + + + Hong Kong (China : Special Administrative Region) + + + + info:lc/vocabulary/gacs/a-cc-hh + Hubei Sheng (China) + a-cc-hh + + Hu-pei (China) + + + Hupeh Province (China) + + + + info:lc/vocabulary/gacs/n-cnh + Hudson Bay + n-cnh + + + info:lc/vocabulary/gacs/a-cc-hu + Hunan Sheng (China) + a-cc-hu + + Hunan Province (China) + + + + info:lc/vocabulary/gacs/e-hu + Hungary + e-hu + + Pannonia + + + + info:lc/vocabulary/gacs/e-ic + Iceland + e-ic + + + info:lc/vocabulary/gacs/n-us-id + Idaho + n-us-id + + + info:lc/vocabulary/gacs/n-us-il + Illinois + n-us-il + + + info:lc/vocabulary/gacs/a-ii + India + a-ii + + Andaman and Nicobar Islands (India) + + + French India + + India, French + + + + Jammu and Kashmir (India) + + Kashmir + + + Kashmir and Jammu (India) + + + + Lakshadweep (India) + + Laccadive, Minicoy, and Amindivi Islands (India) + + + + Sikkim (India) + + Coded [a-sk] (Sikkim) before Mar. 1988 + + + + + info:lc/vocabulary/gacs/i + Indian Ocean + i + + Islands of the Indian Ocean + + + Timor Sea + + + + info:lc/vocabulary/gacs/n-us-in + Indiana + n-us-in + + + info:lc/vocabulary/gacs/ai + Indochina + ai + + French Indochina + + + + info:lc/vocabulary/gacs/a-io + Indonesia + a-io + + Celebes (Indonesia) + + Sulawesi (Indonesia) + + + + Java (Indonesia) + + + Kalimantan Barat (Indonesia) + + + Lesser Sunda Islands (Indonesia and East Timor) + + + Madura Island (Indonesia) + + + Maluku (Indonesia) + + Moluccas (Indonesia) + + + + Papua (Indonesia) + + Irian Barat (Indonesia) + + + Irian Jaya (Indonesia) + + + West Irian + + + West New Guinea + + + + Sunda Islands, Lesser (Indonesia and East Timor) + + + Sumatra (Indonesia) + + + Timor Island + + + Dutch East Indies + + + Netherlands East Indies + + + + info:lc/vocabulary/gacs/a-cc-im + Inner Mongolia (China) + a-cc-im + + Mongolia (Inner Mongolia) + + + + info:lc/vocabulary/gacs/m + Intercontinental areas (Eastern Hemisphere) + m + + + info:lc/vocabulary/gacs/c + Intercontinental areas (Western Hemisphere) + c + + + info:lc/vocabulary/gacs/n-us-ia + Iowa + n-us-ia + + + info:lc/vocabulary/gacs/a-ir + Iran + a-ir + + Armenia + + + Persia + + + + info:lc/vocabulary/gacs/a-iq + Iraq + a-iq + + Babylonia + + + + info:lc/vocabulary/gacs/e-ie + Ireland + e-ie + + Aran Islands (Ireland) + + + British Isles + + + Eire + + + Ireland (Eire) + + + Irish Republic + + + Republic of Ireland + + + + info:lc/vocabulary/gacs/a-is + Israel + a-is + + Jerusalem + + + Palestine + + + + info:lc/vocabulary/gacs/e-it + Italy + e-it + + Sardinia (Italy) + + + Sicily (Italy) + + + + info:lc/vocabulary/gacs/nwjm + Jamaica + nwjm + + + info:lc/vocabulary/gacs/lnjn + Jan Mayen Island + lnjn + + + info:lc/vocabulary/gacs/a-ja + Japan + a-ja + + Okinawa Island (Japan) + + Coded [a-ok] (Okinawa) before 1984] + + + + Ryukyu Islands + + + Ryukyu Islands, Southern + + Coded [pory] (Ryukyu Islands, Southern) before 1984 + + + + + info:lc/vocabulary/gacs/a-cc-ku + Jiangsu Sheng (China) + a-cc-ku + + Kiangsu Province (China) + + + + info:lc/vocabulary/gacs/a-cc-ki + Jiangxi Sheng (China) + a-cc-ki + + Kiangsi Province (China) + + + + info:lc/vocabulary/gacs/a-cc-kr + Jilin Sheng (China) + a-cc-kr + + Kirin Province (China) + + + + info:lc/vocabulary/gacs/poji + Johnston Island + poji + + + info:lc/vocabulary/gacs/a-jo + Jordan + a-jo + + Transjordan + + + + info:lc/vocabulary/gacs/zju + Jupiter (Planet) + zju + + + info:lc/vocabulary/gacs/n-us-ks + Kansas + n-us-ks + + + info:lc/vocabulary/gacs/a-kz + Kazakhstan + a-kz + + Coded [e-ur-kz] (Kazakhstan) before June 1998 + + + Kazakh S.S.R. + + + Kazakstan + + + + info:lc/vocabulary/gacs/n-us-ky + Kentucky + n-us-ky + + + info:lc/vocabulary/gacs/f-ke + Kenya + f-ke + + East Africa Protectorate + + + + info:lc/vocabulary/gacs/poki + Kermadec Islands + poki + + + info:lc/vocabulary/gacs/pokb + Kiribati + pokb + + Coded [pogn] (Gilbert and Ellice Islands) or [poln] (Line Islands) before Mar. + 1988 + + + Banaba (Kiribati) + + Ocean Island (Kiribati) + + + + Canton and Enderbury Islands + + Coded [pocp] (Canton and Enderbury Islands) before Mar. 1988 + + + Enderbury and Canton Islands + + + + Gilbert and Ellice Islands Colony + + Coded [pogn] (Gilbert and Ellice Islands) before Mar. 1988 + + + + Kiritimati (Kiribati) + + Christmas Island (Pacific Ocean) + + + + Phoenix Islands (Kiribati) + + + Gilbert Islands + + + + info:lc/vocabulary/gacs/a-kr + Korea + a-kr + + + info:lc/vocabulary/gacs/a-kn + Korea (North) + a-kn + + Korean People's Republic + + + North Korea + + + + info:lc/vocabulary/gacs/a-ko + Korea (South) + a-ko + + Korea (Republic) + + + South Korea + + + + info:lc/vocabulary/gacs/e-kv + Kosovo + e-kv + + Coded [e-rb] (Serbia) before May 2008 and [e-yu] (Serbia and Montenegro) before April + 2007 + + + + info:lc/vocabulary/gacs/a-cck + Kunlun Mountains (China and India) + a-cck + + Kwenlun Mountains + + + + info:lc/vocabulary/gacs/a-ku + Kuwait + a-ku + + + info:lc/vocabulary/gacs/a-kg + Kyrgyzstan + a-kg + + Coded [e-ur-kg] (Kyrgystan) before June 1998 + + + Kirghiz S.S.R. + + + + info:lc/vocabulary/gacs/nl + Lake States + nl + + Great Lakes States + + + + info:lc/vocabulary/gacs/a-ls + Laos + a-ls + + + info:lc/vocabulary/gacs/cl + Latin America + cl + + Neotropics + + + + info:lc/vocabulary/gacs/e-lv + Latvia + e-lv + + Coded [e-ur-lv] (Latvia) before June 1998 + + + + info:lc/vocabulary/gacs/a-le + Lebanon + a-le + + + info:lc/vocabulary/gacs/nwli + Leeward Islands (West Indies) + nwli + + + info:lc/vocabulary/gacs/f-lo + Lesotho + f-lo + + Basutoland + + + + info:lc/vocabulary/gacs/a-cc-lp + Liaoning Sheng (China) + a-cc-lp + + Liaoning Province (China) + + + + info:lc/vocabulary/gacs/f-lb + Liberia + f-lb + + + info:lc/vocabulary/gacs/f-ly + Libya + f-ly + + Tibesti Mountains + + + + info:lc/vocabulary/gacs/e-lh + Liechtenstein + e-lh + + + info:lc/vocabulary/gacs/poln + Line Islands + poln + + + info:lc/vocabulary/gacs/e-li + Lithuania + e-li + + Coded [e-ur-li] (Lithuania) before March 1998 + + + + info:lc/vocabulary/gacs/n-us-la + Louisiana + n-us-la + + + info:lc/vocabulary/gacs/e-lu + Luxembourg + e-lu + + + info:lc/vocabulary/gacs/a-cc-mh + Macau (China : Special Administrative Region) + a-cc-mh + + Coded [a-mh] (Macao) before May 29, 2000 + + + Macao + + + + info:lc/vocabulary/gacs/e-xn + Macedonia (Republic)] + e-xn + + Coded [e-yu] (Yugoslavia) before Oct. 1992 + + + Macedonia + + + + info:lc/vocabulary/gacs/f-mg + Madagascar + f-mg + + Malagasy Republic + + + + info:lc/vocabulary/gacs/lnma + Madeira Islands + lnma + + Selvagens Islands (Madeira Islands) + + Salvage Islands (Madeira Islands) + + + Salvages (Madeira Islands) + + + + + info:lc/vocabulary/gacs/n-us-me + Maine + n-us-me + + + info:lc/vocabulary/gacs/f-mw + Malawi + f-mw + + Rhodesia and Nyasaland + + Federation of Rhodesia and Nyasaland + + + + Nyasaland + + + + info:lc/vocabulary/gacs/am + Malaya + am + + Malay Peninsula + + + + info:lc/vocabulary/gacs/a-my + Malaysia + a-my + + Sabah + + British North Borneo + + + North Borneo + + + + Sarawak + + + Straits Settlements + + + + info:lc/vocabulary/gacs/i-xc + Maldives + i-xc + + + info:lc/vocabulary/gacs/f-ml + Mali + f-ml + + Songhai Empire + + + French Sudan + + + Sudan, French + + + + info:lc/vocabulary/gacs/e-mm + Malta + e-mm + + + info:lc/vocabulary/gacs/n-cn-mb + Manitoba + n-cn-mb + + + info:lc/vocabulary/gacs/poxd + Mariana Islands + poxd + + Commonwealth of the Northern Mariana Islands + + + Northern Mariana Islands + + + + info:lc/vocabulary/gacs/n-cnm + Maritime Provinces + n-cnm + + + info:lc/vocabulary/gacs/zma + Mars (Planet) + zma + + Red Planet + + + + info:lc/vocabulary/gacs/poxe + Marshall Islands + poxe + + Bikini Atoll (Marshall Islands) + + + + info:lc/vocabulary/gacs/nwmq + Martinique + nwmq + + + info:lc/vocabulary/gacs/n-us-md + Maryland + n-us-md + + Chesapeake Bay (Md. and Va.) + + + Washington Region + + + + info:lc/vocabulary/gacs/n-us-m + Massachusetts + n-us-m + + + info:lc/vocabulary/gacs/f-mu + Mauritania + f-mu + + + info:lc/vocabulary/gacs/i-mf + Mauritius + i-mf + + + info:lc/vocabulary/gacs/i-my + Mayotte + i-my + + Coded [i-cq] (Comoros) before Mar. 1988 + + + + info:lc/vocabulary/gacs/mm + Mediterranean Region + mm + + Byzantine Empire + + + + info:lc/vocabulary/gacs/mm + Mediterranean Sea + mm + + Adriatic Sea + + + Gibraltar, Strait of + + Strait of Gibraltar + + + + Islands of the Mediterranean + + + + info:lc/vocabulary/gacs/ag + Mekong River + ag + + Dza-chu + + + Lan-ts'ang Chiang + + + Lancang Jiang + + + Song Tíên Giang + + + + info:lc/vocabulary/gacs/pome + Melanesia + pome + + + info:lc/vocabulary/gacs/zme + Mercury (Planet) + zme + + + info:lc/vocabulary/gacs/n-mx + Mexico + n-mx + + Colorado River (Colo.-Mexico) + + + Colorado River Delta (Mexico) + + + Middle America + + Coded [cm] (Middle America) before Mar. 1988 + + + + + info:lc/vocabulary/gacs/nm + Mexico, Gulf of + nm + + Gulf of Mexico + + + + info:lc/vocabulary/gacs/n-us-mi + Michigan + n-us-mi + + + info:lc/vocabulary/gacs/pott + Micronesia + pott + + + info:lc/vocabulary/gacs/pomi + Micronesia (Federated States) + pomi + + Coded [pott] (Micronesia) before Mar. 1988 + + + Chuuk (Micronesia) + + Truk (Micronesia) + + + + Kosrae (Micronesia) + + Kusaie (Micronesia) + + + + Pohnpei (Micronesia) + + Ponape (Micronesia) + + + + Yap (Micronesia) + + + Federated States of Micronesia + + + + info:lc/vocabulary/gacs/n-usl + Middle Atlantic States + n-usl + + Middle States + + + + info:lc/vocabulary/gacs/aw + Middle East + aw + + Islamic Empire + + + Latin Orient + + + Rome + + Roman Empire + + + + Asia, Southwestern + + + Asia, Western + + + East (Near East) + + + Eastern Mediterranean + + + Levant + + + Mediterranean Region, Eastern + + + Mideast + + + Near East + + + + info:lc/vocabulary/gacs/n-usc + Middle West + n-usc + + Northwest, Old + + + Midwest + + + North Central States + + + + info:lc/vocabulary/gacs/poxf + Midway Islands + poxf + + + info:lc/vocabulary/gacs/n-us-mn + Minnesota + n-us-mn + + + info:lc/vocabulary/gacs/n-us-ms + Mississippi + n-us-ms + + + info:lc/vocabulary/gacs/n-usm + Mississippi River + n-usm + + + info:lc/vocabulary/gacs/n-us-mo + Missouri + n-us-mo + + Ozark Mountains + + + + info:lc/vocabulary/gacs/n-uss + Missouri River + n-uss + + + info:lc/vocabulary/gacs/e-mv + Moldova + e-mv + + Coded [e-ur-mv] (Moldova) before June 1998 + + + Moldavia + + + Moldavian S.S.R. + + + + info:lc/vocabulary/gacs/e-mc + Monaco + e-mc + + + info:lc/vocabulary/gacs/a-mp + Mongolia + a-mp + + Mongolian People's Republic + + + Outer Mongolia + + + + info:lc/vocabulary/gacs/n-us-mt + Montana + n-us-mt + + + info:lc/vocabulary/gacs/e-mo + Montenegro + e-mo + + Coded [e-yu] (Yugoslavia) before April 2007 + + + + info:lc/vocabulary/gacs/nwmj + Montserrat + nwmj + + + info:lc/vocabulary/gacs/zmo + Moon + zmo + + + info:lc/vocabulary/gacs/f-mr + Morocco + f-mr + + Ifni + + Coded [f-if] (Ifni) before Mar. 1988 + + + + Tangier (Morocco) + + + French Morocco + + + + info:lc/vocabulary/gacs/f-mz + Mozambique + f-mz + + East Africa, Portuguese German East Africa + + + People's Republic of Mozambique + + + Portuguese East Africa + + + + info:lc/vocabulary/gacs/f-sx + Namibia + f-sx + + Africa, Southwest + + + South-West Africa + + + + info:lc/vocabulary/gacs/ponu + Nauru + ponu + + Pleasant Island + + + + info:lc/vocabulary/gacs/n-us-nb + Nebraska + n-us-nb + + + info:lc/vocabulary/gacs/a-np + Nepal + a-np + + + info:lc/vocabulary/gacs/zne + Neptune (Planet) + zne + + + info:lc/vocabulary/gacs/e-ne + Netherlands + e-ne + + Holland + + + + info:lc/vocabulary/gacs/nwna + Netherlands Antilles + nwna + + Dutch West Indies + + + Netherlands West Indies + + + West Indies, Dutch + + + + info:lc/vocabulary/gacs/n-us-nv + Nevada + n-us-nv + + + info:lc/vocabulary/gacs/n-cn-nk + New Brunswick + n-cn-nk + + + info:lc/vocabulary/gacs/ponl + New Caledonia + ponl + + Loyalty Islands (New Caledonia) + + + + info:lc/vocabulary/gacs/n-usn + New England + n-usn + + + info:lc/vocabulary/gacs/a-nw + New Guinea + a-nw + + New Guinea Island + + + + info:lc/vocabulary/gacs/n-us-nh + New Hampshire + n-us-nh + + + info:lc/vocabulary/gacs/n-us-nj + New Jersey + n-us-nj + + + info:lc/vocabulary/gacs/n-us-nm + New Mexico + n-us-nm + + + info:lc/vocabulary/gacs/u-at-ne + New South Wales + u-at-ne + + + info:lc/vocabulary/gacs/n-us-ny + New York (State) + n-us-ny + + + info:lc/vocabulary/gacs/u-nz + New Zealand + u-nz + + + info:lc/vocabulary/gacs/n-cn-nf + Newfoundland and Labrador + n-cn-nf + + Labrador (N.L.) + + + + info:lc/vocabulary/gacs/ncnq + Nicaragua + ncnq + + + info:lc/vocabulary/gacs/f-ng + Niger + f-ng + + Songhai Empire + + + Tibesti Mountains + + + + info:lc/vocabulary/gacs/fi + Niger River + fi + + + info:lc/vocabulary/gacs/f-nr + Nigeria + f-nr + + Adamawa (Emirate) + + + Songhai Empire + + + Biafra + + Coded [f-by] (Biafra) before Mar. 1988 + + + + + info:lc/vocabulary/gacs/fl + Nile River + fl + + + info:lc/vocabulary/gacs/a-cc-nn + Ningxia Huizu Zizhiqu (China) + a-cc-nn + + Ninghsia Province (China) + + + Ningsia Hui Autonomous Region (China) + + + + info:lc/vocabulary/gacs/poxh + Niue + poxh + + + info:lc/vocabulary/gacs/n + North America + n + + America + + + New France + + + Pacific Coast (North America) + + + + info:lc/vocabulary/gacs/ln + North Atlantic Ocean + ln + + Baltic Sea + + + Bermuda Triangle + + + English Channel + + + Fundy, Bay of + + Bay of Fundy + + + + Georges Bank + + + Irish Sea + + + North Sea + + + Norwegian Sea + + + Skagerrak (Denmark and Norway) + + + + info:lc/vocabulary/gacs/n-us-nc + North Carolina + n-us-nc + + + info:lc/vocabulary/gacs/n-us-nd + North Dakota + n-us-nd + + + info:lc/vocabulary/gacs/pn + North Pacific Ocean + pn + + Alaska, Gulf of (Alaska) + + Gulf of Alaska (Alaska) + + + + Bering Sea + + + Philippine Sea + + + Pacific Ocean, North + + + + info:lc/vocabulary/gacs/n-use + Northeastern States + n-use + + Northeast (U.S.) + + + + info:lc/vocabulary/gacs/u-atn + Northern Australia + u-atn + + Coded [u-at] (Australia) before September 2005 + + + Australia, Northern + + + + info:lc/vocabulary/gacs/xb + Northern Hemisphere + xb + + + info:lc/vocabulary/gacs/e-uk-ni + Northern Ireland + e-uk-ni + + Ireland, Northern + + + + info:lc/vocabulary/gacs/u-at-no + Northern Territory + u-at-no + + Carpentaria, Gulf of (N.T. and Qld.) + + Coded [ps] (South Pacific Ocean) before June 1998 + + + Gulf of Carpentaria (N.T. and Qld.) + + + + + info:lc/vocabulary/gacs/n-cn-nt + Northwest Territories + n-cn-nt + + + info:lc/vocabulary/gacs/e-no + Norway + e-no + + Lapland + + + + info:lc/vocabulary/gacs/n-cn-ns + Nova Scotia + n-cn-ns + + + info:lc/vocabulary/gacs/n-cn-nu + Nunavut + n-cn-nu + + + info:lc/vocabulary/gacs/po + Oceania + po + + Oceanica + + + + info:lc/vocabulary/gacs/n-us-oh + Ohio + n-us-oh + + + info:lc/vocabulary/gacs/n-uso + Ohio River + n-uso + + + info:lc/vocabulary/gacs/n-us-ok + Oklahoma + n-us-ok + + Indian Territory + + + Ozark Mountains + + + + info:lc/vocabulary/gacs/a-mk + Oman + a-mk + + Arabia, Southern + + + Muscat and Oman + + + + info:lc/vocabulary/gacs/n-cn-on + Ontario + n-cn-on + + + info:lc/vocabulary/gacs/n-us-or + Oregon + n-us-or + + Pacific States + + + + info:lc/vocabulary/gacs/zo + Outer space + zo + + Space, Outer + + + + info:lc/vocabulary/gacs/p + Pacific Ocean + p + + Pacific Area + + + + info:lc/vocabulary/gacs/a-pk + Pakistan + a-pk + + Azad Kashmir + + Azad Jammu and Kashmir + + + Kashmir + + + + West Pakistan + + + + info:lc/vocabulary/gacs/popl + Palau + popl + + Coded [poci] (Caroline Islands) before Mar. 1988 + + + Belau + + + Pelew + + + Republic of Palau + + + + info:lc/vocabulary/gacs/ncpn + Panama + ncpn + + + info:lc/vocabulary/gacs/a-pp + Papua New Guinea + a-pp + + Admiralty Islands (Papua New Guinea) + + + Bismarck Archipelago (Papua New Guinea) + + + Bougainville Island (Papua New Guinea) + + + D'Entrecasteaux Islands (Papua New Guinea) + + + Louisiade Archipelago (Papua New Guinea) + + + New Britain Island (Papua New Guinea) + + + New Guinea (Territory) + + + New Ireland Island (Papua New Guinea) + + + Papua + + + Trobriand Islands (Papua New Guinea) + + + Woodlark Islands (Papua New Guinea) + + + + info:lc/vocabulary/gacs/aopf + Paracel Islands + aopf + + Hoàng Sa + + + Hsi-sha Islands + + + Xisha Islands + + + + info:lc/vocabulary/gacs/s-py + Paraguay + s-py + + + info:lc/vocabulary/gacs/n-us-pa + Pennsylvania + n-us-pa + + + info:lc/vocabulary/gacs/ap + Persian Gulf + ap + + + info:lc/vocabulary/gacs/s-pe + Peru + s-pe + + + info:lc/vocabulary/gacs/a-ph + Philippines + a-ph + + Eastern Samar (Philippines) + + + Luzon (Philippines) + + + Mindanao Island (Philippines) + + + Negros Island (Philippines) + + + Northern Samar (Philippines) + + + Panay Island (Philippines) + + + Samar (Philippines) + + + Philippine Islands + + + + info:lc/vocabulary/gacs/popc + Pitcairn Island + popc + + + info:lc/vocabulary/gacs/zpl + Pluto (Planet) + zpl + + + info:lc/vocabulary/gacs/e-pl + Poland + e-pl + + + info:lc/vocabulary/gacs/pops + Polynesia + pops + + + info:lc/vocabulary/gacs/e-po + Portugal + e-po + + Iberian Peninsula + + Coded [ei] (Iberian Peninsula) before Mar. 1988 + + + + + info:lc/vocabulary/gacs/n-cnp + Prairie Provinces + n-cnp + + Canada, Western + + Western Canada + + + + + info:lc/vocabulary/gacs/n-cn-pi + Prince Edward Island + n-cn-pi + + + info:lc/vocabulary/gacs/nwpr + Puerto Rico + nwpr + + + info:lc/vocabulary/gacs/ep + Pyrenees + ep + + Pirineos + + + + info:lc/vocabulary/gacs/a-qa + Qatar + a-qa + + + info:lc/vocabulary/gacs/a-cc-ts + Qinghai Sheng (China) + a-cc-ts + + Tsinghai Province (China) + + + + info:lc/vocabulary/gacs/n-cn-qu + Québec (Province) + n-cn-qu + + + info:lc/vocabulary/gacs/u-at-qn + Queensland + u-at-qn + + Carpentaria, Gulf of (N.T. and Qld.) + + Coded [ps] (South Pacific Ocean) before June 1998 + + + Gulf of Carpentaria (N.T. and Qld.) + + + + Great Barrier Reef (Qld.) + + + Torres Strait Islands (Qld.) + + + + info:lc/vocabulary/gacs/mr + Red Sea + mr + + Aden, Gulf of + + Gulf of Aden + + + + Aqaba, Gulf of + + Gulf of Aqaba + + + + + info:lc/vocabulary/gacs/i-re + Réunion + i-re + + + info:lc/vocabulary/gacs/er + Rhine River + er + + + info:lc/vocabulary/gacs/n-us-ri + Rhode Island + n-us-ri + + + info:lc/vocabulary/gacs/su + Rio de la Plata (Argentina and Uruguay) + su + + La Plata River (Argentina and Uruguay) + + + Plata, Rio de la (Argentina and Uruguay) + + + Plate River (Argentina and Uruguay) + + + + info:lc/vocabulary/gacs/nr + Rocky Mountains + nr + + + info:lc/vocabulary/gacs/e-rm + Romania + e-rm + + Moldavia + + + Rumania + + + + info:lc/vocabulary/gacs/e-ru + Russia (Federation) + e-ru + + Coded [e-ur-ru] (Russia (Federation)) before June 1998 + + + Kievan Rus + + Coded [e-ur] (Soviet Union) before June 1998 + + + Kuril Islands (Russia) + + Coded [e-ur-ru] (Russia Federation) before June 1998 + + + Chishima-retto (Russia) + + + Kurile Islands (Russia) + + + Kuril'skie ostrova (Russia) + + + Non-Chernozem Region (Russia) + + Coded [e-ur-ru] (Russia Federation) before June 1998 + + + Non-Black Earth Region (Russia) + + + + Russia, Northern + + Coded [e-ur-ru] (Russia (Federation)) before June 1998 + + + Northern Russia + + + Northern Soviet Union + + + Soviet Union, Northern + + + + Sakha (Russia) + + Àkutskaíà A.S.S.R. (Russia) + + + Yakutia (Russia) + + + + Volgo-Viatskii Region (Russia) + + Coded [e-urv] (Volgo-Viatskii Region, RSFSR) before Mar. 1988 + + + + R.S.F.S.R. + + + Russian Republic + + + Russian S.F.S.R. + + + Russian Soviet Federated Socialist Republic + + + + info:lc/vocabulary/gacs/e-urf + Russian Far East (Russia) + e-urf + + Far East (Russia) + + + Far Eastern Region (Russia) + + + Soviet Far East (Russia) + + Coded [e-uro] (Soviet Central Asia) before 1994 + + + + + info:lc/vocabulary/gacs/f-rw + Rwanda + f-rw + + Ruanda-Urundi + + + German East Africa + + + + info:lc/vocabulary/gacs/nwsd + Saba (Netherlands Antilles) + nwsd + + + info:lc/vocabulary/gacs/fd + Sahara + fd + + Sahara Desert + + + + info:lc/vocabulary/gacs/lsxj + Saint Helena + lsxj + + St. Helena + + + + info:lc/vocabulary/gacs/nwxi + Saint Kitts and Nevis + nwxi + + Nevis + + + Saint Kitts + + + Saint Kitts-Nevis-Anguilla + + St. Christopher-Nevis-Anguilla + + + + Saint Christopher and Nevis + + + + info:lc/vocabulary/gacs/nwxk + Saint Lucia + nwxk + + St. Lucia + + + + info:lc/vocabulary/gacs/nwst + Saint Martin (West Indies) + nwst + + Sint Maarten (West Indies) + + + St. Martin (West Indies) + + + + info:lc/vocabulary/gacs/n-xl + Saint Pierre and Miquelon + n-xl + + Miquelon + + + Iles Saint-Pierre et Miquelon + + + St. Pierre and Miquelon + + + + info:lc/vocabulary/gacs/nwxm + Saint Vincent and the Grenadines + nwxm + + Grenadines (Saint Vincent and the Grenadines and Grenada) + + + Saint Vincent + + St. Vincent + + + + + info:lc/vocabulary/gacs/pows + Samoa + pows + + Western Samoa + + + + info:lc/vocabulary/gacs/posh + Samoan Islands + posh + + Samoa (Islands) + + + + info:lc/vocabulary/gacs/e-sm + San Marino + e-sm + + + info:lc/vocabulary/gacs/f-sf + Sao Tome and Principe + f-sf + + São Thomé e Pr¡ncipe + + + + info:lc/vocabulary/gacs/n-cn-sn + Saskatchewan + n-cn-sn + + + info:lc/vocabulary/gacs/zsa + Saturn (Planet) + zsa + + + info:lc/vocabulary/gacs/a-su + Saudi Arabia + a-su + + + info:lc/vocabulary/gacs/ev + Scandinavia + ev + + + info:lc/vocabulary/gacs/e-uk-st + Scotland + e-uk-st + + Shetland (Scotland) + + + Orkney (Scotland) + + + + info:lc/vocabulary/gacs/f-sg + Senegal + f-sg + + + info:lc/vocabulary/gacs/e-rb + Serbia + e-rb + + Coded [e-yu] (Yugoslavia) before April 2007 + + + + info:lc/vocabulary/gacs/i-se + Seychelles + i-se + + + info:lc/vocabulary/gacs/a-cc-ss + Shaanxi Sheng (China) + a-cc-ss + + Shensi Province (China) + + + + info:lc/vocabulary/gacs/a-cc-sp + Shandong Sheng (China) + a-cc-sp + + Shantung Province (China) + + + + info:lc/vocabulary/gacs/a-cc-sm + Shanghai (China) + a-cc-sm + + + info:lc/vocabulary/gacs/a-cc-sh + Shanxi Sheng (China) + a-cc-sh + + Shansi Province (China) + + + + info:lc/vocabulary/gacs/e-urs + Siberia (Russia) + e-urs + + Siberia, Northeastern (Russia) + + + Siberia, Northwestern (Russia) + + + + info:lc/vocabulary/gacs/e-ure + Siberia, Eastern (Russia) + e-ure + + East Siberian Region (Russia) + + + Eastern Siberia (Russia) + + + + info:lc/vocabulary/gacs/e-urw + Siberia, Western (Russia) + e-urw + + Western Siberia (Russia) + + + + info:lc/vocabulary/gacs/a-cc-sz + Sichuan Sheng (China) + a-cc-sz + + Szechwan Province (China) + + + + info:lc/vocabulary/gacs/f-sl + Sierra Leone + f-sl + + + info:lc/vocabulary/gacs/a-si + Singapore + a-si + + Straits Settlements + + + + info:lc/vocabulary/gacs/nweu + Sint Eustatius (Netherlands Antilles) + nweu + + Saint Eustatius (Netherlands Antilles) + + + St. Eustatius (Netherlands Antilles) + + + Statia (Netherlands Antilles) + + + + info:lc/vocabulary/gacs/e-xo + Slovakia + e-xo + + Coded [e-cs] (Czechoslovakia) before May 1993 + + + Slovak Socialist Republic (Czechoslovakia) + + + + info:lc/vocabulary/gacs/e-xv + Slovenia + e-xv + + Coded [e-yu] (Yugoslavia) before Oct. 1992 + + + + info:lc/vocabulary/gacs/zs + Solar system + zs + + + info:lc/vocabulary/gacs/pobp + Solomon Islands + pobp + + Coded also [posn] (Solomon Islands) before Mar. 1988 + + + Guadalcanal (Solomon Islands) + + + Santa Cruz Islands (Solomon Islands) + + Coded [posc] (Santa Cruz Islands) before Mar. 1988 + + + + British Solomon Islands + + + + info:lc/vocabulary/gacs/f-so + Somalia + f-so + + British Somaliland + + + Italian Somaliland + + + Somali Republic + + + + info:lc/vocabulary/gacs/f-sa + South Africa + f-sa + + Bophuthatswana (South Africa) + + + Homelands (South Africa) + + + Prince Edward Islands + + Froides, Îles + + + Îles Froides + + + + Africa, South + + + Union of South Africa + + + + info:lc/vocabulary/gacs/s + South America + s + + America + + + + info:lc/vocabulary/gacs/az + South Asia + az + + East Indies + + Indies, East + + + + Asia, South + + + + info:lc/vocabulary/gacs/ls + South Atlantic Ocean + ls + + Guinea, Gulf of + + Gulf of Guinea + + + + + info:lc/vocabulary/gacs/u-at-sa + South Australia + u-at-sa + + + info:lc/vocabulary/gacs/n-us-sc + South Carolina + n-us-sc + + + info:lc/vocabulary/gacs/ao + South China Sea + ao + + Islands of the South China Sea + + + + info:lc/vocabulary/gacs/n-us-sd + South Dakota + n-us-sd + + + info:lc/vocabulary/gacs/lsxs + South Georgia and South Sandwich Islands + lsxs + + Coded [lsfk] (Falkland Islands) before Oct. 1992 + + + Sandwich Islands, South + + Coded [lsfk] (Falkland Islands) before Oct. 1992 + + + + South Sandwich Islands + + Coded [lsfk] (Falkland Islands) before Oct. 1992 + + + + + info:lc/vocabulary/gacs/ps + South Pacific Ocean + ps + + Arafura Sea + + + Pacific Ocean, South + + + + info:lc/vocabulary/gacs/as + Southeast Asia + as + + East Indies + + Indies, East + + + + Malay Archipelagon + + + Asia, Southeastern + + + Southeastern Asia + + + + info:lc/vocabulary/gacs/xc + Southern Hemisphere + xc + + + info:lc/vocabulary/gacs/n-usu + Southern States + n-usu + + Confederate States of America + + + Cumberland Mountains + + + Gulf States + + + South Atlantic States + + Atlantic States, South + + + + Southwest, Old + + + Southwestern States + + + Sunbelt States + + + + info:lc/vocabulary/gacs/n-ust + Southwest, New + n-ust + + Southwestern States + + + Sunbelt States + + + + info:lc/vocabulary/gacs/e-ur + Soviet Union + e-ur + + Communist countries + + Coded [v] (Communist countries) before June 1998 + + + + Russia + + Russian Empire + + + + Soviet Union, Southern + + Southern Soviet Union + + + + Soviet Union, Western + + Western Soviet Union + + + + Commonwealth of Independent States countries + + + Former Soviet republics + + + U.S.S.R. + + + + info:lc/vocabulary/gacs/e-urn + Soviet Union, Northwestern + e-urn + + Northwestern Soviet Union + + + + info:lc/vocabulary/gacs/e-sp + Spain + e-sp + + Balearic Islands (Spain) + + + Iberian Peninsula + + Coded [ei] (Iberian Peninsula) before Mar. 1988 + + + + Islamic Empire + + + + info:lc/vocabulary/gacs/f-sh + Spanish North Africa + f-sh + + Ceuta (Spain) + + + Melilla (Spain) + + + Spanish Territories in Northern Morocco + + + + info:lc/vocabulary/gacs/aoxp + Spratly Islands + aoxp + + Nansha Islands + + + Shinnan Islands + + + + info:lc/vocabulary/gacs/a-ce + Sri Lanka + a-ce + + Ceylon + + + + info:lc/vocabulary/gacs/f-sj + Sudan + f-sj + + Anglo-Egyptian Sudan + + + + info:lc/vocabulary/gacs/fn + Sudan (Region) + fn + + + info:lc/vocabulary/gacs/fu + Suez Canal (Egypt) + fu + + + info:lc/vocabulary/gacs/zsu + Sun + zsu + + + info:lc/vocabulary/gacs/s-sr + Suriname + s-sr + + Dutch Guiana + + + Guiana, Dutch + + + Surinam + + + + info:lc/vocabulary/gacs/lnsb + Svalbard (Norway) + lnsb + + Bear Island (Norway) + + Bjørnøya (Norway) + + + + Spitsbergen Island (Norway) + + West Spitsbergen (Norway) + + + + + info:lc/vocabulary/gacs/nwsv + Swan Islands (Honduras) + nwsv + + + info:lc/vocabulary/gacs/f-sq + Swaziland + f-sq + + + info:lc/vocabulary/gacs/e-sw + Sweden + e-sw + + Lapland + + + + info:lc/vocabulary/gacs/e-sz + Switzerland + e-sz + + + info:lc/vocabulary/gacs/a-sy + Syria + a-sy + + United Arab Republic + + + + info:lc/vocabulary/gacs/a-ch + Taiwan + a-ch + + Pescadores Islands + + + Pratas Islands + + + Formosa + + + + info:lc/vocabulary/gacs/a-ta + Tajikistan + a-ta + + Coded [e-ur-ta] (Tajikistan) before June 1998 + + + Tadzik Soviet Socialist Republic + + + Tajik S.S.R. + + + + info:lc/vocabulary/gacs/f-tz + Tanzania + f-tz + + Pemba Island (Tanzania) + + Huthera (Tanzania) + + + + Tanganyika + + + Zanzibar + + + German East Africa + + + + info:lc/vocabulary/gacs/u-at-tm + Tasmania + u-at-tm + + + info:lc/vocabulary/gacs/n-us-tn + Tennessee + n-us-tn + + + info:lc/vocabulary/gacs/i-fs + Terres australes et antarctiques françaises + i-fs + + Kerguelen Islands + + Desolation Islands + + + Îles Kerguélen + + + + French Southern and Antarctic Lands + + + French Southern Indian Ocean Islands + + + Indian Ocean Islands, French + + + T.A.A.F. + + + + info:lc/vocabulary/gacs/n-us-tx + Texas + n-us-tx + + + info:lc/vocabulary/gacs/a-th + Thailand + a-th + + Malay Peninsula + + + Siam + + + + info:lc/vocabulary/gacs/af + Thailand, Gulf of + af + + Gulf of Thailand + + + Siam, Gulf of + + + + info:lc/vocabulary/gacs/a-cc-tn + Tianjin (China) + a-cc-tn + + Tientsin (China) + + + + info:lc/vocabulary/gacs/a-cc-ti + Tibet (China) + a-cc-ti + + Tibetan Autonomous Region (China) + + + + info:lc/vocabulary/gacs/at + Tien Shan + at + + Thian Shan + + + Tian Shan + + + Tien Mountains + + + + info:lc/vocabulary/gacs/f-tg + Togo + f-tg + + Togoland + + + French Togoland + + + Togoland (French) + + + + info:lc/vocabulary/gacs/potl + Tokelau + potl + + Union Islands + + + + info:lc/vocabulary/gacs/poto + Tonga + poto + + Friendly Islands + + + Tonga Islands + + + + info:lc/vocabulary/gacs/nwtr + Trinidad and Tobago + nwtr + + Tobago + + + Trinidad + + + + info:lc/vocabulary/gacs/lstd + Tristan da Cunha + lstd + + + info:lc/vocabulary/gacs/w + Tropics + w + + Equator + + + + info:lc/vocabulary/gacs/f-ti + Tunisia + f-ti + + + info:lc/vocabulary/gacs/a-tu + Turkey + a-tu + + Aegean Islands (Greece and Turkey) + + Islands of the Aegean + + + + Aegean Sea + + + Armenia + + + Asia Minor + + + + info:lc/vocabulary/gacs/a-tk + Turkmenistan + a-tk + + Coded [e-ur-tk] (Turkmenistan) before June 1998 + + + Turkmen S.S.R. + + + + info:lc/vocabulary/gacs/nwtc + Turks and Caicos Islands + nwtc + + Caicos Islands + + + + info:lc/vocabulary/gacs/potv + Tuvalu + potv + + Coded [pogn] (Gilbert and Ellice Islands) before Mar. 1988 + + + Gilbert and Ellice Islands Colony + + Coded [pogn] (Gilbert and Ellice Islands) before Mar. 1988 + + + + Ellice Islands + + + + info:lc/vocabulary/gacs/f-ug + Uganda + f-ug + + + info:lc/vocabulary/gacs/e-un + Ukraine + e-un + + Coded [e-ur-un] (Ukraine) before June 1998 + + + Kievan Rus + + Coded [e-ur] (Soviet Union) before June 1998 + + + + + info:lc/vocabulary/gacs/a-ts + United Arab Emirates + a-ts + + Abū Ẓaby (United Arab Emirates: Emirate) + + Abu Dhabi (United Arab Emirates : Emirate) + + + + Dubayy (United Arab Emirates : Emirate) + + Dubai + + + + Trucial States + + + + info:lc/vocabulary/gacs/n-us + United States + n-us + + Atlantic Coast (U.S.) + + + Atlantic States + + + Saint Lawrence River + + + Snowbelt States + + Frostbelt (U.S.) + + + + + info:lc/vocabulary/gacs/nwuc + United States Miscellaneous Caribbean Islands + nwuc + + Caribbean Island Dependencies of the United States + + + Island Dependencies of the United States in the Caribbean + + + + info:lc/vocabulary/gacs/poup + United States Miscellaneous Pacific Islands + poup + + Includes American Samoa, Guam, Pacific Islands (Trust Territory) treated + collectively + + + Pacific Islands (Trust Territory) + + Pacific Islands (Ter.) + + + Trust Territory of the Pacific Islands + + + + Island Dependencies of the United States in the Pacific + + + Pacific Island Dependencies of the United States + + + + info:lc/vocabulary/gacs/e-uru + Ural Mountains (Russia) + e-uru + + + info:lc/vocabulary/gacs/zur + Uranus (Planet) + zur + + + info:lc/vocabulary/gacs/s-uy + Uruguay + s-uy + + + info:lc/vocabulary/gacs/n-us-ut + Utah + n-us-ut + + + info:lc/vocabulary/gacs/a-uz + Uzbekistan + a-uz + + Coded [e-ur-uz] (Uzbekistan) before June 1998 + + + Uzbek S.S.R. + + + + info:lc/vocabulary/gacs/ponn + Vanuatu + ponn + + Banks Islands (Vanuatu) + + + New Hebrides + + + Republic of Vanuatu + + + + info:lc/vocabulary/gacs/e-vc + Vatican City + e-vc + + Holy See + + + + info:lc/vocabulary/gacs/s-ve + Venezuela + s-ve + + + info:lc/vocabulary/gacs/zve + Venus (Planet) + zve + + + info:lc/vocabulary/gacs/n-us-vt + Vermont + n-us-vt + + + info:lc/vocabulary/gacs/u-at-vi + Victoria + u-at-vi + + + info:lc/vocabulary/gacs/a-vt + Vietnam + a-vt + + Vietnam (Democratic Republic) + + Coded [a-vn] (Vietnam, North) before Mar. 1988 + + + North Vietnam + + + Vietnam, North + + + + Vietnam (Republic) + + Coded [a-vs] (Viet Nam, South) before Mar. 1988 + + + South Vietnam + + + Vietnam, South + + + + + info:lc/vocabulary/gacs/nwvi + Virgin Islands of the United States + nwvi + + Virgin Islands + + Coded [nwvr] (Virgin Islands) before Mar. 1988 + + + + Virgin Islands (American) + + + Virgin Islands (Danish) + + + + info:lc/vocabulary/gacs/n-us-va + Virginia + n-us-va + + Chesapeake Bay (Md. and Va.) + + + Washington Region + + + + info:lc/vocabulary/gacs/e-urp + Volga River (Russia) + e-urp + + + info:lc/vocabulary/gacs/fv + Volta River (Ghana) + fv + + + info:lc/vocabulary/gacs/powk + Wake Island + powk + + + info:lc/vocabulary/gacs/e-uk-wl + Wales + e-uk-wl + + + info:lc/vocabulary/gacs/powf + Wallis and Futuna Islands + powf + + Futuna Islands (Wallis and Futuna Islands) + + + Uvea Island (Wallis and Futuna Islands) + + + + info:lc/vocabulary/gacs/n-us-dc + Washington (D.C.) + n-us-dc + + Washington Region + + + District of Columbia + + + + info:lc/vocabulary/gacs/n-us-wa + Washington (State) + n-us-wa + + Pacific States + + + + info:lc/vocabulary/gacs/n-usp + West (U.S.) + n-usp + + Colorado River (Colo.-Mexico) + + + Great Basin + + + Northwest, Pacific + + Northwest (U.S.) + + + Pacific Northwest + + + + Northwestern States + + + Far West (U.S.) + + + Pacific and Mountain States + + + Western States (U.S.) + + + + info:lc/vocabulary/gacs/awba + West Bank + awba + + Coded [a-is] (Israel) and/or [a-jo] (Jordan) before Mar. 1988 + + + Jerusalem + + + Palestine + + + Judaea and Samaria + + + West Bank of the Jordan River + + + + info:lc/vocabulary/gacs/nw + West Indies + nw + + Antilles, Greater + + Coded [nwga] (Greater Antilles) before Mar. 1988 + + + + Greater Antilles + + Coded [nwga] (Greater Antilles) before Mar. 1988 + + + + Indies, West + + + + info:lc/vocabulary/gacs/n-us-wv + West Virginia + n-us-wv + + + info:lc/vocabulary/gacs/u-at-we + Western Australia + u-at-we + + Australia, Western + + + + info:lc/vocabulary/gacs/xd + Western Hemisphere + xd + + + info:lc/vocabulary/gacs/f-ss + Western Sahara + f-ss + + Spanish Sahara + + + + info:lc/vocabulary/gacs/nwwi + Windward Islands (West Indies) [nwwi] + nwwi + + + info:lc/vocabulary/gacs/n-us-wi + Wisconsin + n-us-wi + + + info:lc/vocabulary/gacs/n-us-wy + Wyoming + n-us-wy + + + info:lc/vocabulary/gacs/a-ccs + Xi River (China) + a-ccs + + Hsi Chiang (China) + + + Si Kiang (China) + + + Si River (China) + + + West River (China) + + + + info:lc/vocabulary/gacs/a-cc-su + Xinjiang Uygur Zizhiqu (China) + a-cc-su + + Hsin-chiang-wei-wy-erh tzu chin chü (China) + + + Sinkiang Uighur Autonomous Region (China) + + + + info:lc/vocabulary/gacs/a-ccg + Yangtze River (China) + a-ccg + + Chang Chiang (China) + + + Long River (China) + + + + info:lc/vocabulary/gacs/a-ccy + Yellow River (China) + a-ccy + + Hoang Ho (China) + + + Huang Ho (China) + + + Hwang Ho (China) + + + + info:lc/vocabulary/gacs/ay + Yellow Sea + ay + + Huang Hai + + + Kwang Sea + + + + info:lc/vocabulary/gacs/a-ye + Yemen (Republic) + a-ye + + Aden + + Coded [a-ys] (Yemen (People's Democratic Republic) before Oct. 1992] + + + + Aden (Protectorate) + + Coded [a-ys] (Yemen (People's Democratic Republic) before Oct. 1992 + + + + Arabia, Southern + + + Federation of South Arabia + + South Arabia, Federation of + + + + Socotra (Yemen) + + Coded [i-xo] (Socotra Island) before Mar. 1988; Coded [a-ys] (Yemen (People's + Democratic Republic) before Oct. 1992 + + + Sokotra (Yemen) + + + + Arab Republic of Yemen + + + People's Democratic Republic of Yemen + + + Southern Yemen + + + Yemen (Arab Republic) + + + Yemen (People's Democratic Republic) + + Coded [a-ys] (Yemen (People's Democratic Republic) before Oct. 1992 + + + + + info:lc/vocabulary/gacs/e-yu + Yugoslavia + e-yu + + Pannonia + + + Former Yugoslav republics + + + + info:lc/vocabulary/gacs/n-cn-yk + Yukon Territory + n-cn-yk + + + info:lc/vocabulary/gacs/a-cc-yu + Yunnan Sheng (China) + a-cc-yu + + Yunnan Province (China) + + + + info:lc/vocabulary/gacs/fz + Zambezi River + fz + + Rio Zambezi + + + + info:lc/vocabulary/gacs/f-za + Zambia + f-za + + Rhodesia + + + Rhodesia and Nyasaland + + Federation of Rhodesia and Nyasaland + + + + Northern Rhodesia + + + + info:lc/vocabulary/gacs/a-cc-ch + Zhejiang Sheng (China) + a-cc-ch + + Chekiang Province (China) + + + + info:lc/vocabulary/gacs/f-rh + Zimbabwe + f-rh + + Rhodesia + + + Rhodesia and Nyasaland + + Federation of Rhodesia and Nyasaland + + + + Rhodesia, Southern + + + Southern Rhodesia + + + + diff --git a/form_elements/xml/languages.xml b/form_elements/xml/languages.xml new file mode 100644 index 00000000..ef5e8eb3 --- /dev/null +++ b/form_elements/xml/languages.xml @@ -0,0 +1,19575 @@ + + + + + + + iso639-2b + MARC Code List for Languages + Network Development and MARC Standards Office, Library of Congress + info:lc/vocabulary/languages + + + + info:lc/vocabulary/languages/abk + Abkhaz + abk + + + info:lc/vocabulary/languages/ace + Achinese + ace + + Atjeh + + + + info:lc/vocabulary/languages/ach + Acoli + ach + + Acholi + + + Gang + + + Lwo + + + Shuli + + + + info:lc/vocabulary/languages/ada + Adangme + ada + + Dangme + + + + info:lc/vocabulary/languages/ady + Adygei + ady + + Circassian, Lower + + + Circassian, West + + + Kiakh + + + Kjax + + + Lower Circassian + + + West Circassian + + + + info:lc/vocabulary/languages/aar + Afar + aar + + Adaiel + + + Danakil + + + + info:lc/vocabulary/languages/afh + Afrihili (Artificial language) + afh + + + info:lc/vocabulary/languages/afr + Afrikaans + afr + + Afrikander + + + Cape Dutch + + + + info:lc/vocabulary/languages/afa + Afroasiatic (Other) + afa + + Angas + + Karan + + + Karang (Nigeria) + + + Ngas + + + + Bidiyo + + + Daba (Cameroon and Nigeria) + + + Dangaleat + + + Day (Chad) + + Dari (Chad) + + + Sara Dai + + + + Gabri + + + Gamo (Ethiopia) + + Gemu + + + + Glavda + + + Goemai + + Ankwe + + + Gamai (Nigeria) + + + Kemai + + + + Gude + + + Guruntum-Mbaaru + + Gurdung + + + Guruntum + + + + Hedi + + Hdi + + + + Huba + + Chobba + + + Kilba + + + + Jongor + + Dionkor + + + Djongor + + + + Kamwe + + Higi + + + Higgi + + + Hiji + + + Vacamwe + + + + Kanakuru + + Dera + + + + Kapsiki + + Kamsiki + + + Psikye + + + Ptsake + + + + Kera + + + Mada (Cameroon) + + + Mafa + + Matakam + + + Natakan + + + + Male (Ethiopia) + + Maale + + + + Masa (Chadic) + + Banaa + + + Banana (Masa) + + + Masana + + + Massa + + + Walai + + + + Miya + + + Musgu + + Masa + + + + Nancere + + + Ngizim + + Gwazum + + + Kirdiwat + + + Nugzum + + + Walu + + + + Paduko + + Podoko + + + + Ron + + Chala + + + Run + + + + Saya + + Sayanci + + + Sayara + + + Sayawa + + + Seiyara + + + Seya + + + Seyawa + + + + Southern Mofu + + Mofu, Southern + + + Mofu-Gudur + + + + Tera + + + Tumak + + Maga + + + Sara Toumak + + + Toumak + + + + Tupuri + + Ndore + + + Tuburi + + + + Uldeme + + Mizlime + + + Ouldémé + + + Udlam + + + Uzlam + + + Uzan + + + Wuzlam + + + + Wandala + + Mandara + + + + Yemsa + + Janjero + + + + Zaar + + Vigzar + + + Vikzar + + + + Zulgo + + Zelgwa + + + + + info:lc/vocabulary/languages/ain + Ainu + ain + + + info:lc/vocabulary/languages/aka + Akan + aka + + Twi-Fante + + + + info:lc/vocabulary/languages/akk + Akkadian + akk + + Assyro-Babylonian + + + Babylonian + + + + info:lc/vocabulary/languages/alb + Albanian + alb + + Calabrian Albanian + + Albanian, Calabrian + + + + + info:lc/vocabulary/languages/ale + Aleut + ale + + Eleuth + + + + info:lc/vocabulary/languages/alg + Algonquian (Other) + alg + + Abenaki + + Abnaki + + + + Algonquin + + Algonkin + + + + Atakapa + + + Atikamekw + + Attikamekw + + + Tête-de-Boule + + + + Fox + + + Illinois + + + Kickapoo + + + Mahican + + + Massachuset + + Natick + + + Niantic + + + Nonantum + + + + Menominee + + + Miami (Ind. and Okla.) + + + Mohegan + + Pequot + + + + Montagnais + + Innu (Montagnais) + + + Montagnais Innu + + + Montagnar + + + Montagnard + + + Montagnie + + + Mountainee + + + + Naskapi + + Nascapee + + + Naskapee + + + + Passamaquoddy + + Etchemin + + + Malecite + + + + Penobscot + + + Potawatomi + + + Powhatan + + + Quileute + + + Roanoak + + + Shawnee + + + Wampanoag + + + Yurok + + + + info:lc/vocabulary/languages/ajm + Aljamía + ajm + + + info:lc/vocabulary/languages/alt + Altai + alt + + Oirat (Turkic) + + + Southern Altai + + + + info:lc/vocabulary/languages/tut + Altaic (Other) + tut + + Turko-Tataric (Other) + + + Bulgaro-Turkic + + Turko-Bulgarian + + + (Altaic (Other)) + + + + Dagur + + Daghur + + + Daur + + + + Dolgan + + + Even + + Lamut + + + + Evenki + + O-wen-k`o + + + Tungus + + + + Gagauz + + + Greek Tatar + + Urum + + + + Karaim + + + Karakhanid + + Khakani + + + Qarakhanid + + + + Khakass + + Xakas + + + Xaqas + + + + Khalaj + + + Khitan + + Kitan + + + Liao + + + + Khorezmian Turkic + + Khwarezmian Turkic + + + + Kipchak + + Coman + + + Cuman + + + Falven + + + Kuman + + + Polovtsi + + + Walwen + + + + Moghol + + Mogol + + + + Mongolian, Middle (13th-16th centuries) + + Middle Mongolian (13th-16th centuries) + + + + Mongour + + Tu + + + + Nanai + + Goldi + + + + Northern Altai + + Altai, Northern + + + + Olcha + + Ulcha + + + + Old Turkic + + Turkic, Old + + + + Oroch + + + Oroqen + + Orochon + + + + Salar + + + Shor + + + Sibo + + Xive + + + + Teleut + + + Turkish, Old (to 1500) + + Anatolian Turkish, Old + + + Old Anatolian Turkish + + + Old Ottoman Turkish + + + Old Turkish + + + Ottoman Turkish, Old + + + + Udekhe + + + Western Yugur + + Yugur, Western + + + + + info:lc/vocabulary/languages/amh + Amharic + amh + + Amarigna + + + Amarinya + + + + info:lc/vocabulary/languages/anp + Angika + anp + + Anga + + + + info:lc/vocabulary/languages/apa + Apache languages + apa + + Chiricahua + + + Mescalero + + + White Mountain Apache + + + + info:lc/vocabulary/languages/ara + Arabic + ara + + Hassaniyya + + + + info:lc/vocabulary/languages/arg + Aragonese + arg + + Altoaragonés + + + Aragoieraz + + + Aragonés + + + Fabla Aragonesa + + + High Aragonese + + + Patués + + + Spanish, Aragonese + + + + info:lc/vocabulary/languages/arc + Aramaic + arc + + Aramean + + + Biblical Aramaic + + + Chaldaic + + + Chaldean (Aramaic) + + + Chaldee + + + + info:lc/vocabulary/languages/arp + Arapaho + arp + + + info:lc/vocabulary/languages/arw + Arawak + arw + + Loko (Arawakan) + + + Lokono + + + + info:lc/vocabulary/languages/arm + Armenian + arm + + Khayasa + + Hayasa + + + Khaiass + + + + + info:lc/vocabulary/languages/rup + Aromanian + rup + + Macedo-Romanian + + + + info:lc/vocabulary/languages/art + Artificial (Other) + art + + Ande (Artificial language) + + + Babm + + + Balaibalan + + Bâl-i bîlen + + + Bala-i-balan + + + Balabalan + + + Bâleybelen + + + Bali belen + + + Bâlibîlen + + + + Enochian + + + Europanto + + + Glosa (Artificial language) + + + International auxiliari linguo (Artificial language) + + INTAL (Artificial language) + + + + Loglan (Artificial language) + + + Neo (Artificial language) + + + Novial (Artificial language) + + + Tsolyáni (Artificial language) + + + Vela (Artificial language) + + + + info:lc/vocabulary/languages/asm + Assamese + asm + + Kāmrūpī + + + Rābhāmija + + Rābhāmiz + + + + + info:lc/vocabulary/languages/ath + Athapascan (Other) + ath + + Ahtena + + + Carrier + + Takulli + + + + Chilcotin + + Tsilkotin + + + + Dena'ina + + Tanaina + + + + Kaska + + + Kiowa Apache + + + Koyukon + + + Sarsi + + + Sekani-Beaver + + + Southern Tutchone + + Tutchone, Southern + + + + Tagish + + + Tahltan + + + Tanacross + + + Tsattine + + + Upper Tanana + + Tanana, Upper + + + + Upper Umpqua + + + + info:lc/vocabulary/languages/aus + Australian languages + aus + + Adnyamathanha + + Atynyamatana + + + Wailpi + + + + Alawa + + Galawa + + + + Alyawarra + + Iliaura + + + + Anindilyakwa + + Andilyaugwa + + + + Awabakal + + + Bandjalang + + Minyung + + + + Bidjara + + Pitjara + + + + Biri (Australia) + + Birri (Australia) + + + + Burarra + + Bara (Australia) + + + Jikai + + + Tchikai + + + + Butchulla + + + Darling River dialects + + Bagandji dialects + + + + Dhungutti + + Daingatti + + + Dyangadi + + + Thangatti + + + + Djaru + + Jaroo + + + Tjaru + + + + Djinang + + Jandjinung + + + Yandjinung + + + + Djingili + + Jingulu + + + Tjingili + + + + Eastern Arrernte + + Aranda, Eastern + + + Arrernte, Eastern + + + + Garawa + + Karawa (Australia) + + + Korrawa + + + Kurrawar + + + Leearrawa + + + + Gidabal + + Kitabul + + + + Gubbi-Gubbi + + Kabi Kabi + + + + Gugada + + Kukota + + + + Gumatj + + Gomadj + + + Kainyao + + + Komaits + + + Kumait + + + + Gungabula + + Kongabula + + + + Gunian + + Gooniyandi + + + + Gunwinggu + + + Gupapuyngu + + + Guugu Yimithirr + + + Iwaidja + + Jiwadja + + + Yiwadja + + + + Kala Lagaw Ya + + Mabuiaq + + + + Kalkatungu + + Galgadung + + + + Kattang + + Kutthung + + + + Kitja + + Gidja + + + Kija + + + + Kuku-Yalanji + + Gugu Yalanji + + + Koko Jelandji + + + + Kuuku Ya'u + + Koko Ya'o + + + + Kwini + + Belaa + + + Cuini + + + Goonan + + + Gunin + + + Gwiini + + + Gwini + + + Kunan (Kwini) + + + Kwini/Belaa + + + Wunambal (Kwini) + + + + Malgana + + Maldjana + + + Maljanna + + + Malkana + + + + Mandjildjara + + Mantjiltjara + + + + Mangarayi + + Manggarai (Australia) + + + Mungerry + + + + Maranunggu + + + Martu Wangka + + + Murrinhpatha + + + Nakara + + + Narangga + + Narungga + + + + Narrinyeri + + + Ngaanyatjarra + + + Ngandi + + + Ngarinyin + + Ungarinjin + + + Wungarinjin + + + + Ngarla + + + Ngarluma + + + Nukunu + + Nugunu + + + + Nunggubuyu + + Wubuy + + + + Pintupi + + Bindubi + + + + Pitjantjatjara + + + Proto Mirndi + + + Ritharrngu + + + Tharrkari + + Dhargari + + + + Tiwi (Australia) + + + Umpila + + + Walmajarri + + + Wandarang + + Andarang + + + Nawariyi + + + + Wanʼguri + + Wonguri + + + + Warlpiri + + Elpira + + + Ilpara + + + Ngaliya + + + Ngardilpa + + + Wailbri + + + Walbiri + + + Waljbiri + + + Walmama + + + Walpiri + + + Warnayaka + + + Warrmarla + + + + Warumungu + + + Western Arrernte + + Aranda, Western + + + Arrernte, Western + + + + Western Desert + + + Wik-Munkan + + Munggan + + + + Wik-Ngathan + + Wik-Ngathana + + + + Worora + + + Wunambal + + Jeidji + + + Jeithi + + + Unambal + + + Wumnabal + + + Wunambullu + + + Yeidji + + + Yeithi + + + + Yandruwandha + + + Yanyuwa + + + Yawuru + + Jaudjibara + + + Jawadjag + + + Jawdjibaia + + + Jawdjibara + + + Winjawindjagu + + + Yaudijbaia + + + Yaudjibara + + + Yawjibara + + + + Yidiny + + + Yindjibarndi + + Jindjibandji + + + + Yinhawangka + + Inawonga + + + + Yualyai + + Euahlayi + + + Jualjai + + + Ualari + + + Uollaroi + + + Wallaroi + + + Yerraleroi + + + Yowalri + + + Yuwaalaraay + + + + Yugambeh + + + + info:lc/vocabulary/languages/map + Austronesian (Other) + map + + Malayo-Polynesian (Other) + + + Adzera + + Acira + + + Atsera + + + Atzera + + + + Ajie + + Houailou + + + Wailu + + + + Ambrym + + + Amis + + Ami + + + + Anesu + + Canala + + + Kanala + + + Xaracuu + + + Yaracuu + + + + Apma + + + Areare + + + Arop-Lokep + + Lokep + + + Lokewe + + + + Arosi + + + Atayal + + Tayal + + + + Bajau + + Badjo + + + Bayo + + + Luaan + + + Orang Laut (Indonesia) + + + Sama (Indonesia) + + + Turije̕ne̕ + + + + Bakumpai + + + Balaesang + + Balaisang + + + Pajo + + + + Banjar Hulu + + Hulu + + + + Barangas + + Alalak + + + + Bareë + + + Begak + + + Berawan + + + Biliau + + + Bimanese + + + Bolaang Mongondow + + + Buang + + + Bugotu + + Mahaga + + + + Bukar Sadong + + Sadong + + + Serian + + + Tebakang + + + + Bunama + + + Bunun + + + Buol + + Bual + + + Bwuolo + + + Dia + + + + Bwaidoga + + + Bwatoo + + + Camuhi + + Cemuhi + + + Tyamuhi + + + Wagap + + + + Carolinian + + + Daa + + Pekawa + + + + Dawawa + + + Dehu + + Drehu + + + Lifu + + + Miny + + + + Dobel + + Kobroor + + + + Dobu + + + Dumbea + + Drubea + + + + Dusun + + Kadazan + + + + East Makian + + Inner Makian + + + Makian, East + + + Makian, Inner + + + Taba + + + + East Uvean + + Uvean, East + + + Wallisian + + + + Enggano + + Etaka + + + + Enim + + + Eromanga + + Sie + + + Sye + + + + Favorlang + + Babuza + + + + Futuna-Aniwa + + Erronan + + + West Futuna + + + + Gapapaiwa + + Manape + + + + Gedaged + + Graged + + + + Gumasi + + + Halia + + + Ham + + Dami + + + + Hote + + + Iai (Loyalty Islands) + + + Iamalele + + Yamalele + + + + Ida'an + + + Iduna + + + Irahutu + + + Kaidipang + + + Kaili + + Ledo' + + + Palu + + + + Kaiwa (Papua New Guinea) + + Iwal + + + + Kambera + + + Kapingamarangi + + + Kara (Papua New Guinea) + + Kara-Lemakot + + + Lemakot + + + Lemusmus + + + + Katingan + + + Kaulong + + + Kayan (Borneo) + + + Kayu Agung + + + Kemak + + Ema + + + + Kerinci + + Kinchai + + + Korintje + + + + Kiput + + + Kiriwinian + + Kilivila + + + Trobriand + + + + Koluwawa + + + Komodo + + + Kubu + + + Kuni + + + Kurada + + Auhelawa + + + Cauhelawa + + + Nuakata + + + + Kutai + + Tenggarong + + + + Kwara'ae + + Fiu + + + + Lamenu + + Lamen + + + Lewo (Lamenu) + + + Varmali + + + + Lampung + + Api + + + Lampong + + + + Lau + + + Lavongai + + Dang (Papua New Guinea) + + + Lavangai + + + New Hanover + + + Tungag + + + Tungak + + + + Lembak Bilide + + + Lenakel + + + Lewo + + Varsu + + + + + Lindrou + + + Lundayeh + + Lun Daya + + + Lun Daye + + + Lun Dayho + + + Lundaya + + + Southern Murut + + + + Manam + + + Mandak + + Lelet + + + + Mandara (Papua New Guinea) + + Madara + + + Tabar + + + + Mangap + + Mbula (Mangap) + + + + Manggarai (Indonesia) + + + Mangseng + + + Marquesan + + + Mekeo + + + Mele-Fila + + Fila + + + + Mentawai + + + Mokilese + + + Mori + + Aikoa + + + + Mortlockese + + Mortlock (Micronesia) + + + Nomoi + + + + Motu + + + Mouk + + + Mukawa + + Kapikapi + + + + Muna + + Mina (Indonesia) + + + Wuna + + + + Nakanai + + Lakalai + + + + Nali + + Yiru + + + + Napu + + Bara (Indonesia) + + + + Nemi + + + Nengone + + + Ngada + + + Ngaju + + Biadju + + + Ngaju Dayak + + + + Ngatik + + + Nguna + + + Notsi + + Nochi + + + + Nuaulu + + + Nukuoro + + + Numfor + + Mafor + + + Noemfoor + + + Nufor + + + + Paiwan + + + Pala + + + Paranan + + Palanan + + + + Pasir (Lawangan) + + + Pazeh + + Bazai + + + + Petats + + + Pileni + + + Puluwat + + + Puyuma + + Kadas language (Puyuma) + + + Panapanayan + + + Pelam + + + Pilam + + + Piyuma + + + Pyuma + + + Tipun + + + + Ramoaaina + + Malu (Papua New Guinea) + + + + Rejang (Sumatra, Indonesia) + + Redjang (Sumatra, Indonesia) + + + + Rennellese + + Bellonese + + + Munggava + + + + Roti + + Rottinese + + + + Rotuman + + + Rukai + + Drukai + + + + Rungus + + Dusun Dayak + + + Melobong Rungus + + + Memagun + + + Memogun + + + Momogun + + + Roongas + + + Rungus Dusun + + + + Saaroa + + La'alua + + + La'arua + + + Pachien + + + Paichien + + + Rarua + + + Saarua + + + Saroa + + + Shishaban + + + Sisyaban + + + + Sangen + + + Sangil + + Sangiré + + + + Sangir (Indonesia and Philippines) + + Sangihe + + + + Saposa + + + Sawu + + Havunese + + + Hawu + + + Sabu + + + Savu + + + + Sedik + + Sazek + + + Seedik + + + Shedekka + + + + Semendo + + + Serawai + + + Sigi + + Idja + + + + Sikka + + + Siladang + + + Sinagoro + + + Sio + + + Sissano + + + Sobei + + + Sokop + + + Sonsorol-Tobi + + Tobi + + + + Suau + + + Sumba + + + Sumbawa + + Semana + + + Soembawa + + + + Sursurunga + + + Suwawa + + Bunda (Indonesia) + + + + Tagal Murut + + Murut Tahol + + + Semambu + + + Semembu + + + Sumambu + + + Sumambu-Tagal + + + Sumambuq + + + + Tagula + + Sudest + + + + Takuu + + Mortlock (Papua New Guinea) + + + Nahoa + + + Taku + + + Taʻu + + + Tauu + + + + Talaud + + Talaoed + + + + Tamuan + + + Tanga (Tanga Islands) + + + Tavara (Papua New Guinea) + + Kehelala + + + Tawala + + + + Tawoyan + + + Teop + + Tiop + + + + Tidore + + + Tikopia + + + Timor + + Atoni + + + Timorese + + + + Timugon + + + Tinputz + + Timputs + + + Vasuii + + + Wasoi + + + + Tolai + + Blanche Bay + + + Gunantuna + + + Kuanua + + + New Britain + + + Raluana + + + Tinata Tuna + + + Tuna + + + + Tolaki + + Kendari + + + Toolaki + + + + Tombulu + + Toumbulu + + + + Tondano + + Tolou + + + Tolour + + + + Tonsea + + + Toraja + + Toradja + + + + Toraja Sa'dan + + Sadan (Indonesia) + + + Saqdab Toraja + + + South Toraja + + + Tae' + + + + Tuamotuan + + Paumotu + + + + Tubetube + + + Ulithi + + + Uma + + Pipikoro + + + + Urak Lawoi̕ + + Chāo Lē + + + Orak Lawoi' + + + Orang Laut (Thailand and Malaysia) + + + + Uripiv + + + Wampar + + + Wandamen + + Windesi + + + Wondama + + + + Wewewa + + Sumba, West + + + Waidjewa + + + West Sumba + + + + Woleaian + + Uleai + + + Woleai + + + + Wolio + + + Yabim + + Jabêm + + + + Yamdena + + Jamdena + + + + + info:lc/vocabulary/languages/ava + Avaric + ava + + + info:lc/vocabulary/languages/ave + Avestan + ave + + Avesta + + + Bactrian, Old (Avestan) + + + Old Bactrian (Avestan) + + + Zend + + + + info:lc/vocabulary/languages/awa + Awadhi + awa + + + info:lc/vocabulary/languages/aym + Aymara + aym + + Aimara + + + + info:lc/vocabulary/languages/aze + Azerbaijani + aze + + Azari + + + Azeri + + + Afshar + + + + info:lc/vocabulary/languages/ast + Bable + ast + + Asturian + + + + info:lc/vocabulary/languages/ban + Balinese + ban + + + info:lc/vocabulary/languages/bat + Baltic (Other) + bat + + Curonian + + + Proto-Baltic + + + Prussian + + Old Prussian + + + + + info:lc/vocabulary/languages/bal + Baluchi + bal + + Balochi + + + Beloutchi + + + Biluchi + + + + info:lc/vocabulary/languages/bam + Bambara + bam + + Bamana (Mandekan) + + + Bamanankan + + + + info:lc/vocabulary/languages/bai + Bamileke languages + bai + + Bandjoun + + Bamileke-Jo + + + + Fe'fe' + + Bafang + + + Bamileke-Fe'fe' + + + Bana (Bamileke) + + + Fa (Bamileke) + + + Fan (Bamileke) + + + Fanwe (Bamileke) + + + Fe'e fe'e + + + Fotouni + + + Kuu + + + Nufi + + + + Ngyemboon + + Nguemba (Bamileke) + + + + Yemba + + + + info:lc/vocabulary/languages/bad + Banda languages + bad + + Banda (Central Africa) + + + Linda + + + + info:lc/vocabulary/languages/bnt + Bantu (Other) + bnt + + Abo (Cameroon) + + Abaw + + + Bo (Cameroon) + + + Bon (Cameroon) + + + + Aka (Central African Republic) + + + Asu + + Athu + + + Chasu + + + Pare + + + + Bafia + + + Bakundu + + Kundu + + + + Bati + + + Bekwil + + Bakwele + + + Bakwil + + + Bekwel + + + Bekwie + + + Bekwyel + + + Kwele + + + Okpele + + + + Bembe (Congo (Brazzaville)) + + KiBembe + + + Mbembe + + + + Benga + + + Bobangi + + Rebu + + + + Bolia + + Bulia + + + + Boma (Congo) + + Buma (Congo) + + + + Bomitaba + + Mbomitaba + + + Mitaba + + + + Bondei + + Bonde + + + Boondei + + + Kibondei + + + Wabondei + + + + Bube + + Bubi (Equatorial Guinea) + + + Fernandian + + + + Bubi (Gabon) + + Pove + + + + Budu + + + Bukusu + + Lubukusu + + + + Bulu + + Boulou + + + + Camtho + + Iscamtho + + + Isicamtho + + + Shalambombo + + + Tsotsitaal (Camtho) + + + + Chaga + + Djaga + + + Dschagga + + + Jagga + + + Tschagga + + + + Chokwe + + Cibokwe + + + Cokwe + + + Jok + + + Katchokue + + + Kioko + + + Quioco + + + Tutchokue + + + + Chopi + + Lenge + + + + Comorian + + + Diriku + + Mbogedo + + + Rugciriku + + + Rumanyo + + + Shimbogedu + + + + Doko (Congo) + + + Duruma + + + Embu + + + Enahara + + Emathipane + + + Enaharra + + + Maharra + + + Nahara + + + Naharra + + + + Fipa + + + Fuliru + + + Ganguela + + Ngangela + + + + Geviya + + Avias + + + Eviya + + + Viya + + + + Giryama + + + Gisu + + Lugisu + + + Lumasaaba + + + Masaba + + + + Gungu + + Lugungu + + + Rugungu + + + + Gusii + + Ekegusii + + + Kisii + + + + Gweno + + Kigweno + + + + Gwere + + + Ha + + + Haya + + Luhaya + + + Lusiba + + + Ruhaya + + + Ziba + + + + Hehe + + + Hunde + + + Ikizu + + Ikiizo + + + Ikikizo + + + Ikikizu + + + Kiikizu + + + + Ila + + + Jita + + Echijita + + + Ecijita + + + Kijita + + + + Kahe + + Kikahe + + + + Kako + + Kaka (Northwest Bantu) + + + Yaka (Cameroon and Central African Republic) + + + + Kalanga (Botswana and Zimbabwe) + + + Kaonde + + Luba-Kaonde + + + + Kare + + Akare + + + Bakare + + + + Kele (Gabon) + + + Kete + + + Kom (Cameroon) + + Nkom + + + + Kombe + + + Komo (Congo) + + Kumu + + + + Koonzime + + Djimu + + + Dzimou + + + Konzime + + + Kooncimo + + + Koozhime + + + Koozime + + + Nzime + + + Zimu + + + + Kuria + + Ekiguria + + + Igikuria + + + Ikikuria + + + Kikoria + + + Kikouria + + + Kikuria + + + Kikuria cha juu + + + Kikuria cha Mashariki + + + Koria + + + Kurya + + + Kurye + + + Tende (Kuria) + + + + Kwangali + + + Kwese + + Kwezo + + + + Kwiri + + Mokpwe + + + + Lala + + + Lega + + + Lenje + + Bwine-Mukuni + + + Ci-Renje + + + + Logooli + + Ragoli + + + + Lomwe (Malawi) + + + Lucazi + + Ponda + + + + Luvale + + + Luyana + + + Luyia + + Oluluyia + + + + Maka (Cameroon) + + Makaa (Cameroon) + + + Mekaa + + + + Makhuwa + + Central Makhuwa + + + Emakhuwa + + + Emakua + + + Macua + + + Makhuwa-Makhuwana + + + Makhuwwa of Nampula + + + Makoane language + + + Makua (Mozambique) + + + Maquoua (Makhuwa) + + + + Makonde + + Chimakonde + + + Konde (Yao group) + + + + Makwe + + Kimakwe + + + Macue + + + Maraba (Makwe) + + + Palma + + + + Mashami + + Kimashami + + + Machambe + + + Machame + + + Madschame + + + + Mbala (Bandundu, Congo) + + + Mbo (Cameroon) + + + Mbosi + + + Mbukushu + + Goba + + + Mambukush + + + Mpukush + + + Thimbukushu + + + + Mbunda (Angola and Zambia) + + + Meru + + Kimeru + + + + Mijikenda languages + + Nika languages + + + Nyika languages + + + + Mituku + + + Mkaaʼ + + Bakaka + + + + Mochi + + Kimochi + + + Kimoshi + + + Moshi (Tanzania) + + + Mosi (Tanzania) + + + Old Moshi + + + + Mpiemo + + Bimu + + + Mbimou + + + Mbimu + + + Mbyemo + + + Mpo + + + Mpyemo + + + + Mpongwe + + Pongwe + + + + Mpur (Congo) + + + Nambya + + + Nande + + Nandi (Congo) + + + + Ndau + + Chindau + + + Shona, Southeastern + + + + Ndumu + + + Ngonde + + Ikinyi-Kiusa + + + Kiusa + + + Konde (Nyakyusa) + + + Mombe + + + Nkonde + + + Nyakyusa + + + Sochile + + + + Ngul + + Engwî + + + Ingul + + + Kingóli + + + Ngoli + + + Nguli + + + Ngulu (Congo (Democratic Republic)) + + + Ngwi (Congo (Democratic Republic)) + + + + Nsenga + + + Ntomba + + + Nyaneka + + Lunyaneka + + + Olunyaneka + + + + Nyanga + + + Nyole (Uganda) + + Lunyole (Uganda) + + + Nyule + + + Nyuli + + + + Nyungwe + + Tete + + + + Nzebi + + Bandzabi + + + Indzèbi + + + Injebi + + + Ndjabi + + + Ndjebi + + + Ndjevi + + + Njabi + + + Njevi + + + Nzabi + + + Yinzabi + + + + Pangwa + + + Pelende + + + Pende + + Kipende + + + Pindi (Pende) + + + + Pokomo + + + Punu + + Bapounou + + + Pounou + + + + Rangi + + Irangi + + + Kilangi + + + Kirangi + + + Langi (Tanzania) + + + + Ronga + + Landim + + + Shironga + + + Xironga + + + + Ruri + + Ciruuri + + + Kiruri + + + Ruuri + + + + Ruund + + Chiluwunda + + + Lunda, Northern + + + Luwunda + + + Muatiamvua + + + Northern Lunda + + + Uruund + + + + Saamia + + Luhya (Saamia) + + + Luluyia (Saamia) + + + Lusaamia + + + Luyia (Saamia) + + + Ólusaamya + + + Olusamia + + + Samia + + + Samya + + + + Sakata + + + Salampasu + + Chisalampasu + + + + Sanga + + Luba, Southern + + + Southern Luba + + + + Sena + + + Shambala + + + Shi + + Mashi + + + Nyabungu + + + + Shimaore + + Mahorais + + + + Simbiti + + Kisimbiti + + + + Songye + + Songe + + + + Subiya + + ciIkuhane + + + Ikuhane + + + Soubiya + + + + Suku (Congo) + + + Sumbwa + + Kisumbwa + + + Shisumbwa + + + Sisumbwa + + + Sisuumbwa + + + + Taita + + Sagalla + + + Teita + + + + Talinga-Bwisi + + Bwisi-Talinga + + + Kitalinga + + + + Teke + + Balali + + + Ilali + + + Itio + + + Lali + + + + Tembo (Sud-Kivu, Congo) + + KiTembo + + + + Temi + + Gitemi + + + Kisonjo + + + Sonjo + + + Sonyo + + + Wasonjo + + + Watemi + + + + Tetela + + + Tharaka + + Saraka + + + + Tiene + + Ketiine + + + Kitiene + + + Kitiini + + + Tende (Congo (Democratic Republic)) + + + + Tiriki + + + Tonga (Inhambane) + + Gitonga + + + + Tonga (Zambezi) + + + Tooro + + Toro + + + + Tsogo + + Apindji + + + Mitsogo + + + + Tswa + + Kitswa + + + Shitswa + + + Tshwa + + + Xitswa + + + + Tunen + + Banen + + + + Yaka (Congo and Angola) + + Iaka + + + + Yanzi + + + Yombe (Congo and Angola) + + + Zanaki + + Iki-Zanaki + + + IkiZanaki + + + + Zigula + + Kizigula + + + Seguha + + + Wayombo + + + Wazegua + + + Wazigua + + + Zeguha + + + Zegura + + + Zigoua + + + Zigua + + + Zigwa + + + + Zinza + + Dzinda + + + Dzindza + + + Echidzindza + + + Echijinja + + + Eciinja + + + Ecizinza + + + Jinja + + + Kizinza + + + Luzinza + + + Zinja + + + + + info:lc/vocabulary/languages/bas + Basa + bas + + + info:lc/vocabulary/languages/bak + Bashkir + bak + + + info:lc/vocabulary/languages/baq + Basque + baq + + Euskara + + + + info:lc/vocabulary/languages/btk + Batak + btk + + Batta (Sumatra) + + + Alas + + + Angkola + + + Dairi Pakpak + + Pakpak + + + + Karo-Batak + + + Mandailing + + Batak Mandailing + + + + Simelungun + + + Toba-Batak + + + + info:lc/vocabulary/languages/bej + Beja + bej + + Bedawiye + + + Bedja + + + Bishári + + + + info:lc/vocabulary/languages/bel + Belarusian + bel + + Belorussian + + + Byelorussian + + + Russian, White + + + White Russian + + + + info:lc/vocabulary/languages/bem + Bemba + bem + + + info:lc/vocabulary/languages/ben + Bengali + ben + + Banga-Bhasa + + + Bangala + + + Bangla + + + Sylheti + + Sylhet + + + Sylhetti Bangla + + + + + info:lc/vocabulary/languages/ber + Berber (Other) + ber + + Mzab + + Mozabite + + + + Rif + + Northern Shilha + + + Shilha, Northern + + + Tarifit + + + + Shilha + + Chleuh + + + Sölha + + + Tachelhait + + + Tashelhiyt + + + + Tamazight + + + + info:lc/vocabulary/languages/bho + Bhojpuri + bho + + Bajpuri + + + Bhojapuri + + + Bhozpuri + + + Bihari (Bhojpuri) + + + Deswali (Bhojpuri) + + + Khotla + + + Piscimas + + + Sadani + + Chota Nagpuri + + + Chotar Nagpuri + + + Dikku Kaji + + + Dikkukaji + + + Nagpuri (Bhojpuri) + + + Nagpuriā + + + Napuria + + + Sadan + + + Sadari + + + Sadati + + + Sadhan + + + Sadhana + + + Sadharan + + + Sadna + + + Sadri + + + Sadrik + + + Santri + + + Siddri + + + Sradri + + + + Western Standard Bhojpuri + + Benarsi + + + Bhojpuri, Western Standard + + + Purbi + + + + + info:lc/vocabulary/languages/bih + Bihari (Other) + bih + + Behari + + + Bajjika + + + Kudmali + + Bedia + + + Dharua + + + Khotta (Kurmali) + + + Kurma + + + Kurmali + + + Kurmali Thar + + + Kurmik + + + Kurni + + + Kurumali + + + + + info:lc/vocabulary/languages/bik + Bikol + bik + + Vikol + + + + info:lc/vocabulary/languages/byn + Bilin + byn + + + info:lc/vocabulary/languages/bis + Bislama + bis + + Beach-la-mar + + + Bêche-de-mer + + + Bichelamar + + + + info:lc/vocabulary/languages/zbl + Blissymbolics + zbl + + + info:lc/vocabulary/languages/bos + Bosnian + bos + + + info:lc/vocabulary/languages/bra + Braj + bra + + Braj bhākhā + + + Braj bhāshā + + + Pingal + + + + info:lc/vocabulary/languages/bre + Breton + bre + + Armoric + + + + info:lc/vocabulary/languages/bug + Bugis + bug + + Buginese + + + + info:lc/vocabulary/languages/bul + Bulgarian + bul + + + info:lc/vocabulary/languages/bua + Buriat + bua + + Buryat + + + Mongolian, Northern + + + Northern Mongolian + + + + info:lc/vocabulary/languages/bur + Burmese + bur + + + info:lc/vocabulary/languages/cad + Caddo + cad + + + info:lc/vocabulary/languages/car + Carib + car + + Galibi + + + + info:lc/vocabulary/languages/cat + Catalan + cat + + Majorcan Catalan + + Catalan, Majorcan + + + + Valencian Catalan + + Catalan, Valencian + + + + + info:lc/vocabulary/languages/cau + Caucasian (Other) + cau + + Abazin + + + Bats + + Bac + + + Tsova-Tush + + + Tush + + + + Bezhta + + + Botlikh + + + Budukh + + + Chamalal + + + Dido + + Tsez + + + + Ginukh + + Ginukhtsy + + + Ginux + + + Hinukh + + + Hinux + + + + Hunzib + + Gunzib + + + + Kubachi + + + Lak + + + Laz + + Chan + + + Chanuri + + + Chanzan + + + Laze + + + Lazian + + + Lazuri + + + Zan + + + + Mingrelian + + + Svan + + + Tabasaran + + + Tsakhur + + + Ubykh + + Oubykh + + + + Udi + + + + info:lc/vocabulary/languages/ceb + Cebuano + ceb + + Binisaya + + + Bisayan + + + Sebuano + + + Sinugboanon + + + Sugbuanon + + + Sugbuhanon + + + Visayan + + + + info:lc/vocabulary/languages/cel + Celtic (Other) + cel + + Celtiberian + + Celti-Iberian + + + Celto-Iberian + + + + Gaulish + + Gallic + + + + Proto-Celtic + + Common Celtic + + + + Welsh, Middle (ca. 1100-1400) + + Middle Welsh (ca. 1100-1400) + + + + Welsh, Old (to 1100) + + Old Welsh (to 1100) + + + + + info:lc/vocabulary/languages/cai + Central American Indian (Other) + cai + + Use for the other languages of Central America and Mexico, as well as for the + languages of the Azteco-Tanoan language phylum. + + + Amuzgo + + Amishgo + + + + Boruca + + Brunka + + + Burunca + + + + Bribri + + + Cabecar + + + Cahita + + + Cahuilla + + Coahuila + + + Kawia (Shoshone) + + + + Chatino + + + Chiapanec + + + Chinantecan languages + + + Chocho + + + Chontal + + Tequistlateca + + + + Cochimi + + + Comanche + + + Cora + + Chora + + + Nayarita + + + + Cuicatec + + + Cuitlateco + + Teco (Cuitlateco) + + + + Cupeño + + + Eudeve + + Batuco + + + Dohema + + + Hegue + + + + Garifuna + + Black Carib + + + Carib, Black + + + + Guarijío + + Huarijío + + + Warijío + + + + Guatuso + + Maléku Jaíka + + + + Guaymi + + + Hopi + + Moki + + + + Huave + + + Huichol + + Guichola + + + + Ixcateco + + + Jicaque + + Tol + + + Torrupan + + + Xicaque + + + + Kawaiisu + + + Kiowa + + Kayowe + + + + Lenca + + + Mangue + + Choluteca + + + + Matagalpa + + Cacaopera + + + + Mayo (Piman) + + + Mazateco + + + Miskito + + Mosquito + + + + Mixe + + Ayook + + + + Mixtec + + + Opata + + + Panamint + + Coso + + + Koso + + + Tümpisa + + + + Pima + + + Popoloca + + + Rama + + + Seri + + + Serrano + + Maarrenga'twich + + + + Shoshoni + + + Sierra Popoluca + + Highland Popoluca + + + Popoluca, Highland + + + Popoluca of Vera Cruz + + + + Southern Paiute + + Paiute, Southern + + + + Sumo + + + Tarahumara + + Rarámuri + + + + Tarascan + + Michoacana + + + Phurhembe + + + Purepecha + + + + Tepehuan + + O'dam + + + + Terraba + + Teribe + + + Tirribi + + + + Tewa + + + Tlapanec + + Chocho (Tlapanec) + + + Tiapaneco + + + + Tohono O'odham + + Papago + + + + Totonac + + + Trique + + + Ulva + + Woolwa + + + Wulwa + + + + Ute + + + Yaqui + + + Zoque + + Soke + + + + + info:lc/vocabulary/languages/chg + Chagatai + chg + + Dschagatai + + + Jagataic + + + Old Uzbek + + + Tschagatai + + + Uzbek, Old + + + + info:lc/vocabulary/languages/cmc + Chamic languages + cmc + + Cham + + Čam + + + + Haroi + + + Jarai + + + Rade + + Ede + + + Rhade + + + + Roglai + + + + info:lc/vocabulary/languages/cha + Chamorro + cha + + Tjamoro + + + + info:lc/vocabulary/languages/che + Chechen + che + + Tchetchen + + + + info:lc/vocabulary/languages/chr + Cherokee + chr + + + info:lc/vocabulary/languages/chy + Cheyenne + chy + + + info:lc/vocabulary/languages/chb + Chibcha + chb + + + info:lc/vocabulary/languages/chi + Chinese + chi + + Cantonese + + + Mandarin + + + + info:lc/vocabulary/languages/chn + Chinook jargon + chn + + Chinook pidgin + + + + info:lc/vocabulary/languages/chp + Chipewyan + chp + + Dene (Chipewyan) + + + Montagnais (Athapascan) + + + + info:lc/vocabulary/languages/cho + Choctaw + cho + + Chahta + + + + info:lc/vocabulary/languages/chu + Church Slavic + chu + + Bulgarian, Old (to 1100) + + + Old Bulgarian (to 1100) + + + Old Church Slavic + + + Old Slovenian + + + Slavonic, Old Church + + + Slovenian, Old + + + + info:lc/vocabulary/languages/chk + Chuukese + chk + + Truk + + + + info:lc/vocabulary/languages/chv + Chuvash + chv + + + info:lc/vocabulary/languages/cop + Coptic + cop + + + info:lc/vocabulary/languages/cor + Cornish + cor + + + info:lc/vocabulary/languages/cos + Corsican + cos + + Corse + + + Corsi + + + Corso + + + Corsu + + + + info:lc/vocabulary/languages/cre + Cree + cre + + Cris + + + Knistenaux + + + Maskegon + + + + info:lc/vocabulary/languages/mus + Creek + mus + + Maskoki + + + Muscogee + + + + info:lc/vocabulary/languages/crp + Creoles and Pidgins (Other) + crp + + Pidgins + + + Ambonese Malay + + Malay, Ambonese + + + + Betawi + + Batawi + + + Jakarta Malay + + + Malay, Jakarta + + + + Chabacano + + Chavacano + + + Zamboangueño + + + + Fanakalo + + Fanagalo + + + Pidgin Kaffir + + + + Kituba (Congo (Democratic Republic)) + + Kibulamatadi + + + Kikongo Commercial + + + Kikongo-Kutuba + + + Kikongo Simplifié + + + Kikongo ya Leta + + + Kikwango + + + Kileta + + + + Naga Pidgin + + Nagamese + + + + San Basilio del Palenque Spanish Creole + + Palenquero (Colombia) + + + Spanish Creole, San Basilio del Palenque + + + + Unami jargon + + + + info:lc/vocabulary/languages/cpe + Creoles and Pidgins, English-based (Other) + cpe + + Bamyili Creole + + + Djuka + + Aucaans + + + Aukan + + + Djoeka + + + Ndjuka + + + + English-based Creoles and Pidgins (Other) + + + Fitzroy Valley Kriol + + + Hawaiian Pidgin English + + + Jamaican Creole + + + Krio + + Aku (Creole) + + + + Kriol + + + Pijin + + Neo-Solomonic + + + Solomons Pidgin + + + + Pidgin English + + + Saramaccan + + + Sea Islands Creole + + Geechee + + + Gullah + + + + + info:lc/vocabulary/languages/cpf + Creoles and Pidgins, French-based (Other) + cpf + + French-based Creoles and Pidgins (Other) + + + Dominican French Creole + + French Creole, Dominican + + + + Louisiana French Creole + + French Creole, Louisiana + + + + Mauritian French Creole + + French Creole, Mauritian + + + + Michif + + Cree, French + + + French Cree + + + Mitchif + + + + Reunionese French Creole + + French Creole, Reunionese + + + + Seychellois French Creole + + French Creole, Seychellois + + + + + info:lc/vocabulary/languages/cpp + Creoles and Pidgins, Portuguese-based (Other) + cpp + + Portuguese-based Creoles and Pidgins (Other) + + + Annobon + + Ambu + + + + Cape Verde Creole + + Brava Island Creole + + + + Crioulo + + + Indo-Portuguese + + Ceylon Portuguese + + + + + info:lc/vocabulary/languages/crh + Crimean Tatar + crh + + Crimean Turkish + + + Tatar, Crimean + + + Turkish, Crimean + + + + info:lc/vocabulary/languages/hrv + Croatian + hrv + + + info:lc/vocabulary/languages/scr + Croatian + scr + + + info:lc/vocabulary/languages/cus + Cushitic (Other) + cus + + Alaba + + Alaaba + + + Allaaba + + + Halaba + + + + Burji + + + Dasenech + + Geleb + + + Marille + + + + Gedeo + + Darasa + + + Derasa + + + + Hadiya + + + Iraqw + + + Kambata + + + Qebena + + K'abena + + + Kebena + + + Qabena + + + Womba + + + Wombi Afoo + + + Wombisanat + + + + Rendille + + + Tunni + + + + info:lc/vocabulary/languages/cze + Czech + cze + + Bohemian + + + + info:lc/vocabulary/languages/dak + Dakota + dak + + Sioux + + + Assiniboine + + + Lakota + + Teton + + + + Santee + + + Yankton + + + + info:lc/vocabulary/languages/dan + Danish + dan + + + info:lc/vocabulary/languages/dar + Dargwa + dar + + Darghi + + + Dargin + + + + info:lc/vocabulary/languages/day + Dayak + day + + Bidayuh + + + Bideyu + + + Dajak + + + Dyak + + + Kendayan + + + Land Dayak + + + Biatah + + + + info:lc/vocabulary/languages/del + Delaware + del + + Lenape + + + Lenni Lenape + + + Munsee + + Minsi + + + + + info:lc/vocabulary/languages/din + Dinka + din + + Denca + + + + info:lc/vocabulary/languages/div + Divehi + div + + Dhivehi + + + Maldivian + + + + info:lc/vocabulary/languages/doi + Dogri + doi + + Dhogaryali + + + Dogari + + + Dogra + + + Dogri Jammu + + + Dogri-Kangri + + + Dogri Pahari + + + Dongari + + + Hindi Dogri + + + Tokkaru + + + Kangri + + Kangari + + + Kangra + + + + + info:lc/vocabulary/languages/dgr + Dogrib + dgr + + Thlingchadinne + + + + info:lc/vocabulary/languages/dra + Dravidian (Other) + dra + + Abujhmaria + + + Alu Kurumba + + + Brahui + + Berouhi + + + Birohi + + + Brohki + + + + Gadaba (Dravidian) + + Gadba (Dravidian) + + + Gudwa (Dravidian) + + + Gutob (Dravidian) + + + Konekor Gadaba + + + Ollari + + + Salur + + + + Kodagu + + Coorg + + + Kodava + + + Kurg + + + + Kolami + + + Kota (India) + + + Kui + + Kandh + + + + Kuvi + + + Malto + + + Pengo + + + Toda (India) + + Tuda (India) + + + + Tulu + + + + info:lc/vocabulary/languages/dua + Duala + dua + + Douala + + + + info:lc/vocabulary/languages/dut + Dutch + dut + + Flemish + + + Netherlandic + + + + info:lc/vocabulary/languages/dum + Dutch, Middle (ca. 1050-1350) + dum + + Diets + + + Middle Dutch + + + + info:lc/vocabulary/languages/dyu + Dyula + dyu + + Dioula + + + Diula + + + Jula + + + + info:lc/vocabulary/languages/dzo + Dzongkha + dzo + + Bhotia of Bhutan + + + Bhutanese + + + + info:lc/vocabulary/languages/frs + East Frisian + frs + + Frisian, East + + + + info:lc/vocabulary/languages/bin + Edo + bin + + Bini + + + + info:lc/vocabulary/languages/efi + Efik + efi + + Calabar + + + Ibibio + + + + info:lc/vocabulary/languages/egy + Egyptian + egy + + Demotic + + + Hieratic + + + Hieroglyphics (Egyptian) + + + + info:lc/vocabulary/languages/eka + Ekajuk + eka + + + info:lc/vocabulary/languages/elx + Elamite + elx + + Amardic + + + Anzanic + + + Susian + + + + info:lc/vocabulary/languages/eng + English + eng + + + info:lc/vocabulary/languages/enm + English, Middle (1100-1500) + enm + + Middle English + + + + info:lc/vocabulary/languages/ang + English, Old (ca. 450-1100) + ang + + Anglo-Saxon + + + Old English + + + West Saxon + + + + info:lc/vocabulary/languages/myv + Erzya + myv + + + info:lc/vocabulary/languages/esk + Eskimo languages + esk + + + info:lc/vocabulary/languages/epo + Esperanto + epo + + + info:lc/vocabulary/languages/esp + Esperanto + esp + + + info:lc/vocabulary/languages/est + Estonian + est + + Seto + + Setu + + + + Võro + + Võru + + + Werro + + + + + info:lc/vocabulary/languages/gez + Ethiopic + gez + + Geez + + + + info:lc/vocabulary/languages/eth + Ethiopic + eth + + + info:lc/vocabulary/languages/ewe + Ewe + ewe + + + info:lc/vocabulary/languages/ewo + Ewondo + ewo + + Jaunde + + + Yaounde + + + Yaunde + + + + info:lc/vocabulary/languages/fan + Fang + fan + + Fan (Bantu) + + + + info:lc/vocabulary/languages/fat + Fanti + fat + + + info:lc/vocabulary/languages/fao + Faroese + fao + + Faeroese + + + + info:lc/vocabulary/languages/far + Faroese + far + + + info:lc/vocabulary/languages/fij + Fijian + fij + + Viti + + + + info:lc/vocabulary/languages/fil + Filipino + fil + + + info:lc/vocabulary/languages/fin + Finnish + fin + + + info:lc/vocabulary/languages/fiu + Finno-Ugrian (Other) + fiu + + Ingrian + + Izhorskii + + + + Khanty + + Ostiak + + + Xanty + + + + Livonian + + + Ludic + + Lydi + + + + Mansi + + Vogul + + + + Mordvin + + Mordva + + + Mordvinian + + + + Veps + + + + info:lc/vocabulary/languages/fon + Fon + fon + + Dahoman + + + Djedji + + + Jeji + + + + info:lc/vocabulary/languages/fre + French + fre + + Allevard French + + French, Allevard + + + + Judeo-French + + Western Loez + + + Zarphatic + + + + Morvan French + + French, Morvan + + + + Poitevin French + + French, Poitevin + + + + Saintongeais French + + French, Saintongeais + + + + + info:lc/vocabulary/languages/frm + French, Middle (ca. 1300-1600) + frm + + Middle French + + + + info:lc/vocabulary/languages/fro + French, Old (ca. 842-1300) + fro + + Old French + + + + info:lc/vocabulary/languages/fry + Frisian + fry + + Friesian + + + West Frisian + + + Stadsfries + + Stadfries + + + Stedsk + + + Town Frisian + + + + + info:lc/vocabulary/languages/fri + Frisian + fri + + + info:lc/vocabulary/languages/fur + Friulian + fur + + + info:lc/vocabulary/languages/ful + Fula + ful + + Adamawa + + + Fulah + + + Fulani + + + Fulbe + + + Fulfulde + + + Peul + + + Poul + + + Bororo (West Africa) + + + Pular + + Poular + + + Toucouleur + + + Tukolor + + + + + info:lc/vocabulary/languages/gaa + + gaa + + Acra + + + Incran + + + + info:lc/vocabulary/languages/glg + Galician + glg + + Gallegan + + + + info:lc/vocabulary/languages/gag + Galician + gag + + + info:lc/vocabulary/languages/lug + Ganda + lug + + Luganda + + + + info:lc/vocabulary/languages/gay + Gayo + gay + + + info:lc/vocabulary/languages/gba + Gbaya + gba + + Baya + + + Gbeya + + + + info:lc/vocabulary/languages/geo + Georgian + geo + + Ingilo + + + + info:lc/vocabulary/languages/ger + German + ger + + Hochdeutsch + + + Alemannic + + Alamannic + + + Alemannisch + + + Allemannic + + + Allemannisch + + + Alsatian + + + Schwyzerdütsch + + + + Cimbrian + + Tzimbro + + + Zimbrisch + + + + + info:lc/vocabulary/languages/gmh + German, Middle High (ca. 1050-1500) + gmh + + Middle High German + + + + info:lc/vocabulary/languages/goh + German, Old High (ca. 750-1050) + goh + + Old High German + + + + info:lc/vocabulary/languages/gem + Germanic (Other) + gem + + Danish, Old (to 1500) + + Old Danish + + + + Dutch, Old (to 1050) + + Franconian, Old Low + + + Old Dutch + + + Old Low Franconian + + + + Frisian, Old (to 1500) + + Old Frisian + + + + Lombard + + + Old Saxon + + Low German, Old (ca. 850-1050) + + + Old Low German (ca. 850-1050) + + + Saxon, Old + + + + Pennsylvania German + + + Swedish, Old (to 1550) + + Old Swedish + + + + Walser + + + + info:lc/vocabulary/languages/gil + Gilbertese + gil + + Arorai + + + I-Kiribati + + + Kiribatese + + + + info:lc/vocabulary/languages/gon + Gondi + gon + + + info:lc/vocabulary/languages/gor + Gorontalo + gor + + + info:lc/vocabulary/languages/got + Gothic + got + + + info:lc/vocabulary/languages/grb + Grebo + grb + + Gdebo + + + Gedebo + + + Krebo + + + + info:lc/vocabulary/languages/grc + Greek, Ancient (to 1453) + grc + + Ancient Greek + + + Biblical Greek + + + Byzantine Greek + + + Classical Greek + + + Greek, Biblical + + + Greek, Byzantine + + + Greek, Classical + + + Greek, Hellenistic + + + Greek, Medieval + + + Greek, Patristic + + + Greek (Koine) + + + Hellenistic Greek + + + Koine (Greek) + + + Medieval Greek + + + Patristic Greek + + + Aeolic Greek + + Greek, Aeolic + + + + Attic Greek + + Greek, Attic + + + + Doric Greek + + Greek, Doric + + + + Ionic Greek + + Greek, Ionic + + + + + info:lc/vocabulary/languages/gre + Greek, Modern (1453- ) + gre + + East Cretan Greek + + Cretan Greek, East + + + Greek, East Cretan + + + + + info:lc/vocabulary/languages/grn + Guarani + grn + + Chiriguano + + Aba + + + Camba + + + Tembeta + + + + Chiripá + + Tsiripa + + + + Mbya + + + + info:lc/vocabulary/languages/gua + Guarani + gua + + + info:lc/vocabulary/languages/guj + Gujarati + guj + + Dhodia + + Dhobi + + + Dhoḍiyā + + + Dhore + + + Dhowari + + + Doria + + + + Gamit + + Gamati + + + Gāmīta + + + Gamta + + + Gavit + + + + Halari + + + Parsi-Gujarati + + + Saurashtri + + Patanuli + + + Patnuli + + + Saurashtra + + + Saurastra + + + Sawrashtra + + + Sourashtra + + + Sowrashtra + + + + Sidi + + + + info:lc/vocabulary/languages/gwi + Gwich'in + gwi + + Kutchin + + + Loucheux + + + Takudh + + + Tukudh + + + + info:lc/vocabulary/languages/hai + Haida + hai + + Skittagetan + + + + info:lc/vocabulary/languages/hat + Haitian French Creole + hat + + French Creole, Haitian + + + + info:lc/vocabulary/languages/hau + Hausa + hau + + + info:lc/vocabulary/languages/haw + Hawaiian + haw + + + info:lc/vocabulary/languages/heb + Hebrew + heb + + Ancient Hebrew + + + + info:lc/vocabulary/languages/her + Herero + her + + Himba + + Chimba + + + Cimba + + + Dhimba + + + Simba + + + Tjimba + + + + + info:lc/vocabulary/languages/hil + Hiligaynon + hil + + Ilongo + + + Panayan + + + + info:lc/vocabulary/languages/hin + Hindi + hin + + Badayuni + + + Bagheli + + Bagelkhandi + + + Bhugelkhud + + + Ganggai + + + Kawathi + + + Kenat + + + Kevat Boli + + + Kevati + + + Kewani + + + Kewat + + + Kewati + + + Kewot + + + Mandal + + + Mannadi + + + Riwai + + + + Bangaru + + Hariani + + + Jatu + + + + Bundeli + + Bundelkhandi + + + + Chattisgarhi + + Chhattisgarhi + + + Khalṭāhī + + + Khatahi + + + Laria + + + + Deswali + + + Kanauji + + Bhakha + + + Braj Kanauji + + + Kannaujī + + + + Khari Boli + + Kauravī + + + Khaṛībolī + + + Kourvi + + + + Marari + + + Pawari + + + Powari + + Povārī + + + + + info:lc/vocabulary/languages/hmo + Hiri Motu + hmo + + Police Motu + + + + info:lc/vocabulary/languages/hit + Hittite + hit + + + info:lc/vocabulary/languages/hmn + Hmong + hmn + + Humung + + + Meo + + + Miao + + + Mong + + + Hmong Njua + + Black Flowery Miao + + + Blue Miao + + + Green Hmong + + + Green Miao + + + Green Mong + + + Hmong Leng + + + Moob Ntsuab + + + Tak Meo + + + + She + + Ho Ne + + + Ho Nte + + + Huo Nte + + + She Yao + + + + White Hmong + + Hmong, White + + + Hmong Daw + + + Hmoob Dawb + + + Miao, White + + + White Miao + + + + + info:lc/vocabulary/languages/hun + Hungarian + hun + + Magyar + + + + info:lc/vocabulary/languages/hup + Hupa + hup + + + info:lc/vocabulary/languages/iba + Iban + iba + + Sea Dyak + + + + info:lc/vocabulary/languages/ice + Icelandic + ice + + + info:lc/vocabulary/languages/ido + Ido + ido + + + info:lc/vocabulary/languages/ibo + Igbo + ibo + + Ibo + + + + info:lc/vocabulary/languages/ijo + Ijo + ijo + + Djo + + + Dzo + + + Ejo + + + Ido (African) + + + Iyo (Nigeria) + + + Izo + + + Izon + + + Ojo + + + Oru + + + Udzo + + + Uzo + + + Ibani + + Bonny + + + Ubani + + + + Nembe + + Nimbi + + + + + info:lc/vocabulary/languages/ilo + Iloko + ilo + + Ilocano + + + + info:lc/vocabulary/languages/smn + Inari Sami + smn + + Finnish Lapp + + + Lapp, Finnish + + + Sami, Inari + + + + info:lc/vocabulary/languages/inc + Indic (Other) + inc + + Adiwasi Garasia + + Adivasi Garasia + + + Ādivāsī Garāsiyā + + + Adiwasi Girasia + + + Adiwasi Gujarati + + + Garasia Adivasi + + + + Ahirani + + Ahiri + + + + Apabhraṃśa + + Apabhramsha + + + + Avahattha + + + Bashgali + + Bashgal + + + Bashgari + + + Kamtoz + + + Katai + + + Kati + + + + Bhili + + + Bote-Majhi + + Bote-Mahi + + + Kushar + + + Pakhe-Bote + + + + Chakma + + + Changari + + + Chinali + + Chana (India) + + + Channali + + + Chinal + + + Dagi + + + Harijan + + + Shipi + + + + Danuwar Rai + + Denwar + + + Dhanvar + + + Dhanwar + + + Donwar + + + + Darai + + + Dehawali + + Dehavali + + + Dehwali + + + + Domaaki + + Bericho + + + Dom + + + Doma + + + Dumaki + + + + Dungra Bhil + + Dungari Bhili + + + Dungri Bhili + + + + Fiji Hindi + + Hindi, Fiji + + + + Garasiya + + Garahaiya + + + Girasia + + + + Garhwali + + Gadhavali + + + Gadhawala + + + Gadwahi + + + Gashwali + + + Girwali + + + Godauli + + + Gorwali + + + Gurvali + + + Pahari Garhwali + + + + Halbi + + Bastari + + + + Hindustani + + + Indus Kohistani + + Khili + + + Kohistani, Indus + + + Kohiste + + + Mair + + + Maiya + + + Maiyan + + + Maiyon + + + Shuthun + + + + Kalami + + Bashgharik + + + Bashkarik + + + Dir Kohistani + + + Diri (Kalami) + + + Dirwali + + + Gaawro + + + Garwa + + + Garwi + + + Gawri + + + Gowri + + + Kalam Kohistani + + + Kalami Kohistani + + + Kohistana + + + Kohistani, Dir + + + Kohistani, Kalam + + + Kohistani, Kalami + + + + Khandesi + + Dhed Gujari + + + Khandeshi + + + Khandish + + + + Khowar + + + Kumaoni + + Kamaoni + + + Kumau + + + Kumauni + + + Kumawani + + + Kumgoni + + + Kumman + + + Kunayaoni + + + + Kupia + + Valmiki + + + + Mawchi + + Mauchi + + + Māvacī + + + Mavchi + + + Mawachi + + + Mawchi Bhil + + + Mowchi + + + + Memoni + + + Parya + + Tajuzbeki + + + + Rajbangsi + + Kamtapuri + + + Rajbanshi + + + Rajbansi + + + Rajbongshi + + + + Rathvi + + Rāthavi + + + Rathwi + + + + Shina + + Sheena + + + Sina + + + + Suriname Hindustani + + Aili-Gaili + + + Hindustani, Suriname + + + Surinam Hindustani + + + Sarnami Hindi + + + + Tharu + + + Vaagri Boli + + + Veddah (Sinhalese) + + + Waigali + + Kalaṣa-alā + + + Vaigalī + + + Wai + + + Wai-alā + + + Waigelī + + + + Wotapuri-Katarqalai + + Katarqalai + + + + + info:lc/vocabulary/languages/ine + Indo-European (Other) + ine + + Carian + + + Dacian + + Daco-Mysian + + + North Thracian + + + + Luwian + + Luian + + + Lûish + + + Luvian + + + + Lycian + + + Lydian + + + Macedonian (Ancient) + + + Messapic + + Iapygian + + + Messapian + + + + Palaic + + Balaic + + + Palâ (Palaic) + + + Palaite + + + Palawi + + + + Phrygian + + + Proto-Indo-European + + Proto-Aryan + + + Protoindoeuropean + + + + Thracian + + + Tokharian + + Kuchean + + + Tocharian + + + Tocharish + + + Turfanish + + + + Venetic + + + Yuezhi + + Yüeh-chih + + + + + info:lc/vocabulary/languages/ind + Indonesian + ind + + Bahasa Indonesia + + + + info:lc/vocabulary/languages/inh + Ingush + inh + + + info:lc/vocabulary/languages/ina + Interlingua (International Auxiliary Language Association) + ina + + + info:lc/vocabulary/languages/int + Interlingua (International Auxiliary Language Association) + int + + + info:lc/vocabulary/languages/ile + Interlingue + ile + + Occidental + + + + info:lc/vocabulary/languages/iku + Inuktitut + iku + + Inuit + + + Inuvialuktun + + + Kopagmiut + + Chiglit + + + Siglit + + + + + info:lc/vocabulary/languages/ipk + Inupiaq + ipk + + Inuit + + + + info:lc/vocabulary/languages/ira + Iranian (Other) + ira + + Bactrian + + + Badzhuv + + Badschu + + + Badžū + + + Bāǰūī + + + + Bakhtiari + + Bakhtiyārī + + + Baxtīarī + + + Lori + + + Lori-ye Khaveri + + + Lur (Bakhtiari) + + + Luri (Bakhtiari) + + + + Bartang + + Bartangi + + + + Ephthalite + + Hephthalite + + + + Gilaki + + Gelaki + + + Gilan + + + + Gorani + + Awromani + + + Gurani + + + Hawramani + + + Hawrami + + + Hewrami + + + Howrami + + + Macho + + + + Hazaragi + + Azargi + + + Hazara + + + Hezareh + + + Hezareʼi + + + Khazara + + + Khezare + + + + Ishkashmi + + + Judeo-Tat + + Bik + + + Dzhuhuric + + + Hebrew Tat + + + Hebrew Tati + + + Jew-Tatish + + + Jewish Tat + + + Judeo-Tatic + + + + Khorezmi + + Choresmian + + + Khwarezmian + + + + Khuf + + Chuf + + + + Laki (Iran) + + Alaki + + + Leki + + + + Māzandarānī + + Mazanderani + + + Tabri + + + + Median + + Medic + + + + Munji + + Mundzhan + + + Munjani + + + + Natanzi + + Naṭanz + + + + Ormuri + + Baraks + + + Bargista + + + + Parthian + + + Roshan + + Rochani + + + Ruschan + + + + Sarikoli + + Sarykoli + + + + Sarmatian + + + Shughni + + Shugnan-Rushan + + + + Sivandi + + Sivendi + + + + Talysh + + + Tat + + + Wakhi + + + Yaghnobi + + Neo-Sogdian + + + Yaghnabi + + + Yaghnubi + + + Yagnabi + + + Yagnob + + + Yagnobi + + + Yagnubi + + + + Yazghulami + + + Zebaki + + Sanglici + + + + + info:lc/vocabulary/languages/gle + Irish + gle + + Erse (Irish) + + + Gaelic (Irish) + + + Irish Gaelic + + + + info:lc/vocabulary/languages/iri + Irish + iri + + + info:lc/vocabulary/languages/mga + Irish, Middle (ca. 1100-1550) + mga + + Middle Irish + + + + info:lc/vocabulary/languages/sga + Irish, Old (to 1100) + sga + + Old Irish + + + + info:lc/vocabulary/languages/iro + Iroquoian (Other) + iro + + Cayuga + + + Iroquois + + + Oneida + + + Onondaga + + + Seneca + + + Tuscarora + + + Wyandot + + Huron + + + + + info:lc/vocabulary/languages/ita + Italian + ita + + Judeo-Italian + + + Milanese + + + Modena Italian + + Italian, Modena + + + + Romagnol + + + Venetian Italian + + Italian, Venetian + + + + + info:lc/vocabulary/languages/jpn + Japanese + jpn + + Use for related Japanese languages and dialects + + + + info:lc/vocabulary/languages/jav + Javanese + jav + + + info:lc/vocabulary/languages/jrb + Judeo-Arabic + jrb + + + info:lc/vocabulary/languages/jpr + Judeo-Persian + jpr + + Judeo-Tajik + + + + info:lc/vocabulary/languages/kbd + Kabardian + kbd + + Cabardan + + + Circassian, East + + + Circassian, Upper + + + East Circassian + + + Qabardian + + + Upper Circassian + + + + info:lc/vocabulary/languages/kab + Kabyle + kab + + + info:lc/vocabulary/languages/kac + Kachin + kac + + Chingpaw + + + Jingpho + + + + info:lc/vocabulary/languages/kal + Kalâtdlisut + kal + + Ammassalimiut + + East Greenlandic + + + Greenlandic, East + + + Tunumiisut + + + + Greenlandic + + + Inuit + + + Kalaallisut + + + + info:lc/vocabulary/languages/kam + Kamba + kam + + + info:lc/vocabulary/languages/kan + Kannada + kan + + Canarese + + + Kanarese + + + Havyaka + + + + info:lc/vocabulary/languages/kau + Kanuri + kau + + Bornu + + + + info:lc/vocabulary/languages/krc + Karachay-Balkar + krc + + Balkar + + + + info:lc/vocabulary/languages/kaa + Kara-Kalpak + kaa + + Karakalpak + + + Qaraqalpaq + + + + info:lc/vocabulary/languages/krl + Karelian + krl + + Carelian + + + + info:lc/vocabulary/languages/kar + Karen languages + kar + + Kayah + + Karen, Red + + + Red Karen + + + + Pwo Karen + + + Sgaw Karen + + + Taungthu + + Pa-o + + + + + info:lc/vocabulary/languages/kas + Kashmiri + kas + + + info:lc/vocabulary/languages/csb + Kashubian + csb + + Cashubian + + + + info:lc/vocabulary/languages/kaw + Kawi + kaw + + Javanese, Old + + + Old Javanese + + + + info:lc/vocabulary/languages/kaz + Kazakh + kaz + + Kirghiz-Kaissak + + + + info:lc/vocabulary/languages/kha + Khasi + kha + + + info:lc/vocabulary/languages/khm + Khmer + khm + + Cambodian + + + Central Khmer + + + + info:lc/vocabulary/languages/cam + Khmer + cam + + + info:lc/vocabulary/languages/khi + Khoisan (Other) + khi + + Ju/'hoan + + !Xũ (!Kung) + + + Zjuc'hôa + + + Žu/'hõasi + + + + Khoikhoi + + Hottentot + + + + Korana + + + Nama + + + Nharo + + Naro + + + + San languages + + Bushman languages + + + + !Xõ + + Gxon + + + Hua-owani + + + !Kõ (Botswana and Namibia) + + + Koon + + + Magong + + + !Xong (Botswana and Namibia) + + + + + info:lc/vocabulary/languages/kho + Khotanese + kho + + Khotan-Saka + + + Khotanese-Sakan + + + Khotani + + + Khotansaka + + + Middle Khotanese + + + North Aryan + + + Old Khotanese + + + Saka + + + Sakan + + + + info:lc/vocabulary/languages/kik + Kikuyu + kik + + Gikuyu + + + + info:lc/vocabulary/languages/kmb + Kimbundu + kmb + + Angola + + + Bunda + + + Mbundu (Luanda Province, Angola) + + + Nbundu + + + Quimbundo (Luanda Province, Angola) + + + + info:lc/vocabulary/languages/kin + Kinyarwanda + kin + + Nyaruanda + + + Ruanda + + + Runyarwanda + + + Rwanda + + + Rufumbira + + + + info:lc/vocabulary/languages/tlh + Klingon (Artificial language) + tlh + + + info:lc/vocabulary/languages/kom + Komi + kom + + Syryenian + + + Zyrian + + + Komi-Permyak + + Permiak + + + + + info:lc/vocabulary/languages/kon + Kongo + kon + + Congo + + + Kikongo + + + Kituba (Congo (Brazzaville)) + + Kikoongo (Kituba (Congo (Brazzaville))) + + + Munukutuba + + + + Laadi + + Kilari + + + + Manyanga + + Kimanyanga + + + Kisi-Ngóombe + + + Manianga + + + + Ntaandu + + Kintaandu + + + Kisantu + + + Santu + + + + Vili + + Civili + + + Fiot + + + Fiote + + + Ki-vili + + + Ki-vumbu + + + Kivili + + + Kivumbu + + + Loango + + + Lu-wumbu + + + Luwumbu + + + Tsivili + + + + Zombo + + + + info:lc/vocabulary/languages/kok + Konkani + kok + + Concani + + + Komkani + + + Koṅkṇi + + + Agri + + Agari + + + + Chitapavani + + Chitpavani + + + Citpāvanī + + + + Jhāḍī + + + Kudali + + Malvani + + + + + info:lc/vocabulary/languages/kut + Kootenai + kut + + Kutenai + + + + info:lc/vocabulary/languages/kor + Korean + kor + + Use for related Korean languages and dialects + + + + info:lc/vocabulary/languages/kos + Kosraean + kos + + Kosrae + + + Kusaie + + + Kusaiean + + + + info:lc/vocabulary/languages/kpe + Kpelle + kpe + + Guerzé + + + + info:lc/vocabulary/languages/kro + Kru (Other) + kro + + Bete + + + Dadjriwalé + + Dadjrignoa + + + Dagli + + + Dajriwali + + + + Dida + + Wawi + + + + Godié + + Go (Côte d'Ivoire) + + + Godia + + + Godye + + + + Kru + + + Kuwaa + + Belle + + + Belleh + + + Kowaao + + + Kwaa + + + + Neyo + + Gwibwen + + + Néouolé + + + Néyau + + + Niyo + + + Towi + + + + Ngere + + Gere + + + Guéré + + + + Nyabwa + + Niaboua + + + + Tchien + + Gien + + + Kien + + + Tie + + + + Tepo + + Kroumen + + + Tewi + + + + Wobe + + Ouobe + + + + + info:lc/vocabulary/languages/kua + Kuanyama + kua + + Cuanhama + + + Kwanyama + + + Ovambo (Kuanyama) + + + + info:lc/vocabulary/languages/kum + Kumyk + kum + + + info:lc/vocabulary/languages/kur + Kurdish + kur + + Kurmanji + + + Mukri + + + + info:lc/vocabulary/languages/kru + Kurukh + kru + + Kurux + + + Oraon + + + Uraon + + + + info:lc/vocabulary/languages/kus + Kusaie + kus + + + info:lc/vocabulary/languages/kir + Kyrgyz + kir + + Kara-Kirghiz + + + Kirghiz + + + + info:lc/vocabulary/languages/lad + Ladino + lad + + Judeo-Spanish + + + Judesmo + + + Ḥakétia + + Ḥakétie + + + Haketiya + + + Ḥakitía + + + Haquetía + + + Haquetiya + + + + + info:lc/vocabulary/languages/lah + Lahndā + lah + + Jaṭkī + + + Lahndi + + + Panjabi, Western + + + Western Panjabi + + + Hindkōo + + + Khetrānī + + + Pōṭhwārī + + + Siraiki + + Bahawalpuri + + + Lahnda, Southern + + + Multani + + + Mutani + + + Panjabi, Southern + + + Reasati + + + Riasati + + + Saraiki + + + Southern Lahnda + + + Southern Panjabi + + + + Sirāikī Hindkī + + Siraiki Lahndi + + + + Sirāikī Sindhī + + Sindhi, Siraiki + + + + + info:lc/vocabulary/languages/lam + Lamba (Zambia and Congo) + lam + + + info:lc/vocabulary/languages/lao + Lao + lao + + + info:lc/vocabulary/languages/lat + Latin + lat + + Latin, Vulgar + + + Vulgar Latin + + + + info:lc/vocabulary/languages/lav + Latvian + lav + + Lettish + + + Latgalian + + East Latvian + + + High Latvian + + + Letgalian + + + + + info:lc/vocabulary/languages/lez + Lezgian + lez + + + info:lc/vocabulary/languages/lim + Limburgish + lim + + Limburger + + + + info:lc/vocabulary/languages/lin + Lingala + lin + + Bangala (Congo) + + + Mangala (Congo) + + + Ngala (Congo) + + + + info:lc/vocabulary/languages/lit + Lithuanian + lit + + + info:lc/vocabulary/languages/jbo + Lojban (Artificial language) + jbo + + + info:lc/vocabulary/languages/nds + Low German + nds + + German, Low + + + Low Saxon + + + Plattdeutsch + + + Plautdietsch + + + Saxon, Low + + + + info:lc/vocabulary/languages/dsb + Lower Sorbian + dsb + + Sorbian, Lower + + + + info:lc/vocabulary/languages/loz + Lozi + loz + + Kololo + + + Rozi + + + Sikololo + + + + info:lc/vocabulary/languages/lub + Luba-Katanga + lub + + Chiluba + + + Katanga + + + + info:lc/vocabulary/languages/lua + Luba-Lulua + lua + + Ciluba + + + Kalebwe (Luba-Lulua) + + + Luba, Western + + + Luba-Kasai + + + Western Luba + + + + info:lc/vocabulary/languages/lui + Luiseño + lui + + + info:lc/vocabulary/languages/smj + Lule Sami + smj + + Lapp, Swedish + + + Sami, Lule + + + Swedish Lapp + + + + info:lc/vocabulary/languages/lun + Lunda + lun + + + info:lc/vocabulary/languages/luo + Luo (Kenya and Tanzania) + luo + + Dho Luo + + + Gaya + + + Jo Luo + + + Kavirondo, Nilotic + + + Nife + + + Nilotic Kavirondo + + + Nyife + + + Wagaya + + + + info:lc/vocabulary/languages/lus + Lushai + lus + + Dulien + + + Mizo + + + Sailau + + + + info:lc/vocabulary/languages/ltz + Luxembourgish + ltz + + Letzebuergesch + + + Letzeburgesch + + + Luxembourgeois + + + Luxemburgian + + + + info:lc/vocabulary/languages/mac + Macedonian + mac + + Bǎlgarski (Macedonian) + + + Balgàrtzki (Macedonian) + + + Bolgàrtski (Macedonian) + + + Bulgàrtski (Macedonian) + + + Dópia + + + Entópia + + + Macedonian Slavic + + + Makedoniski + + + Makedonski + + + Slavic (Macedonian) + + + Slaviká (Macedonian) + + + Slavomacedonian + + + + info:lc/vocabulary/languages/mad + Madurese + mad + + + info:lc/vocabulary/languages/mag + Magahi + mag + + Bihari (Magahi) + + + Magadhi + + + Magaya + + + Maghadi + + + Maghai + + + Maghaya + + + Maghori + + + Magi (India) + + + Magodhi + + + Megahi + + + + info:lc/vocabulary/languages/mai + Maithili + mai + + Apabhramsa (Maithili) + + + Bihari (Maithili) + + + Maitili + + + Maitli + + + Methli + + + Tirahutia + + + Tirhuti + + + Tirhutia + + + Khotta (Maithili) + + Eastern Maithili + + + Khoratha + + + + + info:lc/vocabulary/languages/mak + Makasar + mak + + Macassarese + + + + info:lc/vocabulary/languages/mlg + Malagasy + mlg + + Hova + + + Madagascan + + + Malgache + + + Merina + + + Bara (Madagascar) + + + Betsileo + + + Masikoro + + + Sakalava + + + Tsimihety + + + + info:lc/vocabulary/languages/mla + Malagasy + mla + + + info:lc/vocabulary/languages/may + Malay + may + + Palembang Malay + + + + info:lc/vocabulary/languages/mal + Malayalam + mal + + Malabar + + + Moplah + + + + info:lc/vocabulary/languages/mlt + Maltese + mlt + + + info:lc/vocabulary/languages/mnc + Manchu + mnc + + + info:lc/vocabulary/languages/mdr + Mandar + mdr + + Andian + + + + info:lc/vocabulary/languages/man + Mandingo + man + + Malinka + + + Mandeka + + + Maninka + + + Meninka + + + + info:lc/vocabulary/languages/mni + Manipuri + mni + + Meithei + + + + info:lc/vocabulary/languages/mno + Manobo languages + mno + + Agusan Manobo + + + Ata Manobo + + + Binukid Manobo + + Binokid + + + Bukidnon + + + + Cotabato Manobo + + + Dibabawon + + Debabaon + + + Dibabaon + + + Mandaya + + + + Higaonon + + + Ilianen Manobo + + + Kagayanen + + Cagayano Cillo + + + + Manuvu + + Bagobo, Upper + + + Upper Bagobo + + + + MatigSalug + + + Sarangani Manobo + + Culamanes + + + Kulaman + + + + Western Bukidnon Manobo + + Bukidnon Manobo, Western + + + Central Manobo + + + Central Mindanao Manobo + + + + + info:lc/vocabulary/languages/glv + Manx + glv + + Manx Gaelic + + + + info:lc/vocabulary/languages/max + Manx + max + + + info:lc/vocabulary/languages/mao + Maori + mao + + South Island Maori + + Maori, South Island + + + + + info:lc/vocabulary/languages/arn + Mapuche + arn + + Araucanian + + + Mapudungun + + + + info:lc/vocabulary/languages/mar + Marathi + mar + + Mahratta + + + Mahratti + + + Murathee + + + Are + + Ade Basha + + + Aray + + + Arrey + + + Arya + + + Kalika Arya Bhasha + + + + Koshti (Marathi) + + Kosti (Marathi) + + + + Kunabi + + + Varhadi Nagpuri + + Berar Marathi + + + Berari + + + Dhanagari + + + Kumbhari + + + Madhya Pradesh Marathi + + + Nagpuri (Varhadi Nagpuri) + + + Nagpuri-Varhadi + + + Varhadi-Nagpuri Marathi + + + + + info:lc/vocabulary/languages/chm + Mari + chm + + Cheremissian + + + + info:lc/vocabulary/languages/mah + Marshallese + mah + + Ebon + + + + info:lc/vocabulary/languages/mwr + Marwari + mwr + + Bikaneri + + + Dingal + + + Mewari + + Mevadi + + + Mewa + + + Mewadi + + + + Shekhawati + + Sekhavati + + + + + info:lc/vocabulary/languages/mas + Massai + mas + + Maa (Kenya and Tanzania) + + + Masai + + + + info:lc/vocabulary/languages/myn + Mayan languages + myn + + Achi + + Cubulco Achi + + + Rabinal Achi + + + + Akatek + + Acateco + + + Kanjobal, Western + + + San Miguel Acatán Kanjobal + + + Western Kanjobal + + + + Awakateko + + Aguacatec + + + + Cakchikel + + Kacchiquel + + + + Chol + + + Chontal of Tabasco + + + Chorti + + + Chuj + + + Huastec + + Guastec + + + Wastek + + + + Itzá + + + Ixil + + + Jacalteca + + Jakalteka + + + + Kanjobal + + Conob + + + + Kekchi + + Cacchi + + + Ghec-chi + + + Quekchi + + + + Lacandon + + + Mam + + Zaklohpakap + + + + Maya + + Yucatecan + + + + Mochó + + Motozintlec + + + + Mopan + + Manche + + + + Pokomam + + Pocomam + + + Poqomam + + + + Pokonchi + + + Quiché + + Kiché + + + Utlateca + + + + Tectiteco + + Teco (Mayan) + + + + Tojolabal + + Chañabal + + + + Tzeltal + + Celdal + + + Tseltal + + + Zendal + + + + Tzotzil + + Chamula + + + Querene + + + Zotzil + + + + Tzutuhil + + Zutuhil + + + + Uspanteca + + + + info:lc/vocabulary/languages/men + Mende + men + + + info:lc/vocabulary/languages/mic + Micmac + mic + + + info:lc/vocabulary/languages/min + Minangkabau + min + + Menangkabau + + + + info:lc/vocabulary/languages/mwl + Mirandese + mwl + + + info:lc/vocabulary/languages/mis + Miscellaneous languages + mis + + Andamanese + + + Burushaski + + Boorishki + + + Khajuna + + + + Chukchi + + Tchuktchi + + + Tuski + + + + Etruscan + + + Gilyak + + Guiliak + + + Nivkh + + + + Hattic + + Hattian + + + Khattic + + + Khattili + + + Khattish + + + Proto-Hittite + + + + + Hurrian + + Mitani + + + Subarian + + + + Iberian + + + Indus script + + + Jarawa (India) + + + Kamchadal + + Itelmes + + + + Ket + + Yenisei-Ostiak + + + + Koryak + + + Manipravalam (Malayalam) + + + Mysian + + + Nancowry + + + Nenets + + Jurak + + + Yurak + + + + Nganasan + + Tavgi + + + + Nicobarese + + + Palan + + Pallan + + + + Shelta + + + Urartian + + Chaldean (Urartian) + + + Khaldian + + + Urartaean + + + Urartic + + + Vannic + + + + Yugh + + Sym-Ketish + + + + Yukaghir + + Jukaghir + + + + + info:lc/vocabulary/languages/moh + Mohawk + moh + + + info:lc/vocabulary/languages/mdf + Moksha + mdf + + + info:lc/vocabulary/languages/mol + Moldavian + mol + + + info:lc/vocabulary/languages/mkh + Mon-Khmer (Other) + mkh + + Bahnar + + + Blang + + Bulang + + + Plang + + + Pulang + + + Samtao + + + + Chrau + + + Cua + + Bong Miew + + + Kor + + + Traw + + + + Eastern Mnong + + Mnong, Eastern + + + + Hrê + + Davak + + + + Jah Hut + + Eastern Sakai + + + Sakai, Eastern + + + + Jeh + + Die + + + Yeh + + + + Katu + + Attouat + + + Khat + + + Ta River Van Kieu + + + Teu + + + Thap + + + + Khmu' + + Kamhmu + + + Phouteng + + + + Koho + + + Kui (Mon-Khmer) + + Khmer, Old (Kui) + + + Kuay + + + Kuy + + + Old Khmer (Kui) + + + Suai + + + Suay + + + + Laven + + Loven + + + + Lawa (Thailand) + + La-oop + + + Lava + + + Lavua + + + Luwa + + + + Mah Meri + + Besisi + + + Cellate + + + + Mon + + Peguan + + + Talaing + + + + Muong + + + Northern Khmer + + Khmer, Northern + + + + Nyah Kur + + Chao Bon + + + Niakuol + + + + Pacoh + + Bo + + + River Van Kieu + + + + Rengao + + + Sedang + + + Semai + + Central Sakai + + + Sakai, Central + + + Senoi + + + + Semang + + Kensiu + + + Ngok Pa + + + + Senoic languages + + Aslian languages, Central + + + Central Aslian languages + + + Sakai languages + + + + Srê + + + Stieng + + + Temiar + + Northern Sakai + + + Sakai, Northern + + + + Wa + + + + info:lc/vocabulary/languages/lol + Mongo-Nkundu + lol + + Lolo (Congo) + + + Lomongo + + + Lonkundu + + + Mongo + + + Nkundu + + + + info:lc/vocabulary/languages/mon + Mongolian + mon + + Mongol + + + Chahar + + Čakhar + + + + Dariganga + + Dar'ganga + + + Dariġangġ-a + + + Darigangga + + + + Khalkha + + + Ordos + + + + info:lc/vocabulary/languages/mos + Mooré + mos + + Mole + + + Moré + + + Moshi + + + Mossi + + + Yana (Burkina Faso and Togo) + + + + info:lc/vocabulary/languages/mul + Multiple languages + mul + + + info:lc/vocabulary/languages/mun + Munda (Other) + mun + + Asuri + + + Bhumij + + + Ho + + + Kharia + + + Korwa + + Korava (Munda) + + + + Kurku + + Bondeya + + + Bopchi + + + Kirku + + + Korakū + + + Korki + + + Korku + + + Kuri (India) + + + + Mundari + + Kohl + + + + Nihali + + Nahali + + + + Sora + + Sabara + + + Saora + + + Savara + + + Sawara + + + + + info:lc/vocabulary/languages/nah + Nahuatl + nah + + Aztec + + + Mexican + + + Pipil + + Nahuat + + + + + info:lc/vocabulary/languages/nau + Nauru + nau + + + info:lc/vocabulary/languages/nav + Navajo + nav + + + info:lc/vocabulary/languages/nbl + Ndebele (South Africa) + nbl + + Ndzundza + + + Nrebele (South Africa) + + + Transvaal Ndebele + + + + info:lc/vocabulary/languages/nde + Ndebele (Zimbabwe) + nde + + Nrebele (Zimbabwe) + + + Sindebele + + + Tebele + + + + info:lc/vocabulary/languages/ndo + Ndonga + ndo + + Ambo (Angola and Namibia) + + + Oshindonga + + + Oshiwambo + + + Ovambo (Ndonga) + + + + info:lc/vocabulary/languages/nap + Neapolitan Italian + nap + + + info:lc/vocabulary/languages/nep + Nepali + nep + + Gorkhali + + + Gurkhali + + + Khas + + + Naipali + + + Nepalese + + + Parbate + + + Parbatiya + + + Purbutti + + + Baitadi + + + Kumali + + + Parvati + + Parbati + + + + + info:lc/vocabulary/languages/new + Newari + new + + + info:lc/vocabulary/languages/nwc + Newari, Old + nwc + + Old Newari + + + + info:lc/vocabulary/languages/nia + Nias + nia + + + info:lc/vocabulary/languages/nic + Niger-Kordofanian (Other) + nic + + Niger-Congo (Other) + + + Abidji + + Adidji + + + Ari (Côte d'Ivoire) + + + + Abua + + + Ahanta + + + Aja (Benin and Togo) + + Adja + + + + Alladian + + Aladian + + + Aladyã + + + Aladyan + + + Alagia + + + Alagian + + + Alagya + + + Alajan + + + Alladyan + + + Allagia + + + Allagian language + + + + Anufo + + Chakosi + + + + Anyang + + Denya + + + Nyang (Cameroon) + + + + Anyi + + Agni + + + + Attie + + Akye + + + Kurobu + + + + Avikam + + + Awutu + + + Babungo + + Ngo + + + + Bafut + + + Baka (Cameroon and Gabon) + + + Balanta-Ganja + + Alante (Senegal) + + + Balanda (Senegal) + + + Balant (Senegal) + + + Balante (Senegal) + + + Balãt + + + Ballante (Senegal) + + + Belante (Senegal) + + + Brassa (Senegal) + + + Bulanda (Senegal) + + + Fca + + + Fjaa + + + Fraase + + + + Balanta-Kentohe + + Alante (Balanta-Kentohe) + + + Balanda (Balanta-Kentohe) + + + Balant (Balanta-Kentohe) + + + Balanta + + + Balante (Balanta-Kentohe) + + + Ballante (Balanta-Kentohe) + + + Belante (Balanta-Kentohe) + + + Brassa (Balanta-Kentohe) + + + Bulanda (Balanta-Kentohe) + + + Frase + + + + Bamun + + + Bandial + + Banjaal + + + Eegima + + + Eegimaa + + + + Bariba + + Bargu + + + Berba (Benin and Nigeria) + + + + Bassari + + Ayan + + + Biyan + + + Wo + + + + Baule + + Baoulé + + + + Bedik + + Budik + + + Tenda + + + + Bekwarra + + + Bena (Nigeria) + + Binna + + + Buna (Bena) + + + Ebina (Bena) + + + Ebuna (Bena) + + + Gbinna + + + Yangeru + + + Yongor + + + Yungur (Bena) + + + + Benue-Congo languages + + + Biali + + Berba (Benin and Burkina Faso) + + + Bieri + + + + Bijago + + Bidyogo + + + + Birifor + + + Birom + + Berom + + + Bouroum + + + Burum (Nigeria) + + + Kibo + + + Kibyen + + + Shosho + + + + Blowo + + Blo + + + Dan-blo + + + Western Dan + + + + Bobo Fing + + Black Bobo + + + Bulse + + + Finng + + + + Boomu + + Bomu + + + + Bozo + + Sorko + + + Sorogo + + + + Brissa + + Anufo (Côte d'Ivoire) + + + + Bua languages + + Boua languages + + + + Buli + + Builsa + + + Bulea + + + Bulugu + + + Guresha + + + Kanjaga + + + + Busa + + Boko + + + + Bwamu + + Bobo Wule + + + Bouamou + + + + Cross River Mbembe + + Ekokoma + + + Ifunubwa + + + Oderiga + + + Ofunobwam + + + Okam + + + Wakande + + + + Dagaare + + + Dagbani + + Dagomba + + + + Dan (Côte d'Ivoire) + + Gio + + + Yacouba + + + + Degema + + Atala + + + Udekama + + + + Diola + + Dyola + + + Yola + + + + Djimini + + Dyimini + + + Gimini + + + Jimini + + + Jinmini + + + + Dogon + + Habe + + + Tombo + + + + Ebira + + Egbira + + + Igbira + + + + Eggon + + + Ejagham + + Central Ekoi + + + Ekwe + + + Ezam + + + + Ekpeye + + + Engenni + + Egene + + + Ngene + + + + Esuulaalu + + + Etsako + + Afenmai + + + Iyekhee + + + Kukuruku + + + Yekhee + + + + Fali (Cameroon) + + Falli + + + + Falor + + Palor + + + + Farefare + + Frafra + + + Gurenne + + + Gurne + + + Gurune + + + Nankani + + + Nankanse + + + Ninkare + + + + Gbagyi + + + Gbandi + + Bandi + + + + Gen-Gbe + + Gẽ + + + Mina (Benin and Togo) + + + + Gikyode + + Chode + + + Kyode + + + + Gonja + + Guang + + + + Gua + + Gwa (Ghana) + + + + Gun-Gbe + + Alada + + + Egun + + + + Gurma + + Gourmantché + + + Gulmance + + + + Guyuk + + + Gweetaawu + + Dan-gouéta + + + Eastern Dan + + + Gouéta + + + Gwétaawo + + + + Hanga (Ghana) + + Anga (Ghana) + + + + Hõne + + Jukun of Gwana + + + + Idoma + + Oturkpo + + + + Igede + + + Igo + + Ahlon + + + Anlo + + + + Ikwere + + Oratta-Ikwerri + + + + Indenie + + Ndenie + + + Ndenye + + + Ndinian + + + Ndyenye + + + + Itsekiri + + Isekiri + + + + Izere + + Jarawa (Nigeria) + + + + Izi + + + Jju + + Ju (Benue-Congo) + + + Kaje + + + + Jowulu + + Jo + + + Samogho (Jowulu) + + + Samoighokan + + + + Jukun + + Kurorofa + + + + Kaansa + + Gã (Burkina Faso) + + + Gan (Burkina Faso) + + + Gane (Burkina Faso) + + + Kaan (Burkina Faso) + + + Kaanse + + + Kãasa (Burkina Faso) + + + Kan (Burkina Faso) + + + + Kabiye + + Kabre + + + Kabye + + + + Kagoro (Mali) + + + Kagoro (Nigeria) + + Gworok + + + + Karang (Cameroon) + + + Kasem + + Kasena + + + Kasim + + + Kassem + + + Kassene + + + + Kassonke + + Khassonke + + + + Kissi + + Kisi (West Africa) + + + + Konkomba + + + Konni + + Koma (Ghana) + + + + Kposo + + Akposo + + + Ikposo + + + + Krahn + + Kran + + + Northern Krahn + + + Western Krahn + + + + Krongo + + Kadumodi + + + Kurungu + + + + Kulango + + Koulango + + + Kpelego + + + Nabe + + + Ngwala + + + Nkurange + + + Zazere + + + + Kuo (Cameroon and Chad) + + Ko (Cameroon and Chad) + + + Koh + + + + Kuranko + + Koranko + + + + Kurumba + + Deforo + + + Foulse + + + Fulse + + + Koromfe + + + Kouroumba + + + Kurumfe + + + Lilse + + + + Kusaal + + Kusasi + + + + Kwanja + + + Kweni + + Gouro + + + + Lefana + + Bouem + + + Buem + + + Bwem + + + + Ligbi + + + Limba + + + Limbum + + Llimbumi + + + Ndzungle + + + Njungene + + + Nsugni + + + Wimbum + + + Zungle + + + + Lobi + + + Loko + + Landogo + + + + Loma + + Baru + + + Buzi + + + Lorma + + + + Longuda + + Nunguda + + + + Lorhon + + Loghon + + + + Lyele + + Lele (Burkina Faso) + + + + Mamara + + Bamana (Senufo) + + + Mianka + + + Minianka + + + Minyanka + + + + Mambila + + Lagubi + + + Nor + + + Tagbo + + + Torbi + + + + Mampruli + + + Mandjak + + + Mankanya + + Bola (Portuguese Guinea) + + + Brame + + + Bulama + + + + Mankon + + + Mano + + + Mayogo + + + Mbili + + + Mbum + + Mbam + + + + Mi Gangam + + Dye + + + Gangam + + + Ngangan + + + + Migili + + Koro Lafia + + + + Mo (Côte d'Ivoire and Ghana) + + Buru (Côte d'Ivoire and Ghana) + + + Deg + + + Mmfo + + + + Moba + + + Muana + + + Mumuye + + + Mundang + + Moundang + + + + Mungaka + + Bali (Cameroon) + + + Ngaaka + + + + Nafaanra + + + Nawuri + + + Nchumburu + + + Ndogo-Sere languages + + + Ngbaka + + + Ngbaka ma'bo + + Bwaka + + + Ngbaka limba + + + + Nirere + + + Ninzo + + Akiza + + + Amar Tita + + + Ancha + + + Fadan Wate + + + Gbhu D Amar Randfa + + + Hate (Ninzo) + + + Incha + + + Kwasu + + + Ninzam + + + Nunzo + + + Sambe + + + + Nkonya + + + Nomaante + + + Noon + + + Noone + + Noni + + + + Northern Bullom + + Bullom, Northern + + + + Nunuma + + Nibulu + + + Nouni + + + + Nupe + + Nope + + + + Ogbronuagum + + + Oku + + Bvukoo + + + Ebkuo + + + Ekpwo + + + Kuo (Oku) + + + Ukfwo + + + Uku (Oku) + + + + Oron + + + Pinyin + + + Safaliba + + Safalaba + + + Safalba + + + Safali + + + + Samo (West Africa) + + Goe + + + Matya + + + Maya (Burkina Faso) + + + Samogo-Sane + + + San (Eastern Mande) + + + Sane + + + + Sanwi + + + Sembla + + Sambla + + + Samogho-Senku + + + Samogo-Senku + + + Seeku + + + Sembila + + + Senku + + + Southern Samo (Western Mande) + + + + Senari + + Senufo + + + + Senya + + + Sherbro + + Bullom, Southern + + + Southern Bullom + + + + Sissala + + + Somba + + Betammadibe + + + Ditammari + + + Tamaba + + + + Tagbana + + + Tampulma + + Tamprusi + + + + Téén + + + Tem + + Cotocoli + + + Kotokoli + + + Tim + + + + Tigon Mbembe + + Akonto + + + Akwanto + + + Noale + + + Tigim + + + Tigon + + + Tigong + + + Tigum + + + Tigun + + + Tikun + + + Tukun + + + + Tikar + + + Tobote + + Basari (Togo and Ghana) + + + + Tofingbe + + + Toma (Burkina Faso) + + Makaa (Burkina Faso) + + + Nyaana + + + + Tura + + Toura + + + + Tusia + + Toussia + + + + Tuwunro + + + Tyembara + + + Ukaan + + Aika + + + Anyaran + + + Auga + + + Ikan + + + Kakumo + + + + Urhobo + + + Vagala + + Kira + + + Konosarola + + + Siti + + + + Vige + + + Winyé + + Kõ (Burkina Faso) + + + Kols + + + Kolsi + + + + Yakö + + Kö (Yakö) + + + Lukö + + + + Yom + + Kpilakpila + + + Pila + + + Pilapila + + + + + info:lc/vocabulary/languages/ssa + Nilo-Saharan (Other) + ssa + + Sub-Saharan African (Other) + + + Adhola + + Dhopadhola + + + Ludama + + + + Alur + + Aloro + + + Alua + + + Alulu + + + Aluru + + + Dho Alur + + + Jo Alur + + + Lur (Alur) + + + Luri (Alur) + + + + Anuak + + Yambo + + + + Aringa + + Low Lugbara + + + + Bagirmi + + Barma + + + + Baka + + Tara Baaka + + + + Bari + + Dzilio + + + + Birri (Central African Republic) + + Abiri + + + Ambili + + + Biri (Central African Republic) + + + Bviri + + + Viri language + + + + Bongo + + + Bongo-Bagirmi languages + + + Bor (Lwo) + + Belanda + + + + Dazaga + + Dasa + + + Dasaga + + + Daza (Nilo-Saharan) + + + Dazagada + + + Dazza + + + Dazzaga + + + Tebu (Dazaga) + + + Tibbu (Dazaga) + + + Toubou (Dazaga) + + + Tubu (Dazaga) + + + + Fur + + + Gambai + + Kabba Laka + + + Ngambai + + + Sara Gambai + + + + Ingassana + + Gaam + + + Ingessana + + + Kamanidi + + + Mamidza + + + Memedja + + + Metabi + + + Muntabi + + + Tabi (Ingassana) + + + + Jur Modo + + Jur (Jur Modo) + + + Modo + + + + Kaba (Central Sudanic) + + + Kalenjin + + + Kara (Central African Republic and Sudan) + + Fer + + + Gula (Central African Republic and Sudan) + + + Yama + + + Yamegi + + + + Karamojong + + Akarimojong + + + + Kenga + + + Kipsikis + + + Kreish + + + Kùláál + + Gula (Lake Iro, Chad) + + + + Kunama + + Cunama + + + + Lango (Uganda) + + + Lendu + + + Lese + + + Logo + + Logo Kuli + + + Logoti + + + + Lotuko + + Latuka + + + + Lugbara + + Logbara + + + Logbware + + + Luguaret + + + Lugware + + + + Lwo (Sudan) + + Dhe Lwo + + + Dyur + + + Giur + + + Jo Lwo + + + Jur (Lwo (Sudan)) + + + Luo (Sudan) + + + + Maban + + Meban + + + + Maʾdi (Uganda and Sudan) + + Madi-ti (Uganda and Sudan) + + + + Majingai + + Midjinngay + + + Moggingain + + + Sara-Majingai + + + + Mamvu + + Momvu + + + Monvu + + + Tengo + + + + Mangbetu + + Monbuttu + + + + Mbai (Moissala) + + Moissala Mbai + + + Sara Mbai (Moissala) + + + + Moru + + + Murle + + Beir + + + + Nandi + + + Nara + + Barea + + + Baria + + + Barya + + + Higir + + + Kolkotta + + + Koyta + + + Mogoreb + + + Morda + + + Nera + + + Nere + + + Santora + + + + Ngama + + Sara Ngama + + + + Ngiti + + Druna + + + Lendu, Southern + + + Ndruna + + + Southern Lendu + + + + Nuer + + Abigar + + + Nath + + + + Päri (Sudan) + + + Proto-Eastern Sudanic + + + Sabaot + + + Samburu + + Burkeneji + + + Lokop + + + Nkutuk + + + Sambur + + + Sampur + + + + Sara + + Majingai-Ngama + + + + Suk + + Pokot + + + + Tedaga + + Tebou + + + Tebu (Tedaga) + + + Teda + + + Tedagada + + + Tibbu (Tedaga) + + + Tibu + + + Toda (Africa) + + + Todaga + + + Todga + + + Toubou (Tedaga) + + + Tubu + + + Tuda (Africa) + + + Tuduga + + + + Teso + + Ateso + + + Iteso + + + + Toposa + + Abo (Sudan) + + + Akeroa + + + Dabossa + + + Huma (Sudan) + + + Kare (Sudan) + + + Khumi (Sudan) + + + Taposa + + + + Turkana + + + Uduk + + + Yulu + + + Zaghawa + + Beri-aa + + + Berri + + + Kebadi + + + Merida + + + Soghaua + + + Zeghawa + + + + + info:lc/vocabulary/languages/niu + Niuean + niu + + + info:lc/vocabulary/languages/nqo + N'Ko + nqo + + + info:lc/vocabulary/languages/nog + Nogai + nog + + + info:lc/vocabulary/languages/zxx + No linguistic content + zxx + + + info:lc/vocabulary/languages/nai + North American Indian (Other) + nai + + Use for the other languages of North America north of Mexico excluding the + languages of the Azteco-Tanoan language phylum. + + + Alabama + + + Arikara + + + Atsugewi + + + Beothuk + + + Chickasaw + + + Chimariko + + + Chitimacha + + Chetimacha + + + Shetimasha + + + + Chumash + + + Coahuilteco + + Tejano + + + + Cocopa + + + Coos + + Kaus + + + Kwokwoos + + + + Eastern Pomo + + Pomo, Eastern + + + + Eyak + + Ugalachmut + + + + Hualapai + + Jaguallapai + + + Mataveke-paya + + + Walapai + + + + Karok + + + Keres + + + Kiliwa + + Yukaliwa + + + + Konomihu + + + Kuitsh + + Lower Umpqua + + + Umpqua, Lower + + + + Kumiai + + Campo + + + Cochimi (Diegueño) + + + Comeya + + + Cuchimí + + + Diegueño + + + Digueño + + + Iipay + + + Kamia + + + Kamiai + + + Kamiyahi + + + Kamiyai + + + Ki-Miai + + + Ko'al + + + Ku'ahl + + + Kumeyaai + + + Kumeyaay + + + Kumia + + + Kw'aal + + + Quemayá + + + Tiipay + + + Tipai + + + + Maidu + + Pujunan + + + + Mikasuki + + Mekusuky + + + + Miwok languages + + Mewan + + + Moquelumnan + + + + Mutsun + + + Nez Percé + + Numipu + + + Sahaptin + + + + Northern Sierra Miwok + + Miwok, Northern Sierra + + + + Ohlone + + Costanoan + + + + Paipai + + + Pawnee + + + Southeastern Pomo + + Pomo, Southeastern + + + + Timucua + + + Tlakluit + + Echeloot + + + Wishram + + + + Tonkawa + + + Tunica + + Tonican + + + Yoron + + + Yuron + + + + Wappo + + + Wichita + + + Wikchamni + + Wükchamni + + + + Wintu + + + Wiyot + + + Yahi + + + Yakama + + Yakima + + + + Yuchi + + Uchee + + + + Yuki + + + + info:lc/vocabulary/languages/frr + North Frisian + frr + + Frisian, North + + + + info:lc/vocabulary/languages/sme + Northern Sami + sme + + Sami, Northern + + + + info:lc/vocabulary/languages/nso + Northern Sotho + nso + + Pedi + + + Sepedi + + + Sotho, Northern + + + Transvaal Sotho + + + Pai (South Africa) + + Eastern Sotho + + + + + info:lc/vocabulary/languages/nor + Norwegian + nor + + Bokmål + + + Dano-Norwegian + + + Riksmål + + + Trøndersk + + Trønder + + + Trøndesk + + + Trøndsk + + + + + info:lc/vocabulary/languages/nob + Norwegian (Bokmål) + nob + + Bokmål + + + Dano-Norwegian + + + Riksmål + + + + info:lc/vocabulary/languages/nno + Norwegian (Nynorsk) + nno + + Landsmaal + + + Landsmål + + + Nynorsk + + + + info:lc/vocabulary/languages/nub + Nubian languages + nub + + Dilling + + Delen + + + Warkimbe + + + + Dongola-Kenuz + + Kenuz + + + + Mahas-Fiyadikka + + Fadicca + + + Fiadidja + + + Fiyadikka + + + Nobiin + + + + Midob + + + Old Nubian (to 1300) + + Nubian, Old + + + + + info:lc/vocabulary/languages/nym + Nyamwezi + nym + + + info:lc/vocabulary/languages/nya + Nyanja + nya + + Chinyanja + + + Nyassa + + + Chewa + + Cewa + + + + + info:lc/vocabulary/languages/nyn + Nyankole + nyn + + Lunyankole + + + Nkole + + + Runyankore + + + + info:lc/vocabulary/languages/nyo + Nyoro + nyo + + Lunyoro + + + Urunyoro + + + + info:lc/vocabulary/languages/nzi + Nzima + nzi + + Nsima + + + Nzema + + + Zema + + + + info:lc/vocabulary/languages/oci + Occitan (post-1500) + oci + + Langue d'oc (post-1500) + + + Provençal, Modern (post-1500) + + + Béarnais (post-1500) + + + Gascon (post-1500) + + + + info:lc/vocabulary/languages/lan + Occitan (post 1500) + lan + + + info:lc/vocabulary/languages/xal + Oirat + xal + + Kalmyk + + Calmuck + + + + Oyrat + + + + info:lc/vocabulary/languages/oji + Ojibwa + oji + + Anishinabe + + + Chippewa + + + Otchipwe + + + Salteaux + + + Saulteaux + + + Ottawa + + + + info:lc/vocabulary/languages/non + Old Norse + non + + Altnordish + + + Icelandic, Old (to 1550) + + + Norse, Old + + + Norse, Western + + + Norwegian, Old (to 1350) + + + Old Icelandic (to 1550) + + + Old Norwegian (to 1350) + + + Western Norse + + + + info:lc/vocabulary/languages/peo + Old Persian (ca. 600-400 B.C.) + peo + + Persian, Old (ca. 600-400 B.C.) + + + + info:lc/vocabulary/languages/ori + Oriya + ori + + Uriya + + + Adiwasi Oriya + + Adibasi Oriyā + + + Ādivāsi Oriyā + + + Desai + + + Kotia + + + Kotia Oriya + + + Kotiya + + + Tribal Oriya + + + + Bhatri + + Basturia + + + Bhatra + + + Bhattra + + + Bhattri + + + Bhottada + + + Bhottara + + + + Sambalpuri + + + + info:lc/vocabulary/languages/orm + Oromo + orm + + Afan + + + Galla + + + Gallinya + + + Boran + + + Orma + + Uardai + + + Warday + + + + + info:lc/vocabulary/languages/gal + Oromo + gal + + + info:lc/vocabulary/languages/osa + Osage + osa + + + info:lc/vocabulary/languages/oss + Ossetic + oss + + Āsī + + + Oseti + + + Osi + + + Ūsatī + + + + info:lc/vocabulary/languages/oto + Otomian languages + oto + + Chichimeca-Jonaz + + + Matlatzinca + + Pirinda + + + + Mazahua + + + Ocuiltec + + Atzinca + + + Maclatzinca + + + Tlahuica + + + + Otomi + + Hñahñu + + + Othomi + + + + Pame + + Chichimeca Pame + + + + + info:lc/vocabulary/languages/pal + Pahlavi + pal + + Huzvaresh + + + Middle Persian (Pahlavi) + + + Parsi + + + Pazend + + + Pehlevi + + + Persian, Middle (Pahlavi) + + + + info:lc/vocabulary/languages/pau + Palauan + pau + + Pelew + + + + info:lc/vocabulary/languages/pli + Pali + pli + + + info:lc/vocabulary/languages/pam + Pampanga + pam + + Kapampangan + + + + info:lc/vocabulary/languages/pag + Pangasinan + pag + + + info:lc/vocabulary/languages/pan + Panjabi + pan + + Eastern Panjabi + + + Punjabi + + + + info:lc/vocabulary/languages/pap + Papiamento + pap + + + info:lc/vocabulary/languages/paa + Papuan (Other) + paa + + Abau + + Green River + + + + Abulas + + Ambulas + + + Maprik + + + + Agarabe + + + Alamblak + + + Ama (Papua New Guinea) + + Sawiyanu + + + + Amele + + + Ampale + + Ampeeli + + + Safeyoka + + + + Aneme Wake + + Abia + + + Musa, Upper + + + Upper Musa + + + + Anggor + + Bibriari + + + Senagi + + + Watapor + + + + Ankave + + Angave + + + + Aomie + + Omie + + + + Asaro + + Dano + + + Upper Asaro + + + + Asmat + + + Au + + + Auyana + + + Awa (Eastern Highlands Province, Papua New Guinea) + + + Bahinemo + + Gahom + + + Wogu + + + + Baining + + Kakat + + + Makakat + + + Maqaqet + + + Qaqet + + + + Barai + + + Baruya + + + Bauzi + + Baudi + + + Bauri + + + Pauwi + + + + Benabena + + Bena (Papua New Guinea) + + + Bena-bena + + + + Berik + + + Biangai + + Baingai + + + + Bimin + + + Binumarien + + + Bisorio + + Gadio + + + Iniai + + + + Blagar + + Belagar + + + Tarang + + + + Bom + + Anjam + + + Bogadjim + + + Lalok + + + + Buin + + Rugara + + + Telei + + + + Bunak + + Buna' (Indonesia) + + + Bunake + + + Bunaq + + + + Burum (Papua New Guinea) + + Bulum + + + + Chuave + + Tjuave + + + + Daga + + Dimuga + + + Nawp + + + + Daribi + + Elu + + + Karimui + + + Makarub + + + Mikaru + + + + Dedua + + + Duna + + Yuna + + + + Eipo + + + Enga + + Tsaga + + + + Ese + + Managalasi + + + Managulasi + + + + Faiwol + + Fegolmin + + + + Fasu + + + Folopa + + + Fore + + + Gadsup + + + Gahuku + + + Galela + + + Gimi + + + Gogodala + + + Golin + + + Gope + + Era River + + + Kope + + + + Gresi + + Glesi + + + Gresik + + + Klesi + + + + Guhu-Samane + + Mid-Waria + + + + Gwahatike + + + Gwedena + + Umanakaina + + + + Halopa + + Botelkude + + + Nobonob + + + Nupanob + + + + Huli + + + Iatmul + + Big Sepik + + + + Inanwatan + + Suabo + + + + Inoke + + Yate (Papua New Guinea) + + + + Irumu + + + Iwam + + + Iyo (Papua New Guinea) + + Bure (Papua New Guinea) + + + Nabu + + + Naho + + + Nahu + + + Ndo (Papua New Guinea) + + + + Kalabra + + + Kalam + + Karam + + + + Kaluli + + + Kamano + + Kafe + + + + Kamasau + + + Kamtuk + + Kemtuik + + + + Kanite + + Kemiju Jate + + + + Kapauku + + Ekagi + + + + Kasua + + + Kâte + + + Kelon + + Kalong + + + Kelong + + + Klon + + + Kolon + + + + Ketengban + + Oktengban + + + + Kewa + + + Kobon + + + Komba + + + Komunku + + + Kongara + + + Korape + + Kwarafe + + + Okeina + + + + Kosena + + + Kovai + + Alngubin + + + Kobai + + + Kowai + + + Umboi + + + + Kunimaipa + + + Kwerba + + + Lambau + + + Lunambe + + + Mai Brat + + Mey Brat + + + + Manambu + + + Mape + + + Meax + + + Medlpa + + Hagen + + + Moglei + + + + Menya + + Menyama + + + Menye + + + + Mianmin + + + Migabac + + Migaba' + + + + Monumbo + + + Mountain Arapesh + + Arapesh, Mountain + + + Bukiyup + + + + Mountain Koiari + + Koiali, Mountain + + + + Mpur (Indonesia) + + Amberbaken + + + + Mugil + + Bargam + + + Saker + + + + Nabak + + Wain + + + + Nankina + + + Narak + + Gandja + + + Kandawo + + + Kol (Papua New Guinea) + + + + Nasioi + + + Nek + + + Nii + + Ek Nii + + + + Notu + + Ewage + + + + Oksapmin + + + Olo + + Orlei + + + + Ono + + + Orokaiva + + + Orokolo + + + Orya + + Oria + + + Uria + + + + Pay + + + Pinai-Hagahai + + + Purari + + Eurika + + + Evora + + + Iai (Papua New Guinea) + + + Iare + + + Kaimare + + + Kaura (Papua New Guinea) + + + Kipaia + + + Koriki + + + Maipua + + + Namau + + + + Rawa + + Karo-Rawa + + + + Rotokas + + + Saberi + + Isirawa + + + Okwasar + + + + Sahu + + + Samo (Western Province, Papua New Guinea) + + Supei + + + + Sawos + + Tshwosh + + + + Selepet + + + Sentani + + + Siane + + + Siroi + + Pasa + + + Suroi + + + + Siwai + + Motuna + + + + Sona (Papua New Guinea) + + Kanasi + + + + Suena + + Yarawe + + + Yema + + + + Sulka + + + Tabla + + Tanahmerah (Northeast Irian Jaya) + + + + Tairora + + + Tani + + Miami (Papua New Guinea) + + + Miani + + + Suaru + + + + Tauya + + Inafosa + + + + Telefol + + + Tepera + + + Ternate + + + Tewa (Papuan) + + Teiwa + + + + Tifal + + + Timbe + + + Toaripi + + Motumotu + + + + Tobelo + + + Urii + + + Usarufa + + Usurufa + + + Uturupa + + + + Waffa + + + Wantoat + + + Washkuk + + Kwoma + + + + Wasi + + + Were + + + West Makian + + Desite + + + Makian, West + + + Titinec + + + + Wiru + + + Woisika + + + Yabiyufa + + Jafijufa + + + + Yagaria + + Frigano Jate + + + Kami (Papua New Guinea) + + + + Yangoru + + + Yareba + + + Yau + + + Yessan-Mayo + + Mayo (New Guinea) + + + + Yongkom + + + Yopno + + Yupna + + + + Yui + + Salt-Yui + + + + + info:lc/vocabulary/languages/per + Persian + per + + Farsi + + + Dari + + Kabuli + + + Kabuli-Persian + + + Khorasani + + + + + info:lc/vocabulary/languages/phi + Philippine (Other) + phi + + Abaknon + + Capul + + + Inabaknon + + + Kapul + + + Sama Abaknon + + + + Agta + + Cagayan Agta, Central + + + Central Cagayan Agta + + + + Agutaynon + + + Aklanon + + + Alangan + + + Amganad Ifugao + + Ifugao, Amganad + + + + Atta + + Northern Cagayan Negrito + + + + Ayangan Ifugao + + Ifugao, Ayangan + + + + Bagobo + + + Balangao + + + Balangingì + + Baangingi' + + + Bangingi + + + Northern Sinama + + + Sama Bangingì + + + Sea Samal + + + Sinama, Northern + + + + Banton + + Bantuanon + + + + Batad Ifugao + + Ifugao, Batad + + + + Bilaan + + + Bolinao + + Binubolinao + + + + Bontoc + + Finontok + + + + Botolan Sambal + + Aeta Negrito + + + Sambal Botolan + + + Sambali Botolan + + + + Caluyanun + + + Central Bontoc + + Bontoc, Central + + + + Central Subanen + + Sindangan Subanun + + + Subanen, Central + + + Subanun, Sindangan + + + + Cuyunon + + Kuyonon + + + + Dumagat (Casiguran) + + Agta (Casiguran) + + + Casiguran Agta + + + Casiguran Dumagat + + + + Dumagat (Umirey) + + Agta (Umirey) + + + Dingalan Dumagat + + + Umirey Agta + + + Umirey Dumagat + + + + Eastern Bontoc + + Bontoc, Eastern + + + + Eastern Ifugao + + Ifugao, Eastern + + + + Gaddang + + + Ibaloi + + Benguet Igorot + + + Nabaloi + + + + Ibanag + + + Ifugao + + + Ilongot + + + Isinay + + Inmeas + + + + Isneg + + Apayao + + + + Itawis + + + Itbayat + + + Ivatan + + + Jama Mapun + + Cagayanon + + + Mapun + + + Pullon Mapun + + + Sama Mapun + + + + Ivatan + + Batan + + + Ibatan + + + + Kalamian + + Calamian + + + + Kalinga languages + + + Kankanay + + Cancanai + + + Lepanto-Igorot + + + + Kinaray-a + + Antiqueno + + + Binukidnon + + + Hamtiknon + + + Hinaraya + + + Karay-a + + + + Lower Tanudan Kalinga + + Kalinga, Lower Tanudan + + + Tanudan Kalinga, Lower + + + + Magindanao + + Moro + + + + Mamanwa + + + Mangyan + + Iraya + + + + Mansaka + + + Maranao + + Moro + + + + Masbateno + + Minasbate + + + + Mayoyao Ifugao + + Ifugao, Mayoyao + + + + Melebuganon + + Milebuganon + + + Molbog + + + + Northern Kankanay + + Bontoc, Western + + + Kankanay, Northern + + + Sagada-Igorot + + + Western Bontoc + + + + Palawano + + + Pangutaran Sama + + Sama Pangutaran + + + + Sama Sibutu + + Sibutu Sama + + + Southern Sama + + + + Sambali + + Zambal + + + + Southern Bontoc + + Barlig Bontoc + + + Bontoc, Southern + + + Kadaklan Barlig Bontoc + + + + Southern Subanen + + Lapuyan Subanen + + + Margosatubig Subanun + + + Subanen, Southern + + + + Subanun + + Subano + + + + Sulod + + Mundu (Philippines) + + + + Sulu + + Joloano + + + Moro + + + Sooloo + + + + Tagakaolo + + Kalagan, Tagakaolo + + + + Tagbanua + + Aborlan Tagbanwa + + + Apurahuano + + + + Tausug + + + Tboli + + Tagabili + + + Tiboli + + + + Tina Sambal + + + Tiruray + + Teduray + + + + Tuwali + + + Western Subanon + + Siocan Subanon + + + Subanon, Western + + + + Yakan + + + + info:lc/vocabulary/languages/phn + Phoenician + phn + + Punic + + + + info:lc/vocabulary/languages/pon + Pohnpeian + pon + + Ponape + + + Ponapean + + + + info:lc/vocabulary/languages/pol + Polish + pol + + + info:lc/vocabulary/languages/por + Portuguese + por + + + info:lc/vocabulary/languages/pra + Prakrit languages + pra + + Gandhari Prakrit + + Gandhari + + + + Magadhi Prakrit + + + Maharashtri + + + Śaurasēnī + + + + info:lc/vocabulary/languages/pro + Provençal (to 1500) + pro + + Occitan, Old (to 1500) + + + Old Occitan (to 1500) + + + Old Provençal (to 1500) + + + + info:lc/vocabulary/languages/pus + Pushto + pus + + Afghan + + + Pakhto + + + Pakkhto + + + Pashto + + + Pashtu + + + Pukhtu + + + Pukkhto + + + Pukshto + + + Pushtu + + + Wanetsi + + Vanechi + + + Waneci + + + Wanesi + + + Wenetsi + + + + + info:lc/vocabulary/languages/que + Quechua + que + + Inca + + + Kechua + + + Quichua + + + Runasimi + + + Huanca + + Wanka + + + + Ingano + + Inga + + + + + info:lc/vocabulary/languages/roh + Raeto-Romance + roh + + Rhaeto-Romance + + + Romansh + + + Rumansh + + + + info:lc/vocabulary/languages/raj + Rajasthani + raj + + Bagri + + Bagari + + + Bahgri + + + Baorias + + + + Gujuri + + Gojari + + + Gojri + + + Gujar + + + Gujari + + + Gujer + + + Gujjari + + + Gujri (Gujuri) + + + + Harauti + + + Jaipurī + + Dhundhari + + + + Lambadi + + Banjara + + + Labhani + + + Lamani + + + Lambani + + + + Malvi + + Malavi + + + Mallow + + + Malwi + + + Ujjaini (Malvi) + + + + Nimadi + + Nemadi + + + Nimari + + + + Sondwari + + Sondhavāṛī + + + Sondhwadi + + + Sondhwari + + + Soudhwari + + + + Wagdi + + Vāgaḍī + + + Vāgarī + + + Vagdi + + + Vaged + + + Vageri + + + Vagi + + + Vagri + + + Wagadi + + + Waghari + + + Wagholi + + + + + info:lc/vocabulary/languages/rap + Rapanui + rap + + + info:lc/vocabulary/languages/rar + Rarotongan + rar + + Cook Islands Maori + + + Maori, Cook Islands + + + Manihiki Rarotongan + + Rarotongan, Manihiki + + + + + info:lc/vocabulary/languages/roa + Romance (Other) + roa + + Anglo-Norman + + Anglo-French + + + Norman-French + + + + Cajun French + + Acadian (Louisiana) + + + French, Cajun + + + Louisiana Acadian + + + Louisiana French + + + + Franco-Venetian + + Franco-Italian + + + + Italian, Old (to 1300) + + Old Italian + + + + Ladin + + + Portuñol + + Bayano + + + Brasilero + + + Brasilero + + + Brazilero + + + Fronteiriço + + + Fronterizo + + + Portanhol + + + Portunhol + + + + Spanish, Old (to 1500) + + Old Spanish + + + + + info:lc/vocabulary/languages/rom + Romani + rom + + Gipsy + + + Gypsy + + + Romany + + + Rommany + + + Caló (Romani) + + + Kalderash + + Coppersmith + + + Kaldaraš + + + Kalderaš + + + Kelderaš + + + Kelderashícko + + + + Lovari + + + Nuri + + + Spoitori + + Spoitari + + + + + info:lc/vocabulary/languages/rum + Romanian + rum + + Rumanian + + + Boyash + + + Moldovan + + Moldavian + + + Moldovean + + + Moldovian + + + + + info:lc/vocabulary/languages/run + Rundi + run + + Kirundi + + + + info:lc/vocabulary/languages/rus + Russian + rus + + + info:lc/vocabulary/languages/sal + Salishan languages + sal + + Bella Coola + + + Colville + + + Comox + + Komuk + + + + Cowlitz + + + Kalispel + + Pend d'Oreille + + + + Lillooet + + + Ntlakyapamuk + + Netlakapamuk + + + Thompson + + + + Okanagan + + Okinagan + + + + Quinault + + + Salish + + + Sechelt + + Seshelt + + + + Shuswap + + + Squawmish + + Skwamish + + + + Stalo + + Halkomelem + + + + + info:lc/vocabulary/languages/sam + Samaritan Aramaic + sam + + + info:lc/vocabulary/languages/smi + Sami + smi + + Lapp + + + + info:lc/vocabulary/languages/lap + Sami + lap + + + info:lc/vocabulary/languages/smo + Samoan + smo + + + info:lc/vocabulary/languages/sao + Samoan + sao + + + info:lc/vocabulary/languages/sad + Sandawe + sad + + Kissandaui + + + Wassandaui + + + + info:lc/vocabulary/languages/sag + Sango (Ubangi Creole) + sag + + + info:lc/vocabulary/languages/san + Sanskrit + san + + Sanscrit + + + Buddhist Hybrid Sanskrit + + Hybrid Sanskrit, Buddhist + + + + Epigraphical Hybrid Sanskrit + + Hybrid Sanskrit, Epigraphical + + + + Vedic + + Indic, Old + + + Old Indic + + + Vedic Sanskrit + + + + + info:lc/vocabulary/languages/sat + Santali + sat + + Sonthal + + + + info:lc/vocabulary/languages/srd + Sardinian + srd + + + info:lc/vocabulary/languages/sas + Sasak + sas + + + info:lc/vocabulary/languages/sco + Scots + sco + + Lallans + + + Lowland Scots + + + Scots (English) + + + Scottish (Germanic) + + + + info:lc/vocabulary/languages/gla + Scottish Gaelic + gla + + Erse (Scottish Gaelic) + + + Gaelic (Scots) + + + Scots Gaelic + + + + info:lc/vocabulary/languages/gae + Scottish Gaelix + gae + + + info:lc/vocabulary/languages/sel + Selkup + sel + + Ostiak Samoyed + + + + info:lc/vocabulary/languages/sem + Semitic (Other) + sem + + Ammonite + + + Canaanite + + + Eblaite + + Paleocanaanite + + + + Gurage languages + + + Harari + + Adari + + + Ararge + + + + Inor + + Ennemor + + + + Jibbali + + + Mahri + + Mehri + + + + Mandean + + + Sabaean + + + South Arabic + + Arabic, South + + + + Wolane + + Olane + + + Walane + + + Welene + + + Weleni + + + + Zay + + Gelilla + + + Lak'i (Ethiopia) + + + Laqi + + + Zai + + + Zway + + + + + info:lc/vocabulary/languages/srp + Serbian + srp + + + info:lc/vocabulary/languages/scc + Serbian + scc + + + info:lc/vocabulary/languages/srr + Serer + srr + + + info:lc/vocabulary/languages/shn + Shan + shn + + + info:lc/vocabulary/languages/sna + Shona + sna + + China (Africa) + + + Mashona + + + Karanga + + + Zezuru + + Central Shona + + + + + info:lc/vocabulary/languages/sho + Shona + sho + + + info:lc/vocabulary/languages/iii + Sichuan Yi + iii + + Yi, Sichuan + + + + info:lc/vocabulary/languages/scn + Sicilian Italian + scn + + Italian, Sicilian + + + + info:lc/vocabulary/languages/sid + Sidamo + sid + + + info:lc/vocabulary/languages/sgn + Sign languages + sgn + + American Sign Language + + Ameslan + + + + Australasian Signed English + + + Austrian Sign Language + + ÖGS (Sign language) + + + Österreichische Gebärdensprache + + + + British Sign Language + + + Czech Sign Language + + Český znakový jazyk + + + + Danish Sign Language + + DSL (Danish Sign Language) + + + + French Belgian Sign Language + + Belgian French Sign Language + + + Langue des signes Belge Francophone + + + Langue des signes française Belgique + + + LSFB (Sign language) + + + + Icelandic Sign Language + + ISL (Icelandic Sign Language) + + + + Jordanian Sign Language + + JSL (Sign Language) + + + Lughat al-Ishāra al-Urdunia + + + + Mauritian Sign Language + + + Quebec Sign Language + + Langue des signes québécoise + + + + + info:lc/vocabulary/languages/bla + Siksika + bla + + Blackfoot + + + + info:lc/vocabulary/languages/snd + Sindhi + snd + + Kachchhi + + Kacchī + + + Kutchi + + + + + info:lc/vocabulary/languages/sin + Sinhalese + sin + + Cingalese + + + Singhala + + + Singhalese + + + Sinhala + + + + info:lc/vocabulary/languages/snh + Sinhalese + snh + + + info:lc/vocabulary/languages/sit + Sino-Tibetan (Other) + sit + + Abor + + Adi + + + Miri + + + Miśing + + + + Achang + + A-ch‘ang + + + Atsang + + + + Angami + + + Ao + + Chungli + + + Hatigorria + + + Mongsen + + + Zungi + + + Zwingi + + + + Apatani + + Aka + + + Apa Tanang + + + Hruso + + + + Arakanese + + Maghi + + + Rakhaing + + + + Bai (China) + + Min-chia + + + Pai (China) + + + + Balti + + Baltistani + + + Bhotia of Baltistan + + + Sbalti + + + + Bantawa + + Bontawa + + + Kirāta Rāī + + + + Baram + + + Belhariya + + Athpagari + + + Athpahariya + + + Athpare (Belhariya) + + + Athpariya (Belhariya) + + + Belhare + + + Belhāreor + + + + Bodo + + Bara (India and Nepal) + + + Boro (India and Nepal) + + + Kachari, Plains + + + Mech + + + Plains Kachari + + + + Chamling + + Camling + + + + Chang + + Mojung + + + + Chepang + + + Chinbon + + + Chino + + Jino + + + + Chothe Naga + + Chawte + + + Chothe + + + Chowte + + + + Dafla + + Nisi + + + + Dänjong-kä + + Bhotic of Sikkim + + + Dé-jong ké + + + Sikkim Bhotia + + + Sikkimese + + + + Deori + + Chutia + + + Chutiya + + + Dari (India) + + + Deori Chutiya + + + Deuri + + + Dewri + + + Drori + + + + Dhimal + + + Digaro + + Taraon + + + Taying + + + + Dimasa + + Cachari + + + Hill Kachari + + + Kachari + + + + Dungan + + + Gallong + + + Garo + + + Gurung + + + Haka Chin + + Baungshè + + + Chin, Haka + + + Lai + + + + Jero + + + Kabui + + + Kaw + + Akha + + + Ekaw + + + + Khaling + + + Khiamniungan + + + Kok Borok + + Mrung + + + Tipura + + + Tripuri + + + + Konyak + + Kanyak + + + + Kuki + + + Kusunda + + + Ladakhi + + + Lahu + + Muhso + + + + Laizo (Burma) + + + Lepcha + + Rong + + + + Limbu + + + Lisu + + Yawyin + + + + Lopa + + + Magar + + + Miju + + + Mikir + + Karbi + + + + Mishmi + + + Moklum + + + Monpa + + + Mün Chin + + Chinbok + + + + Naga languages + + + Naxi + + Moso + + + + Nocte + + Borduaria + + + Mohongia + + + Paniduaria + + + + Padam + + + Paite + + + Pānkhū + + Paang (Pānkhū) + + + Pāṃkhoẏā + + + Pang Khua + + + Pang (Pānkhū) + + + Pangkhu + + + Pangkhua + + + Pankho + + + Panko + + + Pankua + + + + Rabha + + + Rawang + + + Rongmei + + + Sampang + + Sāmpāṅ Rāī + + + Sampang Rai + + + Sampange Rai + + + Sangpang Gîn + + + Sangpang Gun + + + Sangpang Kha + + + Sangpang + + + + Singpho + + + Sunwar + + + Tamang + + Murmi + + + + Tamu + + + Tangkhul + + Thankhul + + + + Tangsa + + Tengsa + + + + Tangut + + Hsi-hsia + + + Si-hia + + + Xixia + + + + Tenyidie + + + Thādo + + + Thakali + + + Thami + + + Thulung + + + Tiddim Chin + + Chin, Tiddim + + + Kamhau + + + Sokte + + + + Tshangla + + Canglo Monba + + + Cangluo Menba + + + Cangluo Monba + + + Central Monpa + + + Dirang + + + Dungsam + + + Memba + + + Menba (Tshangla) + + + Monba + + + Monpa (Tshangla) + + + Motuo + + + Motuo Menba + + + Sangla + + + Sarchapkkha + + + Schachop + + + Shachobiikha + + + Shachopkha + + + Sharchagpakha + + + Sharchhop-kha + + + Sharchopkha + + + Tashigang + + + Tsangla + + + Tsangla Monba + + + Tsanglo (Tshangla) + + + Tshalingpa (Tshangla) + + + + Vaiphei + + Bhaipei + + + Veiphei + + + + Wambule + + + Wayu + + Hayu + + + Vayu + + + Wayo + + + + Yao (Southeast Asia) + + Mien + + + + Yi + + Lolo (China) + + + Nosu + + + + Zang Zung + + Zhang-Zhung + + + + + info:lc/vocabulary/languages/sio + Siouan (Other) + sio + + Biloxi + + + Chiwere + + + Crow + + + Dhegiha + + Cegiha + + + + Hidatsa + + Grosventres (Hidatsa) + + + + Mandan + + + Ofo + + Ofogoula + + + + Omaha + + + Oto + + Watoto + + + + Tutelo + + + Winnebago + + Hocak + + + + Woccon + + + + info:lc/vocabulary/languages/sms + Skolt Sami + sms + + Lapp, Russian + + + Russian Lapp + + + Sami, Skolt + + + + info:lc/vocabulary/languages/den + Slavey + den + + Dené (Slavey) + + + Dené Tha + + + Ethchaottine + + + Mackenzian + + + North Slavey + + + Slave + + + Slavi + + + South Slavey + + + Kawchottine + + Hare + + + Peaux-de-Lièvre + + + + + info:lc/vocabulary/languages/sla + Slavic (Other) + sla + + Belarusian, Old (to 1700) + + Old Belarusian + + + + Čakavian + + + Carpatho-Rusyn + + Rusyn + + + + Czech, Old (to 1500) + + Old Czech + + + + Polabian + + + Russian, Old (to 1300) + + East Slavic + + + Old East Slavic + + + Old Russian + + + + Ukrainian, Old (ca. 1300-1700) + + Old Ukrainian + + + + + info:lc/vocabulary/languages/slo + Slovak + slo + + + info:lc/vocabulary/languages/slv + Slovenian + slv + + Windic (Slovenian) + + + + info:lc/vocabulary/languages/sog + Sogdian + sog + + + info:lc/vocabulary/languages/som + Somali + som + + + info:lc/vocabulary/languages/son + Songhai + son + + Dendi + + Dandawa + + + + Zarma + + Djerma + + + Dyerma + + + Zerma + + + + + info:lc/vocabulary/languages/snk + Soninke + snk + + Sarakole + + + + info:lc/vocabulary/languages/wen + Sorbian (Other) + wen + + Wendic (Other) + + + + info:lc/vocabulary/languages/sot + Sotho + sot + + Sesuto + + + Southern Sotho + + + Suto + + + + info:lc/vocabulary/languages/sso + Sotho + sso + + + info:lc/vocabulary/languages/sai + South American Indian (Other) + sai + + Achagua + + + Achuar + + Achuale + + + Achuara Jivaro + + + Jivaro, Achuara + + + + Aguaruna + + + Alacaluf + + Kawesqar + + + + Amahuaca + + Sayaco + + + + Amuesha + + Lorenzo + + + + Andoque + + + Apalai + + + Apinagé + + Apinajé + + + Apinayé + + + + Arabela + + Chiripuno + + + + Araona + + + Arecuna + + + Arekena + + Guarequena + + + Uarequena + + + Warekena + + + + Bakairi + + Bacairi + + + + Baniwa + + + Barasana del Norte + + Bara (Colombia) + + + Northern Barasano + + + + Barasana del Sur + + Bara (Colombia) + + + Southern Barasano + + + + Bora + + Boro (South America) + + + + Bororo (Brazil) + + + Cacua + + Macú de cubeo + + + Macú de desano + + + Macú de guanano + + + + Caduveo + + Kadiweu + + + + Caingua + + Cayua + + + Kaingua + + + Kaiwa (Brazil) + + + + Callahuaya + + Callawalla + + + Callawaya + + + Kallawaya + + + Qollahuaya + + + + Campa + + Ande + + + Asheninca + + + + Camsa + + Coche + + + Kamentzá + + + Kamsa + + + Sebondoy + + + Sibondoy + + + + Canamari (Tucanoan) + + Kanamari (Tucanoan) + + + + Cañari + + + Candoshi + + Kandoshi + + + Morato + + + Murato + + + Shapra + + + + Canella + + Kanela + + + + Capanahua + + + Caquinte + + + Caraja + + Karaja + + + + Carapana (Tucanoan) + + Karapana (Tucanoan) + + + Möchda (Tucanoan) + + + + Cashibo + + Comabo + + + + Cashinawa + + Kashinawa + + + Sheminawa + + + + Catio + + Embena, Northern + + + Epera, Northern + + + Katio + + + Northern Epera + + + + Cauqui + + Jacaru + + + Jaqaru + + + + Cavineño + + + Cayapa + + + Cayapo + + Kayapo + + + + Chacobo + + + Chamacoco + + + Chamí + + Embera Chamí + + + + Chamicuro + + + Chana (Uruguay) + + Čaná + + + Layuna + + + Tšaná + + + Tsaná-Bequá + + + Tschaná + + + Yaro + + + + Chayahuita + + Chawi + + + + Chimane + + Nawazi-Moñtji + + + Tsimane + + + + Chipaya + + Puquina (Chipaya) + + + + Chiquito + + + Cholon + + + Chontaquiro + + Chuntaquiro + + + Piro (Arawakan) + + + Simirenchi + + + + Choroti + + Yofuaha + + + + Chulupí + + Ashluslay + + + Nivacle + + + + Cocama + + Kokama + + + Ucayale + + + + Cofán + + A'i + + + Kofán + + + + Colorado + + Tsacela + + + Yumba + + + + Coreguaje + + Caqueta + + + + Cuaiquer + + Coaiker + + + Koaiker + + + + Cubeo + + + Cuiba + + Cuiva + + + + Culina + + + Cumana + + + Cuna + + Kuna + + + + Damana + + Arosario + + + Guamaca + + + Malayo + + + Maracasero + + + Sanja + + + Wiwa + + + + Desana + + Wira + + + + Emerillon + + Mereo + + + Teco (Tupi) + + + + Epena Saija + + Saija + + + Saixa + + + + Ese Ejja + + Chama (Tacanan) + + + Guacanahua + + + Guarayo (Tacanan) + + + Huarayo (Tacanan) + + + Tiatinagua + + + + Fulnio + + Carnijo + + + Iate + + + Yahthe + + + Yate (Brazil) + + + + Gavião (Pará, Brazil) + + + Goajiro + + Guajira + + + Wayunaiki + + + Wayuu + + + + Guahibo + + Wa-jibi + + + + Guanano + + Anano + + + Kotiria + + + Uanana + + + Wanana + + + + Guarayo + + + Guayabero + + Jiw + + + + Guayaki + + Ache + + + Guaiaqui + + + Guayaki-Ache + + + Guoyagui + + + + Hixkaryana + + + Huambisa + + Ssimaku + + + Wambisa + + + + Huao + + Waorani + + + + Ica + + Arhuaco + + + Aruaco + + + Bintukua + + + Ika (Chibchan) + + + Ike + + + + Ipurina + + Apurina + + + Hypurina + + + Jupurina + + + Kangütü + + + Kankiti + + + + Iquito + + + Itonama + + Machoto + + + + Jaminaua + + Nishinahua + + + Yaminahua + + + + Jaruára + + Jarawara + + + + Jupda + + Hupde Maku + + + Macú de tucano + + + + Kagaba + + Cagaba + + + + Kaingang + + Caingang + + + Taven + + + + Kariri + + Cariri + + + Kiriri + + + + Karitiana + + Caritiana + + + + Lengua + + + Lule + + + Maca + + Maka (Paraguay) + + + + Machiguenga + + + Macuna + + Buhágana + + + + Macusi + + Makushi + + + + Mamaindê + + Tamainde + + + + Masacali + + Machacali + + + Mashakali + + + Maxakali + + + + Mascoi + + Emok + + + Machicui + + + Toba-Emok + + + + Mashco + + Amarakaeri + + + Harakmbet + + + + Mataco + + + Maue + + Andira + + + Arapium + + + Maragua + + + Satere + + + + Mayoruna + + Matses + + + + Moguex + + Cuambia + + + Guambiano + + + + Mojo + + Ignaciano + + + Moxo + + + + Moro (South America) + + Ayoré + + + Ayoweo + + + + Moseten + + + Motilon + + Bari (Venezuela) + + + Yupe + + + + Muinane + + + Munduruku + + + Münkü + + + Murui + + Huitoto, Murui + + + + Nambicuara + + Nhambicuara + + + + Nomatsiguenga + + Pangoa + + + + Ocaina + + + Orejón + + Coto (Tucanoan) + + + Mai Huna + + + Payagua + + + + Paez + + + Palicur + + + Pamoa + + Juna + + + Oa + + + Tatutapuyo + + + + Panare + + + Panobo + + + Paraujano + + Añún + + + + Paressi + + Ariti + + + + Patamona + + Paramuni + + + + Pemón + + + Piapoco + + + Piaroa + + + Pilaga + + + Piratapuyo + + + Puinave + + + Puquina + + + Purupuru + + Paumari + + + + Resigero + + + Rikbaktsa + + Aripaktsa + + + Canoeiro + + + + Saliva + + Saliba (Colombia and Venezuela) + + + + Sanapaná + + Lanapsua + + + Quiativis + + + Quilyacmoc + + + Saapa + + + Sanam + + + + Secoya + + + Sharanahua + + Chandinahua + + + Marinahua + + + + Shipibo-Conibo + + Conibo + + + Sipibo + + + + Shuar + + Jibaro, Shuar + + + Jivaro, Shuar + + + Xivaro, Shuar + + + + Sicuane + + Sikuani + + + + Sioni + + Siona + + + + Siriano + + Chiranga + + + + Tacana (Bolivia) + + + Tanimuca-Retuama + + Letuana + + + Retuara + + + Ufaina + + + Yahuna + + + + Tapirapé + + + Tariana + + + Tenetehara + + Asurini + + + Guajajara + + + Tembe + + + + Tenharim + + + Toba (Indian) + + + Trio + + Tiriyo + + + + Tucano + + Dagsexe + + + Dase + + + Tukano + + + + Tucuna + + Ticuna + + + + Tunebo + + Pedrazá + + + Tame + + + + Tuyuca + + Dochkafuara + + + Tejuka + + + + Urarina + + Itucale + + + Shimacu + + + Simacu + + + + Uru + + Puquina (Uru) + + + + Urubu + + + Vilela + + + Waiwai + + Uaiuai + + + + Warao + + Guarauno + + + Warrau + + + + Waunana + + Chanco + + + Chocama + + + Noanama + + + + Wayampi + + Guayapi + + + Oiampi + + + Waiapi + + + Wayapi + + + + Witoto + + Huitoto + + + + Xavante + + Acuan-Shavante + + + Akwẽ-Shavante + + + Chavante Acuan + + + Oti + + + Shavante Akwe + + + + Yagua + + Yegua + + + + Yahgan + + Jagane + + + + Yanomamo + + + Yaruro + + Hapotein + + + Llaruro + + + Pumé + + + Yuapin + + + + Yecuana + + Maquiritare + + + + Yucuna + + Matapi + + + + Yunca + + Chimu + + + Mochica + + + + Yupa + + + Yuruti + + + Zoró + + + + info:lc/vocabulary/languages/sma + Southern Sami + sma + + Sami, Southern + + + + info:lc/vocabulary/languages/spa + Spanish + spa + + Castilian + + + Chicano + + + Cheso + + + + info:lc/vocabulary/languages/srn + Sranan + srn + + Taki-Taki + + + + info:lc/vocabulary/languages/suk + Sukuma + suk + + Gwe (Tanzania) + + + Kesukuma + + + Kisukuma + + + Suku (Tanzania) + + + + info:lc/vocabulary/languages/sux + Sumerian + sux + + + info:lc/vocabulary/languages/sun + Sundanese + sun + + + info:lc/vocabulary/languages/sus + Susu + sus + + Soso + + + + info:lc/vocabulary/languages/swa + Swahili + swa + + Kae + + + Kingwana + + + + info:lc/vocabulary/languages/ssw + Swazi + ssw + + Siswati + + + + info:lc/vocabulary/languages/swz + Swazi + swz + + + info:lc/vocabulary/languages/swe + Swedish + swe + + + info:lc/vocabulary/languages/gsw + Swiss German + gsw + + German, Swiss + + + + info:lc/vocabulary/languages/syc + Syriac + syc + + Classifical Syriac + + + + info:lc/vocabulary/languages/syr + Syriac, Modern + syr + + Neo-Syriac + + + + info:lc/vocabulary/languages/tgl + Tagalog + tgl + + Filipino (Tagalog) + + + Pilipino + + + + info:lc/vocabulary/languages/tag + Tagalog + tag + + + info:lc/vocabulary/languages/tah + Tahitian + tah + + + info:lc/vocabulary/languages/tai + Tai (Other) + tai + + Ahom + + + Be + + Ongbe + + + + Black Tai + + Tai, Black + + + Tai Dam + + + Tai Noir + + + + Bouyei + + Buyi (China and Vietnam) + + + Dioi (China and Vietnam) + + + Giáy + + + Nhang + + + Puyi + + + Yay + + + + Cao Lan + + + Dong (China) + + Gam (China) + + + Kam (China) + + + Tong (China) + + + T‘ung + + + + Khün + + Hkun + + + Tai Khün + + + + + + Lue + + + Pai-i + + + Tai Lü + + + + Lungming + + + Northern Thai + + Kammyang + + + Lanna Thai + + + Lao, Western + + + Myang + + + Phayap + + + Thai, Northern + + + Western Lao + + + Yuan + + + + Southern Thai + + Pak Thai + + + Thai, Southern + + + + Tai Nüa + + Dai Na + + + Dehong Dai + + + Shan, Yunnanese + + + Tay Nüa + + + Te-hung Tai + + + Yunnanese Shan + + + + Tay-Nung + + + Tho + + + White Tai + + Tai, White + + + + Ya + + Tai Chung + + + Tai Ya + + + + + info:lc/vocabulary/languages/tgk + Tajik + tgk + + Tadjik + + + Tadzhik + + + + info:lc/vocabulary/languages/taj + Tajik + taj + + + info:lc/vocabulary/languages/tmh + Tamashek + tmh + + Amazigh + + + Kidal + + + Kidal Tamasheq + + + Tăhăggart + + + Tahaggart Tamahaq + + + Tahoua + + + Tahoua Tamajeq + + + Tajag + + + Tamachek + + + Tamahaq + + + Tamajaq + + + Tamajeq + + + Tamashekin + + + Tamasheq + + + Tamashiqt + + + Tawallammat Tamajaq + + + Tawarek + + + Tayart Tamajeq + + + Temajaq + + + Tewellemet + + + Timbuktu + + + Tomacheck + + + Tomachek + + + Touareg + + + Touarègue + + + Tourage + + + Toureg + + + Tuareg + + + + info:lc/vocabulary/languages/tam + Tamil + tam + + + info:lc/vocabulary/languages/tat + Tatar + tat + + + info:lc/vocabulary/languages/tar + Tatar + tar + + + info:lc/vocabulary/languages/tel + Telugu + tel + + Andhra + + + Gentoo + + + Telegu + + + + info:lc/vocabulary/languages/tem + Temne + tem + + Timne + + + + info:lc/vocabulary/languages/ter + Terena + ter + + + info:lc/vocabulary/languages/tet + Tetum + tet + + Belu + + + + info:lc/vocabulary/languages/tha + Thai + tha + + Siamese + + + + info:lc/vocabulary/languages/tib + Tibetan + tib + + Bhotanta + + + Helambu Sherpa + + Hyolmo + + + Yohlmo + + + + Kagate + + + Khams Tibetan + + Kam + + + Kang (Tibetan) + + + Kham (China) + + + Khamba (Tibetan) + + + Khampa + + + Khams + + + Khams Bhotia + + + Khams-Yal + + + + Sherpa + + Sharpa + + + + + info:lc/vocabulary/languages/tig + Tigré + tig + + + info:lc/vocabulary/languages/tir + Tigrinya + tir + + Tigriña + + + Tña + + + + info:lc/vocabulary/languages/tiv + Tiv + tiv + + + info:lc/vocabulary/languages/tli + Tlingit + tli + + Koluschan + + + Tongass + + + + info:lc/vocabulary/languages/tpi + Tok Pisin + tpi + + Neo-Melanesian + + + Pisin + + + + info:lc/vocabulary/languages/tkl + Tokelauan + tkl + + + info:lc/vocabulary/languages/tog + Tonga (Nyasa) + tog + + + info:lc/vocabulary/languages/ton + Tongan + ton + + Tonga (Tonga Islands) + + + + info:lc/vocabulary/languages/tru + Truk + tru + + + info:lc/vocabulary/languages/tsi + Tsimshian + tsi + + Zimshīan + + + + info:lc/vocabulary/languages/tso + Tsonga + tso + + Changana + + + Gwamba + + + Shangaan + + + Thonga + + + Tonga (Tsonga) + + + Xitsonga + + + + info:lc/vocabulary/languages/tsn + Tswana + tsn + + Bechuana + + + Chuana + + + Coana + + + Cuana + + + Cwana + + + Sechuana + + + Setswana + + + + info:lc/vocabulary/languages/tsw + Tswana + tsw + + + info:lc/vocabulary/languages/tum + Tumbuka + tum + + Tamboka + + + + info:lc/vocabulary/languages/tup + Tupi languages + tup + + Parintintin + + + Tupi + + Ñeengatú + + + + + info:lc/vocabulary/languages/tur + Turkish + tur + + + info:lc/vocabulary/languages/ota + Turkish, Ottoman + ota + + Osmanli + + + Ottoman Turkish + + + + info:lc/vocabulary/languages/tuk + Turkmen + tuk + + Turkoman + + + + info:lc/vocabulary/languages/tvl + Tuvaluan + tvl + + Ellicean + + + + info:lc/vocabulary/languages/tyv + Tuvinian + tyv + + Soyot + + + Tannu-Tuva + + + Tuba + + + Uriankhai + + + + info:lc/vocabulary/languages/twi + Twi + twi + + Akuapem + + + Ashanti + + + Chwee + + + Odschi + + + Tshi + + + + info:lc/vocabulary/languages/udm + Udmurt + udm + + Votiak + + + Votyak + + + + info:lc/vocabulary/languages/uga + Ugaritic + uga + + + info:lc/vocabulary/languages/uig + Uighur + uig + + Eastern Turki + + + Kashgar-Yarkend + + + Turki, Eastern + + + Uigur + + + Uyghur + + + Wighor + + + Yarkend + + + + info:lc/vocabulary/languages/ukr + Ukrainian + ukr + + + info:lc/vocabulary/languages/umb + Umbundu + umb + + Benguela + + + Mbundu (Benguela Province, Angola) + + + Ovimbundu + + + Quimbundo (Benguela Province, Angola) + + + South Mbundu + + + + info:lc/vocabulary/languages/und + Undetermined + und + + + info:lc/vocabulary/languages/hsb + Upper Sorbian + hsb + + High Sorbian + + + Sorbian, Upper + + + + info:lc/vocabulary/languages/urd + Urdu + urd + + Bihari (Urdu) + + + Gujri (Urdu) + + + Gurjari + + + Islami + + + Moorish (India) + + + Undri + + + Urudu + + + Dakhini + + Dakani + + + Dakhani + + + Dakhini Hindi + + + Dakhini Hindustani + + + Dakhini Urdu + + + Dakhni + + + Dakini + + + Dakkani + + + Dakkhani + + + Deccan + + + Dehlavi + + + Gujari (Dakhini) + + + Hindavi + + + + + info:lc/vocabulary/languages/uzb + Uzbek + uzb + + + info:lc/vocabulary/languages/vai + Vai + vai + + Vei + + + + info:lc/vocabulary/languages/ven + Venda + ven + + Tshivenda + + + Wenda + + + + info:lc/vocabulary/languages/vie + Vietnamese + vie + + Annamese + + + + info:lc/vocabulary/languages/vol + Volapük + vol + + + info:lc/vocabulary/languages/vot + Votic + vot + + Vatjan + + + Vote + + + Votian + + + Votish + + + + info:lc/vocabulary/languages/wak + Wakashan languages + wak + + Bella Bella + + + Haisla + + + Heiltsuk + + Haeltzuk + + + + Kwakiutl + + + Nitinat + + + Nootka + + Aht + + + Noutka + + + Nutka + + + Nuuchahnulth + + + + + info:lc/vocabulary/languages/wln + Walloon + wln + + + info:lc/vocabulary/languages/war + Waray + war + + Leytean + + + Samar-Leyte + + + Samaron + + + + info:lc/vocabulary/languages/was + Washoe + was + + Washo + + + Washoan + + + + info:lc/vocabulary/languages/wel + Welsh + wel + + Cymric + + + + info:lc/vocabulary/languages/him + Western Pahari languages + him + + Himachali + + + Pahadi + + + Pahari, Western + + + Bhadrawahi + + Baderwali + + + Badrohi + + + Bahi + + + Bhadarwahi + + + Bhaderbhai Jamu + + + Bhaderwali Pahari + + + Bhadrava + + + Bhadravāhī + + + Bhadri + + + + Bhalesi + + + Bilaspuri + + Bilāsapurī + + + Bilaspuri Pahari + + + Kahalurī + + + Khalūrī + + + Kehloori + + + Kehloori Pahari + + + Kehluri + + + Pacchmi + + + + Chambeali + + Cameali + + + Chamaya + + + Chambiali + + + Chambiyali + + + Chamiyali + + + Chamiyali Pahari + + + Chamya + + + + Gaddi + + Bharmauri + + + Bharmauri Bhadi + + + Bharmouri + + + Brahmauri + + + Gaddhi + + + Gaddyalali + + + Gaddyali + + + Gadhi + + + Gadhiali + + + Gadi + + + Gadiali + + + Gadiyali + + + Pahari Bharmauri + + + Panchi + + + Panchi Brahmauri Rajput + + + + Jaunsari + + Gaunsari + + + Jansauri + + + Jaunsauri + + + Pahari (Jaunsari) + + + + Kullu Pahari + + Kauli + + + Kullui + + + Kulu + + + Kulu Boli + + + Kulu Pahari + + + Kuluhi + + + Kului + + + Kulvi + + + Kulwali + + + Pahari Kullu + + + Pahari (Kullu Pahari) + + + Phari Kulu + + + + Mandeali + + Himachali (Mandeali) + + + Mandi (Mandeali) + + + Mandiali + + + Pahari Mandiyali + + + + Sirmauri + + Himachali (Sirmauri) + + + Pahari (Sirmauri) + + + Sirmouri + + + Sirmuri + + + + + info:lc/vocabulary/languages/wal + Wolayta + wal + + Ometo + + + Uallamo + + + Walamo + + + + info:lc/vocabulary/languages/wol + Wolof + wol + + Jaloof + + + Jolof + + + Ouolof + + + Volof + + + Yolof + + + Lebou + + + + info:lc/vocabulary/languages/xho + Xhosa + xho + + isiXhosa + + + Kafir + + + Xosa + + + + info:lc/vocabulary/languages/sah + Yakut + sah + + Jakut + + + Sakha + + + + info:lc/vocabulary/languages/yao + Yao (Africa) + yao + + Adjaua + + + Ajawa + + + Ayo + + + Chi-yao + + + Ciyao + + + Djao + + + Hiao + + + Wayao + + + + info:lc/vocabulary/languages/yap + Yapese + yap + + + info:lc/vocabulary/languages/yid + Yiddish + yid + + German Hebrew + + + Jewish + + + Judeo-German + + + + info:lc/vocabulary/languages/yor + Yoruba + yor + + Aku + + + Eyo + + + Nago + + + Yariba + + + + info:lc/vocabulary/languages/ypk + Yupik languages + ypk + + Eskimo languages, Western + + + Western Eskimo languages + + + Central Yupik + + Eskimo, West Alaska + + + West Alaska Eskimo + + + + Cup´ig + + + Pacific Gulf Yupik + + Aleut (Eskimo) + + + Eskimo, South Alaska + + + Sugpiak Eskimo + + + Suk (Eskimo) + + + + Sirinek + + + Yuit + + Asiatic Eskimo + + + Eskimo, Asiatic + + + Saint Lawrence Island Yupik + + + Siberian Yupik + + + + + info:lc/vocabulary/languages/znd + Zande languages + znd + + Nzakara + + Sakara + + + + Zande + + Azande + + + + + info:lc/vocabulary/languages/zap + Zapotec + zap + + + info:lc/vocabulary/languages/zza + Zaza + zza + + Dimili + + + Dimli + + + Kirdki + + + Kirmanjki + + + Zazaki + + + + info:lc/vocabulary/languages/zen + Zenaga + zen + + Senhadja + + + + info:lc/vocabulary/languages/zha + Zhuang + zha + + Chuang + + + + info:lc/vocabulary/languages/zul + Zulu + zul + + + info:lc/vocabulary/languages/zun + Zuni + zun + + + diff --git a/form_elements/xml/relators.rdf b/form_elements/xml/relators.rdf new file mode 100644 index 00000000..66df3d04 --- /dev/null +++ b/form_elements/xml/relators.rdf @@ -0,0 +1,4297 @@ + + + + + MARC Code List for Relators + + <div class="relatorsAbout" title="About the Relator Codes:" datatype="rdf:XMLLiteral" property="rdfs:comment">Relator terms and their associated codes designate the relationship between a name and a bibliographic resource. The relator codes are three-character lowercase alphabetic strings that serve as identifiers. Either the term or the code may be used as controlled values.</div> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Actor + act + Use for a person or organization who + principally exhibits acting skills in a musical or + dramatic presentation or entertainment. + + stable + + + + + + + Adapter + adp + Use for a person or organization who 1) + reworks a musical composition, usually for a + different medium, or 2) rewrites novels or stories + for motion pictures or other audiovisual + medium. + + stable + + + + + + + Analyst + anl + Use for a person or organization that + reviews, examines and interprets data or information + in a specific area. + + stable + + + + + + Animator + anm + Use for a person or organization who draws + the two-dimensional figures, manipulates the three + dimensional objects and/or also programs the + computer to move objects and images for the purpose + of animated film processing. Animation cameras, + stands, celluloid screens, transparencies and inks + are some of the tools of the animator. + + stable + + + + + + + Annotator + ann + Use for a person who writes manuscript + annotations on a printed item. + + stable + + + + + + + Applicant + app + Use for a person or organization + responsible for the submission of an application or + who is named as eligible for the results of the + processing of the application (e.g., bestowing of + rights, reward, title, position). + + stable + + + + + + Architect + arc + Use for a person or organization who + designs structures or oversees their + construction. + + stable + + + + + + + Arranger + arr + Use for a person or organization who + transcribes a musical composition, usually for a + different medium from that of the original; in an + arrangement the musical substance remains + essentially unchanged. + + stable + + + + + + + Art copyist + acp + Use for a person (e.g., a painter or + sculptor) who makes copies of works of visual + art. + + stable + + + + + + Artist + art + Use for a person (e.g., a painter) or + organization who conceives, and perhaps also + implements, an original graphic design or work of + art, if specific codes (e.g., [egr], [etr]) are not + desired. For book illustrators, prefer Illustrator + [ill]. + + stable + Graphic technician + Relator term "Graphic technician" (coded [grt]) used before March 1988 only. + + + + + + + Artistic director + ard + Use for a person responsible for + controlling the development of the artistic style of + an entire production, including the choice of works + to be presented and selection of senior production + staff. + + stable + + + + + + Assignee + asg + Use for a person or organization to whom a + license for printing or publishing has been + transferred. + + stable + + + + + + Associated name + asn + Use for a person or organization + associated with or found in an item or collection, + which cannot be determined to be that of a Former + owner [fmo] or other designated relator indicative + of provenance. + + stable + + + + + + Attributed name + att + Use for an author, artist, etc., relating + him/her to a work for which there is or once was + substantial authority for designating that person as + author, creator, etc. of the work. + + stable + Supposed name + + + + + + Auctioneer + auc + Use for a person or organization in charge + of the estimation and public auctioning of goods, + particularly books, artistic works, + etc. + + stable + + + + + + Author + aut + Use for a person or organization chiefly + responsible for the intellectual or artistic content + of a work, usually printed text. This term may also + be used when more than one person or body bears such + responsibility. + + stable + Joint author + + + + + + + Author in quotations or text + extracts + aqt + Use for a person or organization whose + work is largely quoted or extracted in works to + which he or she did not contribute directly. Such + quotations are found particularly in exhibition + catalogs, collections of photographs, + etc. + + stable + + + + + + + Author of afterword, colophon, + etc. + aft + Use for a person or organization + responsible for an afterword, postface, colophon, + etc. but who is not the chief author of a + work. + + stable + + + + + + + Author of dialog + aud + Use for a person or organization + responsible for the dialog or spoken commentary for + a screenplay or sound recording. + + stable + + + + + + + Author of introduction, etc. + aui + Use for a person or organization + responsible for an introduction, preface, foreword, + or other critical introductory matter, but who is + not the chief author. + + stable + + + + + + + Author of screenplay, etc. + aus + Use for a person or organization + responsible for a motion picture screenplay, dialog, + spoken commentary, etc. + + stable + + + + + + + Bibliographic antecedent + ant + Use for a person or organization + responsible for a work upon which the work + represented by the catalog record is based. This may + be appropriate for adaptations, sequels, + continuations, indexes, etc. + + stable + + + + + + Binder + bnd + Use for a person or organization + responsible for the binding of printed or manuscript + materials. + + stable + + + + + + Binding designer + bdd + Use for a person or organization + responsible for the binding design of a book, + including the type of binding, the type of materials + used, and any decorative aspects of the binding. + + stable + Designer of binding + + + + + + Blurb writer + blw + Use for the named entity responsible for writing a commendation + or testimonial for a work, which appears on or within the publication + itself, frequently on the back or dust jacket of print publications or + on advertising material for all media. + + stable + + + + + + Book designer + bkd + Use for a person or organization + responsible for the entire graphic design of a book, + including arrangement of type and illustration, + choice of materials, and process used. + + stable + Designer of book + + + + + + Book producer + bkp + Use for a person or organization + responsible for the production of books and other + print media, if specific codes (e.g., [bkd], [egr], + [tyd], [prt]) are not desired. + + stable + Producer of book + + + + + + Bookjacket designer + bjd + Use for a person or organization + responsible for the design of flexible covers + designed for or published with a book, including the + type of materials used, and any decorative aspects + of the bookjacket. + + stable + Designer of bookjacket + + + + + + Bookplate designer + bpd + Use for a person or organization + responsible for the design of a book owner's + identification label that is most commonly pasted to + the inside front cover of a book. + + stable + Designer of bookplate + + + + + + Bookseller + bsl + Use for a person or organization who makes + books and other bibliographic materials available + for purchase. Interest in the materials is primarily + lucrative. + + stable + + + + + + Calligrapher + cll + Use for a person or organization who + writes in an artistic hand, usually as a copyist and + or engrosser. + + stable + + + + + + + Cartographer + ctg + Use for a person or organization + responsible for the creation of maps and other + cartographic materials. + + stable + + + + + + + Censor + cns + Use for a censor, bowdlerizer, expurgator, + etc., official or private. + + stable + Bowdlerizer + Expurgator + + + + + + Choreographer + chr + Use for a person or organization who + composes or arranges dances or other movements + (e.g., "master of swords") for a musical or dramatic + presentation or entertainment. + + stable + + + + + + + Cinematographer + cng + Use for a person or organization who is in + charge of the images captured for a motion picture + film. The cinematographer works under the + supervision of a director, and may also be referred + to as director of photography. Do not confuse with + videographer. + + stable + + + + + + + Client + cli + Use for a person or organization for whom + another person or organization is + acting. + + stable + + + + + + Collaborator + clb + Use for a person or organization that + takes a limited part in the elaboration of a work of + another person or organization that brings + complements (e.g., appendices, notes) to the + work. + + stable + + + + + + + Collector + col + Use for a person or organization who has + brought together material from various sources that + has been arranged, described, and cataloged as a + collection. A collector is neither the creator of + the material nor a person to whom manuscripts in the + collection may have been addressed. + + stable + + + + + + Collotyper + clt + Use for a person or organization + responsible for the production of photographic + prints from film or other colloid that has + ink-receptive and ink-repellent + surfaces. + + stable + + + + + + + Colorist + clr + Use for the named entity responsible for applying color to + drawings, prints, photographs, maps, moving images, etc. + + stable + + + + + + Commentator + cmm + Use for a person or organization who + provides interpretation, analysis, or a discussion + of the subject matter on a recording, motion + picture, or other audiovisual medium. + + stable + + + + + + + Commentator for written text + cwt + Use for a person or organization + responsible for the commentary or explanatory notes + about a text. For the writer of manuscript + annotations in a printed book, use Annotator + [ann]. + + stable + + + + + + + Compiler + com + Use for a person or organization who + produces a work or publication by selecting and + putting together material from the works of various + persons or bodies. + + stable + + + + + + + Complainant + cpl + Use for the party who applies to the + courts for redress, usually in an equity + proceeding. + + stable + + + + + + Complainant-appellant + cpt + Use for a complainant who takes an appeal + from one court or jurisdiction to another to reverse + the judgment, usually in an equity + proceeding. + + stable + + + + + + Complainant-appellee + cpe + Use for a complainant against whom an + appeal is taken from one court or jurisdiction to + another to reverse the judgment, usually in an + equity proceeding. + + stable + + + + + + Composer + cmp + Use for a person or organization who + creates a musical work, usually a piece of music in + manuscript or printed form. + + stable + + + + + + + Compositor + cmt + Use for a person or organization + responsible for the creation of metal slug, or molds + made of other materials, used to produce the text + and images in printed matter. + + stable + Typesetter + + + + + + Conceptor + ccp + Use for a person or organization + responsible for the original idea on which a work is + based, this includes the scientific author of an + audio-visual item and the conceptor of an + advertisement. + + stable + + + + + + + Conductor + cnd + Use for a person who directs a performing + group (orchestra, chorus, opera, etc.) in a musical + or dramatic presentation or + entertainment. + + stable + + + + + + + Conservator + con + Use for the named entity responsible for documenting, + preserving, or treating printed or manuscript material, works of art, + artifacts, or other media. + + stable + Preservationist + + + + + + Consultant + csl + Use for a person or organization relevant + to a resource, who is called upon for professional + advice or services in a specialized field of + knowledge or training. + + stable + + + + + + + Consultant to a project + csp + Use for a person or organization relevant + to a resource, who is engaged specifically to + provide an intellectual overview of a strategic or + operational task and by analysis, specification, or + instruction, to create or propose a cost-effective + course of action or solution. + + stable + + + + + + + Contestant + cos + Use for the party who opposes, resists, or + disputes, in a court of law, a claim, decision, + result, etc. + + stable + + + + + + Contestant-appellant + cot + Use for a contestant who takes an appeal + from one court of law or jurisdiction to another to + reverse the judgment. + + stable + + + + + + Contestant-appellee + coe + Use for a contestant against whom an + appeal is taken from one court of law or + jurisdiction to another to reverse the + judgment. + + stable + + + + + + Contestee + cts + Use for the party defending a claim, + decision, result, etc. being opposed, resisted, or + disputed in a court of law. + + stable + + + + + + Contestee-appellant + ctt + Use for a contestee who takes an appeal + from one court or jurisdiction to another to reverse + the judgment. + + stable + + + + + + Contestee-appellee + cte + Use for a contestee against whom an appeal + is taken from one court or jurisdiction to another + to reverse the judgment. + + stable + + + + + + Contractor + ctr + Use for a person or organization relevant + to a resource, who enters into a contract with + another person or organization to perform a specific + task. + + stable + + + + + + + Contributor + ctb + Use for a person or organization one whose + work has been contributed to a larger work, such as + an anthology, serial publication, or other + compilation of individual works. Do not use if the + sole function in relation to a work is as author, + editor, compiler or translator. + + stable + + + + + + + Copyright claimant + cpc + Use for a person or organization listed as + a copyright owner at the time of registration. + Copyright can be granted or later transferred to + another person or organization, at which time the + claimant becomes the copyright holder. + + stable + + + + + + Copyright holder + cph + Use for a person or organization to whom + copy and legal rights have been granted or + transferred for the intellectual content of a work. + The copyright holder, although not necessarily the + creator of the work, usually has the exclusive right + to benefit financially from the sale and use of the + work to which the associated copyright protection + applies. + + stable + + + + + + Corrector + crr + Use for a person or organization who is a + corrector of manuscripts, such as the scriptorium + official who corrected the work of a scribe. For + printed matter, use Proofreader [pfr]. + + stable + + + + + + Correspondent + crp + Use for a person or organization who was + either the writer or recipient of a letter or other + communication. + + stable + + + + + + + Costume designer + cst + Use for a person or organization who + designs or makes costumes, fixes hair, etc., for a + musical or dramatic presentation or + entertainment. + + stable + + + + + + + Cover designer + cov + Use for a person or organization + responsible for the graphic design of a book cover, + album cover, slipcase, box, container, etc. For a + person or organization responsible for the graphic + design of an entire book, use Book designer; for + book jackets, use Bookjacket designer. + + stable + Designer of cover + + + + + + Creator + cre + Use for a person or organization + responsible for the intellectual or artistic content + of a work. + + stable + + + + + + + + Curator of an exhibition + cur + Use for a person or organization + responsible for conceiving and organizing an + exhibition. + + stable + + + + + + + Dancer + dnc + Use for a person or organization who + principally exhibits dancing skills in a musical or + dramatic presentation or entertainment. + + stable + + + + + + + Data contributor + dtc + Use for a person or organization that + submits data for inclusion in a database or other + collection of data. + + stable + + + + + + Data manager + dtm + Use for a person or organization + responsible for managing databases or other data + sources. + + stable + + + + + + Dedicatee + dte + Use for a person or organization to whom a + book, manuscript, etc., is dedicated (not the + recipient of a gift). + + stable + + + + + + Dedicator + dto + Use for the author of a dedication, which + may be a formal statement or in epistolary or verse + form. + + stable + + + + + + Defendant + dfd + Use for the party defending or denying + allegations made in a suit and against whom relief + or recovery is sought in the courts, usually in a + legal action. + + stable + + + + + + Defendant-appellant + dft + Use for a defendant who takes an appeal + from one court or jurisdiction to another to reverse + the judgment, usually in a legal + action. + + stable + + + + + + Defendant-appellee + dfe + Use for a defendant against whom an appeal + is taken from one court or jurisdiction to another + to reverse the judgment, usually in a legal + action. + + stable + + + + + + Degree grantor + dgg + Use for the organization granting a degree + for which the thesis or dissertation described was + presented. + + stable + + + + + + Delineator + dln + Use for a person or organization executing + technical drawings from others' + designs. + + stable + + + + + + + Depicted + dpc + Use for an entity depicted or portrayed in + a work, particularly in a work of art. + + stable + + + + + + + Depositor + dpt + Use for a person or organization placing + material in the physical custody of a library or + repository without transferring the legal + title. + + stable + + + + + + Designer + dsr + Use for a person or organization + responsible for the design if more specific codes + (e.g., [bkd], [tyd]) are not desired. + + stable + + + + + + + Director + drt + Use for a person or organization who is + responsible for the general management of a work or + who supervises the production of a performance for + stage, screen, or sound recording. + + stable + + + + + + + Dissertant + dis + Use for a person who presents a thesis for + a university or higher-level educational + degree. + + stable + + + + + + + Distribution place + dbp + Use for the name of a place from which a resource, + e.g., a serial, is distributed. + + stable + + + + + + Distributor + dst + Use for a person or organization that has + exclusive or shared marketing rights for an + item. + + stable + + + + + + + Donor + dnr + Use for a person or organization who is + the donor of a book, manuscript, etc., to its + present owner. Donors to previous owners are + designated as Former owner[fmo] or Inscriber + [ins]. + + stable + + + + + + Draftsman + drm + Use for a person or organization who + prepares artistic or technical drawings. + + stable + Technical draftsman + + + + + + + Dubious author + dub + Use for a person or organization to which + authorship has been dubiously or incorrectly + ascribed. + + stable + + + + + + Editor + edt + Use for a person or organization who + prepares for publication a work not primarily + his/her own, such as by elucidating text, adding + introductory or other critical matter, or + technically directing an editorial + staff. + + stable + + + + + + + Electrician + elg + Use for a person responsible for setting + up a lighting rig and focusing the lights for a + production, and running the lighting at a + performance. + + stable + Chief electrician + House electrician + Master electrician + + + + + + Electrotyper + elt + Use for a person or organization who + creates a duplicate printing surface by pressure + molding and electrodepositing of metal that is then + backed up with lead for printing. + + stable + + + + + + Engineer + eng + Use for a person or organization that is + responsible for technical planning and design, + particularly with construction. + + stable + + + + + + + Engraver + egr + Use for a person or organization who cuts + letters, figures, etc. on a surface, such as a + wooden or metal plate, for printing. + + stable + + + + + + + Etcher + etr + Use for a person or organization who + produces text or images for printing by subjecting + metal, glass, or some other surface to acid or the + corrosive action of some other + substance. + + stable + + + + + + + Event place + evp + Use for the name of the place where an event such + as a conference or a concert took place. + + stable + + + + + + Expert + exp + Use for a person or organization in charge + of the description and appraisal of the value of + goods, particularly rare items, works of art, etc. + + stable + Appraiser + + + + + + Facsimilist + fac + Use for a person or organization that + executed the facsimile. + + stable + Copier + + + + + + + Field director + fld + Use for a person or organization that + manages or supervises the work done to collect raw + data or do research in an actual setting or + environment (typically applies to the natural and + social sciences). + + stable + + + + + + Film editor + flm + Use for a person or organization who is an + editor of a motion picture film. This term is used + regardless of the medium upon which the motion + picture is produced or manufactured (e.g., acetate + film, video tape). + + stable + Motion picture editor + + + + + + + First party + fpy + Use for a person or organization who is + identified as the only party or the party of the + first part. In the case of transfer of right, this + is the assignor, transferor, licensor, grantor, etc. + Multiple parties can be named jointly as the first + party + + stable + + + + + + Forger + frg + Use for a person or organization who makes + or imitates something of value or importance, + especially with the intent to defraud. + + stable + Copier + Counterfeiter + + + + + + + Former owner + fmo + Use for a person or organization who owned + an item at any time in the past. Includes those to + whom the material was once presented. A person or + organization giving the item to the present owner is + designated as Donor [dnr]. + + stable + + + + + + Funder + fnd + Use for a person or organization that + furnished financial support for the production of + the work. + + stable + + + + + + Geographic information + specialist + gis + Use for a person responsible for + geographic information system (GIS) development and + integration with global positioning system data.. + + + stable + Geospatial information specialist + + + + + + Honoree + hnr + Use for a person or organization in memory + or honor of whom a book, manuscript, etc. is + donated. + + stable + Memorial + + + + + + Host + hst + Use for a person who is invited or + regularly leads a program (often broadcast) that + includes other guests, performers, etc. (e.g., talk + show host). + + stable + + + + + + + Illuminator + ilu + Use for a person or organization + responsible for the decoration of a work (especially + manuscript material) with precious metals or color, + usually with elaborate designs and + motifs. + + stable + + + + + + + Illustrator + ill + Use for a person or organization who + conceives, and perhaps also implements, a design or + illustration, usually to accompany a written + text. + + stable + + + + + + + Inscriber + ins + Use for a person who signs a presentation + statement. + + stable + + + + + + Instrumentalist + itr + Use for a person or organization who + principally plays an instrument in a musical or + dramatic presentation or entertainment. + + stable + + + + + + + Interviewee + ive + Use for a person or organization who is + interviewed at a consultation or meeting, usually by + a reporter, pollster, or some other information + gathering agent. + + stable + + + + + + + Interviewer + ivr + Use for a person or organization who acts + as a reporter, pollster, or other information + gathering agent in a consultation or meeting + involving one or more individuals. + + stable + + + + + + + Inventor + inv + Use for a person or organization who first + produces a particular useful item, or develops a new + process for obtaining a known item or + result. + + stable + + + + + + + Laboratory + lbr + Use for an institution that provides + scientific analyses of material + samples. + + stable + + + + + + Laboratory director + ldr + Use for a person or organization that + manages or supervises work done in a controlled + setting or environment. + + stable + Lab director + + + + + + Lead + led + Use to indicate that a person or + organization takes primary responsibility for a + particular activity or endeavor. Use with another + relator term or code to show the greater importance + this person or organization has regarding that + particular role. If more than one relator is + assigned to a heading, use the Lead relator only if + it applies to all the relators. + + stable + + + + + + Landscape architect + lsa + Use for a person or organization whose + work involves coordinating the arrangement of + existing and proposed land features and + structures. + + stable + + + + + + + Lender + len + Use for a person or organization + permitting the temporary use of a book, manuscript, + etc., such as for photocopying or + microfilming. + + stable + + + + + + Libelant + lil + Use for the party who files a libel in an + ecclesiastical or admiralty case. + + stable + + + + + + Libelant-appellant + lit + Use for a libelant who takes an appeal + from one ecclesiastical court or admiralty to + another to reverse the judgment. + + stable + + + + + + Libelant-appellee + lie + Use for a libelant against whom an appeal + is taken from one ecclesiastical court or admiralty + to another to reverse the judgment. + + stable + + + + + + Libelee + lel + Use for a party against whom a libel has + been filed in an ecclesiastical court or + admiralty. + + stable + + + + + + Libelee-appellant + let + Use for a libelee who takes an appeal from + one ecclesiastical court or admiralty to another to + reverse the judgment. + + stable + + + + + + Libelee-appellee + lee + Use for a libelee against whom an appeal + is taken from one ecclesiastical court or admiralty + to another to reverse the judgment. + + stable + + + + + + Librettist + lbt + Use for a person or organization who is a + writer of the text of an opera, oratorio, + etc. + + stable + + + + + + + Licensee + lse + Use for a person or organization who is an + original recipient of the right to print or + publish. + + stable + + + + + + Licensor + lso + Use for person or organization who is a + signer of the license, imprimatur, etc. + + stable + Imprimatur + + + + + + Lighting designer + lgd + Use for a person or organization who + designs the lighting scheme for a theatrical + presentation, entertainment, motion picture, etc. + + + stable + + + + + + + Lithographer + ltg + Use for a person or organization who + prepares the stone or plate for lithographic + printing, including a graphic artist creating a + design directly on the surface from which printing + will be done. + + stable + + + + + + + Lyricist + lyr + Use for a person or organization who is + the a writer of the text of a song. + + stable + + + + + + + Manufacturer + mfr + Use for a person or organization that + makes an artifactual work (an object made or + modified by one or more persons). Examples of + artifactual works include vases, cannons or pieces + of furniture. + + stable + + + + + + + Marbler + mrb + Use for the named entity responsible for marbling paper, cloth, + leather, etc. used in construction of a resource. + + stable + + + + + + Markup editor + mrk + Use for a person or organization + performing the coding of SGML, HTML, or XML markup + of metadata, text, etc. + + stable + + + + + + Metadata contact + mdc + Use for a person or organization primarily + responsible for compiling and maintaining the + original description of a metadata set (e.g., + geospatial metadata set). + + stable + + + + + + Metal-engraver + mte + Use for a person or organization + responsible for decorations, illustrations, letters, + etc. cut on a metal surface for printing or + decoration. + + stable + + + + + + + Moderator + mod + Use for a person who leads a program + (often broadcast) where topics are discussed, + usually with participation of experts in fields + related to the discussion. + + stable + + + + + + + Monitor + mon + Use for a person or organization that + supervises compliance with the contract and is + responsible for the report and controls its + distribution. Sometimes referred to as the grantee, + or controlling agency. + + stable + + + + + + Music copyist + mcp + Use for a person who transcribes or copies + musical notation. + + stable + + + + + + Musical director + msd + Use for a person responsible for basic + music decisions about a production, including + coordinating the work of the composer, the sound + editor, and sound mixers, selecting musicians, and + organizing and/or conducting sound for rehearsals + and performances. + + stable + + + + + + Musician + mus + Use for a person or organization who + performs music or contributes to the musical content + of a work when it is not possible or desirable to + identify the function more precisely. + + stable + + + + + + + Narrator + nrt + Use for a person who is a speaker relating + the particulars of an act, occurrence, or course of + events. + + stable + + + + + + + Opponent + opn + Use for a person or organization + responsible for opposing a thesis or + dissertation. + + stable + + + + + + Organizer of meeting + orm + Use for a person or organization + responsible for organizing a meeting for which an + item is the report or proceedings. + + stable + + + + + + + Originator + org + Use for a person or organization + performing the work, i.e., the name of a person or + organization associated with the intellectual + content of the work. This category does not include + the publisher or personal affiliation, or sponsor + except where it is also the corporate author. + Includes a person designated in the work as + investigator or principal investigator. + + stable + Principal investigator + + + + + + + Other + oth + Use for relator codes from other lists + which have no equivalent in the MARC list or for + terms which have not been assigned a + code. + + stable + + + + + + Owner + own + Use for a person or organization that + currently owns an item or collection. + + stable + + + + + + Papermaker + ppm + Use for a person or organization + responsible for the production of paper, usually + from wood, cloth, or other fibrous + material. + + stable + + + + + + Patent applicant + pta + Use for a person or organization that + applied for a patent. + + stable + + + + + + Patent holder + pth + Use for a person or organization that was + granted the patent referred to by the item. + + stable + Patentee + + + + + + Patron + pat + Use for a person or organization + responsible for commissioning a work. Usually a + patron means or influence to support the work of + artists, writers, etc. This includes those who + commission and pay for individual + works. + + stable + + + + + + Performer + prf + Use for a person or organization who + exhibits musical or acting skills in a musical or + dramatic presentation or entertainment, if specific + codes for those functions ([act], [dnc], [itr], + [voc], etc.) are not used. If specific codes are + used, [prf] is used for a person whose principal + skill is not known or specified. + + stable + + + + + + + Permitting agency + pma + Use for an authority (usually a government + agency) that issues permits under which work is + accomplished. + + stable + + + + + + Photographer + pht + Use for a person or organization + responsible for taking photographs, whether they are + used in their original form or as + reproductions. + + stable + + + + + + + Plaintiff + ptf + Use for the party who complains or sues in + court in a personal action, usually in a legal + proceeding. + + stable + + + + + + Plaintiff-appellant + ptt + Use for a plaintiff who takes an appeal + from one court or jurisdiction to another to reverse + the judgment, usually in a legal + proceeding. + + stable + + + + + + Plaintiff-appellee + pte + Use for a plaintiff against whom an appeal + is taken from one court or jurisdiction to another + to reverse the judgment, usually in a legal + proceeding. + + stable + + + + + + Platemaker + plt + Use for a person or organization + responsible for the production of plates, usually + for the production of printed images and/or + text. + + stable + + + + + + + Printer + prt + Use for a person or organization who + prints texts, whether from type or + plates. + + stable + + + + + + Printer of plates + pop + Use for a person or organization who + prints illustrations from plates. + + stable + Plates, Printer of + + + + + + Printmaker + prm + Use for a person or organization who makes + a relief, intaglio, or planographic printing + surface. + + stable + + + + + + + Process contact + prc + Use for a person or organization primarily + responsible for performing or initiating a process, + such as is done with the collection of metadata + sets. + + stable + + + + + + Producer + pro + Use for a person or organization + responsible for the making of a motion picture, + including business aspects, management of the + productions, and the commercial success of the + work. + + stable + + + + + + + Production manager + pmm + Use for a person responsible for all + technical and business matters in a + production. + + stable + + + + + + Production personnel + prd + Use for a person or organization + associated with the production (props, lighting, + special effects, etc.) of a musical or dramatic + presentation or entertainment. + + stable + + + + + + + Programmer + prg + Use for a person or organization + responsible for the creation and/or maintenance of + computer program design documents, source code, and + machine-executable digital files and supporting + documentation. + + stable + + + + + + + Project director + pdr + Use for a person or organization with + primary responsibility for all essential aspects of + a project, or that manages a very large project that + demands senior level responsibility, or that has + overall responsibility for managing projects, or + provides overall direction to a project manager. + + stable + + + + + + Proofreader + pfr + Use for a person who corrects printed + matter. For manuscripts, use Corrector + [crr]. + + stable + + + + + + Publication place + pup + Use for the name of the place where a resource is published. + + stable + + + + + + Publisher + pbl + Use for a person or organization that + makes printed matter, often text, but also printed + music, artwork, etc. available to the + public. + + stable + + + + + + + Publishing director + pbd + Use for a person or organization who + presides over the elaboration of a collective work + to ensure its coherence or continuity. This includes + editors-in-chief, literary editors, editors of + series, etc. + + stable + + + + + + Puppeteer + ppt + Use for a person or organization who + manipulates, controls, or directs puppets or + marionettes in a musical or dramatic presentation or + entertainment. + + stable + + + + + + + Recipient + rcp + Use for a person or organization to whom + correspondence is addressed. + + stable + + + + + + Recording engineer + rce + Use for a person or organization who + supervises the technical aspects of a sound or video + recording session. + + stable + + + + + + + Redactor + red + Use for a person or organization who + writes or develops the framework for an item without + being intellectually responsible for its + content. + + stable + + + + + + Renderer + ren + Use for a person or organization who + prepares drawings of architectural designs (i.e., + renderings) in accurate, representational + perspective to show what the project will look like + when completed. + + stable + + + + + + + Reporter + rpt + Use for a person or organization who + writes or presents reports of news or current events + on air or in print. + + stable + + + + + + + Repository + rps + Use for an agency that hosts data or + material culture objects and provides services to + promote long term, consistent and shared use of + those data or objects. + + stable + + + + + + Research team head + rth + Use for a person who directed or managed a + research project. + + stable + + + + + + + Research team member + rtm + Use for a person who participated in a + research project but whose role did not involve + direction or management of it. + + stable + + + + + + + Researcher + res + Use for a person or organization + responsible for performing research. + + stable + Performer of research + + + + + + + Respondent + rsp + Use for the party who makes an answer to + the courts pursuant to an application for redress, + usually in an equity proceeding. + + stable + + + + + + Respondent-appellant + rst + Use for a respondent who takes an appeal + from one court or jurisdiction to another to reverse + the judgment, usually in an equity + proceeding. + + stable + + + + + + Respondent-appellee + rse + Use for a respondent against whom an + appeal is taken from one court or jurisdiction to + another to reverse the judgment, usually in an + equity proceeding. + + stable + + + + + + Responsible party + rpy + Use for a person or organization legally + responsible for the content of the published + material. + + stable + + + + + + + Restager + rsg + Use for a person or organization , other + than the original choreographer or director, + responsible for restaging a choreographic or + dramatic work and who contributes minimal new + content. + + stable + + + + + + + Reviewer + rev + Use for a person or organization + responsible for the review of a book, motion + picture, performance, etc. + + stable + + + + + + + Rubricator + rbr + Use for a person or organization + responsible for parts of a work, often headings or + opening parts of a manuscript, that appear in a + distinctive color, usually red + + stable + + + + + + Scenarist + sce + Use for a person or organization who is + the author of a motion picture + screenplay. + + stable + + + + + + + Scientific advisor + sad + Use for a person or organization who + brings scientific, pedagogical, or historical + competence to the conception and realization on a + work, particularly in the case of audio-visual + items. + + stable + + + + + + + Scribe + scr + Use for a person who is an amanuensis and + for a writer of manuscripts proper. For a person who + makes pen-facsimiles, use Facsimilist + [fac]. + + stable + + + + + + + Sculptor + scl + Use for a person or organization who + models or carves figures that are three-dimensional + representations. + + stable + + + + + + + Second party + spy + Use for a person or organization who is + identified as the party of the second part. In the + case of transfer of right, this is the assignee, + transferee, licensee, grantee, etc. Multiple parties + can be named jointly as the second + party + + stable + + + + + + Secretary + sec + Use for a person or organization who is a + recorder, redactor, or other person responsible for + expressing the views of a + organization.> + + stable + + + + + + + Set designer + std + Use for a person or organization who + translates the rough sketches of the art director + into actual architectural structures for a + theatrical presentation, entertainment, motion + picture, etc. Set designers draw the detailed guides + and specifications for building the + set. + + stable + + + + + + + Signer + sgn + Use for a person whose signature appears + without a presentation or other statement indicative + of provenance. When there is a presentation + statement, use Inscriber [ins]. + + stable + + + + + + Singer + sng + Use for a person or organization who uses + his/her/their voice with or without instrumental + accompaniment to produce music. A performance may or + may not include actual words. + + stable + + + + + + + Sound designer + sds + Use for a person who produces and + reproduces the sound score (both live and recorded), + the installation of microphones, the setting of + sound levels, and the coordination of sources of + sound for a production. + + stable + + + + + + Speaker + spk + Use for a person who participates in a + program (often broadcast) and makes a formalized + contribution or presentation generally prepared in + advance. + + stable + + + + + + + Sponsor + spn + Use for a person or organization that + issued a contract or under the auspices of which a + work has been written, printed, published, + etc. + + stable + + + + + + Stage manager + stm + Use for a person who is in charge of + everything that occurs on a performance stage, and + who acts as chief of all crews and assistant to a + director during rehearsals. + + stable + + + + + + Standards body + stn + Use for an organization responsible for + the development or enforcement of a + standard. + + stable + + + + + + + Stereotyper + str + Use for a person or organization who + creates a new plate for printing by molding or + copying another printing surface. + + stable + + + + + + Storyteller + stl + Use for a person relaying a story with + creative and/or theatrical + interpretation. + + stable + + + + + + + Supporting host + sht + Use for a person or organization that + supports (by allocating facilities, staff, or other + resources) a project, program, meeting, event, data + objects, material culture objects, or other entities + capable of support. + + stable + Host, Supporting + + + + + + Surveyor + srv + Use for a person or organization who does + measurements of tracts of land, etc. to determine + location, forms, and boundaries. + + stable + + + + + + + Teacher + tch + Use for a person who, in the context of a + resource, gives instruction in an intellectual + subject or demonstrates while teaching physical + skills. + + stable + Instructor + + + + + + + Technical director + tcd + Use for a person who is ultimately in + charge of scenery, props, lights and sound for a + production. + + stable + + + + + + Thesis advisor + ths + Use for a person under whose supervision a + degree candidate develops and presents a thesis, + mémoire, or text of a dissertation. + + stable + Promoter + + + + + + Transcriber + trc + Use for a person who prepares a + handwritten or typewritten copy from original + material, including from dictated or orally recorded + material. For makers of pen-facsimiles, use + Facsimilist [fac]. + + stable + + + + + + + Translator + trl + Use for a person or organization who + renders a text from one language into another, or + from an older form of a language into the modern + form. + + stable + + + + + + + Type designer + tyd + Use for a person or organization who + designed the type face used in a particular item. + + stable + Designer of type + + + + + + Typographer + tyg + Use for a person or organization primarily + responsible for choice and arrangement of type used + in an item. If the typographer is also responsible + for other aspects of the graphic design of a book + (e.g., Book designer [bkd]), codes for both + functions may be needed. + + stable + + + + + + University place + uvp + Use for the name of a place where a university that is associated + with a resource is located, for example, a university where an academic + dissertation or thesis was presented. + + stable + + + + + + Videographer + vdg + Use for a person or organization in charge + of a video production, e.g. the video recording of a + stage production as opposed to a commercial motion + picture. The videographer may be the camera operator + or may supervise one or more camera operators. Do + not confuse with cinematographer. + + stable + + + + + + + Vocalist + voc + Use for a person or organization who + principally exhibits singing skills in a musical or + dramatic presentation or entertainment. + + stable + + + + + + + Witness + wit + Use for a person who verifies the + truthfulness of an event or action. + + stable + Deponent + Eyewitness + Observer + Onlooker + Testifier + + + + + + Wood-engraver + wde + Use for a person or organization who makes + prints by cutting the image in relief on the + end-grain of a wood block. + + stable + + + + + + + Woodcutter + wdc + Use for a person or organization who makes + prints by cutting the image in relief on the plank + side of a wood block. + + stable + + + + + + + Writer of accompanying material + wam + Use for a person or organization who + writes significant material which accompanies a + sound recording or other audiovisual + material. + + stable + + + + + Actor + + + + + Adapter + + + + + Analyst + + + + + Animator + + + + + Annotator + + + + + Applicant + + + + + Architect + + + + + Arranger + + + + + Art copyist + + + + + Artist + + + + + Artistic director + + + + + Assignee + + + + + Associated name + + + + + Attributed name + + + + + Auctioneer + + + + + Author + + + + + Author in quotations or text + extracts + + + + + Author of afterword, colophon, + etc. + + + + + Author of dialog + + + + + Author of introduction, etc. + + + + + Author of screenplay, etc. + + + + + Bibliographic antecedent + + + + + Binder + + + + + Binding designer + + + + + Blurb writer + + + + + Book designer + + + + + Book producer + + + + + Bookjacket designer + + + + + Bookplate designer + + + + + Bookseller + + + + + Calligrapher + + + + + Cartographer + + + + + Censor + + + + + Choreographer + + + + + Cinematographer + + + + + Client + + + + + Collaborator + + + + + Collector + + + + + Collotyper + + + + + Colorist + + + + + Commentator + + + + + Commentator for written text + + + + + Compiler + + + + + Complainant + + + + + Complainant-appellant + + + + + Complainant-appellee + + + + + Composer + + + + + Compositor + + + + + Conceptor + + + + + Conductor + + + + + Conservator + + + + + Consultant + + + + + Consultant to a project + + + + + Contestant + + + + + Contestant-appellant + + + + + Contestant-appellee + + + + + Contestee + + + + + Contestee-appellant + + + + + Contestee-appellee + + + + + Contractor + + + + + Contributor + + + + + Copyright claimant + + + + + Copyright holder + + + + + Corrector + + + + + Correspondent + + + + + Costume designer + + + + + Cover designer + + + + + Creator + + + + + Curator of an exhibition + + + + + Dancer + + + + + Data contributor + + + + + Data manager + + + + + Dedicatee + + + + + Dedicator + + + + + Defendant + + + + + Defendant-appellant + + + + + Defendant-appellee + + + + + Degree grantor + + + + + Delineator + + + + + Depicted + + + + + Depositor + + + + + Designer + + + + + Director + + + + + Dissertant + + + + + Distribution place + + + + + Distributor + + + + + Donor + + + + + Draftsman + + + + + Dubious author + + + + + Editor + + + + + Electrician + + + + + Electrotyper + + + + + Engineer + + + + + Engraver + + + + + Etcher + + + + + Event place + + + + + Expert + + + + + Facsimilist + + + + + Field director + + + + + Film editor + + + + + First party + + + + + Forger + + + + + Former owner + + + + + Funder + + + + + Geographic information + specialist + + + + + Honoree + + + + + Host + + + + + Illuminator + + + + + Illustrator + + + + + Inscriber + + + + + Instrumentalist + + + + + Interviewee + + + + + Interviewer + + + + + Inventor + + + + + Laboratory + + + + + Laboratory director + + + + + Lead + + + + + Landscape architect + + + + + Lender + + + + + Libelant + + + + + Libelant-appellant + + + + + Libelant-appellee + + + + + Libelee + + + + + Libelee-appellant + + + + + Libelee-appellee + + + + + Librettist + + + + + Licensee + + + + + Licensor + + + + + Lighting designer + + + + + Lithographer + + + + + Lyricist + + + + + Manufacturer + + + + + Marbler + + + + + Markup editor + + + + + Metadata contact + + + + + Metal-engraver + + + + + Moderator + + + + + Monitor + + + + + Music copyist + + + + + Musical director + + + + + Musician + + + + + Narrator + + + + + Opponent + + + + + Organizer of meeting + + + + + Originator + + + + + Other + + + + + Owner + + + + + Papermaker + + + + + Patent applicant + + + + + Patent holder + + + + + Patron + + + + + Performer + + + + + Permitting agency + + + + + Photographer + + + + + Plaintiff + + + + + Plaintiff-appellant + + + + + Plaintiff-appellee + + + + + Platemaker + + + + + Printer + + + + + Printer of plates + + + + + Printmaker + + + + + Process contact + + + + + Producer + + + + + Production manager + + + + + Production personnel + + + + + Programmer + + + + + Project director + + + + + Proofreader + + + + + Publication place + + + + + Publisher + + + + + Publishing director + + + + + Puppeteer + + + + + Recipient + + + + + Recording engineer + + + + + Redactor + + + + + Renderer + + + + + Reporter + + + + + Repository + + + + + Research team head + + + + + Research team member + + + + + Researcher + + + + + Respondent + + + + + Respondent-appellant + + + + + Respondent-appellee + + + + + Responsible party + + + + + Restager + + + + + Reviewer + + + + + Rubricator + + + + + Scenarist + + + + + Scientific advisor + + + + + Scribe + + + + + Sculptor + + + + + Second party + + + + + Secretary + + + + + Set designer + + + + + Signer + + + + + Singer + + + + + Sound designer + + + + + Speaker + + + + + Sponsor + + + + + Stage manager + + + + + Standards body + + + + + Stereotyper + + + + + Storyteller + + + + + Supporting host + + + + + Surveyor + + + + + Teacher + + + + + Technical director + + + + + Thesis advisor + + + + + Transcriber + + + + + Translator + + + + + Type designer + + + + + Typographer + + + + + University place + + + + + Videographer + + + + + Vocalist + + + + + Witness + + + + + Wood-engraver + + + + + Woodcutter + + + + + Writer of accompanying material + + + diff --git a/ilives/book.inc b/ilives/book.inc new file mode 100644 index 00000000..d05f41d4 --- /dev/null +++ b/ilives/book.inc @@ -0,0 +1,250 @@ +pid = $pid; + $this->item = new Fedora_Item($pid); + } + } + + public function buildDrupalForm($form = array(), $ingest_form = array(), &$form_state = array()) { + $mods_save = ''; + if (isset($form_state['mods_save'])) { + $mods_save = $form_state['mods_save']; + } + + // Set #cache to true to create the $form_state cache + $form['#cache'] = TRUE; + // Prompt the user to enter a record ID to be looked up in Evergreen. + $form['unapi_url'] = array( + '#type' => 'textfield', + '#title' => 'Catalogue item URL', + ); + $form['unapi_url_submit'] = array( + '#type' => 'submit', + '#value' => t('Retrieve MODS record'), + '#submit' => array('fedora_ilives_retrieve_unapi_submit'), + '#ahah' => array( + 'path' => 'fedora/ilives/retrieve_unapi/js', // path we defined in hook_menu + 'wrapper' => 'mods-wrapper', // the HTML that wraps the element that needs to be replaced + 'method' => 'replace', // the method we're going to use: a replace operation + 'effect' => 'fade', // the effect used when replacing the element (try fade!) + ) + ); + drupal_add_js('', 'inline'); + // We define a
      wrapper. Everything in it will be replaced. + $form['mods'] = array( + '#tree' => TRUE, + '#prefix' => '
      ', + '#suffix' => '
      ', + ); + $form['mods']['mods_record'] = array( + '#type' => 'textarea', + '#title' => 'MODS Record to Import', + '#value' => (!empty($mods_save) ? $mods_save['mods']['mods_record'] : ''), + ); + return $form; + } + + public function buildEditMetadataForm($form = array()) { + + $form['submit'] = array( + '#type' => 'submit', + '#weight' => 10, + '#value' => 'Update' + ); + $form['pid'] = array( + '#type' => 'hidden', + '#value' => $this->pid, + ); + $form['dsid'] = array( + '#type' => 'hidden', + '#value' => "DARWIN_CORE", + ); + + return $this->buildDrupalForm($form); + } + + public function handleEditMetadataForm($form_id, $form_values) { + /* + * Process the metadata form + * Update the datastreams + */ + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'plugins/DarwinCore'); + module_load_include('inc', 'fedora_repository', 'MimeClass'); + global $user; + $mimetype = new MimeClass(); + $dwc = new DarwinCore($this->item); + $dwc->handleForm($form_values); + $this->item->purge_datastream('DARWIN_CORE'); + $this->item->add_datastream_from_string($dwc->darwinCoreXML, 'DARWIN_CORE', + 'Darwin Core Metadata', 'text/xml', 'X'); + return TRUE; + } + + public function handleIngestForm($form_values, $form, &$form_state) { + /* + * process the metadata form + * Create fedora object + * Add the datastreams + */ + module_load_include('inc', 'fedora_repository', 'MimeClass'); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + if ($form_state['clicked_button']['#value'] == 'Retrieve MODS record') { + return; + } + + + $mods_simple = simplexml_load_string($form_values['mods']['mods_record']); + $title = ''; + foreach ($mods_simple->children('http://www.loc.gov/mods/v3')->mods[0]->titleInfo[0]->children() as $child) { + if ($child->getName() == 'subTitle') { + // We don't care about subtitles for creating the item label. + continue; + } + $title .= $child; + } + + global $user; + $mimetype = new MimeClass(); + $new_item = Fedora_Item::ingest_new_item($form_values['pid'], 'A', $title, + $user->name); + + $new_item->add_datastream_from_string($form_values['mods']['mods_record'], 'MODS', + 'MODS Metadata', 'text/xml', 'X'); + + $new_item->add_relationship('hasModel', $form_values['content_model_pid'], FEDORA_MODEL_URI); + $new_item->add_relationship(!empty($form_values['relationship']) ? $form_values['relationship'] : 'isMemberOfCollection', $form_values['collection_pid']); + } + + public function buildAddPagesForm($form = array()) { + + } + + public function showFieldSets() { + module_load_include('inc', 'fedora_repository', 'plugins/tagging_form'); + module_load_include('inc', 'fedora_repository', 'plugins/DarwinCore'); + module_load_include('module', 'fedora_ilives'); + global $base_url; + + $tabset = array(); + + $tabset['my_tabset'] = array( + '#type' => 'tabset', + ); + + global $user; + $qs = ''; + if ($user->uid != 0) { + $qs = '?uid='. base64_encode($user->name . ':'. $user->pass); + } + + $viewer_url = variable_get('fedora_base_url', '') . '/get/'. $this->pid . '/ilives:viewerSdef/getViewer'. $qs; + $html = ''; + $tabset['my_tabset']['second_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Full-size'), + '#content' => $html + ); + $tabset['my_tabset']['first_tab'] = array( + // #type and #title are the minimum requirements. + '#type' => 'tabpage', + '#title' => t('Description'), + // This will be the content of the tab. + '#content' => fedora_ilives_create_book_view($this->pid), + ); + + $tabset['my_tabset']['add_pages'] = array( + '#type' => 'tabpage', + '#title' => t('Add pages'), + '#content' => drupal_get_form('book_add_pages_form', $this->pid), + ); + return tabs_render($tabset); + } +} + +function book_add_pages_form(&$form_state, $pid) { + $form['pid'] = array( + '#type' => 'hidden', + '#value' => $pid, + ); + + $form['tiff_dir'] = array( + '#type' => 'textfield', + '#title' => t('TIFF folder'), + '#required' => TRUE, + '#description' => t('Path to a web-accessible folder contining the book\'s page images in TIFF format on this server.'), + ); + + $form['submit'] = array( + '#type' => 'submit', + '#weight' => 10, + '#value' => 'Ingest Pages' + ); + return $form; +} + +function book_add_pages_form_validate($form, &$form_state) { + if ($form_state['values']['tiff_dir'] == '') { + form_set_error('', t('You must select a name for this group of settings.')); + } +} + +function book_add_pages_form_submit($form, &$form_state) { + $pid = $form_state['values']['pid']; + if (!empty($form_state['values']['tiff_dir'])) { + $file_list = array(); + if ($tiff_dir = opendir($form_state['values']['tiff_dir'])) { + while (FALSE !== ($file_name = readdir($tiff_dir))) { + $ext = strrchr($file_name, '.'); + if ($ext == '.tif' || $ext == '.tiff') { + array_push($file_list, $form_state['values']['tiff_dir'] .'/'. $file_name); + } + } + closedir($tiff_dir); + sort($file_list); + ilives_create_page_objects($pid, $file_list); + } + } +} + +/** + * Create a page object for each element in $image_list as a child object of $pid + */ +function ilives_create_page_objects($pid, $image_list = array()) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $book = new Fedora_Item($pid); + if (!$book->exists()) { + return FALSE; + } + $page_pids = array(); + $batch = array( + 'title' => 'Creating page objects', + 'operations' => array(), + 'file' => drupal_get_path('module', 'fedora_ilives') .'/book.inc', + ); + $page_num = 1; + $book_title = $book->objectProfile->objLabel; + foreach ($image_list as $image_path) { + $batch['operations'][] = array('ilives_add_single_page_object', array($pid, $image_path, $page_num, "$book_title - Page ". sprintf("%03d", $page_num))); + $page_num++; + } + batch_set($batch); +} + +function ilives_add_single_page_object($book_pid, $page_file, $page_num = 1, $page_title = NULL) { + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $page_item = Fedora_Item::ingest_new_item("$book_pid-". sprintf("%03d", $page_num), 'A', $page_title); + $page_item->add_relationship('hasModel', 'ilives:pageCModel', FEDORA_MODEL_URI); + $page_item->add_relationship('isMemberOf', $book_pid); + $page_item->add_datastream_from_file($page_file, 'TIFF', 'Archival TIFF', 'image/tiff', 'M'); +} diff --git a/ilives/fedora_ilives.info b/ilives/fedora_ilives.info new file mode 100644 index 00000000..763adfdc --- /dev/null +++ b/ilives/fedora_ilives.info @@ -0,0 +1,7 @@ +; $Id$ +name = Islandora Book +description = Provides book interface +package = Fedora Repository +dependencies[] = fedora_repository +version = 6.1dev +core = 6.x diff --git a/ilives/fedora_ilives.install b/ilives/fedora_ilives.install new file mode 100644 index 00000000..a7f2eadf --- /dev/null +++ b/ilives/fedora_ilives.install @@ -0,0 +1,65 @@ + t('Book view'), + 'page callback' => 'fedora_ilives_create_book_view', + 'type' => MENU_CALLBACK, + 'access arguments' => array('view fedora collection'), + ); + $items['fedora/ilives_book_viewer'] = array( + 'title' => t('Book viewer'), + 'page callback' => 'fedora_ilives_book_viewer', + 'type' => MENU_CALLBACK, + 'access arguments' => array('view fedora collection'), + ); + $items['fedora/ilives_book_search'] = array( + 'title' => t('Book viewer'), + 'page callback' => 'fedora_ilives_book_search', + 'type' => MENU_CALLBACK, + 'access arguments' => array('view fedora collection'), + ); + $items['fedora/ilives_page_search'] = array( + 'title' => t('Book viewer'), + 'page callback' => 'fedora_ilives_page_search', + 'type' => MENU_CALLBACK, + 'access arguments' => array('view fedora collection'), + ); + // This block defines the path and the corresponding callback function. + $items['fedora/ilives/retrieve_unapi/js'] = array( + 'page callback' => 'fedora_ilives_button_retrieve_unapi_ahah', // the AHAH callback function + 'access arguments' => array('add fedora datastreams'), + 'type' => MENU_CALLBACK, + ); + return $items; +} + + + +//function fedora_ilives_book_search($query) { + +//} + +//function fedora_ilives_page_search($query) { + +//} + +function fedora_ilives_block($op = 'list', $delta = 0, $edit = array()) { + // The $op parameter determines what piece of information is being requested. + switch ($op) { + case 'list': + // If $op is "list", we just need to return a list of block descriptions. + // This is used to provide a list of possible blocks to the administrator, + // end users will not see these descriptions. + $blocks[0] = array( + 'info' => t('Book search block'), + ); + $blocks[1] = array( + 'info' => t('Image rotator and tagger'), + ); + $blocks[2] = array( + 'info' => t('Simple book search block'), + ); + + return $blocks; + case 'configure': + // If $op is "configure", we need to provide the administrator with a + // configuration form. The $delta parameter tells us which block is being + // configured. In this example, we'll allow the administrator to customize + // the text of the first block. + // If $op is "configure", we need to provide the administrator with a + // configuration form. The $delta parameter tells us which block is being + // configured. In this example, we'll allow the administrator to customize + // the text of the first block. + $form = array(); + switch ($delta) { + case 0: + // All we need to provide is a text field, Drupal will take care of + // the other block configuration options and the save button. + $form['fedora_ilives_book_search_block_repeat'] = array( + '#type' => 'textfield', + '#title' => t('Number of times to repeat search fields'), + '#size' => 5, + '#description' => t('The number of times you would like the search blocks to be repeated'), + '#default_value' => variable_get('fedora_ilives_book_search_block_repeat', t('3')), + ); + break; + case 1: + // This is the image rotator block. + $form['fedora_ilives_image_rotator_block_query'] = array( + '#type' => 'textarea', + '#title' => t('ITQL Query'), + '#description' => t('The ITQL query to return a list of images.'), + '#default_value' => variable_get('fedora_ilives_image_rotator_tagger_block_query', 'select $object $title from <#ri> +where $object +and $object +and $object $title'), + ); + break; + case 2: + // All we need to provide is a text field, Drupal will take care of + // the other block configuration options and the save button. + $form['fedora_ilives_simple_book_search_block_title'] = array( + '#type' => 'textfield', + '#title' => t('Title'), + '#size' => 15, + '#description' => t('The title of the block'), + '#default_value' => variable_get('fedora_ilives_simple_book_search_block_title', t('Title')), + ); + break; + } + + return $form; + case 'save': + // If $op is "save", we need to save settings from the configuration form. + // Since the first block is the only one that allows configuration, we + // need to check $delta to make sure we only save it. + switch ($delta) { + case 0: + // Have Drupal save the string to the database. + variable_set('fedora_ilives_book_search_block_repeat', $edit['fedora_ilives_book_search_block_repeat']); + break; + case 1: + variable_set('fedora_ilives_image_rotator_tagger_block_query', $edit['fedora_ilives_image_rotator_block_query']); + break; + case 2: + // Have Drupal save the string to the database. + variable_set('fedora_ilives_simple_book_search_block_title', $edit['fedora_ilives_simple_book_search_block_title']); + break; + } + return; + case 'view': default: + // If $op is "view", then we need to generate the block for display + // purposes. The $delta parameter tells us which block is being requested. + switch ($delta) { + case 0: + // The subject is displayed at the top of the block. Note that it + // should be passed through t() for translation. + $block['subject'] = t('Book advanced search'); + // The content of the block is typically generated by calling a custom + // function. + $block['content'] = drupal_get_form('fedora_ilives_book_search_form'); + break; + case 1: + module_load_include('inc', 'fedora_ilives', 'image_rotator_tagger_block'); + $block['subject'] = t('Random repository image'); + $block['content'] = _fedora_image_rotator_tagger_block_content(); + break; + case 2: + // The subject is displayed at the top of the block. Note that it + // should be passed through t() for translation. + $block['subject'] = t('Simple Book Search'); + // The content of the block is typically generated by calling a custom + // function. + $block['content'] = drupal_get_form('fedora_ilives_simple_book_search_form'); + break; + } + + return $block; + } +} + + + +function fedora_ilives_book_viewer($pid) { + global $user; + $qs = ''; + if ($user->uid != 0) { +// $qs = '?uid=' . base64_encode($user->name . ':' . $user->sid); + $qs = '?uid=' . base64_encode($user->name . ':' . $user->pass); + } + + $viewer_url = variable_get('fedora_base_url', '') . '/get/' . $pid . '/ilives:viewerSdef/getViewer' . $qs; + $html = ''; + $fieldset = array( + '#title' => t('Viewer - ') . $pid, + '#collapsible' => TRUE, + '#collapsed' => FALSE, + '#value' => $html); + drupal_add_css(path_to_theme() . '/header-viewer.css', 'theme'); + return theme('fieldset', $fieldset); + +} +//loads an xslt for the main book page uses mods for most of the display. if there is a $query parameter +// it will execute it against the book. +function fedora_ilives_create_book_view($pid, $query = NULL) { + global $user; + module_load_include('inc', 'fedora_repository', 'ObjectHelper' ); + $path = drupal_get_path('module', 'Fedora_Repository'); + $objectHelper = new ObjectHelper; + $xml = $objectHelper->getStream($pid, 'MODS'); + $dc_xml = $objectHelper->getStream($pid, 'DC'); + if (!$dc_xml) { + drupal_set_message(t('Object does not exist.'), 'error'); + return ''; + } + $simpleDCxml = simplexml_load_string($dc_xml); + $types = $simpleDCxml->xpath('//dc:type'); + $ingested = 'false'; + foreach ($types as $type) { + if ($type == 'ingested') { + $ingested = 'true'; + } + } + + if (!isset($pid)) { + drupal_set_message(t('Error getting book view, no identifier specified.')); + return; + } + $proc = NULL; + try { + $proc = new XsltProcessor(); + } catch (Exception $e) { + drupal_set_message(t('Error loading Book View XSLT: $e', array('!e' => $e->getMessage()))); + return; + } + + //inject into xsl stylesheet + $proc->setParameter('', 'userID', $user->uid); + $proc->setParameter('', 'objectsPage', base_path()); + $proc->setParameter('', 'pid', $pid); + $proc->setParameter('', 'ingested', $ingested); + $xsl = new DomDocument(); + $test = $xsl->load($path . '/ilives/xsl/book_view.xsl'); + if (!isset($test)) { + drupal_set_message(t('Error loading search results XSLT.')); + return t('Error loading search results XSLT.'); + } + + $input = new DomDocument(); + $didLoadOk = $input->loadXML($xml); + $output=NULL; + if (!isset($didLoadOk)) { + drupal_set_message(t('Error loading Book View XML.')); + return t('Error loading Book View XML.'); + } + else { + $xsl = $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + $output .= $newdom->saveXML(); + } + if (isset($query)) { + module_load_include('inc', 'fedora_repository', 'SearchClass'); + $searchClass = new SearchClass(); + $pageQuery = convert_query_to_page_query($query, $pid); + $output .= '
      '. $searchClass->custom_search($pageQuery, $startPage, '/ilives/xsl/pageResults.xsl', 500) . '
      '; //limit results to 500 pages of a book since there is no paging if we enable paging in xslt this can be changed + //return $output."
      used this query to find this page $query and new query = $pageQuery
      "; + + return $output; + } + else { + return $output; + } +} + +function convert_query_to_page_query($query, $pid) { + $newQuery= substr($query, 0, strlen($query) - 23); + $pid = str_replace(':', '?', $pid); + $newQuery = $newQuery ." AND PID:$pid* AND dc.type:Text"; + //$newQuery=htmlentities(urlencode($newQuery)); + return $newQuery; +} + +/** +* Custom form element to do our nice images. +*/ +function fedora_ilives_elements() { // Change this line + $type['imagebutton'] = array( + '#input' => TRUE, + '#button_type' => 'submit', + '#executes_submit_callback' => TRUE, + '#name' => 'op', + '#process' => array('hook_imagebutton_process' => array()), + ); + return $type; +} + +function theme_imagebutton($element) { + return '\n"; +} + +/** + * Implementation of hook_theme() to register how to theme image buttons. + */ +function fedora_ilives_theme() { + return array( + 'imagebutton' => array( + 'arguments' => array('form' => NULL), + ), + 'fedora_ilives_book_search_form' => array( + 'arguments' => array('form' => NULL), + ), + 'fedora_ilives_simple_book_search_form' => array( + 'arguments' => array('form' => NULL), + ) + ); +} + +//return array( +// 'fedora_repository_mnpl_advanced_search_form' => array( +// 'arguments' => array('form' => NULL) +// ) +// ); + +function theme_fedora_ilives_book_search_form($form) { + module_load_include('inc', 'fedora_repository', 'SearchClass'); + $advanced_search_form = new SearchClass(); + $repeats = variable_get('fedora_ilives_book_search_block_repeat', t('3')); + return $advanced_search_form->theme_advanced_search_form($form, $repeats); +} + +function fedora_ilives_simple_book_search_form($form) { + $form = array(); + $form['search_type']['type1'] = array( + '#title' => t(''), + '#type' => 'hidden', + '#default_value' => 'tei.fullText' + ); + $form['fedora_terms1'] = array( + '#size' => '24', + '#type' => 'textfield', + '#title' => t(''), + '#required' => TRUE , + '#default_value' => '' + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('search') + ); + return $form; +} + +function fedora_ilives_simple_book_search_form_submit($form, &$form_state) { + $type_id = $form_state['values']['type']; + + $searchString = $form_state['values']['type1'] . ':'. $form_state['values']['fedora_terms1']; + + $searchString = trim($searchString) . '+AND+dc.type:collection'; + $form_state['redirect']="fedora/ilives_book_search/$searchString"; + //drupal_goto("fedora/ilives_book_search/$searchString"); +} + +function fedora_ilives_book_search_form() { + module_load_include('inc', 'fedora_repository', 'SearchClass'); + $searchClass = new SearchClass(); + $repeats = variable_get('fedora_ilives_book_search_block_repeat', t('3')); + $path = drupal_get_path('module', 'Fedora_Repository') . '/ilives'; + $query = NULL; + if (arg(1) == 'ilives_book_search' && arg(2) != 'dc.type:ingested') { + $length = strlen(arg(2)); + if (($test = strpos(arg(2), 'dc.type:collection')) > 0) { + $length=$test - 5; //get rid of the AND + } + $query = trim(substr(arg(2), 0, $length)); + } + return $searchClass->build_advanced_search_form($repeats, $path, $query); +} + +function fedora_ilives_book_search_form_submit($form, &$form_state) { + $type_id = $form_state['values']['type']; + $repeat = variable_get('fedora_ilives_book_search_block_repeat', t('3')); + $searchString = $form_state['values']['type1'] . ':'. $form_state['values']['fedora_terms1']; + if ($form_state['values']['fedora_terms2'] != '') { + $searchString .= '+'. $form_state['values']['andor1'] . '+'. $form_state['values']['type2'] . ':'. $form_state['values']['fedora_terms2']; + } + if ($repeat > 2 && $repeat < 9) { + for ($i = 3; $i < $repeat + 1; $i++) { + $t=$i-1; + if ($form_state['values']["fedora_terms$i"] != '') { + $searchString .= '+'. $form_state['values']["andor$t"] . '+'. $form_state['values']["type$i"] . ':'. $form_state['values']["fedora_terms$i"]; + } + } + } + $searchString = trim($searchString) . '+AND+dc.type:collection'; + $form_state['redirect']="fedora/ilives_book_search/$searchString"; + //drupal_goto("fedora/ilives_book_search/$searchString"); +} + + function fedora_ilives_book_search($query, $startPage = 1) { + module_load_include('inc', 'fedora_repository', 'SearchClass'); + $searchClass = new SearchClass(); + return $searchClass->custom_search($query, $startPage, '/ilives/xsl/results.xsl', 10); + } + + /*function custom_search($query) { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + module_load_include('inc', 'fedora_repository', 'SearchClass'); + if (user_access('view fedora collection')) { + $numberOfHistPerPage = '1000';//hack for IR they do not want next button + $luceneQuery = NULL; + //demo search string ?operation=gfindObjects&indexName=DemoOnLucene&query=fgs.DS.first.text%3Achristmas&hitPageStart=11&hitPageSize=10 + + + $indexName = variable_get('fedora_index_name', 'DemoOnLucene'); + $query.=$query.'+dc.type:collection'; + $query=htmlentities(urlencode($query)); + + $searchUrl = variable_get('fedora_fgsearch_url', 'http://localhost:8080/fedoragsearch/rest'); + $searchString = '?operation=gfindObjects&indexName=' . $indexName . '&restXslt=copyXml&query=' . $query; + $searchString .= '&hitPageSize='.$numberOfHistPerPage.'&hitPageStart=1'; + //$searchString = htmlentities($searchString); + $searchUrl .= $searchString; + + $objectHelper = new ObjectHelper(); + + $resultData = $objectHelper->doCurl($searchUrl,1); + //var_dump($resultData);exit(0); + // $doc = new DOMDocument(); + // $doc->loadXML($resultData); + $searchClass = new SearchClass(); + $output.=$searchClass->applyLuceneXSLT($resultData); + + return $output; + + } + }*/ + + + + +function retrieve_unapi_MODS_record($url) { + $bib_response = drupal_http_request($url); + $bib_html = $bib_response->data; + $bib_doc = new DOMDocument; + $bib_doc->loadHTML($bib_html); + $links = $bib_doc->getElementsByTagName('link'); + foreach ($links as $link) { + if ($link->getAttribute('rel') == 'unapi-server') { + $unapi_server = $link->getAttribute('href'); + break; + } + } + $attrs = $bib_doc->getElementsByTagName('abbr'); + foreach ($attrs as $attr) { + if ($attr->getAttribute('class') == 'unapi-id') { + + $unapi_id = $attr->getAttribute('title'); + break; + } + } + $mods_url = "$unapi_server?id=$unapi_id&format=mods3"; + $mods_resp = drupal_http_request($mods_url); + $mods_data = $mods_resp->data; + return $mods_data; +} + + +/** + * AHAH callback for the 'match type' select. + * This function handles the actual replace and sets the $form and $form_state arrays. + **/ +function fedora_ilives_button_retrieve_unapi_ahah() { + + // this part is used to set up $form_state. + // In Drupal 7, these next 11 lines will be put in a core utility function. + // Just remember you'll need them in D6 when you do AHAH. + $form_state = array('storage' => NULL, 'submitted' => FALSE); + $form_build_id = $_POST['form_build_id']; + $form = form_get_cache($form_build_id, $form_state); + $args = $form['#parameters']; + $form_id = array_shift($args); + $form['#post'] = $_POST; + $form['#redirect'] = FALSE; + $form['#programmed'] = FALSE; + + $form_state['post'] = $_POST; + drupal_process_form($form_id, $form, $form_state); + $form_state['storage']['step'] = 2; + $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id); + // From here on, we'll add our own code. + // We just get the element of $form that needs to be refreshed, and just resubmit that + // part through the json call. In this case we want to rebuild the 'kind'
      wrapper and the + // select box it contains + $changed_elements = $form['mods']['mods_record']; + + + unset($changed_elements['#prefix'], $changed_elements['suffix']); // we'll unset the div to make sure it won't be repeated! + // the actual JSON call + $javascript = drupal_add_js(NULL, NULL, 'header'); + drupal_json(array( + 'status' => TRUE, + 'data' => theme('status_messages') . drupal_render($changed_elements), // rebuild just the part that needs to be changed + 'settings' => call_user_func_array('array_merge_recursive', $javascript['setting']), + )); +} + +/** + * This is the handler for the 'type' box: pressing this will refresh the
      kind wrapper. + **/ +function fedora_ilives_retrieve_unapi_submit($form, &$form_state) { + + unset($form_state['submit_handlers']); // unset all the submit handlers in the form + form_execute_handlers('submit', $form, $form_state); // execute submit handler + $url = $form_state['values']['unapi_url']; + $mods = retrieve_unapi_MODS_record($url); + $form_state['values']['mods']['mods_record'] = $mods; + $mods_save = $form_state['values']; // store all the submitted values in the form + $form_state['mods_save'] = $mods_save; // put the values in a new form + + $form_state['rebuild'] = TRUE; // set to true to make sure the form gets rebuild + return $mods_save; +} diff --git a/ilives/image_rotator_tagger_block.inc b/ilives/image_rotator_tagger_block.inc new file mode 100755 index 00000000..eb29e23f --- /dev/null +++ b/ilives/image_rotator_tagger_block.inc @@ -0,0 +1,107 @@ + +where $object +and $object +and $object $title'; + $collection = new CollectionClass('ilives:figures'); + $results = $collection->getRelatedItems('ilives:figures', $itqlquery); + //drupal_set_message($results); + + + if (empty($results)) { + return NULL; + } + $resultsdoc = new DomDocument(); + $resultsdoc->loadXML($results); + + $resultslist = $resultsdoc->getElementsByTagName('result'); + if ( $resultslist->length == 0 ) { + return NULL; + } + //return htmlentities(substr($results, 0, 1000)); + $randresult = $resultslist->item( rand()%$resultslist->length ); + if (empty($randresult)) { + return NULL; + } + $objs = $randresult->getElementsByTagName('object'); + $obj = $objs->item(0); + $pid = substr( $obj->getAttribute('uri'), 12); + $titles = $randresult->getElementsByTagName('title'); + $title = $titles->item(0); + + return array('pid' => $pid, + //'title' => $randresult->textContent); + 'title' => $title->nodeValue); + +} + + +function _fedora_image_rotator_tagger_block_content() { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'plugins/tagging_form'); + + global $base_url; + if (!empty($_POST['pid'])) { + $image_item = new Fedora_Item($_POST['pid']); + $result['pid'] = $_POST['pid']; + $result['title'] = $image_item->objectProfile->objLabel; + } + elseif (empty($_POST) && !empty($_SESSION['fedora_tagged_image']['pid'])) { + $image_item = new Fedora_Item($_SESSION['fedora_tagged_image']['pid']); + $result['pid'] = $_SESSION['fedora_tagged_image']['pid']; + $result['title'] = $image_item->objectProfile->objLabel; + unset($_SESSION['fedora_tagged_image']); + } + else { + $result = get_random_image(); + + $image_item = new Fedora_Item($result['pid']); + } + if (!empty ($result)) { + return '

      ' + . l( '', 'fedora/repository/'. $result['pid'], array('html' => TRUE, 'alias' => TRUE)) + .'

      This image is from '. l($result['title'], 'fedora/ilives_book_viewer/'. substr($image_item->pid, 0, strrpos($image_item->pid, '-')), array('html' => TRUE, 'alias' => TRUE)) . '.' + . drupal_get_form('fedora_repository_image_tagging_form', $result['pid']) . '

      '; + } + else { + return ''; + } +} + + +/* +function fedora_ilives_preprocess_page(&$variables) { + drupal_add_js(drupal_get_path('module', 'fedora_ilives').'/fedora_ilives_ajax.js', 'theme'); + return TRUE; +}*/ + +class ShowILivesStreamsInFieldSets { + + private $pid =NULL; + + function ShowILivesStreamsInFieldSets($pid) { + //drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); + $this->pid=$pid; + } + + function showJPG() { + module_load_include('inc', 'fedora_repository', 'plugins/tagging_form'); + global $base_url; + $collection_fieldset = array( + '#collapsible' => FALSE, + '#value' => '', + ); + return theme('fieldset', $collection_fieldset) + . drupal_get_form('fedora_repository_image_tagging_form', $this->pid); + } +} diff --git a/ilives/searchTerms.xml b/ilives/searchTerms.xml new file mode 100644 index 00000000..b224c959 --- /dev/null +++ b/ilives/searchTerms.xml @@ -0,0 +1,67 @@ + + + + dc.title + 1000 + + dc.title + Title + + + mods.sor + Author + + + mods.subject + Subject + + + + tei.fullText + Text + + + tei.persName + People + + + + + tei.placeName + Places + + + tei.orgName + Organization Name + + + + + + + + + + + + diff --git a/ilives/xml/ilives_CollectionModel.xml b/ilives/xml/ilives_CollectionModel.xml new file mode 100644 index 00000000..c5d4d7bd --- /dev/null +++ b/ilives/xml/ilives_CollectionModel.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + +ingest + +fedoraAdmin +2009-01-23T20:43:42.518Z +Created with Admin GUI "New Object" command + + + +modifyDatastreamByValue +RELS-EXT +fedoraAdmin +2009-01-23T20:45:33.190Z + + + + +modifyDatastreamByValue +DC +fedoraAdmin +2009-01-23T20:48:22.246Z + + + + +ingest + +fedoraAdmin +2009-01-26T20:27:14.697Z +Ingested from local file /opt/fedora/export/ilives_CollectionModel.xml + + + +ingest + +fedoraAdmin +2009-03-21T22:35:49.622Z +Ingested from local file /Volumes/iLives/iLivesTexts/215258_jpg/Content_Models/CollectionCModel.xml + + + +ingest + +admin +2009-09-14T14:09:41.955Z +Fedora Object Ingested + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This DS-COMPOSITE-MODEL datastream is included as a starting point to + assist in the creation of a content model. The DS-COMPOSITE-MODEL + should define the datastreams that are required for any objects + conforming to this content model. + For more information about content models, see: + http://fedora-commons.org/confluence/x/dgBI. + For examples of completed content model objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:CMImage, demo:UVA_STD_IMAGE, demo:DualResImageCollection, + demo:TEI_TO_PDFDOC, and demo:XML_TO_HTMLDOC. + For more information about the demonstration objects, see: + http://fedora-commons.org/confluence/x/AwFI. + + +
      +
      +
      +
      +
      +
      + + + + + IslandLives Collection Model + ilives:CollectionModel + + + + + + + IslandLives Collection + Made possible through a generous private donation, the IslandLives project builds on the Robertson Library’s mission to preserve and share unique material relating to Prince Edward Island and demonstrates UPEI's ongoing commitment to making PEI's cultural and published heritage available to all. +Utilizing the library’s “Prince Edward Island Collection” and the latest in digitization technology, IslandLives will start by digitizing 300 or so published community histories dating from the mid-1800’s to the present day. These transformed community histories will form the basis of a rich online repository. +IslandLives will provide a variety of search interfaces that will allow users to browse and search the content by name, community, time period, and keyword. The Island community will have a whole new way to rediscover, search and share their stories. +This project will engage and build community – recruiting interested individuals from the cultural heritage community and everyday Islanders. Project staff will travel to communities and host ‘digitization days’, introducing community members to the project and its goals, providing them with an opportunity to digitize their own content, and to contribute their content to the IslandLives collection. + Robertson Library, University of Prince Edward Island + ilives:CollectionModel + + + + +
      \ No newline at end of file diff --git a/ilives/xml/ilives_bookCModel.xml b/ilives/xml/ilives_bookCModel.xml new file mode 100644 index 00000000..b6042042 --- /dev/null +++ b/ilives/xml/ilives_bookCModel.xml @@ -0,0 +1,524 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-11-12T14:56:58.331Z + Ingested from local file /Users/aoneill/dev/iiv/iiv/etc/fedora-objects/ilives_bookCModel.xml + + + + ingest + + fedoraAdmin + 2010-05-31T19:56:44.131Z + Ingested from source repository with pid ilives:bookCModel + + + + ingest + + fedoraAdmin + 2010-06-10T17:43:56.335Z + Ingested from local file /Users/aoneill/fedora_repository/content_models/ilives_bookCModel.xml + + + + addDatastream + ISLANDORACM + fedoraAdmin + 2010-06-10T19:01:39.144Z + DatastreamsPane generated this logMessage. + + + + modifyDatastreamByValue + ISLANDORACM + fedoraAdmin + 2010-06-10T19:29:20.220Z + + + + + modifyDatastreamByValue + ISLANDORACM + fedoraAdmin + 2010-06-10T19:46:24.930Z + + + + + ingest + + fedoraAdmin + 2010-06-16T11:27:32.059Z + Ingested from local file /Users/aoneill/Dropbox/fedora_repository/content_models/ilives_bookCModel.xml + + + + modifyDatastreamByValue + ISLANDORACM + fedoraAdmin + 2010-06-16T11:29:54.285Z + + + + + modifyDatastreamByValue + ISLANDORACM + fedoraAdmin + 2010-06-16T18:36:16.581Z + + + + + ingest + + fedoraAdmin + 2010-06-16T16:14:12.989Z + Ingested from local file /Applications/MAMP/htdocs/f3/sites/default/modules/fedora_repository/content_models/ilives_bookCModel.xml + + + + modifyDatastreamByValue + ISLANDORACM + fedoraAdmin + 2010-09-16T17:43:54.445Z + + + + + + + + + + + + + + + + + + + + + + + + This DS-COMPOSITE-MODEL datastream is included as a starting point to + assist in the creation of a content model. The DS-COMPOSITE-MODEL + should define the datastreams that are required for any objects + conforming to this content model. + For more information about content models, see: + http://fedora-commons.org/confluence/x/dgBI. + For examples of completed content model objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:CMImage, demo:UVA_STD_IMAGE, demo:DualResImageCollection, + demo:TEI_TO_PDFDOC, and demo:XML_TO_HTMLDOC. + For more information about the demonstration objects, see: + http://fedora-commons.org/confluence/x/AwFI. + + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Book Content Model + ilives:bookCModel + + + + + + + + + + image/tiff + image/tif + + + + + ilives + plugins/herbarium.inc + Herbarium + showFieldSets + + + + + + + + text/xml + + + ilives + book.inc + IslandoraBook + ingestBook + MODS + + + + + + + ilives + book.inc + IslandoraBook + buildDrupalForm + handleIngestForm + + + + + ilives + book.inc + IslandoraBook + buildEditMetadataForm + + + ilives + book.inc + IslandoraBook + handleEditMetadataForm + + + + + + + + + + image/tiff + image/tif + + + + + fedora_ilives + plugins/herbarium.inc + Herbarium + showFieldSets + + + + + + + + text/xml + + + fedora_ilives + book.inc + IslandoraBook + ingestBook + MODS + + + + + + + fedora_ilives + book.inc + IslandoraBook + buildDrupalForm + handleIngestForm + + + + + fedora_ilives + book.inc + IslandoraBook + buildEditMetadataForm + + + fedora_ilives + book.inc + IslandoraBook + handleEditMetadataForm + + + + + + + + + + image/tiff + + + + + fedora_ilives + plugins/herbarium.inc + Herbarium + showFieldSets + + + + + + + + text/xml + + + fedora_ilives + book.inc + IslandoraBook + ingestBook + MODS + + + + + + + fedora_ilives + book.inc + IslandoraBook + buildDrupalForm + handleIngestForm + + + + + fedora_ilives + book.inc + IslandoraBook + buildEditMetadataForm + + + fedora_ilives + book.inc + IslandoraBook + handleEditMetadataForm + + + + + + + + + + image/tiff + + + + + fedora_ilives + book.inc + IslandoraBook + showFieldSets + + + + + + + + + text/xml + + + fedora_ilives + book.inc + IslandoraBook + ingestBook + MODS + + + + + + + fedora_ilives + book.inc + IslandoraBook + buildDrupalForm + handleIngestForm + + + + + fedora_ilives + book.inc + IslandoraBook + buildEditMetadataForm + + + fedora_ilives + book.inc + IslandoraBook + handleEditMetadataForm + + + + + + + + + + text/xml + + + + + fedora_ilives + book.inc + IslandoraBook + showFieldSets + + + + + + + + text/xml + + + fedora_ilives + book.inc + IslandoraBook + ingestBook + MODS + + + + + + + fedora_ilives + book.inc + IslandoraBook + buildDrupalForm + handleIngestForm + + + + + fedora_ilives + book.inc + IslandoraBook + buildEditMetadataForm + + + fedora_ilives + book.inc + IslandoraBook + handleEditMetadataForm + + + + + + + + + + text/xml + + + + text/xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/ilives/xml/ilives_collection.xml b/ilives/xml/ilives_collection.xml new file mode 100644 index 00000000..23801263 --- /dev/null +++ b/ilives/xml/ilives_collection.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + +ingest + +fedoraAdmin +2009-05-14T19:32:21.132Z +Created with Admin GUI "New Object" command + + + +modifyDatastreamByValue +DC +fedoraAdmin +2009-05-14T19:35:11.912Z + + + + + + + + + + + IslandLives Collection + ilives:collection + + + + + + + IslandLives Collection + Made possible through a generous private donation, IslandLives contains community and church histories and it builds on the Robertson Library's mission to preserve and share unique material relating to Prince Edward Island and demonstrates UPEI"s ongoing commitment to making PEI"s cultural and published heritage available to all. Welcome. + ilives:collection + + + + + \ No newline at end of file diff --git a/ilives/xml/ilives_figuresCModel.xml b/ilives/xml/ilives_figuresCModel.xml new file mode 100644 index 00000000..7b63ae7b --- /dev/null +++ b/ilives/xml/ilives_figuresCModel.xml @@ -0,0 +1,20 @@ + + + + image/jpeg + + + + + fedora_ilives + image_rotator_tagger_block.inc + ShowILivesStreamsInFieldSets + showJPG + + + + image/jpeg + + + + diff --git a/ilives/xml/ilives_jp2Sdef.xml b/ilives/xml/ilives_jp2Sdef.xml new file mode 100644 index 00000000..f7212084 --- /dev/null +++ b/ilives/xml/ilives_jp2Sdef.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-11-12T14:56:59.840Z + Ingested from local file /Users/aoneill/dev/iiv/iiv/etc/fedora-objects/ilives_jp2Sdef.xml + + + + ingest + + admin + 2010-05-25T13:17:14.106Z + Fedora Object Ingested + + + + ingest + + fedoraAdmin + 2010-06-01T01:40:47.337Z + Ingested from local file /Users/al/fedora_repository/content_models/ilives_jp2Sdef.xml + + + + + + + + + + + + + + + + + + + + + ilives:jp2Sdef + ilives:jp2Sdef + + + + + + + + + + + + + + + diff --git a/ilives/xml/ilives_jp2Sdep-pageCModel.xml b/ilives/xml/ilives_jp2Sdep-pageCModel.xml new file mode 100644 index 00000000..7eedea6d --- /dev/null +++ b/ilives/xml/ilives_jp2Sdep-pageCModel.xml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-11-12T14:57:00.246Z + Ingested from local file /Users/aoneill/dev/iiv/iiv/etc/fedora-objects/ilives_jp2Sdep-pageCModel.xml + + + + ingest + + fedoraAdmin + 2010-06-01T00:46:19.239Z + Ingested from local file /Users/al/Desktop/ilives_jp2Sdep-pageCModel.xml + + + + modifyDatastreamByValue + RELS-EXT + fedoraAdmin + 2010-06-01T00:48:39.302Z + + + + + + + + + + + ilives:jp2Sdep-pageCModel + ilives:jp2Sdep-pageCModel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DC + text/xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ilives/xml/ilives_pageCModel.xml b/ilives/xml/ilives_pageCModel.xml new file mode 100644 index 00000000..0f24edeb --- /dev/null +++ b/ilives/xml/ilives_pageCModel.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-11-12T14:57:00.652Z + Ingested from local file /Users/aoneill/dev/iiv/iiv/etc/fedora-objects/ilives_pageCModel.xml + + + + + + + + + + + + + + + + + + + + + + + + + This DS-COMPOSITE-MODEL datastream is included as a starting point to + assist in the creation of a content model. The DS-COMPOSITE-MODEL + should define the datastreams that are required for any objects + conforming to this content model. + For more information about content models, see: + http://fedora-commons.org/confluence/x/dgBI. + For examples of completed content model objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:CMImage, demo:UVA_STD_IMAGE, demo:DualResImageCollection, + demo:TEI_TO_PDFDOC, and demo:XML_TO_HTMLDOC. + For more information about the demonstration objects, see: + http://fedora-commons.org/confluence/x/AwFI. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page Content Model + ilives:pageCModel + + + + + diff --git a/ilives/xml/ilives_tei2htmlSdef.xml b/ilives/xml/ilives_tei2htmlSdef.xml new file mode 100644 index 00000000..f626c690 --- /dev/null +++ b/ilives/xml/ilives_tei2htmlSdef.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-11-12T14:57:01.057Z + Ingested from local file /Users/aoneill/dev/iiv/iiv/etc/fedora-objects/ilives_tei2htmlSdef.xml + + + + + + + + + + + + + + + + + + + + + ilives:tei2htmlSdef + ilives:tei2htmlSdef + + + + + + + + + + + + + + diff --git a/ilives/xml/ilives_tei2htmlSdep-pageCModel.xml b/ilives/xml/ilives_tei2htmlSdep-pageCModel.xml new file mode 100644 index 00000000..3a2c5d9a --- /dev/null +++ b/ilives/xml/ilives_tei2htmlSdep-pageCModel.xml @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-11-12T14:57:01.366Z + Ingested from local file /Users/aoneill/dev/iiv/iiv/etc/fedora-objects/ilives_tei2htmlSdep-pageCModel.xml + + + + modifyDatastreamByValue + XSL + fedoraAdmin + 2009-12-11T19:09:52.417Z + + + + + modifyDatastreamByValue + XSL + fedoraAdmin + 2009-12-11T19:22:11.096Z + + + + + + + + + + + + + + + + + + + + + + + + ilives:tei2htmlSdep-pageCModel + ilives:tei2htmlSdep-pageCModel + + + + + + + + + + TEI + text/xml + + + + XSL + text/xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:value-of select="normalize-space(tei:teiHeader/tei:fileDesc/tei:titleStmt/tei:title)"/> + + + + + + + + +
      + +
      +
      + +

      + +

      +
      + + + + + + + + + + + search persName + _blank + http://islandlives.net/fedora/ilives_book_search/tei.persNameTERM:%22+%22+AND+dc.type:collection + + + + + + + + + + + + search placeName + _blank + http://islandlives.net/fedora/ilives_book_search/tei.placeNameTERM:%22%22+AND+dc.type:collection + + + + + + search orgName + _blank + http://islandlives.net/fedora/ilives_book_search/tei.orgNameTERM:%22%22+AND+dc.type:collection + + + + +
      +
      +
      +
      +
      diff --git a/ilives/xml/ilives_viewerSdef.xml b/ilives/xml/ilives_viewerSdef.xml new file mode 100644 index 00000000..a97c50a2 --- /dev/null +++ b/ilives/xml/ilives_viewerSdef.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-11-12T17:09:29.912Z + Ingested from local file /Users/aoneill/dev/iiv/iiv/etc/fedora-objects/ilives_viewerSdef.xml + + + + + + + + + + + + + + + + + + + + + ilives:viewerSdef + ilives:viewerSdef + + + + + + + + + + + + + + diff --git a/ilives/xml/ilives_viewerSdep-bookCModel.xml b/ilives/xml/ilives_viewerSdep-bookCModel.xml new file mode 100644 index 00000000..e5688998 --- /dev/null +++ b/ilives/xml/ilives_viewerSdep-bookCModel.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-11-12T17:09:41.797Z + Ingested from local file /Users/aoneill/dev/iiv/iiv/etc/fedora-objects/ilives_viewerSdep-bookCModel.xml + + + + + + + + + + ilives:viewerSdep-bookCModel + ilives:viewerSdep-bookCModel + + + + + + + + + + + + + + + + + + + + + + + DC + text/xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ilives/xml/ilives_viewerSdep-pageCModel.xml b/ilives/xml/ilives_viewerSdep-pageCModel.xml new file mode 100644 index 00000000..6b30cd67 --- /dev/null +++ b/ilives/xml/ilives_viewerSdep-pageCModel.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-11-24T14:52:27.296Z + Ingested from local file /Users/aoneill/dev/iiv/iiv/etc/fedora-objects/ilives_viewerSdep-pageCModel.xml + + + + + + + + + + + + + + + + + + + + + + + ilives:viewerSdep-pageCModel + ilives:viewerSdep-pageCModel + + + + + + + + + + + + + + + + + + + + + + + + + DC + text/xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ilives/xsl/book_view.xsl b/ilives/xsl/book_view.xsl new file mode 100644 index 00000000..a8bfb825 --- /dev/null +++ b/ilives/xsl/book_view.xsl @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + +

      + :

      +

      + +

      +
      +
      + + fedora/repository//TN + + + + + +
      + + + + + + + + +
      By Statement:
      Place of Publication:
      Publisher:
      Date:
      Language:
      Pagination:
      ISBN 10:
      Subjects: + + fedora/ilives_book_search/mods.subject:""%20AND%20dc.type:collection%20AND%20dc.type:ingested + + +
      +
      + + + + + + +
      + +
      +
      \ No newline at end of file diff --git a/ilives/xsl/book_view.xsl.bak b/ilives/xsl/book_view.xsl.bak new file mode 100644 index 00000000..4acce98b --- /dev/null +++ b/ilives/xsl/book_view.xsl.bak @@ -0,0 +1,45 @@ + + + + + + + + + + + +

      + :

      +

      + +

      +
      +
      + + fedora/repository//TN + + + + + +
      + + + + + + + + +
      By Statement:
      Place of Publication:
      Publisher:
      Date:
      Language:
      Pagination:
      ISBN 10:
      Subjects: + + fedora/repository/mnpl_advanced_search/mods.subject:"" + + +
      +
      + +
      +
      \ No newline at end of file diff --git a/ilives/xsl/book_view.xsl2009-05-26 b/ilives/xsl/book_view.xsl2009-05-26 new file mode 100644 index 00000000..d05a0341 --- /dev/null +++ b/ilives/xsl/book_view.xsl2009-05-26 @@ -0,0 +1,44 @@ + + + + + + + + + + + +

      + :

      +

      + +

      +
      +
      + + fedora/repository//TN + + + + + +
      + + + + + + + + +
      By Statement:
      Place of Publication:
      Publisher:
      Date:
      Language:
      Pagination:
      ISBN 10:
      Subjects: + + fedora/repository/mnpl_advanced_search/mods.subject:"" + + +
      +
      + +
      +
      \ No newline at end of file diff --git a/ilives/xsl/pageResults.xsl b/ilives/xsl/pageResults.xsl new file mode 100644 index 00000000..fccee47a --- /dev/null +++ b/ilives/xsl/pageResults.xsl @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Total Hits = + + , + + +
      We have repeated your search within this book and found results on the following pages. + +
      + + + + +
      + +
      +
      + + + +
      + + + + + + + + + +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fedora/ilives_book_viewer/ + + + Thumbnail + + + fedora/repository//TN + + + +
      + + + fedora/ilives_book_viewer/ + + +
      +
      + + + + + + + +
      + + + + +   + + + + + + + +
      diff --git a/ilives/xsl/results.xsl b/ilives/xsl/results.xsl new file mode 100644 index 00000000..0757ea1e --- /dev/null +++ b/ilives/xsl/results.xsl @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Total Hits = , + Number of Hits/page = + + +
      + +
      + + + + + + + + +
      + +
      + +

      Your search yielded no results

      + +
        +
      • Check if your spelling is correct.
      • + +
      • Remove quotes around phrases to match each word individually: "blue smurf" will match less than blue smurf.
      • +
      • Consider loosening your query with OR: blue smurf will match less than blue OR smurf.
      • +
      + +
      + +
      +
      +
      + + + +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fedora/ilives// + + + + fedora/repository//TN + + 100 + + + + + + + + + + + + + + + fedora/ilives// + + + + + + + + + + : + + + + + + + + + + + / + + + + + + + + + + + + + + : + + + + + + + , . + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      diff --git a/images/Crystal_Clear_mimetype_pdf.png b/images/Crystal_Clear_mimetype_pdf.png new file mode 100644 index 00000000..4e5abe69 Binary files /dev/null and b/images/Crystal_Clear_mimetype_pdf.png differ diff --git a/images/Gnome-emblem-photos.png b/images/Gnome-emblem-photos.png new file mode 100644 index 00000000..eee312a7 Binary files /dev/null and b/images/Gnome-emblem-photos.png differ diff --git a/images/Thumbs.db b/images/Thumbs.db new file mode 100644 index 00000000..545faa6f Binary files /dev/null and b/images/Thumbs.db differ diff --git a/images/contentModel.jpg b/images/contentModel.jpg new file mode 100644 index 00000000..c92683b9 Binary files /dev/null and b/images/contentModel.jpg differ diff --git a/images/edit.gif b/images/edit.gif new file mode 100644 index 00000000..0222e1dc Binary files /dev/null and b/images/edit.gif differ diff --git a/images/export.png b/images/export.png new file mode 100644 index 00000000..48913e35 Binary files /dev/null and b/images/export.png differ diff --git a/images/export_big.png b/images/export_big.png new file mode 100644 index 00000000..8ce8bc9a Binary files /dev/null and b/images/export_big.png differ diff --git a/images/exported_big.png b/images/exported_big.png new file mode 100644 index 00000000..625c7778 Binary files /dev/null and b/images/exported_big.png differ diff --git a/images/flashThumb.jpg b/images/flashThumb.jpg new file mode 100644 index 00000000..59f60488 Binary files /dev/null and b/images/flashThumb.jpg differ diff --git a/images/ingest.png b/images/ingest.png new file mode 100644 index 00000000..eb65de2c Binary files /dev/null and b/images/ingest.png differ diff --git a/images/list-add.png b/images/list-add.png new file mode 100644 index 00000000..306d3d89 Binary files /dev/null and b/images/list-add.png differ diff --git a/images/noImage.jpg b/images/noImage.jpg new file mode 100644 index 00000000..d3338e48 Binary files /dev/null and b/images/noImage.jpg differ diff --git a/images/purge.gif b/images/purge.gif new file mode 100644 index 00000000..b3037e09 Binary files /dev/null and b/images/purge.gif differ diff --git a/images/purge_big.png b/images/purge_big.png new file mode 100644 index 00000000..462ef399 Binary files /dev/null and b/images/purge_big.png differ diff --git a/images/remove_icon.png b/images/remove_icon.png new file mode 100644 index 00000000..282e4478 Binary files /dev/null and b/images/remove_icon.png differ diff --git a/images/replace.png b/images/replace.png new file mode 100644 index 00000000..2f4b0459 Binary files /dev/null and b/images/replace.png differ diff --git a/images/smileytn.png b/images/smileytn.png new file mode 100644 index 00000000..bcd1e52a Binary files /dev/null and b/images/smileytn.png differ diff --git a/images/view.gif b/images/view.gif new file mode 100644 index 00000000..eee58178 Binary files /dev/null and b/images/view.gif differ diff --git a/installer_files/foxml/islandora-collectionCModel.xml b/installer_files/foxml/islandora-collectionCModel.xml new file mode 100644 index 00000000..ef247072 --- /dev/null +++ b/installer_files/foxml/islandora-collectionCModel.xml @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-02-17T16:49:02.191Z + Created with Admin GUI "New Object" command + + + + modifyDatastreamByValue + DS-COMPOSITE-MODEL + fedoraAdmin + 2009-02-17T16:50:04.876Z + + + + + addDatastream + ISLANDORACM + ppound + 2009-02-26T17:23:07.848Z + datastream added + + + + purgeDatastream + ISLANDORACM + ppound + 2009-02-26T17:24:28.067Z + Purged . . . Purged datastream (ID=ISLANDORACM), versions ranging from the beginning of time to the end of time. This resulted in the permanent removal of 1 datastream version(s) (2009-02-26T13:23:07.848Z) and all associated audit records. + + + + addDatastream + ISLANDORACM + ppound + 2009-02-26T17:27:10.814Z + datastream added + + + + purgeDatastream + ISLANDORACM + fedoraAdmin + 2009-02-26T17:37:58.880Z + DatastreamPane generated this logMessage. . . . Purged datastream (ID=ISLANDORACM), versions ranging from 2009-02-26T13:27:10.814Z to 2009-02-26T13:27:10.814Z. This resulted in the permanent removal of 1 datastream version(s) (2009-02-26T13:27:10.814Z) and all associated audit records. + + + + addDatastream + test + fedoraAdmin + 2009-02-26T19:02:49.879Z + DatastreamsPane generated this logMessage. + + + + purgeDatastream + test + fedoraAdmin + 2009-02-26T19:03:04.069Z + DatastreamPane generated this logMessage. . . . Purged datastream (ID=test), versions ranging from 2009-02-26T15:02:49.879Z to 2009-02-26T15:02:49.879Z. This resulted in the permanent removal of 1 datastream version(s) (2009-02-26T15:02:49.879Z) and all associated audit records. + + + + addDatastream + ISLANDORACM + ppound + 2009-02-26T19:03:36.147Z + datastream added + + + + addDatastream + ISLANDORACM + plux + 2009-03-13T19:11:44.755Z + datastream added + + + + modifyDatastreamByReference + ISLANDORACM + fedoraAdmin + 2010-01-26T21:10:29.212Z + + + + + modifyDatastreamByReference + ISLANDORACM + fedoraAdmin + 2010-09-15T11:47:31.885Z + + + + + + + + + + + + + + + + + + + + + + + This DS-COMPOSITE-MODEL datastream is included as a starting point to + assist in the creation of a content model. The DS-COMPOSITE-MODEL + should define the datastreams that are required for any objects + conforming to this content model. + For more information about content models, see: + $FEDORA_HOME/docs/userdocs/digitalobjects/objectModel.html#CMODEL. + For examples of completed content model objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:CMImage, demo:UVA_STD_IMAGE, demo:DualResImageCollection, + demo:TEI_TO_PDFDOC, and demo:XML_TO_HTMLDOC. + For more information about the demonstration objects, see: + $FEDORA_HOME/docs/userdocs/distribution/demos.html + + + + + + + + + + + + This DS-COMPOSITE-MODEL datastream is included as a starting point to + assist in the creation of a content model. The DS-COMPOSITE-MODEL + should define the datastreams that are required for any objects + conforming to this content model. + For more information about content models, see: + $FEDORA_HOME/docs/userdocs/digitalobjects/objectModel.html#CMODEL. + For examples of completed content model objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:CMImage, demo:UVA_STD_IMAGE, demo:DualResImageCollection, + demo:TEI_TO_PDFDOC, and demo:XML_TO_HTMLDOC. + For more information about the demonstration objects, see: + $FEDORA_HOME/docs/userdocs/distribution/demos.html + + + + + + + + + + + + + + + + + + + Islandora Collection Content Model + islandora:collectionCModel + + + + + + + + + + + + + + + + diff --git a/installer_files/foxml/islandora-demos.xml b/installer_files/foxml/islandora-demos.xml new file mode 100644 index 00000000..4e59cf29 --- /dev/null +++ b/installer_files/foxml/islandora-demos.xml @@ -0,0 +1,5 @@ + + + Islandora Demo Collections + islandora:demos + diff --git a/installer_files/foxml/islandora-pdfcollection.xml b/installer_files/foxml/islandora-pdfcollection.xml new file mode 100644 index 00000000..b57cb712 --- /dev/null +++ b/installer_files/foxml/islandora-pdfcollection.xml @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + ingest + + admin + 2009-04-02T14:39:19.525Z + Fedora Object Ingested + + + + addDatastream + TN + fedoraAdmin + 2009-04-02T17:06:32.540Z + DatastreamsPane generated this logMessage. + + + + purgeDatastream + COLLECTION_POLICY + fedoraAdmin + 2009-04-02T17:10:50.929Z + DatastreamPane generated this logMessage. . . . Purged datastream (ID=COLLECTION_POLICY), versions ranging from 2009-04-02T11:39:19.554Z to 2009-04-02T11:39:19.554Z. This resulted in the permanent removal of 1 datastream version(s) (2009-04-02T11:39:19.554Z) and all associated audit records. + + + + addDatastream + COLLECTION_POLICY + fedoraAdmin + 2009-04-02T17:11:49.698Z + DatastreamsPane generated this logMessage. + + + + ingest + + aoneill + 2010-10-11T23:08:16.035Z + Fedora Object Ingested + + + + addDatastream + TN + aoneill + 2010-10-11T23:08:16.169Z + Ingested object TN + + + + + + + + + + + + + + + + + + + + + + PDF COllection + + none + A bunch of PDFs + + + + none + + islandora:collection-18 + + eng + + + + + + + + + + + + + islandora:strictpdf + islandora:strict_pdf + ISLANDORACM + + + isMemberOfCollection + + dc.description + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.relation + dc.relation + + + dcterms.temporal + dcterms.temporal + + + dcterms.spatial + dcterms.spatial + + + fgs.DS.first.text + Full Text + + + + + + + + + + + + diff --git a/installer_files/foxml/islandora-strictpdfCModel.xml b/installer_files/foxml/islandora-strictpdfCModel.xml new file mode 100644 index 00000000..ddebd132 --- /dev/null +++ b/installer_files/foxml/islandora-strictpdfCModel.xml @@ -0,0 +1,808 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-02-26T14:50:44.411Z + Created with Admin GUI "New Object" command + + + + addDatastream + ISLANDORACM + fedoraAdmin + 2009-02-26T14:52:58.161Z + DatastreamsPane generated this logMessage. + + + + purgeDatastream + ISLANDORACM + fedoraAdmin + 2009-03-31T18:33:27.172Z + DatastreamPane generated this logMessage. . . . Purged datastream (ID=ISLANDORACM), versions ranging from 2009-02-26T10:52:58.161Z to 2009-02-26T10:52:58.161Z. This resulted in the permanent removal of 1 datastream version(s) (2009-02-26T10:52:58.161Z) and all associated audit records. + + + + ingest + + admin + 2009-09-14T14:09:06.847Z + Fedora Object Ingested + + + + addDatastream + ISLANDORACM + fedoraAdmin + 2010-03-08T20:08:32.004Z + DatastreamsPane generated this logMessage. + + + + modifyDatastreamByValue + ISLANDORACM + fedoraAdmin + 2010-09-30T17:11:42.958Z + + + + + modifyDatastreamByValue + ISLANDORACM + fedoraAdmin + 2010-09-30T17:12:24.421Z + + + + + addDatastream + pdf_test + avc_db + 2010-10-06T16:04:03.630Z + Ingested object pdf_test + + + + + + + + + + + + + + + + + + + + + + This DS-COMPOSITE-MODEL datastream is included as a starting point to + assist in the creation of a content model. The DS-COMPOSITE-MODEL + should define the datastreams that are required for any objects + conforming to this content model. + For more information about content models, see: + http://fedora-commons.org/confluence/x/dgBI. + For examples of completed content model objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:CMImage, demo:UVA_STD_IMAGE, demo:DualResImageCollection, + demo:TEI_TO_PDFDOC, and demo:XML_TO_HTMLDOC. + For more information about the demonstration objects, see: + http://fedora-commons.org/confluence/x/AwFI. + + + + + + + + + + + + + Strict PDF + islandora:strict_pdf + + + + + + + + + + + + plugins/ShowStreamsInFieldSets.php + ShowStreamsInFieldSets + showPDFPreview + + + + application/pdf + + plugins/ImageManipulation.php + ImageManipulation + createThumbnailFromPDF + jpg + TN + + 100 + 120 + + + + + + application/pdf + + + + + application/pdf + + + + plugins/ImageManipulation.php + ImageManipulation + createThumbnailFromPDF + jpg + TN + + 100 + 120 + + + + + + dis1 + + + 200 + + + + + + + + + + + + + + + + + + + + + plugins/FormBuilder.php + FormBuilder + buildQDCForm + handleQDCForm + + + + + dc:title + textfield + The name given to the resource + true + + + + dc:creator + textfield + An entity primarily responsible for making the content of the resource such as a person, organization or service. + false + + + + dc:subject + select + An entity primarily responsible for making the content of the resource such as a person, organization or service. + false + + + experiment session + experiment session + + + home recording + home recording + + + image + image + + + meeting + meeting + + + presentation + presentation + + + sound + sound + + + text + text + + + + + + dc:description + textarea + Examples include an abstract, table of contents, or free-text account of the content of the resource. + true + + + + dc:publisher + textfield + An entity, (including persons, organizations, or services), responsible for making the resource available. + false + + + + dc:contributor + textfield + An entity responsible for contributing to the content of the resource such as a person, organization or service. + false + + + + dc:date + textfield + Temporal scope of the content if known. Date format is YYYY-MM-DD (e.g. 1890,1910-10,or 2007-10-23) + false + + + + dc:type + select + Genre of the content of the resource. Examples include: home page, novel, poem, working paper, technical report, essay, dictionary. + false + + + none + none + + + collection + collection + + + dataset + dataset + + + event + event + + + image + image + + + interactive resource + interactive resource + + + model + model + + + party + party + + + physical object + physical object + + + place + place + + + service + service + + + software + software + + + sound + sound + + + text + text + + + + + + dc:source + textfield + A reference to a resource from which the present resource is derived. + false + + + + dc:identifier + textfield + A unique reference to the resource; In this instance, the accession number or collection number. + false + + + + dc:language + select + The language of the intellectual content of the resource. + false + + + eng + English + + + fre + French + + + + + + dc:relation + textfield + Reference to a related resource. + false + + + + dc:rights + textarea + Information about intellectual property rights, copyright, and various property rights. + false + + + + + + + + + + + + + plugins/ShowStreamsInFieldSets.inc + ShowStreamsInFieldSets + showPDFPreview + + + + application/pdf + + plugins/ImageManipulation.inc + ImageManipulation + createThumbnailFromPDF + jpg + TN + + 100 + 120 + + + + + + application/pdf + + + + + application/pdf + + + + plugins/ImageManipulation.inc + ImageManipulation + createThumbnailFromPDF + jpg + TN + + 100 + 120 + + + + + + dis1 + + + 200 + + + + + + + + + + + + + + + + + + + + + plugins/FormBuilder.inc + FormBuilder + buildQDCForm + handleQDCForm + + + + + dc:title + textfield + The name given to the resource + true + + + + dc:creator + textfield + An entity primarily responsible for making the content of the resource such as a person, organization or service. + false + + + + dc:subject + select + An entity primarily responsible for making the content of the resource such as a person, organization or service. + false + + + experiment session + experiment session + + + home recording + home recording + + + image + image + + + meeting + meeting + + + presentation + presentation + + + sound + sound + + + text + text + + + + + + dc:description + textarea + Examples include an abstract, table of contents, or free-text account of the content of the resource. + true + + + + dc:publisher + textfield + An entity, (including persons, organizations, or services), responsible for making the resource available. + false + + + + dc:contributor + textfield + An entity responsible for contributing to the content of the resource such as a person, organization or service. + false + + + + dc:date + textfield + Temporal scope of the content if known. Date format is YYYY-MM-DD (e.g. 1890,1910-10,or 2007-10-23) + false + + + + dc:type + select + Genre of the content of the resource. Examples include: home page, novel, poem, working paper, technical report, essay, dictionary. + false + + + none + none + + + collection + collection + + + dataset + dataset + + + event + event + + + image + image + + + interactive resource + interactive resource + + + model + model + + + party + party + + + physical object + physical object + + + place + place + + + service + service + + + software + software + + + sound + sound + + + text + text + + + + + + dc:source + textfield + A reference to a resource from which the present resource is derived. + false + + + + dc:identifier + textfield + A unique reference to the resource; In this instance, the accession number or collection number. + false + + + + dc:language + select + The language of the intellectual content of the resource. + false + + + eng + English + + + fre + French + + + + + + dc:relation + textfield + Reference to a related resource. + false + + + + dc:rights + textarea + Information about intellectual property rights, copyright, and various property rights. + false + + + + + + + + + + + application/pdf + + + + application/pdf + + + + 100 + 120 + + + + + + + + + + + + + 100 + 120 + + + + + + + + + The name given to the resource + + + An entity primarily responsible for making the content of the resource such as a person, organization or service. + + + An entity primarily responsible for making the content of the resource such as a person, organization or service. + + experiment session + home recording + image + meeting + presentation + sound + text + + + + Examples include an abstract, table of contents, or free-text account of the content of the resource. + + + An entity, (including persons, organizations, or services), responsible for making the resource available. + + + An entity responsible for contributing to the content of the resource such as a person, organization or service. + + + Temporal scope of the content if known. Date format is YYYY-MM-DD (e.g. 1890,1910-10,or 2007-10-23) + + + Genre of the content of the resource. Examples include: home page, novel, poem, working paper, technical report, essay, dictionary. + + none + collection + dataset + event + image + interactive resource + model + party + physical object + place + service + software + sound + text + + + + A reference to a resource from which the present resource is derived. + + + A unique reference to the resource; In this instance, the accession number or collection number. + + + The language of the intellectual content of the resource. + + English + French + + + + Reference to a related resource. + + + Information about intellectual property rights, copyright, and various property rights. + + + + + + + + + + + + + + diff --git a/installer_files/foxml/islandora-top.xml b/installer_files/foxml/islandora-top.xml new file mode 100644 index 00000000..523fb29c --- /dev/null +++ b/installer_files/foxml/islandora-top.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2009-03-23T16:42:07.367Z + Created with Admin GUI "New Object" command + + + + addDatastream + RELS-EXT + fedoraAdmin + 2009-03-23T16:47:49.180Z + + + + + addDatastream + COLLECTION_POLICY + fedoraAdmin + 2009-03-23T16:49:38.149Z + DatastreamsPane generated this logMessage. + + + + ingest + + admin + 2009-03-27T15:56:09.271Z + Fedora Object Ingested + + + + addDatastream + TN + admin + 2009-03-27T15:56:09.381Z + Ingested object TN + + + + purgeDatastream + COLLECTION_POLICY + fedoraAdmin + 2009-03-30T14:31:16.296Z + DatastreamPane generated this logMessage. . . . Purged datastream (ID=COLLECTION_POLICY), versions ranging from 2009-03-23T13:49:38.149Z to 2009-03-23T13:49:38.149Z. This resulted in the permanent removal of 1 datastream version(s) (2009-03-23T13:49:38.149Z) and all associated audit records. + + + + ingest + + aoneill + 2010-10-11T23:08:15.103Z + Fedora Object Ingested + + + + addDatastream + COLLECTION_POLICY + aoneill + 2010-10-11T23:08:15.240Z + Ingested object COLLECTION_POLICY + + + + addDatastream + TN + aoneill + 2010-10-11T23:08:15.373Z + Ingested object TN + + + + + + + + + + Islandora Top-Level Collection + islandora:top + + + + + + + + + + + + + + + + + + + + + + + + dc.title + dc.creator + dc.description + dc.date + dc.identifier + dc.language + dc.publisher + dc.rights + dc.subject + dc.relation + dcterms.temporal + dcterms.spatial + Full Text + + isMemberOfCollection + + + + + + + + + + diff --git a/islandoracm.xsd b/islandoracm.xsd new file mode 100644 index 00000000..204c198c --- /dev/null +++ b/islandoracm.xsd @@ -0,0 +1,167 @@ + + + + Islandora Content Model Schema + Islandora, Robertson Library, University of Prince Edward Island, 550 University Ave., Charlottetown, Prince Edward Island + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/iiv/slideviewer.js.bak b/js/iiv/slideviewer.js.bak new file mode 100644 index 00000000..c46c1711 --- /dev/null +++ b/js/iiv/slideviewer.js.bak @@ -0,0 +1,497 @@ +var iiv = {}; + +iiv.Class = function(prototype) { + var c = function(options) { + jQuery.extend(this, options); + this.initialize.apply(this); + }; + + c.prototype = prototype; + return c; +}; + +iiv.Viewer = new iiv.Class({ + ui: null, + iivContainer: '.iiv', + mapContainer: 'iiv-image-panel', + fedoraUrl: 'http://' + location.host + '/fedora', + pids: null, + pageIndex: 0, + map: null, + + initialize: function(options) { + this.ui = new iiv.Viewer.UI({viewer: this}); + this.riSearch = new iiv.Viewer.RISearch(this.riSearchOptions()); + this.riSearch.search(); + jQuery.iiv = this; + }, + + intercept: function(object, method, interceptor) { + object[method + '_without_interceptor'] = object[method]; + object[method] = interceptor; + }, + + riSearchOptions: function() { + var viewer = this; + return { + pid: this.pid, + cmodel: this.cmodel, + dsid: this.dsid, + fedoraUrl: this.fedoraUrl, + uid: this.uid, + searchCallback: this.createSearchCallback() + } + }, + + createSearchCallback: function() { + var viewer = this; + + return function(results) { + viewer.pids = results; + for (i = 0; i < viewer.pids.length; i++) { + if (viewer.pids[i] == viewer.pid) { + viewer.pageIndex = i; + break; + } + } + + viewer.loadText(); + viewer.initializeMap(); + viewer.ui.initializeUI(); + }; + }, + + initializeMap: function() { + OpenLayers.Layer.OpenURL.viewerWidth = jQuery('.iiv-canvas').width(); + OpenLayers.Layer.OpenURL.viewerHeight = jQuery('.iiv-canvas').height(); + var imageLayer = this.createImageLayer(); + var mapOptions = this.createMapOptions(imageLayer); + mapOptions.controls = this.createMapControls(); + this.map = new OpenLayers.Map(this.mapContainer, mapOptions); + this.map.addLayer(imageLayer); + var lon = this.map.maxExtent.width / 2; + var lat = this.map.maxExtent.height / 2; + this.map.setCenter(new OpenLayers.LonLat(lon, lat), 0); + }, + + createMapControls: function() { + var controls = [ + new OpenLayers.Control.MouseDefaults(), + new OpenLayers.Control.KeyboardDefaults() + ]; + + return controls; + }, + + createMapOptions: function(imageLayer) { + var metadata = imageLayer.getImageMetadata(); + var resolutions = imageLayer.getResolutions(); + var maxExtent = new OpenLayers.Bounds(0, 0, metadata.width, metadata.height); + var tileSize = imageLayer.getTileSize(); + return options = {resolutions: resolutions, maxExtent: maxExtent, tileSize: tileSize}; + }, + + createImageLayer: function() { + var pid = this.currentPid(); + var djatokaUrl = this.djatokaUrl(pid); + + var imageLayer = new iiv.Viewer.ImageLayer('OpenURL', '', { + isBaseLayer : true, + layername : 'basic', + format : 'image/jpeg', + rft_id : this.rftUrl(pid), + metadataUrl : djatokaUrl + '/getMetadata?uid=' + this.uid + }); + + imageLayer.djatokaUrl = djatokaUrl; + imageLayer.uid = this.uid; + + return imageLayer; + }, + + rftUrl: function(pid) { + return this.djatokaUrl(pid) + '/JP2?uid=djatoka'; + }, + + currentPid: function() { + return this.pids[this.pageIndex]; + }, + + djatokaUrl: function(pid) { + return this.pidUrl(pid) + '/ilives:jp2Sdef'; + }, + + pidUrl: function(pid) { + return this.fedoraUrl + '/get/' + pid; + }, + + teiUrl: function(pid) { + return this.fedoraUrl + '/get/' + pid + '/ilives:tei2htmlSdef/tei2html?uid=' + this.uid; + }, + + setPage: function(index) { + if (index != this.pageIndex && index >= 0 && index < this.pids.length) { + this.pageIndex = index; + this.loadText(); + + var nextLayer = this.createImageLayer(); + var options = this.createMapOptions(nextLayer); + this.map.resolutions = options.resolutions; + this.map.maxExtent = options.maxExtent; + this.map.tileSize = options.tileSize; + + var baseLayer = this.map.baseLayer; + + this.map.addLayer(nextLayer); + this.map.setBaseLayer(nextLayer); + this.map.removeLayer(baseLayer); + this.ui.updatePageControls(index); + } + }, + + nextPid: function() { + this.setPage(this.pageIndex + 1); + }, + + previousPid: function() { + this.setPage(this.pageIndex - 1); + }, + + loadText: function() { + /* var container = this.ui.textContainer; + container.html(''); + jQuery.get(this.teiUrl(this.currentPid()), function(data) { + container.html(data); + }, 'html');*/ + }, + + getPrintUrl: function() { + var imageExtent = this.map.getMaxExtent(); + var aspect = imageExtent.getWidth() / imageExtent.getHeight(); + var scale = aspect > 1.3333 ? "600,0" : "0,800"; + var level = '3'; // TODO calculate + + // assemble url + var imageUrl = this.djatokaUrl(this.currentPid()) + '/getRegion?uid=' + this.uid + '&level=' + level + '&scale=' + scale; + var printUrl = '/iiv/print.html?pid=' + this.currentPid() + '&image=' + escape(imageUrl); + + return printUrl; + } +}); + +iiv.Viewer.UI = new iiv.Class({ + viewer: null, + //sliderPage: null, + //buttonPagePrevious: null, + //buttonPageNext: null, + sliderZoom: null, + buttonZoomIn: null, + buttonZoomOut: null, + buttonZoomMax: null, + buttonText: null, + imagePanel: null, + //textPanel: null, + //textContainer: null, + buttonPrint: null, + + initialize: function(options) { + this.createUI(); + }, + + createDiv: function(parent, cssClass) { + var div = jQuery('
      '); + parent.append(div); + return div; + }, + + createUI: function() { + var container = jQuery(this.viewer.iivContainer); + container.append(''); + container.append(''); + container.append(''); + + var ui = this.createDiv(container, 'iiv-ui ui-corner-all'); + var toolbar = this.createDiv(ui, 'iiv-toolbar'); + + this.createZoomControls(toolbar); + //this.createPageControls(toolbar); + //this.createOtherControls(toolbar); + + var canvas = this.createDiv(ui, 'iiv-canvas') + //this.textPanel = this.createDiv(canvas, 'iiv-text-panel'); + //this.textContainer = this.createDiv(this.textPanel, 'iiv-text-container'); + + this.imagePanel = this.createDiv(canvas, 'iiv-image-panel'); + this.imagePanel.attr('id', 'iiv-image-panel'); + + var clear = this.createDiv(container, 'iiv-clear'); + + jQuery('.ui-state-default').hover ( + function(){ + jQuery(this).addClass("ui-state-hover"); + }, + function(){ + jQuery(this).removeClass("ui-state-hover"); + } + ); + }, + + createZoomControls: function(toolbar) { + var controls = this.createControlSet(toolbar, 'zoom'); + this.buttonZoomIn = this.createButton(controls, 'zoom-in', 'Zoom in', 'ui-icon-zoomin'); + this.buttonZoomOut = this.createButton(controls, 'zoom-out', 'Zoom out', 'ui-icon-zoomout'); + this.buttonZoomMax = this.createButton(controls, 'zoom-max', 'Zoom to full image', 'ui-icon-search'); + return controls; + }, + + createPageControls: function(toolbar) { + var controls = this.createControlSet(toolbar, 'page'); + this.buttonPagePrevious = this.createButton(controls, 'page-previous', 'Previous page', 'ui-icon-arrowthick-1-w'); + this.createPageNumberDisplay(controls); + this.buttonPageNext = this.createButton(controls, 'page-next', 'Next page', 'ui-icon-arrowthick-1-e'); + return controls; + }, + + createOtherControls: function(toolbar) { + var controls = this.createControlSet(toolbar, 'other'); + //this.buttonText = this.createButton(controls, 'text', 'Show text', 'iiv-icon-text'); + this.buttonPrint = this.createButton(controls, 'print', 'Print page', 'ui-icon-print'); + return controls; + }, + + createPageNumberDisplay: function(parent) { + var container = this.createDiv(parent, 'iiv-page-number'); + this.currentPageSpan = jQuery('-'); + this.maxPageSpan = jQuery('-'); + container.append(this.currentPageSpan); + container.append(' / '); + container.append(this.maxPageSpan); + return container; + }, + + createControlSet: function(parent, name) { + var controls = this.createDiv(parent, 'iiv-controlset ' + name); + parent.append(controls); + return controls; + }, + + createButton: function(parent, name, title, iconClass) { + var button = jQuery(''); + parent.append(button); + return button; + }, + + + initializeUI: function() { + this.addInterceptors(); + + this.updateZoomControls(this.viewer.map.getZoom()); + + this.addEventHandlers(); + }, + + addInterceptors: function() { + var ui = this; + ui.viewer.intercept(this.viewer.map, 'setCenter', function(lonlat, zoom, dragging, forceZoomChange) { + if (zoom != null && zoom != ui.viewer.map.getZoom()) { + ui.updateZoomControls(zoom); + } + + ui.viewer.map.setCenter_without_interceptor(lonlat, zoom, dragging, forceZoomChange); + }); + }, + + addEventHandlers: function() { + var viewerUI = this; + viewerUI.buttonZoomIn.click(function() { + viewerUI.viewer.map.zoomIn(); + }); + + viewerUI.buttonZoomOut.click(function() { + viewerUI.viewer.map.zoomOut(); + }); + + viewerUI.buttonZoomMax.click(function() { + viewerUI.viewer.map.zoomToMaxExtent(); + }); + + viewerUI.sliderZoom.bind('slidestop', function(event, ui) { + viewerUI.viewer.map.zoomTo(ui.value); + }); + + + viewerUI.buttonPrint.click(function() { + viewerUI.printPage(); + }); + }, + + printPage: function() { + var url = this.viewer.getPrintUrl(); + + // open popup window + var popupWidth = Math.max(312, Math.min(624, window.screen.availWidth)); + var popupHeight = Math.max(312, Math.min(824 / 2, window.screen.availHeight)); + var features = 'width=' + popupWidth + ',height=' + popupHeight; + window.open(url, '_blank', features); + }, + + updatePageControls: function(page) { + this.sliderPage.slider('value', page) + this.currentPageSpan.text(page + 1); + + if (page == 0) { + this.disable(this.buttonPagePrevious); + } + + else { + this.enable(this.buttonPagePrevious); + } + + if (page == this.sliderPage.slider('option', 'max')) { + this.disable(this.buttonPageNext); + } + + else { + this.enable(this.buttonPageNext); + } + }, + + updateZoomControls: function(zoom) { + + this.enable(this.buttonZoomOut); + + this.enable(this.buttonZoomIn); + }, + + disable: function(button) { + button.attr('disabled', 'disabled'); + }, + + enable: function(button) { + button.removeAttr('disabled'); + }, + + toggleText: function() { + this.buttonText.toggleClass('ui-state-active'); + this.buttonText.toggleClass('ui-state-default'); + this.imagePanel.toggleClass('narrow'); + this.textPanel.toggle(); + this.viewer.map.updateSize(); + } +}); + +iiv.Viewer.RISearch = new iiv.Class({ + type: 'tuples', + lang: 'itql', + format: 'csv', + query: null, + results: null, + + initialize: function(options) { + if (!this.query) { + if (this.cmodel == 'ilives:bookCModel') { + this.query = 'select $object from <#ri> ' + + 'where ($object ' + + 'and $object ) ' + + 'order by $object'; + } + + else if (this.cmodel == 'ilives:pageCModel') { + this.query = 'select $parent ' + + 'subquery (' + + ' select $sibling from <#ri> ' + + ' where $sibling $parent ' + + ' and $sibling ' + + ' order by $sibling) ' + + 'from <#ri> ' + + 'where $child ' + + 'and $child $parent ' + + 'and $parent '; + } /* + else if (this.cmodel == 'islandora:slideCModel') { + this.query = 'select $parent ' + + 'subquery (' + + ' select $sibling from <#ri> ' + + ' where $sibling $parent ' + + ' and $sibling ' + + ' order by $sibling) ' + + 'from <#ri> ' + + 'where $child ' + + 'and $child $parent ' + + 'and $parent '; + } */ + else { + // no query -- pid will be used alone. + this.query = 'select $object from <#ri>' + + 'where $object \'' + this.pid + '\''; + } + } + }, + + search: function() { + if (this.query == null) { + + this.results = [this.pid]; + } + + else { + options = { + type: this.type, + lang: this.lang, + format: this.format, + query: this.query, + uid: this.uid + }; + + jQuery.post(this.fedoraUrl + '/risearch', options, this.createCallback(), 'text'); + } + }, + + extractPid: function(riSearchResult) { + return riSearchResult.replace(/^.*\//, ''); + }, + + createCallback: function() { + var riSearch = this; + + return function(data, status) { + var results = []; + if ('success' == status) { + var lines = data.split("\n"); + for (i = 0; i < lines.length; i++) { + if (i > 0 && lines[i] != '') { + results.push(riSearch.extractPid(lines[i])); + } + } + } + + riSearch.searchCallback(results); + } + } +}); + +/* monkey patch OpenLayers.Layer.OpenURL */ +iiv.Viewer.ImageLayer = OpenLayers.Class(OpenLayers.Layer.OpenURL, { + djatokaUrl: null, + uid: null, + + /** + * this implementation is the same as the superclass, except that we use a + * fedora service as the url base, not djatoka itself + */ + getURL: function(bounds) { + bounds = this.adjustBounds(bounds); + this.calculatePositionAndSize(bounds); + var z = this.map.getZoom() + this.zoomOffset; + + // uid and djatokaUrl set in createImageLayer + var path = this.djatokaUrl + '/getRegion?uid=' + this.uid + '&level=' + z + + '®ion=' + this.tilePos.lat + "," + this.tilePos.lon + "," + this.imageSize.h + "," + this.imageSize.w; + + var url = this.url; + if (url instanceof Array) { + url = this.selectUrl(path, url); + } + return url + path; + } +}); diff --git a/js/printer_tool.js b/js/printer_tool.js new file mode 100644 index 00000000..f5ff8802 --- /dev/null +++ b/js/printer_tool.js @@ -0,0 +1,14 @@ +// $Id$ /** +/* Add printer-friendly tool to page. */ +var PrinterTool = {}; +PrinterTool.windowSettings = 'toolbar=no,location=no,' + 'status=no,menu=no,scrollbars=yes,width=650,height=400'; +/** * Open a printer-friendly page and prompt for printing. * @param tagID * The ID of the tag that contains the material that should * be printed. */ +PrinterTool.print = function (tagID) { var target = document.getElementById(tagID); var title = document.title; +if(!target || target.childNodes.length === 0) { alert("Nothing to Print"); return; +} +var content = target.innerHTML; +var text = '' + title + +'' + content +''; +printerWindow = window.open('', '', PrinterTool.windowSettings); printerWindow.document.open(); printerWindow.document.write(text); printerWindow.document.close(); +printerWindow.print(); +}; diff --git a/js/swfobject.js b/js/swfobject.js new file mode 100644 index 00000000..6d541852 --- /dev/null +++ b/js/swfobject.js @@ -0,0 +1,217 @@ +// $Id$ +/** + * SWFObject v2.0: Flash Player detection and embed - http://blog.deconcept.com/swfobject/ + * + * SWFObject is (c) 2006 Geoff Stearns and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + */ +if(typeof deconcept == "undefined") var deconcept = new Object(); +if(typeof deconcept.util == "undefined") deconcept.util = new Object(); +if(typeof deconcept.SWFObjectUtil == "undefined") deconcept.SWFObjectUtil = new Object(); +deconcept.SWFObject = function(swf, id, w, h, ver, c, quality, xiRedirectUrl, redirectUrl, detectKey) { + if (!document.getElementById) { return; } + this.DETECT_KEY = detectKey ? detectKey : 'detectflash'; + this.skipDetect = deconcept.util.getRequestParameter(this.DETECT_KEY); + this.params = new Object(); + this.variables = new Object(); + this.attributes = new Array(); + if(swf) { this.setAttribute('swf', swf); } + if(id) { this.setAttribute('id', id); } + if(w) { this.setAttribute('width', w); } + if(h) { this.setAttribute('height', h); } + if(ver) { this.setAttribute('version', new deconcept.PlayerVersion(ver.toString().split("."))); } + this.installedVer = deconcept.SWFObjectUtil.getPlayerVersion(); + if (!window.opera && document.all && this.installedVer.major > 7) { + // only add the onunload cleanup if the Flash Player version supports External Interface and we are in IE + deconcept.SWFObject.doPrepUnload = true; + } + if(c) { this.addParam('bgcolor', c); } + var q = quality ? quality : 'high'; + this.addParam('quality', q); + this.setAttribute('useExpressInstall', false); + this.setAttribute('doExpressInstall', false); + var xir = (xiRedirectUrl) ? xiRedirectUrl : window.location; + this.setAttribute('xiRedirectUrl', xir); + this.setAttribute('redirectUrl', ''); + if(redirectUrl) { this.setAttribute('redirectUrl', redirectUrl); } +} +deconcept.SWFObject.prototype = { + useExpressInstall: function(path) { + this.xiSWFPath = !path ? "expressinstall.swf" : path; + this.setAttribute('useExpressInstall', true); + }, + setAttribute: function(name, value){ + this.attributes[name] = value; + }, + getAttribute: function(name){ + return this.attributes[name]; + }, + addParam: function(name, value){ + this.params[name] = value; + }, + getParams: function(){ + return this.params; + }, + addVariable: function(name, value){ + this.variables[name] = value; + }, + getVariable: function(name){ + return this.variables[name]; + }, + getVariables: function(){ + return this.variables; + }, + getVariablePairs: function(){ + var variablePairs = new Array(); + var key; + var variables = this.getVariables(); + for(key in variables){ + variablePairs.push(key +"="+ variables[key]); + } + return variablePairs; + }, + getSWFHTML: function() { + var swfNode = ""; + if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { // netscape plugin architecture + if (this.getAttribute("doExpressInstall")) { + this.addVariable("MMplayerType", "PlugIn"); + this.setAttribute('swf', this.xiSWFPath); + } + swfNode = ' 0){ swfNode += 'flashvars="'+ pairs +'"'; } + swfNode += '/>'; + } else { // PC IE + if (this.getAttribute("doExpressInstall")) { + this.addVariable("MMplayerType", "ActiveX"); + this.setAttribute('swf', this.xiSWFPath); + } + swfNode = ''; + swfNode += ''; + var params = this.getParams(); + for(var key in params) { + swfNode += ''; + } + var pairs = this.getVariablePairs().join("&"); + if(pairs.length > 0) {swfNode += '';} + swfNode += ""; + } + return swfNode; + }, + write: function(elementId){ + if(this.getAttribute('useExpressInstall')) { + // check to see if we need to do an express install + var expressInstallReqVer = new deconcept.PlayerVersion([6,0,65]); + if (this.installedVer.versionIsValid(expressInstallReqVer) && !this.installedVer.versionIsValid(this.getAttribute('version'))) { + this.setAttribute('doExpressInstall', true); + this.addVariable("MMredirectURL", escape(this.getAttribute('xiRedirectUrl'))); + document.title = document.title.slice(0, 47) + " - Flash Player Installation"; + this.addVariable("MMdoctitle", document.title); + } + } + if(this.skipDetect || this.getAttribute('doExpressInstall') || this.installedVer.versionIsValid(this.getAttribute('version'))){ + var n = (typeof elementId == 'string') ? document.getElementById(elementId) : elementId; + n.innerHTML = this.getSWFHTML(); + return true; + }else{ + if(this.getAttribute('redirectUrl') != "") { + document.location.replace(this.getAttribute('redirectUrl')); + } + } + return false; + } +} + +/* ---- detection functions ---- */ +deconcept.SWFObjectUtil.getPlayerVersion = function(){ + var PlayerVersion = new deconcept.PlayerVersion([0,0,0]); + if(navigator.plugins && navigator.mimeTypes.length){ + var x = navigator.plugins["Shockwave Flash"]; + if(x && x.description) { + PlayerVersion = new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split(".")); + } + }else{ + // do minor version lookup in IE, but avoid fp6 crashing issues + // see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/ + try{ + var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); + }catch(e){ + try { + var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); + PlayerVersion = new deconcept.PlayerVersion([6,0,21]); + axo.AllowScriptAccess = "always"; // throws if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code) + } catch(e) { + if (PlayerVersion.major == 6) { + return PlayerVersion; + } + } + try { + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); + } catch(e) {} + } + if (axo != null) { + PlayerVersion = new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(",")); + } + } + return PlayerVersion; +} +deconcept.PlayerVersion = function(arrVersion){ + this.major = arrVersion[0] != null ? parseInt(arrVersion[0]) : 0; + this.minor = arrVersion[1] != null ? parseInt(arrVersion[1]) : 0; + this.rev = arrVersion[2] != null ? parseInt(arrVersion[2]) : 0; +} +deconcept.PlayerVersion.prototype.versionIsValid = function(fv){ + if(this.major < fv.major) return false; + if(this.major > fv.major) return true; + if(this.minor < fv.minor) return false; + if(this.minor > fv.minor) return true; + if(this.rev < fv.rev) return false; + return true; +} +/* ---- get value of query string param ---- */ +deconcept.util = { + getRequestParameter: function(param) { + var q = document.location.search || document.location.hash; + if(q) { + var pairs = q.substring(1).split("&"); + for (var i=0; i < pairs.length; i++) { + if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) { + return pairs[i].substring((pairs[i].indexOf("=")+1)); + } + } + } + return ""; + } +} +/* fix for video streaming bug */ +deconcept.SWFObjectUtil.cleanupSWFs = function() { + var objects = document.getElementsByTagName("OBJECT"); + for (var i=0; i < objects.length; i++) { + objects[i].style.display = 'none'; + for (var x in objects[i]) { + if (typeof objects[i][x] == 'function') { + objects[i][x] = function(){}; + } + } + } +} +// fixes bug in fp9 see http://blog.deconcept.com/2006/07/28/swfobject-143-released/ +if (deconcept.SWFObject.doPrepUnload) { + deconcept.SWFObjectUtil.prepUnload = function() { + __flash_unloadHandler = function(){}; + __flash_savedUnloadHandler = function(){}; + window.attachEvent("onunload", deconcept.SWFObjectUtil.cleanupSWFs); + } + window.attachEvent("onbeforeunload", deconcept.SWFObjectUtil.prepUnload); +} +/* add Array.push if needed (ie5) */ +if (Array.prototype.push == null) { Array.prototype.push = function(item) { this[this.length] = item; return this.length; }} + +/* add some aliases for ease of use/backwards compatibility */ +var getQueryParamValue = deconcept.util.getRequestParameter; +var FlashObject = deconcept.SWFObject; // for legacy support +var SWFObject = deconcept.SWFObject; diff --git a/plugins/CollectionFormBuilder.inc b/plugins/CollectionFormBuilder.inc new file mode 100644 index 00000000..6c5e33b6 --- /dev/null +++ b/plugins/CollectionFormBuilder.inc @@ -0,0 +1,45 @@ +getType($file); + $fileUrl = $base_url . '/'. drupal_urlencode($file); + $beginIndex = strrpos($fileUrl, '/'); + $dtitle = substr($fileUrl, $beginIndex + 1); + $dtitle = substr($dtitle, 0, strpos($dtitle, ".")); + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "COLLECTION_POLICY"); //set the ID + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "M"); + $ds1v= $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "COLLECTION_POLICY.0"); + $ds1v->setAttribute("MIMETYPE", "$dformat"); + $ds1v->setAttribute("LABEL", "$dtitle"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $ds1content->setAttribute("REF", "$fileUrl"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + $rootElement->appendChild($ds1); + } +} diff --git a/plugins/CreateCollection.inc b/plugins/CreateCollection.inc new file mode 100644 index 00000000..0c185705 --- /dev/null +++ b/plugins/CreateCollection.inc @@ -0,0 +1,22 @@ +owner = $item; + if ( array_key_exists('DARWIN_CORE', $item->get_datastreams_list_as_array())) { + $dwc = $item->get_datastream_dissemination('DARWIN_CORE'); + if (!empty($dwc)) { + $this->darwinCoreXML = $dwc; + } + } + } + } + + public function buildDrupalForm($form = array()) { + + $dwc_xml = $this->darwinCoreXML; + + $dwc = DOMDocument::loadXML($dwc_xml); + + $form['dc:type'] = array( + '#title' => 'dc:type', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://purl.org/dc/terms/', 'type')->item(0)->nodeValue, + '#description' => '', + ); + + $form['dc:language'] = array( + '#title' => 'dc:language', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://purl.org/dc/terms/', 'language')->item(0)->nodeValue, + '#description' => '', + ); + + $form['dwc:basisOfRecord'] = array( + '#title' => 'Basis of Record', + '#type' => 'select', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'basisOfRecord')->item(0)->nodeValue, + '#options' => $this->vocabulary['basisOfRecord'], + '#description' => '', + ); + $form['dwc:scientificName'] = array( + '#title' => 'dwc:scientificName', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'scientificName')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:specificEpithet'] = array( + '#title' => 'dwc:specificEpithet', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'specificEpithet')->item(0)->nodeValue, + '#description' => '', + ); + + $form['dwc:family'] = array( + '#title' => 'dwc:family', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'family')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:genus'] = array( + '#title' => 'dwc:genus', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'genus')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:vernacularName'] = array( + '#title' => 'dwc:vernacularName', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'vernacularName')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:continent'] = array( + '#title' => 'dwc:continent', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'continent')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:country'] = array( + '#title' => 'dwc:country', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'country')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:stateProvince'] = array( + '#title' => 'dwc:stateProvince', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'stateProvince')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:county'] = array( + '#title' => 'dwc:county', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'county')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:locality'] = array( + '#title' => 'dwc:locality', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'locality')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:habitat'] = array( + '#title' => 'dwc:habitat', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'habitat')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:occurrenceRemarks'] = array( + '#title' => 'dwc:occurrenceRemarks', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'occurrenceRemarks')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:occurrenceID'] = array( + '#title' => 'dwc:occurrenceID', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'occurrenceID')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:institutionCode'] = array( + '#title' => 'dwc:institutionCode', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'institutionCode')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:collectionCode'] = array( + '#title' => 'dwc:collectionCode', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'collectionCode')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:collectionCode'] = array( + '#title' => 'dwc:collectionCode', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'collectionCode')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:catalogNumber'] = array( + '#title' => 'dwc:catalogNumber', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'catalogNumber')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:catalogNumber'] = array( + '#title' => 'dwc:catalogNumber', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'catalogNumber')->item(0)->nodeValue, + '#description' => '', + ); + $form['dwc:recordedBy'] = array( + '#title' => 'dwc:recordedBy', + '#type' => 'textfield', + '#default_value' => $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'recordedBy')->item(0)->nodeValue, + '#description' => '', + ); + $date = $dwc->getElementsByTagNameNS('http://rs.tdwg.org/dwc/terms/', 'eventDate')->item(0)->nodeValue; + $format = 'Y-m-d H:i:s'; + $form['dwceventDate'] = array( + '#type' => 'date_popup', // types 'date_text' and 'date_timezone' are also supported. See .inc file. + '#title' => 'select a date', + '#default_value' => $date, + '#date_format' => $format, + '#date_label_position' => 'within', // See other available attributes and what they do in date_api_elements.inc + '#date_increment' => 15, // Optional, used by the date_select and date_popup elements to increment minutes and seconds. + '#description' => '', + ); + return $form; + } + + public function handleForm($form_values) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + global $user; + //$new_item = Fedora_Item::ingest_new_item($form_values['pid'], 'A', $form_values['dwc:institutionCode'].':'.$form_values['dwc:collectionCode'].':'.$form_values['dwc:catalogNumber'], $user->name); + //$new_item->add_datastream_from_string($this->darwinCoreXML, 'DARWIN_CORE', 'Darwin Core Metadata', 'text/xml', 'X'); + // For each form element, find and replace that element's value in the XML stream. + $dwc = new SimpleXMLElement($this->darwinCoreXML); + $dc_elements = $dwc->SimpleDarwinRecord->children('http://purl.org/dc/terms/'); + $dc_elements->type = $form_values['dc:type']; + $dc_elements->language = $form_values['dc:language']; + + $dwc_elements = $dwc->SimpleDarwinRecord->children('http://rs.tdwg.org/dwc/terms/'); + $dwc_elements->basisOfRecord = $form_values['dwc:basisOfRecord']; + $dwc_elements->scientificName = $form_values['dwc:scientificName']; + $dwc_elements->specificName = $form_values['dwc:specificName']; + $dwc_elements->specificName = $form_values['dwc:family']; + $dwc_elements->genus = $form_values['dwc:genus']; + $dwc_elements->vernacularName = $form_values['dwc:vernacularName']; + $dwc_elements->continent = $form_values['dwc:continent']; + $dwc_elements->country = $form_values['dwc:country']; + $dwc_elements->countryCode = $form_values['dwc:countryCode']; + $dwc_elements->stateProvince = $form_values['dwc:stateProvince']; + $dwc_elements->locality = $form_values['dwc:locality']; + $dwc_elements->habitat = $form_values['dwc:habitat']; + $dwc_elements->occurrenceRemarks = $form_values['dwc:occurrenceRemarks']; + $dwc_elements->occurrenceID = $form_values['dwc:occurrenceID']; + $dwc_elements->institutionCode = $form_values['dwc:institutionCode']; + $dwc_elements->collectionCode = $form_values['dwc:collectionCode']; + $dwc_elements->catalogNumber = $form_values['dwc:catalogNumber']; + $dwc_elements->recordedBy = $form_values['dwc:recordedBy']; + $dwc_elements->eventDate = $form_values['dwceventDate']; + + $this->darwinCoreXML = $dwc->saveXML(); + } + + public function asXML() { + return $this->darwinCoreXML; + } + + public function asHTML() { + $path=drupal_get_path('module', 'Fedora_Repository'); + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + module_load_include('inc', 'fedora_repository', 'CollectionClass'); + + $xmlstr = $this->darwinCoreXML; + html_entity_decode($xmlstr); + + if ($xmlstr == NULL || strlen($xmlstr) < 5) { + return " "; + } + + try { + $proc = new XsltProcessor(); + } + catch (Exception $e) { + drupal_set_message(t("!e", array('!e' => $e->getMessage())), 'error'); + return " "; + } + + $xsl = new DomDocument(); + $xsl->load($path . '/xsl/specdwc.xsl'); + $input = new DomDocument(); + $input->loadXML(trim($xmlstr)); + $xsl = $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + $content=$newdom->saveXML(); + + return $content; + } + + public $vocabulary = array( + 'basisOfRecord' => array( + 'Occurrence' => 'Occurrence', + 'Event' => 'Event', + 'Location' => 'Location', + 'Taxon' => 'Taxon', + 'PreservedSpecimen' => 'PreservedSpecimen', + 'FossilSpecimen' => 'FossilSpecimen', + 'LivingSpecimen' => 'LivingSpecimen', + 'HumanObservation' => 'HumanObservation', + 'MachineObservation' => 'MachineObservation', + 'NomenclaturalChecklist' => 'NomenclaturalChecklist', + ), + + ); + + public $dwcFields = array( + 'dc:type', + 'dc:language', + 'dwc:basisofrecord', + 'dwc:scientificName', + 'dwc:specificName', + 'dwc:family', + 'dwc:genus', + 'dwc:vernacularName', + 'dwc:continent', + 'dwc:country', + 'dwc:countryCode', + 'dwc:stateProvince', + 'dwc:locality', + 'dwc:habitat', + 'dwc:occurrenceRemarks', + 'dwc:occurrenceID', + 'dwc:institutionCode', + 'dwc:collectionCode', + 'dwc:catalogNumber', + 'dwc:recordedBy', + 'dwc:eventDate', + 'dwc:eventTime', + ); + + + public $darwinCoreXML = ' + + + + en + + + + + + + + + + + + + + + + + + + + + + +'; + +} diff --git a/plugins/DemoFormBuilder.inc b/plugins/DemoFormBuilder.inc new file mode 100644 index 00000000..913d8005 --- /dev/null +++ b/plugins/DemoFormBuilder.inc @@ -0,0 +1,77 @@ +getType($file); + $fileUrl = $base_url .'/'. drupal_urlencode($file); + $beginIndex = strrpos($fileUrl, '/'); + $dtitle = substr($fileUrl, $beginIndex + 1); + $dtitle = urldecode($dtitle); + // $dtitle = substr($dtitle, 0, strpos($dtitle, ".")); + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "FULL_SIZE"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "M"); + $ds1v = $dom->createElement("foxml:datastreamVersion"); + $rootElement->appendChild($ds1); + + $ds1v->setAttribute("ID", "FULL_SIZE.0"); + $ds1v->setAttribute("MIMETYPE", "$dformat"); + $ds1v->setAttribute("LABEL", "$dtitle"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $ds1content->setAttribute("REF", "$fileUrl"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + } + if (!empty($_SESSION['fedora_ingest_files'])) { + foreach ($_SESSION['fedora_ingest_files'] as $dsid => $createdFile) { + $createdFile = strstr($createdFile, $file); + $dformat = $mimetype->getType($createdFile); + $fileUrl = $base_url .'/'. drupal_urlencode( $createdFile ); + $beginIndex = strrpos($fileUrl, '/'); + $dtitle = substr($fileUrl, $beginIndex + 1); + $dtitle = urldecode($dtitle); + // $dtitle = substr($dtitle, 0, strpos($dtitle, ".")); + $dtitle = $dtitle; + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "$dsid"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "M"); + $ds1v= $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "$dsid.0"); + $ds1v->setAttribute("MIMETYPE", "$dformat"); + $ds1v->setAttribute("LABEL", "$dtitle"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $ds1content->setAttribute("REF", "$fileUrl"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + $rootElement->appendChild($ds1); + } + } + } +} + diff --git a/plugins/DocumentConverter.inc b/plugins/DocumentConverter.inc new file mode 100644 index 00000000..3aafb49f --- /dev/null +++ b/plugins/DocumentConverter.inc @@ -0,0 +1,79 @@ +converter_service_url = $converter_url; + } + + function convert($parameterArray = NULL, $dsid, $file, $output_ext) { + module_load_include('inc', 'fedora_repository', 'MimeClass'); + + #debug: + #drupal_set_message("Sending $file to ". $this->converter_service_url ." for convertsion to $output_ext", 'status'); + + if (!empty($parameterArray['converter_url'])) { + $this->converter_service_url = $parameterArray['converter_url']; + } + + $helper = new MimeClass(); + $inputType = $helper->get_mimetype($file); + $outputType = $helper->get_mimetype($output_ext); + $inputData = file_get_contents($file); + + $outputFile = $file ."_". $dsid .".". $output_ext; + + #debug: + #drupal_set_message("inputType: $inputType", 'status'); + #drupal_set_message("outputType: $outputType", 'status'); + #drupal_set_message("outputFile: $outputFile", 'status'); + + $ch = curl_init($this->converter_service_url); + curl_setopt($ch, CURLOPT_HTTPHEADER, array( "Content-Type: $inputType", "Accept: $outputType" ) ); + curl_setopt($ch, CURLOPT_POST, 1 ); + curl_setopt($ch, CURLOPT_TIMEOUT, 120); // times out after 2 minutes + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // return into a variable + curl_setopt($ch, CURLOPT_POSTFIELDS, $inputData); // add POST fields + #curl_setopt($ch, CURLOPT_HEADER, 1); + #curl_setopt($ch, CURLOPT_VERBOSE, 1); + + $data = curl_exec($ch); // run the whole process + + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + if (200 == $code) { + + $returnValue = file_put_contents($outputFile, $data); + if ($returnValue > 0) { + drupal_set_message("Conversion successful.", 'status'); + $_SESSION['fedora_ingest_files']["$dsid"] = $outputFile; + return $outputFile; + } + else { + return $returnValue; // a.k.a. FALSE. + } + } + else { + drupal_set_message("Conversion Failed. Webservice returned $code.", 'status'); + return FALSE; + } + } +} + +/* +$documentConverter = new DocumentConverter(); +$inputFile = "document.docx"; +$outputType = "txt"; +$documentConverter->convert( null, 'TXT', $inputFile, $outputType); +/* */ diff --git a/plugins/Flv.inc b/plugins/Flv.inc new file mode 100644 index 00000000..4b16fe7d --- /dev/null +++ b/plugins/Flv.inc @@ -0,0 +1,271 @@ +createElement("foxml:datastream"); + $datastream->setAttribute("ID", "QDC"); + $datastream->setAttribute("STATE", "A"); + $datastream->setAttribute("CONTROL_GROUP", "X"); + $version = $dom->createElement("foxml:datastreamVersion"); + $version->setAttribute("ID", "QDC.0"); + $version->setAttribute("MIMETYPE", "text/xml"); + $version->setAttribute("LABEL", "QDC Dublin Core Record"); + $datastream->appendChild($version); + $content = $dom->createElement("foxml:xmlContent"); + $version->appendChild($content); + ///begin writing qdc + $oai = $dom->createElement("oai_dc:dc"); + $oai->setAttribute('xmlns:oai_dc', "http://www.openarchives.org/OAI/2.0/oai_dc/"); + $oai->setAttribute('xmlns:dc', "http://purl.org/dc/elements/1.1/"); + $oai->setAttribute('xmlns:dcterms', "http://purl.org/dc/terms/"); + $oai->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $content->appendChild($oai); + //dc elements + $previousElement=NULL; //used in case we have to nest elements for qualified dublin core + foreach ($form_values as $key => $value) { + $index = strrpos($key, '-'); + if ($index > 01) { + $key = substr($key, 0, $index); + } + + $test = substr($key, 0, 2); + + if ($test=='dc'||$test=='ap') {//don't try to process other form values + try { + if (!strcmp(substr($key, 0, 4), 'app_')) { + $key = substr($key, 4); + $previousElement->appendChild($dom->createElement($key, $value)); + } + else { + $previousElement = $dom->createElement($key, $value); + $oai->appendChild($previousElement); + } + } + catch (exception $e) { + drupal_set_message(t("!e", array('!e' => $e->getMessage())), 'error'); + continue; + } + } + $rootElement->appendChild($datastream); + } + } + + function handleQDCForm($form_values) { + $dom = new DomDocument("1.0", "UTF-8"); + $dom->formatOutput = TRUE; + $pid=$form_values['pid']; + $rootElement = $dom->createElement("foxml:digitalObject"); + $rootElement->setAttribute('PID', "$pid"); + $rootElement->setAttribute('xmlns:foxml', "info:fedora/fedora-system:def/foxml#"); + $rootElement->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $rootElement->setAttribute('xsi:schemaLocation', "info:fedora/fedora-system:def/foxml# http://www.fedora.info/definitions/1/0/foxml1-0.xsd"); + $dom->appendChild($rootElement); + //create standard fedora stuff + $this->createStandardFedoraStuff($form_values, $dom, $rootElement); + //create relationships + $this->createRelationShips($form_values, $dom, $rootElement); + //create dublin core + $this->createQDCStream($form_values, $dom, $rootElement); + $this->createFedoraDataStreams($form_values, $dom, $rootElement); + $params = array( + 'objectXML' => $dom->saveXML(), + 'format' => "foxml1.0", + 'logMessage' => "Fedora Object Ingested", + ); + + try { + $soapHelper = new ConnectionHelper(); + $client=$soapHelper->getSoapClient(variable_get('fedora_soap_manage_url', 'http://localhost:8080/fedora/services/management?wsdl')); + + if ($client == NULL) { + drupal_set_message(t('Error getting SOAP client.'), 'error'); + return; + } + $object=$client->__soapCall('ingest', array($params)); + $deleteFiles = $form_values['delete_file']; //remove files from drupal file system + + if ($deleteFiles > 0) { + foreach ($_SESSION['fedora_ingest_files'] as $dsid => $createdFile) { + unlink($createdFile); + } + unlink($form_values['fullpath']); + } + } + catch (exception $e) { + drupal_set_message(t('Error ingesting object: !e', array('!e' => $e->getMessage())), 'error'); + return; + } + } + + function createFedoraDataStreams($form_values, &$dom, &$rootElement) { + module_load_include('inc', 'fedora_repository', 'MimeClass'); + $mimetype = new MimeClass(); + $server = NULL; + $file=$form_values['ingest-file-location']; + $dformat = $mimetype->getType($file); + $fileUrl = 'http://'. $_SERVER['HTTP_HOST'] . $file; + $beginIndex = strrpos($fileUrl, '/'); + $dtitle = substr($fileUrl, $beginIndex + 1); + $dtitle = substr($dtitle, 0, strpos($dtitle, ".")); + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "OBJ"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "M"); + $ds1v= $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "OBJ.0"); + $ds1v->setAttribute("MIMETYPE", "$dformat"); + $ds1v->setAttribute("LABEL", "$dtitle"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $ds1content->setAttribute("REF", "$fileUrl"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + $rootElement->appendChild($ds1); + + foreach ($_SESSION['fedora_ingest_files'] as $dsid => $createdFile) { + $createdFile = strstr($createdFile, $file); + $dformat = $mimetype->getType($createdFile); + $fileUrl = 'http://'. $_SERVER['HTTP_HOST'] . $createdFile; + $beginIndex = strrpos($fileUrl, '/'); + $dtitle = substr($fileUrl, $beginIndex + 1); + $dtitle = substr($dtitle, 0, strpos($dtitle, ".")); + $dtitle = $dtitle . '_'. $dsid; + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "$dsid"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "M"); + $ds1v= $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "$dsid.0"); + $ds1v->setAttribute("MIMETYPE", "$dformat"); + $ds1v->setAttribute("LABEL", "$dtitle"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $ds1content->setAttribute("REF", "$fileUrl"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + $rootElement->appendChild($ds1); + } + } + + /** + * creates the RELS-EXT for the foxml + */ + function createRelationShips($form_values, &$dom, &$rootElement) { + $drdf = $dom->createElement("foxml:datastream"); + $drdf->setAttribute("ID", "RELS-EXT"); + $drdf->setAttribute("CONTROL_GROUP", "X"); + $dvrdf = $dom->createElement("foxml:datastreamVersion"); + $dvrdf->setAttribute("ID", "RELS-EXT.0"); + $dvrdf->setAttribute("MIMETYPE", "text/xml"); + $dvrdf->setAttribute("LABEL", "Fedora Object-to-Object Relationship Metadata"); + $dvcontent = $dom->createElement("foxml:xmlContent"); + $rdf = $dom->createElement("rdf:RDF"); + $rdf->setAttribute("xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + $rdf->setAttribute("xmlns:rdfs", "http://www.w3.org/2000/01/rdf-schema#"); + $rdf->setAttribute("xmlns:fedora", "info:fedora/fedora-system:def/relations-external#"); + $rdf->setAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/"); + $rdf->setAttribute("xmlns:oai_dc", "http://www.openarchives.org/OAI/2.0/oai_dc/"); + $rdfdesc = $dom->createElement("rdf:description"); + $pid = $form_values['pid']; + $rdfdesc->setAttribute("rdf:about", "info:fedora/$pid"); + $member = $dom->createElement("fedora:isMemberOfCollection"); + $membr = $form_values['collection_pid']; + $member->setAttribute("rdf:resource", "info:fedora/$membr"); + + $drdf->appendChild($dvrdf); + $dvrdf->appendChild($dvcontent); + $dvcontent->appendChild($rdf); + $rdf->appendChild($rdfdesc); + $rdfdesc->appendChild($member); + $rootElement->appendChild($drdf); + + } + + /** + * creates the standard foxml properties + */ + function createStandardFedoraStuff($form_values, &$dom, &$rootElement) { + /*foxml object properties section */ + $objproperties = $dom->createElement("foxml:objectProperties"); + $prop1 = $dom->createElement("foxml:property"); + $prop1->setAttribute("NAME", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); + $prop1->setAttribute("VALUE", "FedoraObject"); + $prop2 = $dom->createElement("foxml:property"); + $prop2->setAttribute("NAME", "info:fedora/fedora-system:def/model#state"); + $prop2->setAttribute("VALUE", "A"); + $prop3 = $dom->createElement("foxml:property"); + $prop3->setAttribute("NAME", "info:fedora/fedora-system:def/model#label"); + $prop3->setAttribute("VALUE", $form_values['dc:title']); + $prop4 = $dom->createElement("foxml:property"); + $prop4->setAttribute("NAME", "info:fedora/fedora-system:def/model#contentModel"); + $prop4->setAttribute("VALUE", $form_values['content_model_name']); + $prop5 = $dom->createElement("foxml:property"); + $prop5->setAttribute("NAME", "info:fedora/fedora-system:def/model#ownerId"); + $prop5->setAttribute("VALUE", $form_values['user_id']); + $objproperties->appendChild($prop1); + $objproperties->appendChild($prop2); + $objproperties->appendChild($prop3); + $objproperties->appendChild($prop4); + $objproperties->appendChild($prop5); + $rootElement->appendChild($objproperties); + } + + + function buildQDCForm(&$form, $ingest_form_definition, &$form_values) { + $form['indicator2'] = array( + '#type' => 'fieldset', + '#title' => t('Ingest Digital Object Step #2') + ); + foreach ($ingest_form_definition->form_elements->element as $element) { + $name = strip_tags($element->name->asXML()); + $title = strip_tags($element->label->asXML()); + $required = strip_tags($element->required->asXML()); + $required = strtolower($required); + if ($required != 'TRUE') { + $required='0'; + } + + $description = strip_tags($element->description->asXML()); + $type = strip_tags($element->type->asXML()); + $options = array(); + if ($element->type == 'select') { + foreach ($element->authoritative_list->item as $item) { + $field = strip_tags($item->field->asXML()); + $value = strip_tags($item->value->asXML()); + $options["$field"] = $value; + } + $form['indicator2']["$name"] = array( + '#title' => $title, + '#required' => $required, + '#description' => $description, + '#type' => $type, + '#options' => $options, + ); + + } + else { + $form['indicator2']["$name"] = array( + '#title' => $title, + '#required' => $required, + '#description' => $description, + '#type' => $type + ); + } + } + + return $form; + } + +} diff --git a/plugins/FlvFormBuilder.inc b/plugins/FlvFormBuilder.inc new file mode 100644 index 00000000..37b0e0d2 --- /dev/null +++ b/plugins/FlvFormBuilder.inc @@ -0,0 +1,64 @@ +getType($file); + //$fileUrl = 'http://'.$_SERVER['HTTP_HOST'].$file; + $fileUrl = $base_url .'/'. drupal_urlencode($file); + $beginIndex = strrpos($fileUrl, '/'); + $dtitle = substr($fileUrl, $beginIndex + 1); + $dtitle = substr($dtitle, 0, strpos($dtitle, ".")); + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "FLV"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "M"); + $ds1v= $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "FLV.0"); + $ds1v->setAttribute("MIMETYPE", "$dformat"); + $ds1v->setAttribute("LABEL", "$dtitle"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $ds1content->setAttribute("REF", "$fileUrl"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + $rootElement->appendChild($ds1); + + $createdFile = drupal_get_path('module', 'Fedora_Repository') . '/images/flashThumb.jpg'; + $fileUrl = $base_url .'/'. drupal_urlencode($createdFile); //'http://'.$_SERVER['HTTP_HOST'].'/'.$createdFile; + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "TN"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "M"); + $ds1v = $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "TN.0"); + $ds1v->setAttribute("MIMETYPE", "image/jpeg"); + $ds1v->setAttribute("LABEL", "Thumbnail"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $ds1content->setAttribute("REF", "$fileUrl"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + $rootElement->appendChild($ds1); + } +} + diff --git a/plugins/FormBuilder.inc b/plugins/FormBuilder.inc new file mode 100644 index 00000000..7cb8acdc --- /dev/null +++ b/plugins/FormBuilder.inc @@ -0,0 +1,354 @@ +createElement("foxml:datastream"); + $datastream->setAttribute("ID", "DC"); + $datastream->setAttribute("STATE", "A"); + $datastream->setAttribute("CONTROL_GROUP", "X"); + $version = $dom->createElement("foxml:datastreamVersion"); + $version->setAttribute("ID", "DC.0"); + $version->setAttribute("MIMETYPE", "text/xml"); + $version->setAttribute("LABEL", "Dublin Core Record"); + $datastream->appendChild($version); + $content = $dom->createElement("foxml:xmlContent"); + $version->appendChild($content); + ///begin writing qdc + $oai = $dom->createElement("oai_dc:dc"); + $oai->setAttribute('xmlns:oai_dc', "http://www.openarchives.org/OAI/2.0/oai_dc/"); + $oai->setAttribute('xmlns:dc', "http://purl.org/dc/elements/1.1/"); + $oai->setAttribute('xmlns:dcterms', "http://purl.org/dc/terms/"); + $oai->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $content->appendChild($oai); + //dc elements + $previousElement=NULL;//used in case we have to nest elements for qualified dublin core + foreach ($form_values as $key => $value) { + $key = str_replace('_', ':', $key); + $index = strrpos($key, '-'); + if ($index > 01) { + $key = substr($key, 0, $index); + } + $test = substr($key, 0, 2); + + if ($test == 'dc' || $test == 'ap') { + //don't try to process other form values + try { + if (!strcmp(substr($key, 0, 4), 'app_')) { + $key = substr($key, 4); + $previousElement->appendChild($dom->createElement($key, $value)); + } + else { + $previousElement = $dom->createElement($key, $value); + $oai->appendChild($previousElement); + } + } + catch (exception $e) { + drupal_set_message(t("!e", array('!e' => $e->getMessage())), 'error'); + continue; + } + } + $rootElement->appendChild($datastream); + } + + } + + //create the security Policy + function createPolicy($collectionPid, &$dom, &$rootElement) { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + $objectHelper = new ObjectHelper(); + + $dsid = 'CHILD_SECURITY'; + $policyStreamDoc = $objectHelper->getStream($collectionPid, $dsid, FALSE); + if (!isset($policyStreamDoc)) { + return NULL; //there is no policy stream so object will not have a policy stream + } + try { + $xml = new SimpleXMLElement($policyStreamDoc); + } + catch (Exception $e) { + watchdog(t("Fedora_Repository"), t("Problem getting security policy."), NULL, WATCHDOG_ERROR); + drupal_set_message(t('Problem getting security policy: !e', array('!e' => $e->getMessage())), 'error'); + return FALSE; + } + $policyElement = $dom->createDocumentFragment(); + if (!$policyElement) { + drupal_set_message(t('Error parsing security policy stream.')); + watchdog(t("Fedora_Repository"), t("Error parsing security policy stream, could not parse policy stream."), NULL, WATCHDOG_NOTICE); + return FALSE; + } + $dom->importNode($policyElement, TRUE); + $value=$policyElement->appendXML($policyStreamDoc); + if (!$value) { + drupal_set_message(t('Error creating security policy stream.')); + watchdog(t("Fedora_Repository"), t("Error creating security policy stream, could not parse collection policy template file."), NULL, WATCHDOG_NOTICE); + return FALSE; + } + + $ds1 = $dom->createElement("foxml:datastream"); + $rootElement->appendChild($ds1); + $ds1->setAttribute("ID", "POLICY"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "X"); + $ds1v = $dom->createElement("foxml:datastreamVersion"); + $ds1->appendChild($ds1v); + $ds1v->setAttribute("ID", "POLICY.0"); + $ds1v->setAttribute("MIMETYPE", "text/xml"); + $ds1v->setAttribute("LABEL", "POLICY"); + $content = $dom->createElement("foxml:xmlContent"); + $ds1v->appendChild($content); + $content->appendChild($policyElement); + return TRUE; + } + + + function handleQDCForm($form_values) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + + $dom = new DomDocument("1.0", "UTF-8"); + $dom->formatOutput = TRUE; + $pid=$form_values['pid']; + $rootElement = $dom->createElement("foxml:digitalObject"); + $rootElement->setAttribute('VERSION', '1.1'); + $rootElement->setAttribute('PID', "$pid"); + $rootElement->setAttribute('xmlns:foxml', "info:fedora/fedora-system:def/foxml#"); + $rootElement->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $rootElement->setAttribute('xsi:schemaLocation', "info:fedora/fedora-system:def/foxml# http://www.fedora.info/definitions/1/0/foxml1-1.xsd"); + $dom->appendChild($rootElement); + // Create standard fedora stuff + $this->createStandardFedoraStuff($form_values, $dom, $rootElement); + // Create relationships + $this->createRelationShips($form_values, $dom, $rootElement); + $collectionPid = $form_values['collection_pid']; + + if (($cp = CollectionPolicy::LoadFromCollection($collectionPid)) !== FALSE) { + $collectionName = trim($cp->getName()); + if (trim($collectionName) != '') { + $form_values['dc_relation'] = $collectionName; + } + } + // Create dublin core + $this->createQDCStream($form_values, $dom, $rootElement); + + if (!empty($form_values['ingest-file-location'])) { + $this->createFedoraDataStreams($form_values, $dom, $rootElement); + } + $this->createPolicy($collectionPid, &$dom, &$rootElement); + + try { + + $object = Fedora_Item::ingest_from_FOXML($dom); + if (!empty($object->pid)) { + // drupal_set_message("Item ". l($object->pid, 'fedora/repository/'. $object->pid) . " created successfully.", "status"); + drupal_set_message(t("Item !pid created successfully.", array('!pid' => l($object->pid, 'fedora/repository/'. $object->pid))), "status"); + } + if (!empty( $_SESSION['fedora_ingest_files'])) { + foreach ($_SESSION['fedora_ingest_files'] as $dsid => $createdFile) { + file_delete($createdFile); + } + } + file_delete($form_values['ingest-file-location']); + } + catch (exception $e) { + drupal_set_message(t('Error ingesting object: !e', array('!e' => $e->getMessage())), 'error'); + watchdog(t("Fedora_Repository"), t("Error ingesting object: !e", array('!e' => $e->getMessage())), NULL, WATCHDOG_ERROR); + return; + } + } + + function createFedoraDataStreams($form_values, &$dom, &$rootElement) { + module_load_include('inc', 'fedora_repository', 'MimeClass'); + global $base_url; + $mimetype = new MimeClass(); + $server=NULL; + $file=$form_values['ingest-file-location']; + + if (!empty( $file)) { + $dformat = $mimetype->getType($file); + $fileUrl = $base_url . '/'. drupal_urlencode($file); + $beginIndex = strrpos($fileUrl, '/'); + $dtitle = substr($fileUrl, $beginIndex + 1); + $dtitle = urldecode($dtitle); + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "OBJ"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "M"); + $ds1v= $dom->createElement("foxml:datastreamVersion"); + $rootElement->appendChild($ds1); + + $ds1v->setAttribute("ID", "OBJ.0"); + $ds1v->setAttribute("MIMETYPE", "$dformat"); + $ds1v->setAttribute("LABEL", "$dtitle"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $ds1content->setAttribute("REF", "$fileUrl"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + } + if (!empty($_SESSION['fedora_ingest_files'])) { + + + + foreach ($_SESSION['fedora_ingest_files'] as $dsid => $createdFile) { + + + if (!empty($file)) { + $found = strstr($createdFile, $file); + if ($found !== FALSE) { + $createdFile = $found; + } + } + + $dformat = $mimetype->getType($createdFile); + $fileUrl = $base_url . '/'. drupal_urlencode($createdFile); + + $beginIndex = strrpos($fileUrl, '/'); + $dtitle = substr($fileUrl, $beginIndex + 1); + $dtitle = urldecode($dtitle); + $dtitle = $dtitle; + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "$dsid"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "M"); + $ds1v= $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "$dsid.0"); + $ds1v->setAttribute("MIMETYPE", "$dformat"); + $ds1v->setAttribute("LABEL", "$dtitle"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $ds1content->setAttribute("REF", "$fileUrl"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + $rootElement->appendChild($ds1); + } + } + } + + + /** + * Creates the RELS-EXT for the foxml + */ + function createRelationShips($form_values, &$dom, &$rootElement) { + $drdf = $dom->createElement("foxml:datastream"); + $drdf->setAttribute("ID", "RELS-EXT"); + $drdf->setAttribute("CONTROL_GROUP", "X"); + $dvrdf = $dom->createElement("foxml:datastreamVersion"); + $dvrdf->setAttribute("FORMAT_URI", "info:fedora/fedora-system:FedoraRELSExt-1.0"); + $dvrdf->setAttribute("ID", "RELS-EXT.0"); + $dvrdf->setAttribute("MIMETYPE", "application/rdf+xml"); + $dvrdf->setAttribute("LABEL", "RDF Statements about this Object"); + $dvcontent = $dom->createElement("foxml:xmlContent"); + $rdf = $dom->createElement("rdf:RDF"); + $rdf->setAttribute("xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + $rdf->setAttribute("xmlns:rdfs", "http://www.w3.org/2000/01/rdf-schema#"); + $rdf->setAttribute("xmlns:fedora", "info:fedora/fedora-system:def/relations-external#"); + $rdf->setAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/"); + $rdf->setAttribute("xmlns:oai_dc", "http://www.openarchives.org/OAI/2.0/oai_dc/"); + $rdf->setAttribute("xmlns:fedora-model", "info:fedora/fedora-system:def/model#"); + $rdfdesc = $dom->createElement("rdf:Description"); + $pid = $form_values['pid']; + $rdfdesc->setAttribute("rdf:about", "info:fedora/$pid"); + $relationship = $form_values['relationship']; + if (!isset($relationship)) { + $relationship = 'isMemberOfCollection'; + } + $member = $dom->createElement("fedora:". $relationship); + $membr = $form_values['collection_pid']; + $member->setAttribute("rdf:resource", "info:fedora/$membr"); + $rdfHasModel = $dom->createElement("fedora-model:hasModel"); + $contentModelPid=$form_values['content_model_pid']; + $rdfHasModel->setAttribute("rdf:resource", "info:fedora/$contentModelPid"); + $drdf->appendChild($dvrdf); + $dvrdf->appendChild($dvcontent); + $dvcontent->appendChild($rdf); + $rdf->appendChild($rdfdesc); + $rdfdesc->appendChild($member); + $rdfdesc->appendChild($rdfHasModel); + $rootElement->appendChild($drdf); + } + + + /** + * Creates the standard foxml properties + */ + function createStandardFedoraStuff($form_values, &$dom, &$rootElement) { + // Foxml object properties section + $objproperties = $dom->createElement("foxml:objectProperties"); + $prop2 = $dom->createElement("foxml:property"); + $prop2->setAttribute("NAME", "info:fedora/fedora-system:def/model#state"); + $prop2->setAttribute("VALUE", "A"); + $prop3 = $dom->createElement("foxml:property"); + $prop3->setAttribute("NAME", "info:fedora/fedora-system:def/model#label"); + $prop3->setAttribute("VALUE", $form_values['dc:title']); + $prop5 = $dom->createElement("foxml:property"); + $prop5->setAttribute("NAME", "info:fedora/fedora-system:def/model#ownerId"); + $prop5->setAttribute("VALUE", $form_values['user_id']); + $objproperties->appendChild($prop2); + $objproperties->appendChild($prop3); + $objproperties->appendChild($prop5); + $rootElement->appendChild($objproperties); + } + + + function buildQDCForm(&$form, $elements, &$form_values) { + $form['#multistep'] = TRUE; // used so that it triggers a form rebuild every time. + $form['indicator2'] = array( + '#type' => 'fieldset', + '#title' => t('Ingest digital object step #2'), + ); + + foreach ($elements as $element) { + $el = array( + '#title' => $element['label'], + '#required' => ($element['required'] ? 1 : 0), + '#description' => $element['description'], + '#type' => $element['type'] + ); + + $name = explode('][', $element['name']); + $elLocation = &$form['indicator2']; + while (isset($elLocation[$name[0]]) && ($partial = array_shift($name)) != NULL) { + $elLocation = &$elLocation[$partial]; + } + + $autocomplete_path = FALSE; + $autocomplete_omit_collection = FALSE; + foreach ($element['parameters'] as $key => $val) { + if ($key == '#autocomplete_path') { + $autocomplete_path = $val; + } elseif ($key == '#autocomplete_omit_collection') { + $autocomplete_omit_collection = TRUE; + } else { + $el[$key]=$val; + } + } + + if ($autocomplete_path !== FALSE) { + $el['#autocomplete_path'] = $autocomplete_path . (!$autocomplete_omit_collection?'/'.$form_values['storage']['collection_pid']:'/'); + } + + if ($element['type'] == 'select' || $element['type'] == 'other_select') { + $el['#options']= isset($element['authoritative_list'])?$element['authoritative_list']:array(); + } + + $elLocation[join('][', $name)] = $el; + } + + return $form; + } + +} diff --git a/plugins/ImageManipulation.inc b/plugins/ImageManipulation.inc new file mode 100644 index 00000000..2e2f9b1c --- /dev/null +++ b/plugins/ImageManipulation.inc @@ -0,0 +1,200 @@ +&1 &', $output, $returnValue); + } + else + $returnValue = '0'; + + if ($returnValue == '0') { + $_SESSION['fedora_ingest_files']["$dsid"] = $destFile; + return TRUE; + } + else { + return $returnValue; + } + } + + function createPNG($parameterArray = NULL, $dsid, $file, $file_ext) { + $file_suffix = '_' . $dsid . '.' . $file_ext; + $returnValue = TRUE; + + if (!file_exists($file . $file_suffix)) { + system("convert \"$file\" \"$file$file_suffix\" 2>&1 &", $returnValue); + } + else { + $returnValue = '0'; + } + + if ($returnValue == '0') { + $_SESSION['fedora_ingest_files']["$dsid"] = $file . $file_suffix; + return TRUE; + } + else { + return $returnValue; + } + } + + function createJP2($parameterArray = NULL, $dsid, $file, $file_ext) { + $file_suffix = "_$dsid.$file_ext"; + $return_value = TRUE; + + $output = array(); + + exec('kdu_compress -i "' . $file . '" -o "' . $file . $file_suffix . '" -rate 0.5 Clayers=1 Clevels=7 "Cprecincts={256,256},{256,256},{256,256},{128,128},{128,128},{64,64},{64,64},{32,32},{16,16}" "Corder=RPCL" "ORGgen_plt=yes" "ORGtparts=R" "Cblk={32,32}" Cuse_sop=yes', $output, $returnValue); + + if ($returnValue == '0') { + $_SESSION['fedora_ingest_files'][$dsid] = $file . $file_suffix; + } + else { + ObjectHelper::warnIfMisconfigured('Kakadu'); + } + + exec('kdu_compress -i "' . $file . '" -o "' . $file . "_lossless.jp2" . '" -rate -,0.5 Clayers=2 Creversible=yes Clevels=8 "Cprecincts={256,256},{256,256},{128,128}" Corder="RPCL" ORGgen_plt="yes" ORGtparts="R" Cblk="{32,32}"', $output, $returnValue); + if ($returnValue == '0') { + $_SESSION['fedora_ingest_files']["LOSSLESS_JP2"] = $file . '_lossless.jp2'; + } + else { + ObjectHelper::warnIfMisconfigured('Kakadu'); + } + exec("convert -resize 800 \"{$file}\"[0] \"$file-med.jpg\"", $output, $returnValue); + if ($returnValue == '0') { + $_SESSION['fedora_ingest_files']["JPG"] = $file . '-med.jpg'; + } + else { + ObjectHelper::warnIfMisconfigured('ImageMagick'); + } + exec("convert {$file}[0] -thumbnail x2000 -thumbnail x450 -resize '450x<' -resize 50% -fuzz 1% -trim +repage -gravity center -crop 200x200+0+0 +repage -format jpg -quality 100 $file-tn.jpg", $output, $returnValue); + if ($returnValue == '0') { + $_SESSION['fedora_ingest_files']["TN"] = $file . '-tn.jpg'; + } + else { + ObjectHelper::warnIfMisconfigured('ImageMagick'); + } + + if ($returnValue == '0') { + return TRUE; + } + else { + + return $returnValue; + } + } + + //use imagemapi to manipulate images instead of going directly to imagemagick or whatever + function manipulateImage($parameterArray = NULL, $dsid, $file, $file_ext) { + $height = $parameterArray['height']; + $width = $parameterArray['width']; + + $file_suffix = '_' . $dsid . '.' . $file_ext; + $returnValue = TRUE; + + + $image = imageapi_image_open($file); + + if (!$image) { + drupal_set_message(t("Error opening image.")); + return FALSE; + } + + if (!empty($height) || !empty($width)) { + $returnValue = imageapi_image_scale($image, $height, $width); + } + + if (!$returnValue) { + drupal_set_message(t("Error scaling image.")); + return $returnValue; + } + $filename = substr(strrchr($file, '/'), 1); + $output_path = $_SERVER['DOCUMENT_ROOT'] . base_path() . file_directory_path() . '/' . $filename . $file_suffix; + $returnValue = imageapi_image_close($image, $output_path); + if ($returnValue) { + $_SESSION['fedora_ingest_files']["$dsid"] = $file . $file_suffix; + return TRUE; + } + else { + return $returnValue; + } + } + + function createThumbnailFromPDF($parameterArray, $dsid, $file, $file_ext) { + $height = $parameterArray['height']; + $width = $parameterArray['width']; + $file_suffix = '_' . $dsid . '.' . $file_ext; + $returnValue = TRUE; + //system("convert $file\[0\] -thumbnail 128x128 $uploaddir$thumb"); + // Use this for Linux. + if (stristr($_SERVER['SERVER_SOFTWARE'], 'microsoft')) { + + } + elseif (stristr($_SERVER['SERVER_SOFTWARE'], 'linux')) { + $cmdline = "/usr/local/bin/convert \"$file\"\[0\] -colorspace RGB -thumbnail $width" . "x$height \"$file$file_suffix\""; + } + elseif (stristr($_SERVER['SERVER_SOFTWARE'], 'unix')) { + // Use this for Mac OS X (MAMP) + $cmdline = "sips -s format jpeg \"$file\" -z $height $height --out \"$file$file_suffix\" >/dev/null"; + } + else { + $cmdline = "convert \"$file\"\[0\] -colorspace RGB -thumbnail " . $width . "x" . $height . " \"$file$file_suffix\""; + } + + system($cmdline, $returnValue); + //system("convert $file\[0\] -thumbnail 128x128 $uploaddir$thumb"); + $var = $file . $file_suffix . ' returnvalue= ' . $returnValue; + + if ($returnValue == '0') { + $_SESSION['fedora_ingest_files']["$dsid"] = $file . $file_suffix; + return TRUE; + } + else { + return $returnValue; + } + } + + function createThumbnail($parameterArray, $dsid, $file, $file_ext) { + // var_dump($parameterArray);exit(0); + $file_suffix = '_' . $dsid . '.' . $file_ext; + $height = $parameterArray['height']; + $width = $parameterArray['width']; + $returnValue = TRUE; + system("convert -resize $width -quality 85 \"$file\"\[0\] -strip \"$file$file_suffix\" 2>&1 &", $returnValue); + //system("convert -resize $width -quality 85 \"$file\" -strip \"$file$file_suffix\"",$returnValue); + + if ($returnValue == '0') { + $_SESSION['fedora_ingest_files']["$dsid"] = $file . $file_suffix; + return TRUE; + } + else { + return $returnValue; + } + } + +} diff --git a/plugins/ModsFormBuilder.inc b/plugins/ModsFormBuilder.inc new file mode 100644 index 00000000..49cca136 --- /dev/null +++ b/plugins/ModsFormBuilder.inc @@ -0,0 +1,626 @@ +pid=$pid; + $this->cm = ContentModel::loadFromObject($pid); + $this->item = new fedora_item($pid); + } + } + + function handleEditMetadataForm(&$form_id, &$form_values, &$soap_client) + { + $dom = new DomDocument("1.0", "UTF-8"); + $dom->formatOutput = TRUE; + $mods = $this->modsFromForm($form_values,$dom); + $dom->appendChild($mods); + + if ($this->item->modify_datastream_by_value($dom->saveXML(), 'MODS', "MODS Record", 'text/xml') !== NULL) { + drupal_set_message(t('Successfully updated MODS datastream for object %pid', array('%pid'=>$this->pid))); + } + drupal_goto('/fedora/repository/'.$this->pid); + } + + function buildEditMetadataForm() + { + $form['#multistep'] = TRUE; // used so that it triggers a form rebuild every time. + $form['indicator2'] = array( + '#type' => 'fieldset', + '#title' => t('Edit metadata'), + ); + + if ($this->cm !== FALSE && $this->item != NULL) { + $form['pid'] = array('#type'=>'hidden','#value'=>$this->pid); + + $elements = $this->cm->getIngestFormElements(); + $content = $this->item->get_datastream_dissemination('MODS'); + + if (trim($content) != '') { + $dom = DOMDocument::loadXML($content); + $xpath = new DOMXPath($dom); + // Register the php: namespace (required) + $xpath->registerNamespace("php", "http://php.net/xpath"); + + // Register PHP functions (no restrictions) + $xpath->registerPHPFunctions(); + + foreach ($elements as $element) { + + $el = array( + '#title' => $element['label'], + '#required' => ($element['required'] ? 1 : 0), + '#description' => $element['description'], + '#type' => $element['type'] + ); + + $includeEl = true; + $name = explode('][', $element['name']); + $elLocation = &$form['indicator2']; + while (isset($elLocation[$name[0]]) && ($partial = array_shift($name)) != NULL) { + $elLocation = &$elLocation[$partial]; + } + + foreach ($element['parameters'] as $key => $val) { + switch ($key) { + case '#autocomplete_path': + $val .= '/'. $form_values['storage']['collection_pid']; + break; + + case '#exclude_from_edit_metadata': + $includeEl=FALSE; + break; + + case '#edit_metadata_xpath': + $nodeList = $xpath->evaluate($val); +// echo $val. ' '.$nodeList->length.' '. $nodeList. '
      '; + + if (is_string($nodeList)) + { + $el['#default_value']=$nodeList; + } else if ($nodeList->length > 1) + { + $el['#default_value'] = array(); + foreach ($nodeList as $node) + { + $el['#default_value'][] = $node->nodeValue; + } + } else if ($nodeList->length > 0) + { + $el['#default_value'] = $nodeList->item(0)->nodeValue; + } + break; + } + + if ($key != '#sticky') { + $el[$key]=$val; + } + + } + + if ($element['type'] == 'people') + { + + $names = $xpath->evaluate('/mods:mods/mods:name'); + $people=array(); + foreach ($names as $mname) { + + $type = $mname->getAttribute('type'); + $role = $mname->getElementsByTagName('roleTerm')->item(0)->nodeValue; + + $nameParts = $mname->getElementsByTagName('namePart'); + foreach ($nameParts as $namePart) + { + switch ($namePart->getAttribute('type')) { + case 'given': $given = $namePart->nodeValue; break; + case 'family': $family = $namePart->nodeValue; break; + case 'termsOfAddress': $title = $namePart->nodeValue; break; + case 'date': $date = $namePart->nodeValue; break; + default: $orgName = $namePart->nodeValue; break; + } + } + + $person=array('role'=>$role); + switch ($type) + { + case 'personal': + $person['fname']=$given; + $person['lname']=$family; + $person['title']=$title; + $person['date']=$date; + break; + case 'organization': + $person['organization'] = $orgName; + break; + case 'conference': + $person['conference']=$orgName; + $person['date']=$date; + break; + } + $people[]=$person; + } + + $el['#default_value'] = $people; + + } + + + if ($element['type'] == 'select' || $element['type'] == 'other_select') { + $el['#options']= isset($element['authoritative_list'])?$element['authoritative_list']:array(); + } + + if ($includeEl) { + $elLocation[join('][', $name)] = $el; + } + } + + $form['submit'] = array( + '#type' => 'submit', + '#submit' => array('fedora_repository_edit_qdc_form_submit'), + '#value' => 'Save Metadata' + ); + + return $form; + + } + } + + } + + function handleModsForm($form_values) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'CollectionPolicy'); + + $dom = new DomDocument("1.0", "UTF-8"); + $dom->formatOutput = TRUE; + $pid=$form_values['pid']; + $rootElement = $dom->createElement("foxml:digitalObject"); + $rootElement->setAttribute('VERSION', '1.1'); + $rootElement->setAttribute('PID', "$pid"); + $rootElement->setAttribute('xmlns:foxml', "info:fedora/fedora-system:def/foxml#"); + $rootElement->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $rootElement->setAttribute('xsi:schemaLocation', "info:fedora/fedora-system:def/foxml# http://www.fedora.info/definitions/1/0/foxml1-1.xsd"); + $dom->appendChild($rootElement); + + // Create standard fedora stuff + $form_values['dc:title'] = $form_values['mods_title']; + $this->createStandardFedoraStuff($form_values, $dom, $rootElement); + + // Create relationships + $this->createRelationShips($form_values, $dom, $rootElement); + $collectionPid = $form_values['collection_pid']; + + if (($cp = CollectionPolicy::LoadFromCollection($collectionPid)) !== FALSE) { + $collectionName =trim($cp->getName()); + if (trim($collectionName)!='') { + $form_values['dc_relation']=$collectionName; + } + } + // Create MODS + $this->createModsStream($form_values, $dom, $rootElement); + $this->createCollectionPolicy($form_values, $dom, $rootElement); + $this->createWorkflowStream($form_values, $dom, $rootElement); + + if (!empty($form_values['ingest-file-location'])) { + $this->createFedoraDataStreams($form_values, $dom, $rootElement); + } + $this->createPolicy($collectionPid, &$dom, &$rootElement); + +/* header('Content-type: application/xml'); + echo $dom->saveXML(); exit();*/ + + try { + $object = Fedora_Item::ingest_from_FOXML($dom); + //for some reason, ingest_from_FOXML does not generate a JMS message + //I just modify the workflow DS and it sends a JMS message. + $item = new Fedora_Item($object->pid); + $item->modify_datastream_by_value( $item->get_datastream_dissemination('WORKFLOW'), 'WORKFLOW', "Workflow Record", 'text/xml'); + + if (!empty($object->pid)) { + drupal_set_message(t("Item !pid created successfully.", array('!pid' => l($object->pid, 'fedora/repository/'. $object->pid))), "status"); + } + if (!empty( $_SESSION['fedora_ingest_files'])) { + foreach ($_SESSION['fedora_ingest_files'] as $dsid => $createdFile) { + file_delete($createdFile); + } + } + file_delete($form_values['ingest-file-location']); + } + catch (exception $e) { + drupal_set_message(t('Error ingesting object: !e', array('!e' => $e->getMessage())), 'error'); + watchdog(t("Fedora_Repository"), t("Error ingesting object: !e", array('!e' => $e->getMessage())), NULL, WATCHDOG_ERROR); + return; + } + } + + + function createCollectionPolicy($form_values, &$dom, &$rootElement) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $model = new fedora_item($form_values['content_model_pid']); + $ds_list = $model->get_datastreams_list_as_array(); + if (isset($ds_list['COLLECTION_POLICY_TMPL'])) { + $cp = $model->get_datastream_dissemination('COLLECTION_POLICY_TMPL'); + $cpDom = DOMDocument::loadXML($cp); + $cpRootEl = $cpDom->getElementsByTagName('collection_policy'); + if ($cpRootEl->length >0) { + $cpRootEl=$cpRootEl->item(0); + $newNode = $dom->importNode($cpRootEl, TRUE); + + $datastream = $dom->createElement("foxml:datastream"); + $datastream->setAttribute("ID", "COLLECTION_POLICY"); + $datastream->setAttribute("STATE", "A"); + $datastream->setAttribute("CONTROL_GROUP", "X"); + $version = $dom->createElement("foxml:datastreamVersion"); + $version->setAttribute("ID", "COLLECTION_POLICY.0"); + $version->setAttribute("MIMETYPE", "text/xml"); + $version->setAttribute("LABEL", "Collection Policy"); + $datastream->appendChild($version); + $content = $dom->createElement("foxml:xmlContent"); + $version->appendChild($content); + $content->appendChild($newNode); + $rootElement->appendChild($datastream); + } + } + } + + function createWorkflowStream($form_values, &$dom, &$rootElement) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $model = new fedora_item($form_values['content_model_pid']); + $ds_list = $model->get_datastreams_list_as_array(); + if (isset($ds_list['WORKFLOW_TMPL'])) { + $workflow = $model->get_datastream_dissemination('WORKFLOW_TMPL'); + $workflowDom = DOMDocument::loadXML($workflow); + $workflowRootEl = $workflowDom->getElementsByTagName('workflow'); + if ($workflowRootEl->length >0) { + $workflowRootEl=$workflowRootEl->item(0); + $newNode = $dom->importNode($workflowRootEl, TRUE); + + $datastream = $dom->createElement("foxml:datastream"); + $datastream->setAttribute("ID", "WORKFLOW"); + $datastream->setAttribute("STATE", "A"); + $datastream->setAttribute("CONTROL_GROUP", "X"); + $version = $dom->createElement("foxml:datastreamVersion"); + $version->setAttribute("ID", "WORKFLOW.0"); + $version->setAttribute("MIMETYPE", "text/xml"); + $version->setAttribute("LABEL", "Workflow Record"); + $datastream->appendChild($version); + $content = $dom->createElement("foxml:xmlContent"); + $version->appendChild($content); + $content->appendChild($newNode); + $rootElement->appendChild($datastream); + } + } + } + + function createModsStream($form_values, &$dom, &$rootElement) { + + $datastream = $dom->createElement("foxml:datastream"); + $datastream->setAttribute("ID", "MODS"); + $datastream->setAttribute("STATE", "A"); + $datastream->setAttribute("CONTROL_GROUP", "X"); + $version = $dom->createElement("foxml:datastreamVersion"); + $version->setAttribute("ID", "MODS.0"); + $version->setAttribute("MIMETYPE", "text/xml"); + $version->setAttribute("LABEL", "MODS Record"); + $datastream->appendChild($version); + $content = $dom->createElement("foxml:xmlContent"); + $version->appendChild($content); + + $mods = $this->modsFromForm($form_values,$dom); + $content->appendChild($mods); + + $rootElement->appendChild($datastream); + } + + + function modsFromForm(&$form_values,&$dom) + { + + ///begin writing MODS + $mods = $dom->createElement("mods:mods"); + $mods->setAttribute('version', '3.4'); + $mods->setAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink"); + $mods->setAttribute('xmlns:mods', "http://www.loc.gov/mods/v3"); + $mods->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $mods->setAttribute('xsi:schemaLocation', "http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-0.xsd"); + + + if (isset($form_values['mods_title']) && trim($form_values['mods_title']) != '') { + $titleinfo = $dom->createElement('mods:titleInfo'); + $title = $dom->createElement('mods:title', htmlspecialchars($form_values['mods_title'])); + $titleinfo->appendChild($title); + $mods->appendChild($titleinfo); + } + + if (isset($form_values['mods_description']) && trim($form_values['mods_description']) != '') { + $abstract = $dom->createElement('mods:abstract', htmlspecialchars(trim($form_values['mods_description']))); + $mods->appendChild($abstract); + } + + if (isset($form_values['pid']) && trim($form_values['pid']) != '') { + $identifier = $dom->createElement('mods:identifier', htmlspecialchars(trim(preg_replace('/\:/','\/',$form_values['pid'])))); + $identifier->setAttribute('type', 'hdl'); + $mods->appendChild($identifier); + } + + if (isset($form_values['collection_pid']) && trim($form_values['collection_pid']) != '') { + $relatedItem = $dom->createElement('mods:relatedItem'); + $relatedItem->setAttribute('type', 'isMemberOfCollection'); + $identifier = $dom->createElement('mods:identifier', htmlspecialchars(trim($form_values['collection_pid']))); + $relatedItem->appendChild($identifier); + $mods->appendChild($relatedItem); + } + + if (isset($form_values['mods_identifier']) && trim($form_values['mods_identifier']) != '') { + $identifier = $dom->createElement('mods:identifier', htmlspecialchars(trim($form_values['mods_identifier']))); + $identifier->setAttribute('type', 'local'); + $mods->appendChild($identifier); + } + + if (isset($form_values['mods_physicalLocation']) && trim($form_values['mods_physicalLocation']) != '') { + $location = $dom->createElement('mods:location'); + $physLocation = $dom->createElement('mods:physicalLocation', htmlspecialchars(trim($form_values['mods_physicalLocation']))); + $location->appendChild($physLocation); + if (isset($form_values['mods_shelfLocator']) && trim($form_values['mods_shelfLocator']) != '') { + $shelfLocator = $dom->createElement('mods:shelfLocator', htmlspecialchars(trim($form_values['mods_shelfLocator']))); + $location->appendChild($shelfLocator); + } + $mods->appendChild($location); + } + + $originInfo = $dom->createElement('mods:originInfo'); + $addOriginInfo = FALSE; + if (isset($form_values['mods_pubinfo_place']) && trim($form_values['mods_pubinfo_place']) != '') { + $place = $dom->createElement('mods:place'); + $placeTerm=$dom->createElement('mods:placeTerm', htmlspecialchars(trim($form_values['mods_pubinfo_place']))); + $placeTerm->setAttribute('type', 'text'); + $place->appendChild($placeTerm); + $originInfo->appendChild($place); + $addOriginInfo = TRUE; + } + + if (isset($form_values['mods_pubinfo_publisher']) && trim($form_values['mods_pubinfo_publisher']) != '') { + $publisher = $dom->createElement('mods:publisher', htmlspecialchars(trim($form_values['mods_pubinfo_publisher']))); + $originInfo->appendChild($publisher); + $addOriginInfo = TRUE; + } + + if (isset($form_values['mods_pubinfo_edition']) && trim($form_values['mods_pubinfo_edition']) != '') { + $edition = $dom->createElement('mods:edition', htmlspecialchars(trim($form_values['mods_pubinfo_edition']))); + $originInfo->appendChild($edition); + $addOriginInfo = TRUE; + } + + if (isset($form_values['mods_pubinfo_date']) && trim($form_values['mods_pubinfo_date']) != '' && + isset($form_values['mods_pubinfo_dateType']) && trim($form_values['mods_pubinfo_dateType']) != '') { + if (in_array($form_values['mods_pubinfo_dateType'], array('issued', 'created', 'copyright', 'captured'))) { + $date = $dom->createElement('mods:'. trim($form_values['mods_pubinfo_dateType']) .'Date', htmlspecialchars(trim($form_values['mods_pubinfo_date']))); + } + else { + //how to handle other types? otherDate? + $date= $dom->createElement('mods:otherDate', htmlspecialchars(trim($form_values['mods_pubinfo_date']))); + $date->setAttribute('type', htmlspecialchars(trim($form_values['mods_pubinfo_dateType']))); + } + $originInfo->appendChild($date); + $addOriginInfo = TRUE; + } + + if (isset($form_values['mods_pubinfo_journalFreq']) && trim($form_values['mods_pubinfo_journalFreq']) != '') { + $frequency = $dom->createElement('mods:frequency', htmlspecialchars(trim($form_values['mods_pubinfo_journalFreq']))); + $originInfo->appendChild($frequency); + $issuance= $dom->createElement('mods:issuance', 'journal'); + $addOriginInfo = TRUE; + } + else { + $issuance= $dom->createElement('mods:issuance', 'monographic'); + } + $originInfo->appendChild($issuance); + + if ($addOriginInfo) { + $mods->appendChild($originInfo); + } + + if (isset($form_values['mods_note']) && trim($form_values['mods_note']) != '') { + $note = $dom->createElement('mods:note', htmlspecialchars(trim($form_values['mods_note']))); + $mods->appendChild($note); + } + + if (isset($form_values['mods_format']) && trim($form_values['mods_format']) != '') { + $typeOfResource = $dom->createElement('mods:typeOfResource', htmlspecialchars($form_values['mods_format'])); + $mods->appendChild($typeOfResource); + } + + + if (isset($form_values['mods_language']) && trim($form_values['mods_language']) != '') + { + $languageList = explode(';', htmlspecialchars($form_values['mods_language'])); + foreach ($languageList as $lang) + { + $language = $dom->createElement('mods:language'); + $langTerm = $dom->createElement('mods:languageTerm',htmlspecialchars($lang)); + $langTerm->setAttribute('type','text'); + $language->appendChild($langTerm); + $mods->appendChild($language); + } + } + + + $hasSubject = FALSE; + $subject = $dom->createElement('mods:subject'); + + + // Hierarchical Geographic Subject + if (isset($form_values['mods_country']) && trim($form_values['mods_country']) != '') { + $hasSubject = TRUE; + $geographic = $dom->createElement('mods:hierarchicalGeographic'); + + $country=$dom->createElement('mods:country', htmlspecialchars($form_values['mods_country'])); + $geographic->appendChild($country); + + if (isset($form_values['mods_province']) && trim($form_values['mods_province']) != '') { + $province = $dom->createElement('mods:province', htmlspecialchars($form_values['mods_province'])); + $geographic->appendChild($province); + } + + if (isset($form_values['mods_state']) && trim($form_values['mods_state']) != '') { + $state = $dom->createElement('mods:state', htmlspecialchars($form_values['mods_state'])); + $geographic->appendChild($state); + } + + if (isset($form_values['mods_city']) && trim($form_values['mods_city']) != '') { + $city = $dom->createElement('mods:city', htmlspecialchars($form_values['mods_city'])); + $geographic->appendChild($city); + } + $subject->appendChild($geographic); + } + + if (isset($form_values['mods_date']) && trim($form_values['mods_date']) != '') { + $hasSubject = TRUE; + $temporal = $dom->createElement('mods:temporal', htmlspecialchars($form_values['mods_date'])); + $subject->appendChild($temporal); + } + + if (isset($form_values['mods_subjtitle']) && trim($form_values['mods_subjtitle']) != '') { + $hasSubject = TRUE; + $titleInfo= $dom->createElement('mods:titleInfo'); + $title = $dom->createElement('mods:title', htmlspecialchars($form_values['mods_subjtitle'])); + $titleInfo->appendChild($title); + $subject->appendChild($titleInfo); + } + + if (isset($form_values['mods_lname']) && trim($form_values['mods_lname']) != '') { + $hasSubject = TRUE; + $name = $dom->createElement('mods:name'); + $name->setAttribute('type', 'personal'); + $namePart = $dom->createElement('mods:namePart', htmlspecialchars($form_values['mods_lname'])); + $namePart->setAttribute('type', 'family'); + $name->appendChild($namePart); + + if (isset($form_values['mods_fname']) && trim($form_values['mods_fname']) != '') { + $namePart = $dom->createElement('mods:namePart', htmlspecialchars($form_values['mods_fname'])); + $namePart->setAttribute('type', 'given'); + $name->appendChild($namePart); + } + + $subject->appendChild($name); + } + + if (isset($form_values['mods_topics']) && trim($form_values['mods_topics']) != '') { + $hasSubject = TRUE; + $topicList = explode(';', htmlspecialchars($form_values['mods_topics'])); + $authority = 'unknown'; + if (isset($form_values['mods_topicAuthority']) && trim($form_values['mods_topicAuthority']) != '') { + $authority = htmlspecialchars($form_values['mods_topicAuthority']); + } + + foreach ($topicList as $t) { + $topic = $dom->createElement('mods:topic', $t); + $topic->setAttribute('authority', $authority); + $subject->appendChild($topic); + } + } + if ($hasSubject) { + $mods->appendChild($subject); + } + + if (isset($form_values['mods_cc']['cc']) && $form_values['mods_cc']['cc']['cc_enable']) { + + $commercial = trim($form_values['mods_cc']['cc']['cc_commercial']); + $modifications = trim($form_values['mods_cc']['cc']['cc_modifications']); + $jurisdiction = trim($form_values['mods_cc']['cc']['cc_jurisdiction']); + + module_load_include('inc','islandora_form_elements','includes/creative_commons.inc'); + + if (!isset(CreativeCommons::$cc_jurisdiction_vals[$jurisdiction])) + $jurisdiction=''; + $version = CreativeCommons::$cc_versions[$jurisdiction]; + + $license = 'by'. ($commercial != ''?'-'.$commercial:'') . ($modifications != ''?'-'.$modifications:'') . '/' . $version . '/'.($jurisdiction != ''?$jurisdiction.'/':'') ; + + $accessCondition = $dom->createElement('mods:accessCondition', htmlspecialchars($license)); + $accessCondition->setAttribute('type', 'Creative Commons License'); + $mods->appendChild($accessCondition); + + + } + + if (isset($form_values['mods_rights']) && trim($form_values['mods_rights']) != '') { + $accessCondition = $dom->createElement('mods:accessCondition', htmlspecialchars($form_values['mods_rights'])); + $accessCondition->setAttribute('type', 'restriction on access; use and reproduction'); + $mods->appendChild($accessCondition); + } + + if (isset($form_values['mods_people']) && isset($form_values['mods_people']['people']) && is_array($form_values['mods_people']['people']) ) { + foreach ($form_values['mods_people']['people'] as $key => $val) { + $name = $dom->createElement('mods:name'); + + if (isset($val['role'])) { + $role = $dom->createElement('mods:roleTerm', htmlspecialchars(trim($val['role']))); + $role->setAttribute('type', 'text'); + $role->setAttribute('authority', 'marcrelator'); + $name->appendChild($role); + } + + if (isset($val['organization'])) { + $name->setAttribute('type', 'organization'); + if (trim($val['organization']) != '') { + $namePart=$dom->createElement('mods:namePart', htmlspecialchars(trim($val['organization']))); + $name->appendChild($namePart); + $mods->appendChild($name); + } + } + elseif (isset($val['conference'])) { + $name->setAttribute('type', 'conference'); + if (trim($val['conference']) != '') { + $namePart=$dom->createElement('mods:namePart', htmlspecialchars(trim($val['conference']))); + $name->appendChild($namePart); + $mods->appendChild($name); + } + } + else { + $name->setAttribute('type', 'personal'); + if (trim($val['title']) != '') { + $namePart=$dom->createElement('mods:namePart', htmlspecialchars(trim($val['title']))); + $namePart->setAttribute('type', 'termsOfAddress'); + $name->appendChild($namePart); + } + + if (trim($val['fname']) != '' && trim($val['lname']) != '') { + $namePart=$dom->createElement('mods:namePart', htmlspecialchars(trim($val['fname']))); + $namePart->setAttribute('type', 'given'); + $name->appendChild($namePart); + + $namePart=$dom->createElement('mods:namePart', htmlspecialchars(trim($val['lname']))); + $namePart->setAttribute('type', 'family'); + $name->appendChild($namePart); + + $mods->appendChild($name); + } + } + + if (isset($val['date'])) { + $namePart=$dom->createElement('mods:namePart', htmlspecialchars(trim($val['date']))); + $namePart->setAttribute('type','date'); + $name->appendChild($namePart); + } + + } + } + return $mods; + } + +} diff --git a/plugins/Newspaper.inc b/plugins/Newspaper.inc new file mode 100644 index 00000000..b4583459 --- /dev/null +++ b/plugins/Newspaper.inc @@ -0,0 +1,98 @@ +pid = $pid; + $this->item = new Fedora_Item($pid); + } + } + + + public function showFieldSets() { + + global $base_url; + + $tabset = array(); + + $tabset['my_tabset'] = array( + '#type' => 'tabset', + ); + + global $user; + $qs = ''; + if ($user->uid != 0) { + $qs = '?uid='. base64_encode($user->name . ':'. $user->pass); + } + + $viewer_url = variable_get('fedora_base_url', '') . '/get/'. $this->pid . '/ilives:viewerSdef/getViewer'. $qs; + $html = ''; + + $tabset['my_tabset']['first_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Read'), + '#content' => $html + ); + + $item = new Fedora_Item($this->pid); + + $tabset['my_tabset']['second_tab'] = array( + '#type' => 'tabpage', + '#title' => 'Description', + '#content' => $item->get_dissemination('islandora:mods2htmlSdef', 'mods2html'), + ); + + return tabs_render($tabset); + } + + public function showPageFieldSets() { + + global $base_url; + + $tabset = array(); + + $tabset['my_tabset'] = array( + '#type' => 'tabset', + ); + + global $user; + $qs = ''; + if ($user->uid != 0) { + $qs = '?uid='. base64_encode($user->name . ':'. $user->pass); + } + + $viewer_url = variable_get('fedora_base_url', '') . '/get/'. $this->pid . '/ilives:viewerSdef/getViewer'. $qs; + $html = ''; + + $tabset['my_tabset']['first_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Read'), + '#content' => $html + ); + + $item = new Fedora_Item($this->pid); + + // Get this page's parent item to show the issue's metadata. + $rels = $item->get_relationships(); + $parent_pid = ''; + foreach ($rels as $rel) { + if (strstr($rel['predicate'], 'isPartOf')) { + $parent_pid = $rel['object']; + break; + } + } + $parent_item = new Fedora_Item($parent_pid); + $tabset['my_tabset']['second_tab'] = array( + '#type' => 'tabpage', + '#title' => 'Description', + '#content' => $parent_item->get_dissemination('islandora:mods2htmlSdef', 'mods2html'), + ); + + return tabs_render($tabset); + } +} diff --git a/plugins/PersonalCollectionClass.inc b/plugins/PersonalCollectionClass.inc new file mode 100644 index 00000000..9644dd71 --- /dev/null +++ b/plugins/PersonalCollectionClass.inc @@ -0,0 +1,204 @@ +formatOutput = TRUE; + + $rootElement = $dom->createElement("foxml:digitalObject"); + $rootElement->setAttribute('PID', "$pid"); + $rootElement->setAttribute('xmlns:foxml', "info:fedora/fedora-system:def/foxml#"); + $rootElement->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $rootElement->setAttribute('xsi:schemaLocation', "info:fedora/fedora-system:def/foxml# http://www.fedora.info/definitions/1/0/foxml1-0.xsd"); + $dom->appendChild($rootElement); + //create standard fedora stuff + $this->createStandardFedoraStuff($theUser, $dom, $rootElement); + //create dublin core + $this->createDCStream($theUser, $dom, $rootElement); + $value = $this->createPolicyStream($theUser, $dom, $rootElement); + + if (!$value) { + return FALSE;//error should already be logged. + } + $this->createCollectionPolicyStream($theUser, $dom, $rootElement); + try { + $params = array( + 'objectXML' => $dom->saveXML(), + 'format' => "foxml1.0", + 'logMessage' => "Fedora object ingested", + ); + + $object = $soapClient->__soapCall('ingest', array( + $params + )); + + } + catch (exception $e) { + drupal_set_message(t('Error ingesting personal collection object: !e', array('!e' => $e->getMessage())), 'error'); + return FALSE; + } + return TRUE; + } + + function createCollectionPolicyStream($user, $dom, $rootElement) { + $collectionTemplate = file_get_contents(drupal_get_path('module', 'Fedora_Repository') . '/collection_policies/PERSONAL-COLLECTION-POLICY.xml'); + try { + $xml = new SimpleXMLElement($collectionTemplate); + } + catch (Exception $e) { + watchdog(t("Fedora_Repository"), t("Problem creating personal collection policy, could not parse collection policy stream."), NULL, WATCHDOG_ERROR); + drupal_set_message(t('Problem creating personal collection policy, could not parse collection policy stream: !e', array('!e' => $e->getMessage())), 'error'); + return FALSE; + } + $policyElement = $dom->createDocumentFragment(); + + if (!$policyElement) { + drupal_set_message(t('Error parsing policy stream.')); + watchdog(t("Fedora_Repository"), t("Error parsing policy stream, could not parse policy stream."), NULL, WATCHDOG_NOTICE); + return FALSE; + } + $dom->importNode($policyElement, TRUE); + + $value = $policyElement->appendXML($collectionTemplate); + if (!$value) { + drupal_set_message(t('Error creating collection policy stream.')); + watchdog(t("Fedora_Repository"), t("Error creating collection policy stream, could not parse collection policy template file."), NULL, WATCHDOG_NOTICE); + return FALSE; + } + + $ds1 = $dom->createElement("foxml:datastream"); + $rootElement->appendChild($ds1); + $ds1->setAttribute("ID", "COLLECTION_POLICY"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "X"); + $ds1v = $dom->createElement("foxml:datastreamVersion"); + $ds1->appendChild($ds1v); + $ds1v->setAttribute("ID", "COLLECTION_POLICY.0"); + $ds1v->setAttribute("MIMETYPE", "text/xml"); + $ds1v->setAttribute("LABEL", "COLLECTION_POLICY"); + //$ds1v->setAttribute("FORMAT_URI","info:fedora/fedora-system:format/xml.fedora.audit"); + $content = $dom->createElement("foxml:xmlContent"); + $ds1v->appendChild($content); + $content->appendChild($policyElement); + return TRUE; + } + + function createPolicyStream($user, $dom, $rootElement) { + module_load_include('inc', 'fedora_repository', 'SecurityClass'); + + $securityClass = new SecurityClass(); + $policyStreamDoc = $securityClass->createPersonalPolicy($user); + $policyNodes = $policyStreamDoc->getElementsByTagName('Policy'); + $policyStream = $policyNodes->item(0); + $policyStream = $dom->importNode($policyStream, TRUE); + + $ds1 = $dom->createElement("foxml:datastream"); + $rootElement->appendChild($ds1); + $ds1->setAttribute("ID", "POLICY"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "X"); + $ds1v = $dom->createElement("foxml:datastreamVersion"); + $ds1->appendChild($ds1v); + $ds1v->setAttribute("ID", "POLICY.0"); + $ds1v->setAttribute("MIMETYPE", "text/xml"); + $ds1v->setAttribute("LABEL", "SECURITY_POLICY"); + //$ds1v->setAttribute("FORMAT_URI","info:fedora/fedora-system:format/xml.fedora.audit"); + $content = $dom->createElement("foxml:xmlContent"); + $ds1v->appendChild($content); + $content->appendChild($policyStream); + return $this->createChildPolicyStream($dom, $rootElement, $policyStream->cloneNode(TRUE)); + } + + //right now this is the same as the policy stream for this object, may change + //objects in this collection will reference this datastream as their own POLICY stream + function createChildPolicyStream($dom, $rootElement, $policyStream) { + $ds1 = $dom->createElement("foxml:datastream"); + + $rootElement->appendChild($ds1); + $ds1->setAttribute("ID", "CHILD_SECURITY"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "X"); + $ds1v = $dom->createElement("foxml:datastreamVersion"); + $ds1->appendChild($ds1v); + $ds1v->setAttribute("ID", "CHILD_SECURITY.0"); + $ds1v->setAttribute("MIMETYPE", "text/xml"); + $ds1v->setAttribute("LABEL", "SECURITY_POLICY"); + //$ds1v->setAttribute("FORMAT_URI","info:fedora/fedora-system:format/xml.fedora.audit"); + $content = $dom->createElement("foxml:xmlContent"); + $ds1v->appendChild($content); + $content->appendChild($policyStream); + return TRUE; + } + + function createStandardFedoraStuff($user, & $dom, & $rootElement) { + /*foxml object properties section */ + $objproperties = $dom->createElement("foxml:objectProperties"); + $prop1 = $dom->createElement("foxml:property"); + $prop1->setAttribute("NAME", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); + $prop1->setAttribute("VALUE", "FedoraObject"); + $prop2 = $dom->createElement("foxml:property"); + $prop2->setAttribute("NAME", "info:fedora/fedora-system:def/model#state"); + $prop2->setAttribute("VALUE", "A"); + $prop3 = $dom->createElement("foxml:property"); + $prop3->setAttribute("NAME", "info:fedora/fedora-system:def/model#label"); + $prop3->setAttribute("VALUE", $user->name); + $prop4 = $dom->createElement("foxml:property"); + $prop4->setAttribute("NAME", "info:fedora/fedora-system:def/model#contentModel"); + $prop4->setAttribute("VALUE", 'Collection'); + $prop5 = $dom->createElement("foxml:property"); + $prop5->setAttribute("NAME", "info:fedora/fedora-system:def/model#ownerId"); + $prop5->setAttribute("VALUE", $user->name); + $objproperties->appendChild($prop1); + $objproperties->appendChild($prop2); + $objproperties->appendChild($prop3); + $objproperties->appendChild($prop4); + $objproperties->appendChild($prop5); + $rootElement->appendChild($objproperties); + } + + function createDCStream($theUser, & $dom, & $rootElement) { + global $user; + $datastream = $dom->createElement("foxml:datastream"); + $datastream->setAttribute("ID", "DC"); + $datastream->setAttribute("STATE", "A"); + $datastream->setAttribute("CONTROL_GROUP", "X"); + $version = $dom->createElement("foxml:datastreamVersion"); + $version->setAttribute("ID", "DC.0"); + $version->setAttribute("MIMETYPE", "text/xml"); + $version->setAttribute("LABEL", "Dublin Core Record"); + $datastream->appendChild($version); + $content = $dom->createElement("foxml:xmlContent"); + $version->appendChild($content); + ///begin writing dc + $oai = $dom->createElement("oai_dc:dc"); + $oai->setAttribute('xmlns:oai_dc', "http://www.openarchives.org/OAI/2.0/oai_dc/"); + $oai->setAttribute('xmlns:dc', "http://purl.org/dc/elements/1.1/"); + $oai->setAttribute('xmlns:dcterms', "http://purl.org/dc/terms/"); + $oai->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $content->appendChild($oai); + //dc elements + $element = $dom->createElement('dc:type', 'Collection'); + $oai->appendChild($element); + $element = $dom->createElement('dc:title', $theUser->name . ' Personal Collection'); + $oai->appendChild($element); + $element = $dom->createElement('dc:date', date(DATE_RFC822)); + $oai->appendChild($element); + $element = $dom->createElement('dc:subject', $theUser->name); + $oai->appendChild($element); + $element = $dom->createElement('dc:contributor', ''); + $oai->appendChild($element); + $element = $dom->createElement('dc:creator', $user->name); + $oai->appendChild($element); + + $element = $dom->createElement('dc:language', ''); + $oai->appendChild($element); + + $rootElement->appendChild($datastream); + } + +} diff --git a/plugins/Refworks.inc b/plugins/Refworks.inc new file mode 100644 index 00000000..f6e43f95 --- /dev/null +++ b/plugins/Refworks.inc @@ -0,0 +1,449 @@ +romeoUrlString = "http://www.sherpa.ac.uk/romeo/api24.php?issn="; + } + + function buildForm( &$form, $ingest_form_definition, &$form_values) { + $form['indicator2'] = array( + '#type' => 'fieldset', + '#title' => t('Ingest digital object step #2'), + ); + foreach ($ingest_form_definition->form_elements->element as $element) { + $name = strip_tags($element->name->asXML()); + $title = strip_tags($element->label->asXML()); + $required = strip_tags($element->required->asXML()); + $prefix = strip_tags($element->prefix); + $required = strtolower($required); + if ($required != 'TRUE') { + $required = '0'; + } + + $description = strip_tags($element->description->asXML()); + $type = strip_tags($element->type->asXML()); + + $form['indicator2']["$name"] = array( + '#title' => $title, + '#required' => $required, + '#description' => $description, + '#prefix' => $prefix, + '#type' => $type + ); + } + + return $form; + } + + /** + * Read the input file and generate a list of Reference items. + * + * @param array $form_values + * @param SimpleXMLElement $dom + * @return SimpleXMLElement + */ + function parse_refworks_item(&$form_values) { + + $file = $form_values['ingest-file-location']; + try { + $dom = new DOMDocument('1.0', 'UTF-8'); + $dom->substituteEntities = FALSE; + $dom->loadXML(trim(file_get_contents($file))); + $xml = simplexml_import_dom($dom); + //$xml=simplexml_load_string(trim(file_get_contents($file),NULL,TRUE)); + //$dom = dom_import_simplexml($xml);//test to see if it behaves better + //$xml = new SimpleXMLElement(trim(file_get_contents($file))); + } + catch (Exception $e) { + drupal_set_message(t('Error processing Refworks file: ') . $e->getMessage()); + return FALSE; + } + $this->referenceList = array(); + foreach ($xml->reference as $reference) { + array_push( $this->referenceList, $reference ); + } + + return $this->referenceList; + } + + //create A DC stream with ID of DC + function createQDCStream( &$dom, &$rootElement, $reference ) { + $datastream = $dom->createElement("foxml:datastream"); + $datastream->setAttribute("ID", "DC"); + $datastream->setAttribute("STATE", "A"); + $datastream->setAttribute("CONTROL_GROUP", "X"); + $version = $dom->createElement("foxml:datastreamVersion"); + $version->setAttribute("ID", "DC.0"); + $version->setAttribute("MIMETYPE", "text/xml"); + $version->setAttribute("LABEL", "DC Dublin Core Record"); + $datastream->appendChild($version); + $content = $dom->createElement("foxml:xmlContent"); + $version->appendChild($content); + ///begin writing qdc + $oai = $dom->createElement("oai_dc:dc"); + $oai->setAttribute('xmlns:oai_dc', "http://www.openarchives.org/OAI/2.0/oai_dc/"); + $oai->setAttribute('xmlns:dc', "http://purl.org/dc/elements/1.1/"); + $oai->setAttribute('xmlns:dcterms', "http://purl.org/dc/terms/"); + $oai->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $content->appendChild($oai); + + foreach ($reference->sr as $value) { + $element = $dom->createElement('dc:type', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->id as $value) { + $identifier = $value; + } + foreach ($reference->a1 as $value) { + $element = $dom->createElement('dc:creator', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->t1 as $value) { + // $form_values['dc:title'] = $value; + $element = $dom->createElement('dc:title', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->jf as $value) { + $source = $value; + } + foreach ($reference->yr as $value) { + $element = $dom->createElement('dc:date', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->vo as $value) { + $source .= ' Volume: '. $value; + } + foreach ($reference->is as $value) { + $source .= ' Issue: '. $value; + } + foreach ($reference->sp as $value) { + $source .= ' Start Page: '. $value; + } + foreach ($reference->op as $value) { + $source .= ' Other Pages: '. $value; + } + foreach ($reference->ul as $value) { + $source .= ' URL: '. $value; + } + foreach ($reference->k1 as $value) { + $element = $dom->createElement('dc:subject', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->a2 as $value) { + $element = $dom->createElement('dc:contributor', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->a3 as $value) { + $element = $dom->createElement('dc:contributor', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->a4 as $value) { + $element = $dom->createElement('dc:contributor', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->a5 as $value) { + $element = $dom->createElement('dc:contributor', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->la as $value) { + $element = $dom->createElement('dc:language', htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + } + foreach ($reference->pb as $value) { + $source = 'Publisher: ' . $value; + } + foreach ($reference->pp as $value) { + $source .= ' Place of publication: ' . $value; + } + foreach ($reference->sn as $value) { + $identifier .= ' ISSN/ISBN: ' . $value; + //$this->romeoUrlString = $this->romeoUrlString . $value; + if (!$this->issn == '') { + $this->issn=$value; + } + else { + $this->issn .= ','. $value; + } + } + foreach ($reference->ab as $value) { + $description = ' abstract: '. $value; + } + foreach ($reference->cr as $value) { + $description .= ' Cited reference: '. $value; + } + $element = $dom->createElement('dc:description', htmlspecialchars($description, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + $element = $dom->createElement('dc:source', htmlspecialchars($source, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + $element = $dom->createElement('dc:identifier', htmlspecialchars($identifier, ENT_NOQUOTES, 'UTF-8')); + $oai->appendChild($element); + //$rootElement->appendChild($datastream); + return $datastream; + } + + function handleForm( &$form_values ) { + $errorMessage = NULL; + module_load_include('inc', 'fedora_repository', 'CollectionClass'); + module_load_include('inc', 'fedora_repository', 'ContentModel'); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $contentModelPid = ContentModel::getPidFromIdentifier($form_values['models']); + $contentModelDsid = ContentModel::getDSIDFromIdentifier($form_values['models']); + $collectionHelper = new CollectionClass(); + $startTime=time(); + $collection_pid = $form_values['collection_pid']; + + $this->parse_refworks_item( $form_values ); + + $this->securityHelper = new SecurityClass(); + + $collection_item = new Fedora_Item($collection_pid); + $this->collectionPolicyStream = $collection_item->get_datastream_dissemination('CHILD_SECURITY'); + if (empty($this->collectionPolicyStream)) { + $this->collectionPolicyStream = file_get_contents(drupal_get_path('module', 'fedora_repository') . '/policies/noObjectEditPolicy.xml'); + } + $success = 0; + $errors = 0; + foreach ($this->referenceList as $reference) { + $dom = new DomDocument("1.0", "UTF-8"); + $dom->substituteEntities = FALSE; + $dom->formatOutput = TRUE; + $pid = $collectionHelper->getNextPid($collection_pid, $contentModelDsid); + + $rootElement = $dom->createElement("foxml:digitalObject"); + $rootElement->setAttribute('VERSION', '1.1'); + $rootElement->setAttribute('PID', "$pid"); + $rootElement->setAttribute('xmlns:foxml', "info:fedora/fedora-system:def/foxml#"); + $rootElement->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + $rootElement->setAttribute('xsi:schemaLocation', "info:fedora/fedora-system:def/foxml# http://www.fedora.info/definitions/1/0/foxml1-1.xsd"); + $dom->appendChild($rootElement); + + //create standard fedora stuff + $qdc_element = $this->createQDCStream($dom, $rootElement, $reference); + if (!$qdc_element) { + drupal_set_message(t('Error creating DC for Refworks'), 'error'); + continue; + } + $item_title=''; + foreach ($reference->t1 as $value) { + $item_title .= ' --- '. $value; + } + $this->createStandardFedoraStuff($form_values, $dom, $rootElement, $reference ); + $rootElement->appendChild($qdc_element); + //create relationships + $this->createRelationShips($form_values, $dom, $rootElement, $pid); + //create dublin core + + $this->createFedoraDataStreams($form_values, $dom, $rootElement, $reference); + + if (!empty ( $this->collectionPolicyStream)) { + $this->create_security_policies($dom, $rootElement, $reference); + } + + $params = array( + 'objectXML' => $dom->saveXML(), + 'format' => 'info:fedora/fedora-system:FOXML-1.1', + 'logMessage' => "Fedora Object Ingested", + ); + + try { + $soapHelper = new ConnectionHelper(); + $client = $soapHelper->getSoapClient(variable_get('fedora_soap_manage_url', 'http://localhost:8080/fedora/services/management?wsdl')); + + if ($client == NULL) { + drupal_set_message(t('Error getting SOAP client.'), 'error'); + watchdog(t("FEDORA_REPOSITORY"), t("Error getting SOAP client: !e", array('!e' => $e)), NULL, WATCHDOG_ERROR); + return; + } + $object = $client->__soapCall('ingest', array( + $params + )); + watchdog(t("FEDORA_REPOSITORY"), t("Successfully added repository item !pid - !it", array('!pid' => $pid, '!it' => $item_title)), NULL, WATCHDOG_INFO); + $deleteFiles = $form_values['delete_file']; //remove files from drupal file system + + if ($deleteFiles > 0) { + unlink($form_values['fullpath']); + } + } + catch (exception $e) { + $errors++; + $errorMessage = 'yes'; + watchdog(t("FEDORA_REPOSITORY"), t("Error during ingest !it !e", array('!it' => $item_title, '!e' => $e)), NULL, WATCHDOG_ERROR); + } + $success++; + } + if (isset($errorMessage)) { + drupal_set_message(t('Error ingesting one or more records! Check Drupal watchdog logs for more info') , 'error'); + } + $endTime = time(); + drupal_set_message(t('Successfull ingest of %success records. %errors records failed. Ingest took %seconds seconds', + array('%success' => $success-$errors, '%errors' => $errors, '%seconds' => $endTime-$startTime)) , 'info'); + } + + /** + * Creates the RELS-EXT for the foxml + */ + function createRelationShips( $form_values, &$dom, &$rootElement, $pid = NULL ) { + $drdf = $dom->createElement("foxml:datastream"); + $drdf->setAttribute("ID", "RELS-EXT"); + $drdf->setAttribute("CONTROL_GROUP", "X"); + $dvrdf = $dom->createElement("foxml:datastreamVersion"); + $dvrdf->setAttribute("ID", "RELS-EXT.0"); + $dvrdf->setAttribute("MIMETYPE", "text/xml"); + $dvrdf->setAttribute("LABEL", "Fedora Object-to-Object Relationship Metadata"); + $dvcontent = $dom->createElement("foxml:xmlContent"); + $rdf = $dom->createElement("rdf:RDF"); + $rdf->setAttribute("xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + $rdf->setAttribute("xmlns:rdfs", "http://www.w3.org/2000/01/rdf-schema#"); + $rdf->setAttribute("xmlns:fedora", "info:fedora/fedora-system:def/relations-external#"); + $rdf->setAttribute("xmlns:fedora-model", "info:fedora/fedora-system:def/model#"); + $rdfdesc = $dom->createElement("rdf:description"); + $rdfdesc->setAttribute("rdf:about", "info:fedora/$pid"); + $member = $dom->createElement("fedora:isMemberOfCollection"); + $membr = $form_values['collection_pid']; + $member->setAttribute("rdf:resource", "info:fedora/$membr"); + $model = $dom->createElement("fedora-model:hasModel"); + $model->setAttribute("rdf:resource", "info:fedora/islandora:refworksCModel"); + + $drdf->appendChild($dvrdf); + $dvrdf->appendChild($dvcontent); + $dvcontent->appendChild($rdf); + $rdf->appendChild($rdfdesc); + $rdfdesc->appendChild($member); + $rdfdesc->appendChild($model); + $rootElement->appendChild($drdf); + + } + + function createRomeoDataStream(&$dom, &$rootElement) { + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "ROMEO"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "E"); + $ds1v = $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "ROMEO.0"); + $ds1v->setAttribute("MIMETYPE", "text/xml"); + $ds1v->setAttribute("LABEL", "ROMEO"); + $ds1content = $dom->createElement('foxml:contentLocation'); + $url = $this->romeoUrlString . $this->issn; + $this->issn=''; //clear the issn's for next ingest in case we are doing batch + $ds1content->setAttribute("REF", "$url"); + $ds1content->setAttribute("TYPE", "URL"); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + $rootElement->appendChild($ds1); + } + + function createFedoraDataStreams($form_values, &$dom, &$rootElement, $reference) { + global $base_url; + module_load_include('inc', 'fedora_repository', 'MimeClass'); + $mimetype = new MimeClass(); + $server = NULL; + $this->createRomeoDataStream($dom, $rootElement); + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "refworks"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "X"); + $ds1v = $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "refworks.0"); + $ds1v->setAttribute("MIMETYPE", "text/xml"); + $ds1v->setAttribute("LABEL", "Refworks datastream"); + $ds1content = $dom->createElement("foxml:xmlContent"); + + $ds1content->appendChild($dom->importNode(dom_import_simplexml($reference), TRUE)); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + $rootElement->appendChild($ds1); + + $count = 0; + } + + /** + * Creates the standard foxml properties + */ + function createStandardFedoraStuff($form_values, &$dom, &$rootElement, $reference) { + // Foxml object properties section + $objproperties = $dom->createElement("foxml:objectProperties"); + $prop2 = $dom->createElement("foxml:property"); + $prop2->setAttribute("NAME", "info:fedora/fedora-system:def/model#state"); + $prop2->setAttribute("VALUE", "A"); + $prop3 = $dom->createElement("foxml:property"); + $prop3->setAttribute("NAME", "info:fedora/fedora-system:def/model#label"); + $label = $reference->t1; + if (strlen($label) > 254) { + $label = substr($label, 0, 245); + } + $prop3->setAttribute("VALUE", $label); + $prop5 = $dom->createElement("foxml:property"); + $prop5->setAttribute("NAME", "info:fedora/fedora-system:def/model#ownerId"); + $prop5->setAttribute("VALUE", $form_values['user_id']); + $objproperties->appendChild($prop2); + $objproperties->appendChild($prop3); + $objproperties->appendChild($prop5); + $rootElement->appendChild($objproperties); + } + + + /** + * Read the list of Users from the U1 field and Roles from the U2 field and add elements + * to the security policy record for this item, then add the record as the security policy datastream. + * + * @param array $form_values + * @param DOMDocument $dom + * @param $rootElement + * @param SimpleXMLElement $reference + */ + function create_security_policies($dom, &$rootElement, $reference) { + global $user; + $ds1 = $dom->createElement("foxml:datastream"); + $ds1->setAttribute("ID", "POLICY"); + $ds1->setAttribute("STATE", "A"); + $ds1->setAttribute("CONTROL_GROUP", "X"); + $ds1v = $dom->createElement("foxml:datastreamVersion"); + $ds1v->setAttribute("ID", "POLICY.0"); + $ds1v->setAttribute("MIMETYPE", "text/xml"); + $ds1v->setAttribute("LABEL", "POLICY Record"); + $ds1content = $dom->createElement( "foxml:xmlContent" ); + + $custom_policy = $this->collectionPolicyStream; + $allowed_users_and_roles = array(); + $allowed_users_and_roles['users'] = array(); + $allowed_users_and_roles['roles'] = array(); + foreach ($reference->u1 as $namelist) { + foreach (explode(';', strip_tags($namelist->asXML())) as $name) { + array_push($allowed_users_and_roles['users'], $name); + } + } + if (empty( $reference->u1)) { + // If no "u1" value exists, add the currently logged-in user to the item's security policy. + array_push($allowed_users_and_roles['users'], $user->name); + } + + foreach ($reference->u2 as $rolelist) { + foreach (explode(';', strip_tags($rolelist->asXML())) as $role) { + array_push($allowed_users_and_roles['roles'], $role); + } + } + $custom_policy = $this->securityHelper->set_allowed_users_and_roles($custom_policy, $allowed_users_and_roles); + $custom_policy_sxe = new SimpleXMLElement($custom_policy); + $ds1->appendChild($ds1v); + $ds1v->appendChild($ds1content); + + $rootElement->appendChild($ds1); + $ds1content->appendChild($dom->importNode( dom_import_simplexml($custom_policy_sxe), TRUE)); + } +} diff --git a/plugins/ShowDemoStreamsInFieldSets.inc b/plugins/ShowDemoStreamsInFieldSets.inc new file mode 100644 index 00000000..dd81410f --- /dev/null +++ b/plugins/ShowDemoStreamsInFieldSets.inc @@ -0,0 +1,25 @@ +pid = $pid; + } + + function showMediumSize() { + global $base_url; + $collection_fieldset = array( + '#collapsible' => FALSE, + '#value' => '', + ); + return theme('fieldset', $collection_fieldset); + } +} diff --git a/plugins/ShowStreamsInFieldSets.inc b/plugins/ShowStreamsInFieldSets.inc new file mode 100644 index 00000000..ad3f2829 --- /dev/null +++ b/plugins/ShowStreamsInFieldSets.inc @@ -0,0 +1,188 @@ +pid = $pid; + } + + function showFlv() { + //FLV is the datastream id + $path = drupal_get_path('module', 'Fedora_Repository'); + $fullPath = base_path() . $path; + $content = ""; + $pathTojs = drupal_get_path('module', 'Fedora_Repository') . '/js/swfobject.js'; + drupal_add_js("$pathTojs"); + $content .= '
      Get the Flash Player to see this player.
      '; + drupal_add_js('var s1 = new SWFObject("'. $fullPath . '/flash/flvplayer.swf","single","320","240","7"); + s1.addParam("allowfullscreen","TRUE"); + s1.addVariable("file","'. base_path() . 'fedora/repository/'. $this->pid . '/FLV/FLV.flv"); + s1.write("player'. $this->pid . 'FLV");', 'inline', 'footer'); + $collection_fieldset = array( + '#title' => t('Flash Video'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + '#value' => $content); + return theme('fieldset', $collection_fieldset); + } + + function showTN() { + global $base_url; + $collection_fieldset = array( + '#title' => '', + '#attributes' => array(), + '#collapsible' => FALSE, + '#value' => '', + ); + return theme('fieldset', $collection_fieldset); + } + + + // Same as showTN but artinventory stores the image in a dsid of IMAGE instead of OBJ + function showArtInventoryTN() { + global $base_url; + $collection_fieldset = array( + '#collapsible' => FALSE, + '#value' => '', + ); + return theme('fieldset', $collection_fieldset); + } + + /** + * Embed Google Docs' PDF viewer into the page. + */ + function showPDFPreview() { + global $base_url; + + $tabset = array(); + + $tabset['my_tabset'] = array( + '#type' => 'tabset', + ); + $tabset['my_tabset']['first_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Description'), + '#content' => $this->showQdc(), + ); + + $tabset['my_tabset']['second_tab'] = array( +// $collection_fieldset = array ( + '#type' => 'tabpage', + '#title' => t('Read Online'), + '#content' => "" + ); + + // Render the tabset. + return tabs_render($tabset); + + return theme('fieldset', $collection_fieldset); +// . (user_access('add fedora datastreams') ? drupal_get_form('fedora_ilives_image_tagging_form', $this->pid) : ''); + } + + + function showQdc() { + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + $objectHelper = new ObjectHelper(); + $content=$objectHelper->getQDC($this->pid); + $collection_fieldset = array( + '#title' => t('Description'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + '#value' => $content, + ); + return theme('fieldset', $collection_fieldset); + } + + function showOBJLink() { + global $base_url; + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $item = new Fedora_Item($this->pid); + $streams = $item->get_datastreams_list_as_array(); + return "". $streams['OBJ']['label'] .""; + } + + + + function showRefworks() { + $path=drupal_get_path('module', 'fedora_repository'); + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + $collectionHelper = new CollectionClass(); + $xmlstr=$collectionHelper->getStream($this->pid, "refworks"); + html_entity_decode($xmlstr); + if ($xmlstr == NULL || strlen($xmlstr) < 5) { + return " "; + } + try { + $proc = new XsltProcessor(); + } + catch (Exception $e) { + drupal_set_message(t("!e", array('!e' => $e->getMessage())), 'error'); + return " "; + } + $xsl = new DomDocument(); + $xsl->load($path . '/xsl/refworks.xsl'); + $input = new DomDocument(); + $input->loadXML(trim($xmlstr)); + $xsl = $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + $content = $newdom->saveXML(); + + $collection_fieldset = array( + '#title' => t('Refworks'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + '#value' => $content); + return theme('fieldset', $collection_fieldset); + } + + function showJP2($collapsed = FALSE) { + $viewer_url = variable_get('fedora_base_url', '') . '/get/'. $this->pid . '/ilives:viewerSdef/getViewer'; + $html = ''; + $fieldset = array( + '#title' => t('Viewer'), + '#collapsible' => TRUE, + '#collapsed' => $collapsed, + '#value' => $html + ); + return theme('fieldset', $fieldset); + } + + function showRomeo($collapsed = FALSE) { + $path = drupal_get_path('module', 'Fedora_Repository'); + module_load_include('inc', 'fedora_repository', 'CollectionClass'); + $collectionHelper = new CollectionClass(); + $xmlstr = $collectionHelper->getStream($this->pid, "ROMEO", 0); + + if ($xmlstr == NULL || strlen($xmlstr) < 5) { + return " "; + } + + try { + $proc = new XsltProcessor(); + } + catch (Exception $e) { + drupal_set_message(t("!e", array('!e' => $e->getMessage())), 'error'); + return; + } + $xsl = new DomDocument(); + $xsl->load($path . '/xsl/romeo.xsl'); + $input = new DomDocument(); + $input->loadXML(trim($xmlstr)); + $xsl = $proc->importStylesheet($xsl); + $newdom = $proc->transformToDoc($input); + $content = $newdom->saveXML(); + + $collection_fieldset = array( + '#title' => t('Romeo'), + '#collapsible' => TRUE, + '#collapsed' => $collapsed, + '#value' => $content + ); + return theme('fieldset', $collection_fieldset); + } +} diff --git a/plugins/fedora_attach/fedora_attach.admin.inc b/plugins/fedora_attach/fedora_attach.admin.inc new file mode 100644 index 00000000..655dee51 --- /dev/null +++ b/plugins/fedora_attach/fedora_attach.admin.inc @@ -0,0 +1,34 @@ + 'select', + '#title' => t('Fedora Attach PID namespace'), + '#options' => $options, + '#default_value' => $default_value, + '#description' => t('The PID namespace into which the Fedora Attach module will ingest objects.'), + ); + return (system_settings_form($form)); +} + diff --git a/plugins/fedora_attach/fedora_attach.info b/plugins/fedora_attach/fedora_attach.info new file mode 100644 index 00000000..fc1c2aa7 --- /dev/null +++ b/plugins/fedora_attach/fedora_attach.info @@ -0,0 +1,8 @@ +; $Id$ +name = Fedora Attach +description = Allows users to attach files to node content which then get ingested into Fedora. +package = Fedora Repository +dependencies[] = fedora_repository +dependencies[] = upload +version = 6.1dev +core = 6.x diff --git a/plugins/fedora_attach/fedora_attach.install b/plugins/fedora_attach/fedora_attach.install new file mode 100644 index 00000000..45aeda5e --- /dev/null +++ b/plugins/fedora_attach/fedora_attach.install @@ -0,0 +1,14 @@ +files)) { + foreach ($node->files as $fid => $file) { + $file = (object) $file; // Convert file to object type for compatibility. + $fid = $file->fid; // For the cases where we have temp fid for uplaoded files. + $success = FALSE; + $filepath = $file->filepath; // Need copy if file_move fails. + $public = file_directory_path(); + + $file_is_ingested = _fedora_attach_is_file_in_repository($filepath); + if (!empty($file->ingested) && !$file_is_ingested) { + // Attach flag is set, but file is not listed as being in the repository. + // so try and ingest it now. + if (user_access('select file access by role')) { + $roles = array(); + if (!empty($file->roles)) { + foreach ($file->roles as $rolename => $rolevalue) { + if (!empty($rolevalue)) { + array_push($roles, $rolevalue); + } + } + } + // if (!empty($roles)) { + // Generate the security policy datastream. + $policy_stream = _fedora_attach_create_policy($roles); + // } + } + try { + $pid_namespace = variable_get('fedora_attach_pid_namespace','default:'); + $pid_namespace = substr($pid_namespace, 0, strpos($pid_namespace, ":")); + $pid = fedora_item::get_next_PID_in_namespace( $pid_namespace ); + $new_item = fedora_item::ingest_new_item($pid, 'A', $file->description); // PID will be generated using getNextPID + if (empty($new_item->objectProfile)) { + drupal_set_message("Unable to create fedora object. Check Watchdog log for details.", "error"); + $success = FALSE; + } + else { + if (user_access('select file access by role')) { + $new_item->add_datastream_from_string($policy_stream, 'POLICY', "Security Policy", "text/xml", "X"); + } + $new_item->add_datastream_from_file($file->filepath, 'OBJ', $file->filename, $file->filemime, 'M'); + $new_item->add_relationship("hasModel","islandora:genericCModel",FEDORA_MODEL_URI); + module_load_include('inc', 'fedora_repository', 'api/dublin_core'); + $dc = new Dublin_Core(); + $dc->add_element('dc:title', $file->description); + $dc->add_element('dc:identifier', $new_item->pid); + + $new_item->modify_datastream_by_value($dc->as_xml(), 'DC', 'Default Dublin Core Metadata', 'text/xml', 'X'); + + $success = TRUE; + } + } + catch (exception $e) { + drupal_set_message(t('An error occurred ingesting the file: ') . $e, 'error'); + $new_item->purge(); + drupal_set_message(t('The item has been removed from the repository')); + } + if ($success) { // We were able to ingest the file, so update the file path. + $new_filepath = '/fedora/repository/'. $new_item->pid . '/OBJ/'. $file->description; + _fedora_attach_update_filepath($new_filepath, $fid); + file_delete($filepath); + } + } + // Convert file to object for compatibility + + // Remove file. Process removals first since no further processing + // will be required. + if (!empty($file->remove)) { + + // If the file isn't used by any other revisions warn the user. + $count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $fid)); + if ($count < 1) { + file_delete($file->filepath); + db_query('DELETE FROM {files} WHERE fid = %d', $fid); + } + + // Remove it from the session in the case of new uploads, + // that you want to disassociate before node submission. + unset($node->files[$fid]); + // Move on, so the removed file won't be added to new revisions. + continue; + } + + } + } + } + break; + case 'view': + // ****************************************************** + // *** VIEW + // Re-theme the file attachments table. + + // Rebuild the files table and overwrite default. + // Using the rules from upload.module. + if (isset($node->files) && count($node->files) && user_access('view uploaded files') && !$teaser) { + $node->content['files']['#value'] = theme('fedora_attach_attachments', $node->files); + } + break; + } +} + +/** + *Implementation of hook_menu(). + */ +function fedora_attach_menu() { + $items['admin/settings/fedora_repository/attach'] = array( + 'title' => 'Fedora Attach', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('fedora_attach_admin'), + 'access arguments' => array('administer site configuration'), + 'type' => MENU_LOCAL_TASK, + 'file' => 'fedora_attach.admin.inc', + ); + return $items; +} + + +function fedora_attach_save(&$node) { + print ("FNARF!"); +} + +/** + * Implements hook_form_alter() + * + * Add a 'add to repository' checkbox to the file attach form. + * + * @param unknown_type $form + * @param unknown_type $form_state + * @param unknown_type $form_id + * Two paths, one for normal submit, one for JavaScript + */ +function fedora_attach_form_alter(&$form, $form_state, $form_id) { + $disabled = TRUE; + global $base_url; + if (isset($form['type'])) { + $node = $form['#node']; + if ($form['type']['#value'] . '_node_form' == $form_id && variable_get("upload_$node->type", TRUE)) { + $form['#submit'][] = 'fedora_attach_form_submit'; + if (!empty($node->files) && is_array($node->files) && count($node->files)) { // Hijack theme function. + $form['attachments']['wrapper']['files']['#theme'] = 'fedora_attach_form'; + $form['#validate']['private_upload_form_validate'] = array(); + foreach ($node->files as $fid => $file) { + + // Add ingest checkbox + if (is_array($file) && isset($file['ingest'])) { // Preview + $default_value = $file['ingest']; + } + else { // Node load + $default_value = _fedora_attach_is_file_in_repository($file->filepath); + $disabled = $default_value; + } + + $form['attachments']['wrapper']['files'][$fid]['ingested'] = array( + '#type' => 'checkbox', + '#default_value' => $default_value, + '#disabled' => $disabled, + ); + $form['attachments']['wrapper']['files'][$fid]['description']['#description'] = $base_url.$file->filepath; + } + if (user_access('select file access by role')) { + _fedora_attach_build_roles_form($form, FALSE); + } + } + } + } + elseif ($form_id == 'upload_js') { + $form['files']['#theme'] = 'fedora_attach_form'; + + foreach ($form['files'] as $fid => $file) { + + if (!_fedora_attach_starts_with($fid, '#')) {// Ignore properties. + if (!empty($_POST['files'][$fid])) { + $ingested = (!empty($_POST['files'][$fid]['ingested']) ? $_POST['files'][$fid]['ingested'] : FALSE); + //$form['files'][$fid]['list']['#default_value'] = (!empty($_POST['files'][$fid]['[$_POST['files'][$fid]['list']; + //$form['files'][$fid]['remove']['#default_value'] = $_POST['files'][$fid]['remove']; + } + else { + $ingested = (variable_get('fedora_attach_default', 'ingested') == 'ingested'); + } + $form['files'][$fid]['ingested'] = array( + '#type' => 'checkbox', + '#default_value' => $ingested, + ); + + $form['attachments']['wrapper']['files'][$fid]['description']['#description'] = $base_url.$file['filepath']; + if (user_access('select file access by role')) { + _fedora_attach_build_roles_form($form, TRUE); + } + } + } + } +} + +/** + * Called to validate the attach form. + * + * @param string $formid + * @param array $form_values + */ +function fedora_attach_form_validate($formid, $form_values) { + if (is_array($form_values['files']) && count($form_values['files'])) { + $file = array_shift($form_values['files']); + if (!isset($file['ingested'])) { + drupal_set_message(t('Fedora Attach cannot find add repository settings.'), 'error'); + // Be sure we are going after core upload module + $upload_weight = (int)db_result(db_query("SELECT weight FROM {system} WHERE name = 'upload'")); + $attach_weight = (int)db_result(db_query("SELECT weight FROM {system} WHERE name = 'fedora_attach'")); + if ($attach_weight <= $uplaod_weight) { + $new_weight = $upload_weight + 1; + drupal_set_message(t('Adjusting Fedora Attach module\'s weight to') . $new_weight, 'warning'); + db_query("UPDATE {system} SET weight = '%d' WHERE name = 'fedora_attach'", $new_weight);; + } + else { + drupal_set_message(t('Please check for modules that conflict with Fedora Attach'), 'error'); + } + } + } +} + +/** + * Fixes edge case: When the node is first being created, the file->private info does not + * get moved automatically into the node. So we need to copy it by hand. + * + * @param array $form + * @param array $form_state + */ +function fedora_attach_form_submit($form, &$form_state) { + global $base_url; + if ($form_state['values'] && $form_state['values']['files']) { + + foreach ($form_state['values']['files'] as $fid => $file) { + if ($file['remove'] && !empty($file['ingested']) && $file['ingested']) { + drupal_set_message("The attachment ${file['filename']} was removed from this node but it will remain in the repository until it is purged it directly."); + } + if (!isset($file->ingested)) { // Newly-inserted file. + if (isset($form['attachments']['wrapper']['files'])) { + // I know it is naughty to look at the $_POST, but I can't find this value anywhere else. + // Seems like it should be in $form_state somewhere. + $ingested = !empty($_POST['files'][$fid]['ingested']); + } + else { + $ingested = (variable_get('fedora_attach_ingested', 'ingested') == 'ingested'); // Submit before attach + } + $form_state['values']['files'][$fid]['ingested'] = $ingested; + } + $form_state['values']['files'][$fid]['roles'] = (!empty($_POST['files']['roles']) ? $_POST['files']['roles'] : array()); + } + } +} + +// ***************************************************************************** +// Theme functions *********************************************************** +// ***************************************************************************** + +/** + * hook_theme = Theme registry + * + * @return array + */ +function fedora_attach_theme() { + return array( + 'fedora_attach_form' => array( + 'arguments' => array('form' => NULL), + ), + 'fedora_attach_attachments' => array( + 'arguments' => array('files' => NULL), + ), + ); +} + +/** + * Based on theme_upload_form_current + * Adds the Ingest checkbox. + * + * @param array $form + */ +function theme_fedora_attach_form(&$form) { + $header = array(t('Delete'), t('List'), t('Add to Repository'), t('Label'), t('Weight'), t('Size'), ''); + drupal_add_tabledrag('upload-attachments', 'order', 'sibling', 'upload-weight'); + + foreach (element_children($form) as $key) { + // Add class to group weight fields for drag and drop. + $form[$key]['weight']['#attributes']['class'] = 'upload-weight'; + + $row = array(); + $row[] = drupal_render($form[$key]['remove']); + $row[] = drupal_render($form[$key]['list']); + $row[] = drupal_render($form[$key]['ingested']); + $row[] = drupal_render($form[$key]['description']); + $row[] = drupal_render($form[$key]['weight']); + $row[] = drupal_render($form[$key]['size']); + $row[] = drupal_render($form[$key]['msg']); + $rows[] = array('data' => $row, 'class' => 'draggable'); + } + $output = theme('table', $header, $rows, array('id' => 'upload-attachments')); + $output .= drupal_render($form); + return $output; +} + +/** + * Displays file attachments in table. + * + * @param array $files + */ +function theme_fedora_attach_attachments($files) { + $header = array(t('Attachment'), t('Size')); + $rows = array(); + if (is_array($files)) { + foreach ($files as $file) { + $file = (object) $file; + if ($file->list && empty($file->remove)) { + $inspect_item = ''; + if (_fedora_attach_is_file_in_repository($file->filepath)) { + $inspect_item = ' '. theme_image(drupal_get_path('module', 'Fedora_Repository') . '/images/view.gif', '', 'View the item\'s repository page' ) . ''; + } + $href = _fedora_attach_create_url($file); // this is the changed line + $text = $file->description ? $file->description : $file->filename; + $rows[] = array(l($text, $href) . $inspect_item, format_size($file->filesize)); + } + } + if (count($rows)) { + return theme('table', $header, $rows, array('id' => 'attachments')); + } + } +} + +function _fedora_attach_build_roles_form(&$form, $inside_js = FALSE) { + //$result = db_query("SELECT {name} from {role}"); + global $user; + //while ($role = db_fetch_array($result)) { + foreach ($user->roles as $role) { + if ($role != 'anonymous user') { + $roles[] = $role; + } + } + if (empty($roles)) { + return ''; + } + $new_form_elements = array( + '#type' => 'checkboxes', + '#title' => t('Roles which can view the attached items'), + '#options' => array_combine($roles, $roles), + '#description' => t('This only applies to files which you add to the repository. If no roles are checked the item will be public.'), + ); + + if ($inside_js) { + $form['files']['roles'] = $new_form_elements; + } + else { + $form['attachments']['wrapper']['roles'] = $new_form_elements; + } +// var_dump($form['files']); + //return $output; +} + +function _fedora_attach_create_policy($roles) { + $policy_filename = !empty($roles) ? drupal_get_path('module', 'fedora_repository') . '/policies/viewANDeditbyrole.xml' + : drupal_get_path('module', 'fedora_repository') . '/policies/noObjectEditPolicy.xml'; + $policy_document = new DOMDocument(); + $policy_document->load($policy_filename); + $designators = $policy_document->getElementsByTagName("SubjectAttributeDesignator"); + + if (!empty($designators)) { + foreach ($designators as $designator) { + if ($designator->hasAttribute("AttributeId")) { + if ($designator->getAttribute('AttributeId') == 'fedoraRole') { + foreach ($roles as $role) { + //$apply = $designator->nextSibling; + foreach ($designator->parentNode->childNodes as $apply) { + if ($apply->nodeName == "Apply") { + $new_role_node = $policy_document->createElement('AttributeValue', $role); + $new_role_node->setAttribute('DataType', 'http://www.w3.org/2001/XMLSchema#string'); + $apply->appendChild($new_role_node); + } + } + } + } + elseif ($designator->getAttribute('AttributeId') == 'urn:fedora:names:fedora:2.1:subject:loginId') { + // $apply = $designator->nextSibling; + foreach ($designator->parentNode->childNodes as $apply) { + if ($apply->nodeName == "Apply") { + global $user; + $new_user_node = $policy_document->createElement('AttributeValue', $user->name); + $new_user_node->setAttribute('DataType', 'http://www.w3.org/2001/XMLSchema#string'); + $apply->appendChild($new_user_node); + } + } + } + } + } + } + return $policy_document->saveXML(); +} + +function fedora_attach_file_download($filepath) { + // Pass through if this isn't a repository item. + if (!strstr($filepath, 'fedora/repository')) { + return; + } + $result = db_query("SELECT DISTINCT(u.nid) FROM {upload} u INNER JOIN {files} f ON u.fid = f.fid ". + "WHERE f.filepath LIKE '%s'", $filepath.'%'); + $has_results = FALSE; + while($row = db_fetch_array($result)) { + $has_results = TRUE; + $node = node_load($row['nid']); + if (node_access('view', $node)) { + return; // Access is ok as far as we are concerned. + } + } + if ($has_results) { + return -1; + } + else { + return; + } +} + +/** + * Create a URL to a file that changes if the file is in the repository. + * + * @param file object $file + * @return str: the correct URL + */ +function _fedora_attach_create_url($file) { + if ( _fedora_attach_is_file_in_repository( $file->filepath)) { + $href = $GLOBALS['base_url'] . $file->filepath; + } + else { + $href = file_create_url((strpos($file->fid, 'upload') === FALSE ? $file->filepath : file_create_filename($file->filename, file_create_path()))); + } + return $href; +} + +/** + * Checks if the file path references a file in the repository. + * + * @param string $filepath + * @return boolean + */ +function _fedora_attach_is_file_in_repository($filepath) { + $repository_path = '/fedora/repository'; + $is_in = _fedora_attach_starts_with($filepath, $repository_path); + return $is_in; +} + +function _fedora_attach_starts_with($str, $start) { + if (count($str) == 0) { // Avoid FALSE positives. + return FALSE; + } + return strstr($str, $start) == $str; +} + +/** + * Alters the file's path in the files table to point to the repository datastream. + * + * @param string $filepath + * @param int $fid + */ +function _fedora_attach_update_filepath( $filepath, $fid ) { + db_query("UPDATE {files} SET filepath = '%s' WHERE fid=%d", $filepath, $fid); +} diff --git a/plugins/fedora_imageapi.info b/plugins/fedora_imageapi.info new file mode 100644 index 00000000..a83ef4e6 --- /dev/null +++ b/plugins/fedora_imageapi.info @@ -0,0 +1,8 @@ +; $Id$ +name = Fedora ImageAPI +description = Adds image manipulation support through a REST interface +package = Fedora Repository +dependencies[] = fedora_repository +dependencies[] = imageapi +version = 6.1dev +core = 6.x diff --git a/plugins/fedora_imageapi.module b/plugins/fedora_imageapi.module new file mode 100644 index 00000000..3f0a4a99 --- /dev/null +++ b/plugins/fedora_imageapi.module @@ -0,0 +1,116 @@ + t('Image manipulation functions'), + 'page callback' => 'fedora_repository_image_manip', + 'type' => MENU_CALLBACK, + 'access arguments' => array('view fedora collection'), + ); + return $items; +} + +/** + * Call out to the Drupal ImageAPI module and return the resulting image as a stream. + * + * @param string $pid + * @param string $dsid + * @param string $op + * @param string $params + */ +function fedora_repository_image_manip($pid = '', $dsid = '', $op = '', $params = '') { + module_load_include( 'inc', 'Fedora_Repository', 'ObjectHelper'); + module_load_include( 'module', 'imageapi'); + $obj = new ObjectHelper(); + $mimetype = $obj->getMimeType( $pid, $dsid); + $ext = substr( strstr($mimetype, '/'), 1); + $op = (!empty($_GET['op']) ? $_GET['op'] : ''); + $safe_pid = str_replace(':', '_', $pid); + + $cache_key = 'fedora_repository_image_manip_'.md5($safe_pid.'_'.$dsid.'_'.$ext.'_'.$op.(isset($_GET['width'])?'_'.$_GET['width']:'').(isset($_GET['height'])?'_'.$_GET['height']:'')); + if (($file=cache_get($cache_key))===0) + { + //added the slash as sys_get_temp_dir in linux does not seem to include the slash + $tmp_file_name = sys_get_temp_dir() .'/'. $safe_pid . '_'. $dsid . '.'. $ext; + $handle = fopen( $tmp_file_name, "w"); + $numbytes = fwrite($handle, $obj->getStream($pid, $dsid)); + fclose($handle); + if ($numbytes == 0) { + return; + } + + + $image = imageapi_image_open( $tmp_file_name); + + switch ($op) { + case 'scale': + if (!empty( $_GET['height'] ) || !empty( $_GET['width'])) { + imageapi_image_scale($image, $_GET['width'], $_GET['height']); + } + case 'centerscale': + if (!empty($_GET['height']) && !empty($_GET['width'])) { + imageapi_image_scale_and_crop($image, $_GET['width'], $_GET['height']); + + } + } + imageapi_image_close($image); + $file = file_get_contents($tmp_file_name); + cache_set($cache_key,$file,'cache',time()+variable_get('fedora_image_blocks_cache_time',3600)); + file_delete($tmp_file_name); + } else { + $file = $file->data; + } + + + header("Content-type: $mimetype"); + header('Content-Disposition: attachment; filename="'. $dsid . '.'. $ext . '"'); + echo $file; + + +// return "$numbytes bytes written to ".sys_get_temp_dir()."$pid_$dsid.$ext\n"; +} + +/** + * Implementation of hook_form_alter + * + * @param unknown_type $form + * @param unknown_type $form_state + * @param unknown_type $form_id + */ + /* +function fedora_imageapi_form_alter( &$form, $form_state, $form_id) { + + switch ( $form_id ) { + case 'fedora_repository_admin': + + $fedora_base_url = $form['fedora_base_url']['#default_value']; + + $fedora_server_url = substr($fedora_base_url,0,strpos($fedora_base_url,'/',7)); + // Add the Djatoka server location. Set it to default to the same server as fedora. + $form['djatoka_server_url'] = array ( + '#type' => 'textfield', + '#title' => '

      '.t('Fedora Image API Module').'


      '.t('aDORe Djatoka image server resolver URL'), + '#default_value' => variable_get('djatoka_server_url', $fedora_server_url.'/adore-djatoka/resolver' ), + '#description' => t('The location of your aDORe Djatoka image server, if you have one installed.'), + '#weight' => 1, + ); + $form['openlayers_server_url'] = array( + '#type' => 'textfield', + '#title' => t('OpenLayers servlet URL'), + '#default_value' => variable_get('openlayers_server_url', $fedora_server_url.'/islandora/OpenLayers'), + '#description' => t('URL of your installation of the OpenLayers servlet, if you have one.'), + '#weight' => 1, + ); + $form['buttons']['#weight'] = 2; + break; + } +} + +function show_openlayers_viewer() { + $output = 'Hi.'; + + return $output; +} +*/ diff --git a/plugins/herbarium.inc b/plugins/herbarium.inc new file mode 100644 index 00000000..54a7d331 --- /dev/null +++ b/plugins/herbarium.inc @@ -0,0 +1,176 @@ +pid = $pid; + $this->item = new Fedora_Item($pid); + } + } + + public function buildDrupalForm($form = array(), $form_state = array()) { + // We don't need to add anything beyond the standard Darwin Core form so just pass this through + // If we wanted to we could add other fields. + module_load_include('inc', 'fedora_repository', 'plugins/DarwinCore'); + + $dwc = new DarwinCore($this->item); + return $dwc->buildDrupalForm($form); + } + + public function buildEditMetadataForm($form = array()) { + $form['submit'] = array( + '#type' => 'submit', + '#weight' => 10, + '#value' => 'Update' + ); + $form['pid'] = array( + '#type' => 'hidden', + '#value' => $this->pid, + ); + $form['dsid'] = array( + '#type' => 'hidden', + '#value' => "DARWIN_CORE", + ); + + return $this->buildDrupalForm($form); + } + + public function handleEditMetadataForm($form_id, $form_values) { + /* + * Process the metadata form + * Update the datastreams + */ + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'plugins/DarwinCore'); + module_load_include('inc', 'fedora_repository', 'MimeClass'); + global $user; + $mimetype = new MimeClass(); + $dwc = new DarwinCore($this->item); + $dwc->handleForm($form_values); + $this->item->purge_datastream('DARWIN_CORE'); + $this->item->add_datastream_from_string($dwc->darwinCoreXML, 'DARWIN_CORE', + 'Darwin Core Metadata', 'text/xml', 'X'); + return TRUE; + } + + public function handleIngestForm($form_values) { + /* + * process the metadata form + * Create fedora object + * Add the datastreams + */ + module_load_include('inc', 'fedora_repository', 'MimeClass'); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'plugins/DarwinCore'); + global $user; + $mimetype = new MimeClass(); + $dwc = new DarwinCore(); + $dwc->handleForm($form_values); + $label = $form_values['dwc:institutionCode'] . ':' + . $form_values['dwc:collectionCode'] . ':' + . $form_values['dwc:catalogNumber']; + + $new_item = Fedora_Item::ingest_new_item($form_values['pid'], 'A', $label, + $user->name); + + $new_item->add_datastream_from_string($dwc->darwinCoreXML, 'DARWIN_CORE', + 'Darwin Core Metadata', 'text/xml', 'X'); + $file = $form_values['ingest-file-location']; + + if (!empty( $file)) { + $dformat = $mimetype->getType($file); + $new_item->add_datastream_from_file($file, 'FULL_SIZE', + "$label-full-size", $dformat, 'M'); + } + + $new_item->add_relationship('hasModel', $form_values['content_model_pid'], FEDORA_MODEL_URI); + $new_item->add_relationship(!empty($form_values['relationship']) ? $form_values['relationship'] : 'isMemberOfCollection', $form_values['collection_pid']); + + if (!empty($_SESSION['fedora_ingest_files'])) { + foreach ($_SESSION['fedora_ingest_files'] as $dsid => $created_file) { + $created_file_format = $mimetype->getType($created_file); + $created_filename = strstr($created_file, $file); + $new_item->add_datastream_from_file($created_file, $dsid, + $created_filename, $created_file_format, 'M'); + + } + } + } + + public function showFieldSets() { + module_load_include('inc', 'fedora_repository', 'plugins/tagging_form'); + module_load_include('inc', 'fedora_repository', 'plugins/DarwinCore'); + global $base_url; + + $tabset = array(); + + $tabset['my_tabset'] = array( + '#type' => 'tabset', + ); + + global $user; + $qs = ''; + if ($user->uid != 0) { + $qs = '?uid='. base64_encode($user->name . ':'. $user->pass); + } + + $viewer_url = variable_get('fedora_base_url', '') . '/get/'. $this->pid . '/ilives:viewerSdef/getViewer'. $qs; + $html = ''; + $tabset['my_tabset']['second_tab'] = array( +// $collection_fieldset = array ( + '#type' => 'tabpage', + '#title' => t('Full-size'), + '#content' => $html + ); + $tabset['my_tabset']['first_tab'] = array( + // #type and #title are the minimum requirements. + '#type' => 'tabpage', + '#title' => t('View'), + // This will be the content of the tab. + '#content' => ''. '

      '. drupal_get_form('fedora_repository_image_tagging_form', $this->pid) . '

      ', + ); + + $dwc = new DarwinCore($this->item); + $tabset['my_tabset']['third_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Description'), + ); + $tabset['my_tabset']['third_tab']['tabset'] = array( + '#type' => 'tabset', + ); + + $tabset['my_tabset']['third_tab']['tabset']['view'] = array( + '#type' => 'tabpage', + '#title' => t('Darwin Core'), + '#content' => $dwc->asHTML(), + ); + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + $obj = new ObjectHelper(); + if (fedora_repository_access(OBJECTHELPER :: $EDIT_FEDORA_METADATA, $this->pid, $user)) { + $editform = drupal_get_form('fedora_repository_edit_qdc_form', $this->pid, 'DARWIN_CORE'); + $tabset['my_tabset']['third_tab']['tabset']['edit'] = array( + '#type' => 'tabpage', + '#title' => t('Edit'), + '#content' => $editform, + ); + $tabset['my_tabset']['third_tab']['tabset']['source'] = array( + '#type' => 'tabpage', + '#title' => t('Vew Source'), + ); + $xmlsrc = $dwc->asXML(); + $tabset['my_tabset']['third_tab']['tabset']['source']['srctext'] = array( + '#name' => 'source', + '#type' => 'textarea', + '#value' => $xmlsrc, + '#id' => 'source', + '#height' => 50, + ); + } + + return tabs_render($tabset); + } +} diff --git a/plugins/map_viewer.inc b/plugins/map_viewer.inc new file mode 100644 index 00000000..acd990ab --- /dev/null +++ b/plugins/map_viewer.inc @@ -0,0 +1,55 @@ +pid = $pid; + } + + function showJPG() { + module_load_include('inc', 'fedora_repository', 'plugins/tagging_form'); + module_load_include('inc', 'fedora_repository', 'plugins/ShowStreamsInFieldSets'); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + + global $base_url; + + $tabset = array(); + + $tabset['my_tabset'] = array( + '#type' => 'tabset', + ); + + global $user; + $qs = ''; + if ($user->uid != 0) { + $qs = '?uid=' . base64_encode($user->name . ':' . $user->pass); + } + + $viewer_url = variable_get('fedora_base_url', '') . '/get/'. $this->pid . '/ilives:viewerSdef/getViewer'. $qs; + $html = ''; + + drupal_add_css(path_to_theme() . '/header-viewer.css', 'theme'); + drupal_add_css(drupal_get_path('module', 'fedora_repository') . '/js/iiv/css/jquery-ui/smoothness/jquery-ui-1.7.2.custom.css'); + drupal_add_css(drupal_get_path('module', 'fedora_repository') . '/js/iiv/css/iiv.css'); + + + $tabset['my_tabset']['second_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Full-size'), + '#content' => $html//'
      ' + ); + + $item = new Fedora_Item($this->pid); + $tabset['my_tabset']['third_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Description'), + '#content' => $item->get_dissemination('islandora:mods2htmlSdef', 'mods2html'), + ); + // Render the tabset. + return tabs_render($tabset); + + return theme('fieldset', $collection_fieldset); + } +} diff --git a/plugins/newspaper/newspapers_guardian.xml b/plugins/newspaper/newspapers_guardian.xml new file mode 100644 index 00000000..be9a63da --- /dev/null +++ b/plugins/newspaper/newspapers_guardian.xml @@ -0,0 +1,378 @@ + + + + + + + + + + + + + + + + modifyDatastreamByValue + MODS + fedoraAdmin + 2010-05-28T18:38:36.223Z + + + + + ingest + + fedoraAdmin + 2010-05-31T15:14:58.313Z + Ingested from local file /Users/al/Desktop/newspapers_guardian.xml + + + + + + + + + + This is an object-specific policy. It could be stored inside the digital object in the POLICY datastream OR in the directory for object-specific policies. (The directory location is set in the Authorization module configuration in the Fedora server configuration file (fedora.fcfg). By using multiple policy Rules, this policy shows how to deny access to all raw datastreams in the object except to particular users (e.g., the object owners). It also shows how to deny access to a particular disseminations to selected user roles. + + + + + + + + + + + urn:fedora:names:fedora:2.1:action:id-ingest + + + + + + urn:fedora:names:fedora:2.1:action:id-modifyDatastreamByReference + + + + + + urn:fedora:names:fedora:2.1:action:id-modifyDatastreamByValue + + + + + + urn:fedora:names:fedora:2.1:action:id-modifyDisseminator + + + + + + urn:fedora:names:fedora:2.1:action:id-modifyDisseminator + + + + + + urn:fedora:names:fedora:2.1:action:id-purgeObject + + + + + + urn:fedora:names:fedora:2.1:action:id-purgeDatastream + + + + + + urn:fedora:names:fedora:2.1:action:id-purgeDisseminator + + + + + + urn:fedora:names:fedora:2.1:action:id-setDatastreamState + + + + + + urn:fedora:names:fedora:2.1:action:id-setDisseminatorState + + + + + + urn:fedora:names:fedora:2.1:action:id-setDatastreamVersionable + + + + + + urn:fedora:names:fedora:2.1:action:id-addDatastream + + + + + + urn:fedora:names:fedora:2.1:action:id-addDisseminator + + + + + + + + + + + + administrator + + + + + + fedoraAdmin + + + + + + + + + + + + + + + + + + + + The Guardian + Guardian (Charlottetown, P.E.I.) + The Island guardian + The Charlottetown guardian + The Morning guardian + Newspapers + Newspapers + The Guardian, the successor to the Island Guardian, began publication in 1890 a a politically independent newspaper printing news and advertisements. Its editorials often discussed trade and tariffs, and it supported temperance and the Scott Act. Lcal, national and international news coverage was excellent in the paper. Twoards the end of the 1890s, headlines and line drawings illustrating the news stories began appearing in the Guardian. + + The tone of the newspaper changed during the first decade of the twentieth century; its news coverage became more sensational and its editorials offered less political commentary. Special weekend issues were printed during the second half of this decade, featuring comic strips, housekeeping articles, popular songs, sermons, local history and Sunday School lessons. Photographs and line drawings appeared frequently during the final years of the decade. + + .... more in Heather Boylan ... p.54-Checklist and Historical Directory of Prince Edward Island Newspapers. + Title varies: 1887- , The Island guardian; Dec. 1890-Jan. 1891, The Daily guardian; Jan. 1891- , The Morning guardian. + Ceased publication in 1920? + Missing issues. + Microfilm of the original in Prince Edward Island Public and Legislative Libraries. Ottawa, Canadian Library Association Newspaper Microfilming Project, 1963- reels. + Hood, J. P. + 1887-1920 + Text + v. + microfilm + http://islandpines.roblib.upei.ca/opac/extras/supercat/mods33/record/274634 + newspapers:guardian + eng + Prince Edward Island + Charlottetown (P.E.I.) + + + + + + + + + + The + Guardian + + + Guardian (Charlottetown, P.E.I.) + + + The + Island guardian + + + The + Charlottetown guardian + + + The + Morning guardian + + + Hood, J. P. + + + Manager + + + Business Manager from Dec. 29, 1891 - Mar. 9, 1903; Managing Director from July 2, 1912 - Jan. 30, 1913. + + + text + + + pic + + + Charlottetown, P.E.I + + 1887-1920 + 1887 + 1920 + continuing + + + eng + + The Guardian, the successor to the Island Guardian, began publication in 1890 a a politically independent newspaper printing news and advertisements. Its editorials often discussed trade and tariffs, and it supported temperance and the Scott Act. Lcal, national and international news coverage was excellent in the paper. Twoards the end of the 1890s, headlines and line drawings illustrating the news stories began appearing in the Guardian. + + The tone of the newspaper changed during the first decade of the twentieth century; its news coverage became more sensational and its editorials offered less political commentary. Special weekend issues were printed during the second half of this decade, featuring comic strips, housekeeping articles, popular songs, sermons, local history and Sunday School lessons. Photographs and line drawings appeared frequently during the final years of the decade. + + .... more in Heather Boylan ... p.54-Checklist and Historical Directory of Prince Edward Island Newspapers. + + + microfilm +
      microform
      + v. +
      + Title varies: 1887- , The Island guardian; Dec. 1890-Jan. 1891, The Daily guardian; Jan. 1891- , The Morning guardian. + Ceased publication in 1920? + Missing issues. + Microfilm of the original in Prince Edward Island Public and Legislative Libraries. Ottawa, Canadian Library Association Newspaper Microfilming Project, 1963- reels. + + Prince Edward Island + Newspapers + + + Charlottetown (P.E.I.) + Newspapers + + http://islandpines.roblib.upei.ca/opac/extras/supercat/mods33/record/274634 + + CaPCU + 760913 + 20090407151822.0 + +
      +
      +
      + + + + + The + Guardian + + + Guardian (Charlottetown, P.E.I.) + + + The + Island guardian + + + The + Charlottetown guardian + + + The + Morning guardian + + + Hood, J. P. + + + Manager + + + Business Manager from Dec. 29, 1891 - Mar. 9, 1903; Managing Director from July 2, 1912 - Jan. 30, 1913. + + + text + + + pic + + + Charlottetown, P.E.I + + 1887-1920 + 1887 + 1920 + continuing + + + eng + + The Guardian, the successor to the Island Guardian, began publication in 1890 a a politically independent newspaper printing news and advertisements. Its editorials often discussed trade and tariffs, and it supported temperance and the Scott Act. Lcal, national and international news coverage was excellent in the paper. Twoards the end of the 1890s, headlines and line drawings illustrating the news stories began appearing in the Guardian. + + The tone of the newspaper changed during the first decade of the twentieth century; its news coverage became more sensational and its editorials offered less political commentary. Special weekend issues were printed during the second half of this decade, featuring comic strips, housekeeping articles, popular songs, sermons, local history and Sunday School lessons. Photographs and line drawings appeared frequently during the final years of the decade. + + .... more in Heather Boylan ... p.54-Checklist and Historical Directory of Prince Edward Island Newspapers. + + +
      microfilm
      +
      microform
      + v. +
      + Title varies: 1887- , The Island guardian; Dec. 1890-Jan. 1891, The Daily guardian; Jan. 1891- , The Morning guardian. + Ceased publication in 1920? + Missing issues. + Microfilm of the original in Prince Edward Island Public and Legislative Libraries. Ottawa, Canadian Library Association Newspaper Microfilming Project, 1963- reels. + + Prince Edward Island + Newspapers + + + Charlottetown (P.E.I.) + Newspapers + + http://islandpines.roblib.upei.ca/opac/extras/supercat/mods33/record/274634 + + CaPCU + 760913 + 20090407151822.0 + +
      +
      +
      +
      + + + + + + + + + + + + +
      diff --git a/plugins/newspaper/newspapers_issueCModel.xml b/plugins/newspaper/newspapers_issueCModel.xml new file mode 100644 index 00000000..133c6eaa --- /dev/null +++ b/plugins/newspaper/newspapers_issueCModel.xml @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2010-05-28T19:34:22.355Z + Created with Admin GUI "New Object" command + + + + ingest + + fedoraAdmin + 2010-05-31T15:15:15.889Z + Ingested from local file /Users/al/Desktop/newspapers_issueCModel.xml + + + + addDatastream + ISLANDORACM + fedoraAdmin + 2010-05-31T19:28:19.883Z + DatastreamsPane generated this logMessage. + + + + modifyDatastreamByValue + RELS-EXT + fedoraAdmin + 2010-05-31T20:00:31.353Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This DS-COMPOSITE-MODEL datastream is included as a starting point to + assist in the creation of a content model. The DS-COMPOSITE-MODEL + should define the datastreams that are required for any objects + conforming to this content model. + For more information about content models, see: + http://fedora-commons.org/confluence/x/dgBI. + For examples of completed content model objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:CMImage, demo:UVA_STD_IMAGE, demo:DualResImageCollection, + demo:TEI_TO_PDFDOC, and demo:XML_TO_HTMLDOC. + For more information about the demonstration objects, see: + http://fedora-commons.org/confluence/x/AwFI. + + +
      + + + + + + + + + + Newspaper Issue Content Model + newspapers:issueCModel + + + + + + + + + + + + + plugins/Newspaper.inc + Newspaper + showFieldSets + + + + + + + + + + + + + plugins/Newspaper.inc + Newspaper + buildDrupalForm + handleIngestForm + + + + + plugins/Newspaper.inc + Newspaper + buildEditMetadataForm + + + plugins/Newspaper.inc + Newspaper + handleEditMetadataForm + + + + + + + diff --git a/plugins/newspaper/newspapers_pageCModel.xml b/plugins/newspaper/newspapers_pageCModel.xml new file mode 100644 index 00000000..99e3f94e --- /dev/null +++ b/plugins/newspaper/newspapers_pageCModel.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2010-05-28T19:37:09.514Z + Created with Admin GUI "New Object" command + + + + ingest + + fedoraAdmin + 2010-05-31T15:15:26.657Z + Ingested from local file /Users/al/Desktop/newspapers_pageCModel.xml + + + + ingest + + fedoraAdmin + 2010-06-01T13:22:40.275Z + Ingested from local file /Users/aoneill/fedora_repository/plugins/newspaper/newspapers_pageCModel.xml + + + + addDatastream + ISLANDORACM + fedoraAdmin + 2010-06-21T16:26:53.809Z + DatastreamsPane generated this logMessage. + + + + ingest + + fedoraAdmin + 2010-06-21T19:39:20.139Z + Ingested from source repository with pid newspapers:pageCModel + + + + + + + + + + + + + + + + + + + + + + This DS-COMPOSITE-MODEL datastream is included as a starting point to + assist in the creation of a content model. The DS-COMPOSITE-MODEL + should define the datastreams that are required for any objects + conforming to this content model. + For more information about content models, see: + http://fedora-commons.org/confluence/x/dgBI. + For examples of completed content model objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:CMImage, demo:UVA_STD_IMAGE, demo:DualResImageCollection, + demo:TEI_TO_PDFDOC, and demo:XML_TO_HTMLDOC. + For more information about the demonstration objects, see: + http://fedora-commons.org/confluence/x/AwFI. + + + + + + + + + + + + + Newspaper Page Content Model + newspapers:pageCModel + + + + + + + + + + + + + plugins/Newspaper.inc + Newspaper + showPageFieldSets + + + + + + + + + + + + plugins/Newspaper.inc + Newspaper + buildEditMetadataForm + + + plugins/Newspaper.inc + Newspaper + handleEditMetadataForm + + + + + + + diff --git a/plugins/newspaper/newspapers_viewerSdep-issueCModel.xml b/plugins/newspaper/newspapers_viewerSdep-issueCModel.xml new file mode 100644 index 00000000..d6fd2349 --- /dev/null +++ b/plugins/newspaper/newspapers_viewerSdep-issueCModel.xml @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2010-05-31T20:54:30.053Z + Created with Admin GUI "New Object" command + + + + modifyDatastreamByValue + DSINPUTSPEC + fedoraAdmin + 2010-05-31T20:55:13.521Z + + + + + modifyDatastreamByValue + METHODMAP + fedoraAdmin + 2010-05-31T20:55:35.100Z + + + + + modifyDatastreamByValue + WSDL + fedoraAdmin + 2010-05-31T20:55:59.039Z + + + + + modifyDatastreamByValue + RELS-EXT + fedoraAdmin + 2010-05-31T20:57:54.728Z + + + + + modifyDatastreamByValue + METHODMAP + fedoraAdmin + 2010-05-31T20:59:03.704Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This METHODMAP datastream is included as a starting point to + assist in the creation of a service deployment. The METHODMAP + should define the the mapping of the WSDL to Fedora object methods. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This DSINPUTSPEC datastream is included as a starting point to + assist in the creation of a service deployment. The DSINPUTSPEC + should define the datastreams to be used by WSDL-defined methods. + + + + + + + + DC + text/xml + + + + + + + + + + + This WSDL datastream is included as a starting point to + assist in the creation of a service deployment. The WSDL + should define the services provided by this + service deployment. + For more information about service deployments, see: + http://fedora-commons.org/confluence/x/dgBI. + For examples of completed service deployment objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:2, demo:13, demo:20, and demo:28. + For more information about the demonstration objects, see: + http://fedora-commons.org/confluence/x/AwFI. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Viewer service deployment for Newspaper content model + newspapers:viewerSdep-issueCModel + + + + + diff --git a/plugins/newspaper/newspapers_viewerSdep-pageCModel.xml b/plugins/newspaper/newspapers_viewerSdep-pageCModel.xml new file mode 100644 index 00000000..de804348 --- /dev/null +++ b/plugins/newspaper/newspapers_viewerSdep-pageCModel.xml @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + ingest + + fedoraAdmin + 2010-06-21T17:47:30.096Z + Created with Admin GUI "New Object" command + + + + modifyDatastreamByValue + RELS-EXT + fedoraAdmin + 2010-06-21T17:49:00.674Z + + + + + modifyDatastreamByValue + METHODMAP + fedoraAdmin + 2010-06-21T17:50:01.411Z + + + + + modifyDatastreamByValue + DSINPUTSPEC + fedoraAdmin + 2010-06-21T17:50:23.252Z + + + + + modifyDatastreamByValue + WSDL + fedoraAdmin + 2010-06-21T17:51:49.022Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This METHODMAP datastream is included as a starting point to + assist in the creation of a service deployment. The METHODMAP + should define the the mapping of the WSDL to Fedora object methods. + + + + + + + + + + + + + + + + + + + + + + This DSINPUTSPEC datastream is included as a starting point to + assist in the creation of a service deployment. The DSINPUTSPEC + should define the datastreams to be used by WSDL-defined methods. + + + + + + + + DC + text/xml + + + + + + + + + + + This WSDL datastream is included as a starting point to + assist in the creation of a service deployment. The WSDL + should define the services provided by this + service deployment. + For more information about service deployments, see: + http://fedora-commons.org/confluence/x/dgBI. + For examples of completed service deployment objects, see the demonstration + objects included with your Fedora distribution, such as: + demo:2, demo:13, demo:20, and demo:28. + For more information about the demonstration objects, see: + http://fedora-commons.org/confluence/x/AwFI. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Viewer for newspaper pages + newspapers:viewerSdep-pageCModel + + + + + diff --git a/plugins/nmlt/cck/scorm_fedora_type.txt b/plugins/nmlt/cck/scorm_fedora_type.txt new file mode 100644 index 00000000..1679dc0b --- /dev/null +++ b/plugins/nmlt/cck/scorm_fedora_type.txt @@ -0,0 +1,223 @@ +$content['type'] = array ( + 'name' => 'SCORM Repository Item', + 'type' => 'repository_item', + 'description' => 'Contains a reference to an item in the Fedora repository. The item will be fully rendered when a user views the node. Comments and other node-attached content can then be added to the node page.', + 'title_label' => 'Title', + 'body_label' => 'Body', + 'min_word_count' => '0', + 'help' => '', + 'node_options' => + array ( + 'status' => true, + 'promote' => true, + 'sticky' => false, + 'revision' => false, + ), + 'upload' => '1', + 'old_type' => 'repository_item', + 'orig_type' => '', + 'module' => 'node', + 'custom' => '1', + 'modified' => '1', + 'locked' => '0', + 'comment' => '2', + 'comment_default_mode' => '4', + 'comment_default_order' => '1', + 'comment_default_per_page' => '50', + 'comment_controls' => '3', + 'comment_anonymous' => 0, + 'comment_subject_field' => '1', + 'comment_preview' => '1', + 'comment_form_location' => '0', + 'fivestar' => 1, + 'fivestar_stars' => '5', + 'fivestar_labels_enable' => 1, + 'fivestar_label_0' => 'Cancel rating', + 'fivestar_label_1' => 'Poor', + 'fivestar_label_2' => 'Okay', + 'fivestar_label_3' => 'Good', + 'fivestar_label_4' => 'Great', + 'fivestar_label_5' => 'Awesome', + 'fivestar_label_6' => 'Give it @star/@count', + 'fivestar_label_7' => 'Give it @star/@count', + 'fivestar_label_8' => 'Give it @star/@count', + 'fivestar_label_9' => 'Give it @star/@count', + 'fivestar_label_10' => 'Give it @star/@count', + 'fivestar_style' => 'average', + 'fivestar_text' => 'dual', + 'fivestar_title' => 1, + 'fivestar_feedback' => 1, + 'fivestar_unvote' => 1, + 'fivestar_position_teaser' => 'hidden', + 'fivestar_position' => 'below', +); +$content['fields'] = array ( + 0 => + array ( + 'label' => 'SCORM Object', + 'field_name' => 'field_scorm_obj', + 'type' => 'filefield', + 'widget_type' => 'SCORM_widget', + 'change' => 'Change basic information', + 'weight' => '-3', + 'file_extensions' => 'zip', + 'progress_indicator' => 'bar', + 'file_path' => '', + 'max_filesize_per_file' => '', + 'max_filesize_per_node' => '', + 'description' => 'Embed a SCORM object into this node.', + 'required' => 0, + 'multiple' => '0', + 'list_field' => '0', + 'list_default' => 1, + 'description_field' => '0', + 'op' => 'Save field settings', + 'module' => 'filefield', + 'widget_module' => 'SCORM', + 'columns' => + array ( + 'fid' => + array ( + 'type' => 'int', + 'not null' => false, + 'views' => true, + ), + 'list' => + array ( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => false, + 'views' => true, + ), + 'data' => + array ( + 'type' => 'text', + 'serialize' => true, + 'views' => true, + ), + ), + 'display_settings' => + array ( + 'label' => + array ( + 'format' => 'above', + 'exclude' => 0, + ), + 'teaser' => + array ( + 'format' => 'SCORM_embedded', + 'exclude' => 0, + ), + 'full' => + array ( + 'format' => 'SCORM_embedded', + 'exclude' => 0, + ), + 4 => + array ( + 'format' => 'SCORM_embedded', + 'exclude' => 0, + ), + 2 => + array ( + 'format' => 'SCORM_embedded', + 'exclude' => 0, + ), + 3 => + array ( + 'format' => 'SCORM_embedded', + 'exclude' => 0, + ), + ), + ), + 1 => + array ( + 'label' => 'Fedora Object Reference', + 'field_name' => 'field_fedora_pid_reference', + 'type' => 'pidfield', + 'widget_type' => 'pidfield_widget', + 'change' => 'Change basic information', + 'weight' => '-2', + 'size' => '60', + 'description' => 'A Fedora object PID that this node references.', + 'default_value' => + array ( + 0 => + array ( + 'value' => '', + '_error_element' => 'value', + ), + ), + 'default_value_php' => '', + 'default_value_widget' => + array ( + 'field_fedora_pid_reference' => + array ( + 0 => + array ( + 'value' => '', + '_error_element' => 'value', + ), + ), + ), + 'required' => 0, + 'multiple' => '0', + 'max_length' => '64', + 'op' => 'Save field settings', + 'module' => 'pidfield', + 'widget_module' => 'pidfield', + 'columns' => + array ( + 'value' => + array ( + 'type' => 'varchar', + 'length' => '64', + 'not null' => false, + 'sortable' => true, + 'views' => true, + ), + ), + 'display_settings' => + array ( + 'label' => + array ( + 'format' => 'above', + 'exclude' => 0, + ), + 'teaser' => + array ( + 'format' => 'default', + 'exclude' => 0, + ), + 'full' => + array ( + 'format' => 'default', + 'exclude' => 0, + ), + 4 => + array ( + 'format' => 'default', + 'exclude' => 0, + ), + 2 => + array ( + 'format' => 'default', + 'exclude' => 0, + ), + 3 => + array ( + 'format' => 'default', + 'exclude' => 0, + ), + ), + ), +); +$content['extra'] = array ( + 'title' => '-5', + 'body_field' => '-1', + 'revision_information' => '0', + 'comment_settings' => '3', + 'menu' => '-4', + 'path' => '1', + 'attachments' => '2', +); diff --git a/plugins/nmlt/collection_policies/nmlt_collection_policy.xml b/plugins/nmlt/collection_policies/nmlt_collection_policy.xml new file mode 100644 index 00000000..4e0df197 --- /dev/null +++ b/plugins/nmlt/collection_policies/nmlt_collection_policy.xml @@ -0,0 +1,22 @@ + + + + + + + dc.title + dc.creator + dc.description + dc.date + dc.identifier + dc.language + dc.publisher + dc.rights + dc.subject + dc.relation + dcterms.temporal + dcterms.spatial + Full Text + + isMemberOfCollection + diff --git a/plugins/nmlt/collection_policies/nmlt_collection_view.xslt b/plugins/nmlt/collection_policies/nmlt_collection_view.xslt new file mode 100644 index 00000000..11041e12 --- /dev/null +++ b/plugins/nmlt/collection_policies/nmlt_collection_view.xslt @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/plugins/nmlt/collection_policies/query.txt b/plugins/nmlt/collection_policies/query.txt new file mode 100644 index 00000000..37c6638a --- /dev/null +++ b/plugins/nmlt/collection_policies/query.txt @@ -0,0 +1,5 @@ +select $object $title from <#ri> + where ($object $title + and ($object ) + and $object ) + order by $title \ No newline at end of file diff --git a/plugins/nmlt/content_models/islandora_SCORMCModel.xml b/plugins/nmlt/content_models/islandora_SCORMCModel.xml new file mode 100644 index 00000000..241de3d1 --- /dev/null +++ b/plugins/nmlt/content_models/islandora_SCORMCModel.xml @@ -0,0 +1,20 @@ + + + application/zip + + + + application/zip + + + + + + + + + + + + + diff --git a/plugins/nmlt/fedora_nmlt.info b/plugins/nmlt/fedora_nmlt.info new file mode 100644 index 00000000..28b22363 --- /dev/null +++ b/plugins/nmlt/fedora_nmlt.info @@ -0,0 +1,9 @@ +; $Id$ +name = Islandora NMLT +description = Provides SCORM learning object support for Islandora +package = Fedora Repository +dependencies[] = fedora_repository +dependencies[] = content_copy +dependencies[] = SCORM +version = 6.1dev +core = 6.x diff --git a/plugins/nmlt/fedora_nmlt.install b/plugins/nmlt/fedora_nmlt.install new file mode 100644 index 00000000..55d699f2 --- /dev/null +++ b/plugins/nmlt/fedora_nmlt.install @@ -0,0 +1,48 @@ +', '', $file); +} + +function fedora_nmlt_enable() { + // Set the module weight so it can override other modules. + db_query("UPDATE {system} SET weight = 50 WHERE name = 'fedora_nmlt'"); +} + +/** + * Programmatically create CCK fields and types using the content copy module + * @param $type string + * content type to create, defaults to new type, if type exists, only fields will be added + * @param $macro array + * exported array from content types -> export. If file is not specified, macro will be used + * @param $file string + * path to file containing content copy exported macro data structure. no escaping needed. + */ +function fedora_nmlt_import_content_type($type = '', $macro = '', $file = '') { + if(!module_exists("content_copy")){ + drupal_set_message('Programmatically creating CCK fields requires the Content Copy module. Exiting.'); + return; + } + + include_once( $_SERVER['DOCUMENT_ROOT'].'/'. drupal_get_path('module', 'content') .'/includes/content.admin.inc'); + include_once( $_SERVER['DOCUMENT_ROOT'].'/'. drupal_get_path('module', 'node') .'/content_types.inc'); + + $values = array(); + $values['type_name'] = $type; + if($file){ + if(file_exists($file)){ + $values['macro'] = file_get_contents($file); + }else{ + drupal_set_message('Unable to read input file for import. Exiting.'); + return; + } + }elseif($macro){ + $values['macro'] = $macro; + } + $form_state = array(); + $form_state['values'] = $values; + //drupal_set_message('
      DEBUG: '.print_r($values['macro'],1).'
      '); + drupal_execute("content_copy_import_form", $form_state); + content_clear_type_cache(); +} \ No newline at end of file diff --git a/plugins/nmlt/fedora_nmlt.module b/plugins/nmlt/fedora_nmlt.module new file mode 100644 index 00000000..427bcc49 --- /dev/null +++ b/plugins/nmlt/fedora_nmlt.module @@ -0,0 +1,12 @@ + 'Results', + 'page callback' => 'scorm_show_results', + 'page arguments' => array(1), + 'access callback' => user_access('use scorm'), + 'type' => MENU_NORMAL_ITEM, + ); + return $items; +} \ No newline at end of file diff --git a/plugins/nmlt/scorm.inc b/plugins/nmlt/scorm.inc new file mode 100644 index 00000000..09b05076 --- /dev/null +++ b/plugins/nmlt/scorm.inc @@ -0,0 +1,367 @@ +pid = $pid; + $this->item = new Fedora_Item($pid); + } + } + + public function buildIngestForm($form = array(), $form_state = array()) { + $form['bulk_ingest_location'] = array( + '#title' => 'Bulk ingest location', + '#type' => 'textfield', + '#size' => 60, + '#description' => "Server location from which to upload SCORM objects. Leave this blank if you are uploading a single file.", + ); + return $form; + } + + public function buildEditMetadataForm($form = array()) { + + $form['submit'] = array( + '#type' => 'submit', + '#weight' => 10, + '#value' => 'Update' + ); + $form['pid'] = array( + '#type' => 'hidden', + '#value' => $this->pid, + ); + $form['dsid'] = array( + '#type' => 'hidden', + '#value' => "DARWIN_CORE", + ); + + return $this->buildDrupalForm($form); + } + + public function handleEditMetadataForm($form_id, $form_values) { + /* + * Process the metadata form + * Update the datastreams + */ + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'plugins/DarwinCore'); + module_load_include('inc', 'fedora_repository', 'MimeClass'); + global $user; + $mimetype = new MimeClass(); + $dwc = new DarwinCore($this->item); + $dwc->handleForm($form_values); + $this->item->purge_datastream('DARWIN_CORE'); + $this->item->add_datastream_from_string($dwc->darwinCoreXML, 'DARWIN_CORE', + 'Darwin Core Metadata', 'text/xml', 'X'); + return TRUE; + } + + /** + * process the metadata form + * Create fedora object + * Add the datastreams + */ + public function handleIngestForm($form_values) { + + module_load_include('inc', 'fedora_repository', 'MimeClass'); + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + + global $user; + $mimetype = new MimeClass(); + $file_list = array(); + if (!empty($form_values['bulk_ingest_location'])) { + if ($scorm_dir = opendir($form_values['bulk_ingest_location'])) { + while (FALSE !== ($file_name = readdir($scorm_dir))) { + $ext = strrchr($file_name, '.'); + if ($ext == '.zip') { + + array_push($file_list, $form_values['bulk_ingest_location'] .'/'. $file_name); + } + } + closedir($scorm_dir); + sort($file_list); + } + } + else { + array_push($file_list, $form_values['ingest-file-location']); + } + scorm_create_scorm_objects($form_values['collection_pid'], $file_list, $form_values['content_model_pid'], $form_values['relationship'] ); + } + + public function showFieldSets() { + global $base_url; +// Try and get a node that references this object. + //$result = db_query("SELECT * FROM {content_node_field} nf INNER JOIN {content_node_field_instance} ni ON nf.field_name = ni.field_name WHERE nf.type='field_fedora_pid_reference'"); + + fedora_pidfield_redirect_to_node($this); + module_load_include('module', 'SCORM', 'SCORM'); + $dest_array = explode('/', urldecode(drupal_get_destination())); + $nid = $dest_array[count($dest_array) - 1]; + $node = node_load($nid); + + $tabset = array(); + + $tabset['my_tabset'] = array( + '#type' => 'tabset', + ); + + $tabset['my_tabset']['first_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Description'), + ); + $tabset['my_tabset']['second_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Results'), + '#content' => scorm_show_results($node), + ); + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + $obj = new ObjectHelper(); + $tabset['my_tabset']['first_tab']['tabset'] = array( + '#type' => 'tabset', + ); + + $tabset['my_tabset']['first_tab']['tabset']['view'] = array( + '#type' => 'tabpage', + '#title' => t('View'), + '#content' => $obj->getQDC($this->pid), + ); + if (fedora_repository_access(OBJECTHELPER :: $EDIT_FEDORA_METADATA, $this->pid, $user)) { + $editform = drupal_get_form('fedora_repository_edit_qdc_form', $this->pid, 'DC'); + $tabset['my_tabset']['first_tab']['tabset']['edit'] = array( + '#type' => 'tabpage', + '#title' => t('Edit'), + '#content' => $editform, + ); + + } + + return tabs_render($tabset); + } + + public function extractFile($filename) { + // Get a file from the zip and put it in a temporary location. + $tmpdir = sys_get_temp_dir(); + + exec("unzip $this->file $filename -d $tmpdir", $output); + if (file_exists($tmpdir.'/'.$filename)) { + return $tmpdir.'/'.$filename; + } + else { + return FALSE; + } + } + + private function _cleanUpHTML($html) { + + $tmp = substr($html, strpos($html, '')); + + return _filter_html($tmp, FILTER_HTML_STRIP); + + } + + public function _createSCORMObjectNode($scorm_file, $item) { + module_load_include('inc', 'node', 'node.pages'); // required\ + module_load_include('inc', 'fedora_repository', 'api/dublin_core'); + + global $user; + $node = array('type' => 'repository_item'); + $form_state = array(); + + $dc = new Dublin_Core($item); + $title = $dc->dc['dc:title'][0]; + if (empty($title)) { + $title = $pid; + } + $form_state['values']['title'] = $title; // node's title + + // Prepare the file field. + $mime = 'application/zip'; + $file = new stdClass(); + $file->filename = basename($scorm_file); + $file->filepath = $scorm_file; + $file->filemime = $mime; + $file->filesize = filesize($scorm_file); + + $file->uid = $user->uid; + $file->status = 0; + $file->timestamp = time(); + drupal_write_record('files', $file); + $file->fid = db_result(db_query("SELECT fid FROM {files} WHERE filepath = '%s'", $file->filepath)); + + + + // Create a drupal node that includes a SCORM object and reference to this Fedora PID. + // Drupal Content Type is SCORM Fedora Object. Fields are + // field_scorm_obj-0-value + // field_fedora_pid_reference-0-value + $form_state['values']['field_fedora_pid_reference'][0]['value'] = $item->pid; + /*$form_state['values']['field_scorm_obj'] = array ( + array( + 'fid' => $file->fid, + 'title' => basename($file->filename), + 'filename' => $file->filename, + 'filepath' => $file->filepath, + 'filesize' => $file->filesize, + 'mimetype' => $mime, + 'description' => basename($file->filename), + 'list' => 1, + ), + );*/ + $form_state['values']['op'] = t('Save'); // required value + drupal_execute('repository_item_node_form', $form_state, (object)$node); + + // you can probably configure the node-author in $form_state or $node, + // but i'm doing it this way to demonstrate the use of $form_state['nid']. + // the following lines aren't required, but otherwise the node-author will be "Anonymous" in this case. + $node = node_load($form_state['nid']); // nid from the node that gets created is set in $form_state['nid'] after drupal_execute() + $node->uid = $user->uid; // set author to the current user + $field = content_fields('field_scorm_obj', 'repository_item'); + // Load up the appropriate validators + //$validators = array_merge(filefield_widget_upload_validators($field), SCORM_widget_upload_validators($field)); + $validators = SCORM_widget_upload_validators($field); + // Where do we store the files? + $files_path = filefield_widget_file_path($field); + // Create the file object + $file = field_file_save_file($scorm_file, $validators, $files_path); + // Apply the file to the field + $file['data']['width'] = 640; + $file['data']['height'] = 480; + $node->field_scorm_obj = array(0 => $file); + $this->_processSCORMObject($file); + node_save($node); + return $node; + } + + private function _processSCORMObject($field) { + + $packagedata=scorm_validate_file($field['filepath']); + + $scorm->pkgtype = $packagedata->pkgtype; + $scorm->datadir = $packagedata->datadir; + $scorm->launch = $packagedata->launch; + $scorm->parse = 1; + + $scorm->timemodified = time(); + /* if (!scorm_external_link($scorm->reference)) { + $scorm->md5hash = md5_file($CFG->dataroot.'/'.$scorm->course.'/'.$scorm->reference); + } else { + $scorm->dir = $CFG->dataroot.'/'.$scorm->course.'/moddata/scorm'; + $scorm->md5hash = md5_file($scorm->dir.$scorm->datadir.'/'.basename($scorm->reference)); + }*/ + + $scorm = scorm_option2text($scorm); + //TODO: Implement form for user to set height and width for SCORM package + $scorm->width = '640'; + $scorm->height = '480'; + + if (!isset($scorm->whatgrade)) { + $scorm->whatgrade = 0; + } + $scorm->grademethod = ($scorm->whatgrade * 10) + $scorm->grademethod; + + //TODO: Do we need this fields: + $scorm->name="SCORM"; + $scorm->summary="SCORM 2004."; + $scorm->grademethod=''; + $scorm->maxgrade=100; + $scorm->maxattempt=0; + $scorm->updatefreq=0; + $scorm->course=1; + + + //At this point it is still empty + $scorm->version=''; + $scorm->skipview=0; + $scorm->hidebrowse=0; + $scorm->hidetoc=0; + $scorm->hidenav=0; + $scorm->auto=0; + $scorm->popup=0; + + //TODO: Do we still need it? + //$scorm->reference=$field->filepath; + + + //TODO: Remove MD5 field, we dont use it. + //$id = insert_record('scorm', $scorm); + + $result = db_query("INSERT INTO {scorm} + (course,name,nodereference,reference,summary,version,maxgrade,grademethod,whatgrade,maxattempt,updatefreq,md5hash,launch, + skipview,hidebrowse,hidetoc,hidenav,auto,popup,options,width,height,timemodified) + VALUES (%d,'%s',%d,'%s','%s','%s',%d,%d,%d,%d,%d,'%s',%d,%d,%d,%d,%d,%d,%d,'%s',%d,%d,%d)", $scorm->course, $scorm->name, NULL, NULL, $scorm->summary, $scorm->version, + $scorm->maxgrade, $scorm->grademethod, $scorm->whatgrade, $scorm->maxattempt, $scorm->updatefreq, NULL, $scorm->launch, $scorm->skipview, $scorm->hidebrowse, + $scorm->hidetoc, $scorm->hidenav, $scorm->auto, $scorm->popup, $scorm->options, $scorm->width, $scorm->height, $scorm->timemodified ); + + $id = db_last_insert_id('scorm', 'id'); //$id=mysql_insert_id(); + + //TODO: Test it on Linux + // Move SCORM from temp dir to scorm dir + + $storedir=file_directory_path() .'/SCORM'; + $path=$storedir .'/'. $id; + + if (!file_exists($storedir)) { + mkdir($storedir); + } + $res=mkdir($path); + if ($res==TRUE) { + full_copy($packagedata->tempdir, $path); + //rmdirr($packagedata->tempdir); + scorm_delete_files($packagedata->tempdir); + //Replace reference field with node field. + db_query("UPDATE {scorm} SET reference = '%s' WHERE id = %d", $field['fid'], $id); + } + else + return FALSE; + + + $scorm->id = $id; + //Parse SCORM manifest + $scorm->launch=scorm_parse_scorm($path, $scorm->id); + + //Save SCORM launch instance + db_query("UPDATE {scorm} SET launch = '%s' WHERE id = %d", $scorm->launch, $scorm->id); + + } +} + +function scorm_create_scorm_objects($collection_pid, $file_list = array(), $content_model_pid = 'islandora:SCORMCModel', $relationship = 'isMemberOfCollection') { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + + $batch = array( + 'title' => 'Ingesting SCORM objects', + 'operations' => array(), + 'file' => drupal_get_path('module', 'fedora_nmlt') .'/scorm.inc', + ); + + foreach ($file_list as $file_path) { + $batch['operations'][] = array('_create_single_SCORM_object', array($file_path, $collection_pid, $content_model_pid, $relationship)); + } + batch_set($batch); +} + +function _create_single_SCORM_object($file, $collection_pid, $content_model_pid, $relationship = 'isMemberOfCollection') { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $url = parse_url(variable_get('fedora_base_url', 'http://localhost:8080/fedora')); + $fedora_host = ("{$url['scheme']}://{$url['host']}" . (!empty($url['port']) ? ":{$url['port']}/" : '/')); + $scorm2fedora_url = $fedora_host . 'scorm2fedora'; + $ch = curl_init($scorm2fedora_url); + curl_setopt($ch, CURLOPT_POSTFIELDS, array('scormfile' => "@{$file}")); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $post_result = curl_exec($ch); + curl_close($ch); + $scorm2fedora_result = json_decode($post_result); + $scorm_object_pid = $scorm2fedora_result->pid; + if (!empty($scorm_object_pid)) { + $scorm_object = new Fedora_Item($scorm_object_pid); + $scorm_object->add_relationship('hasModel', $content_model_pid, FEDORA_MODEL_URI); + $scorm_object->add_relationship($relationship, $collection_pid); + $scorm = new SCORMObject($scorm_object_pid); + $scorm->_createSCORMObjectNode($file, $scorm_object); + } +} \ No newline at end of file diff --git a/plugins/pidfield/pidfield.info b/plugins/pidfield/pidfield.info new file mode 100644 index 00000000..e7b9d96f --- /dev/null +++ b/plugins/pidfield/pidfield.info @@ -0,0 +1,8 @@ +; $Id$ +name = PID Field +description = Defines a field type for referencing a Fedora item from a node. +dependencies[] = content +dependencies[] = fedora_repository +package = Fedora Repository +core = 6.x + diff --git a/plugins/pidfield/pidfield.install b/plugins/pidfield/pidfield.install new file mode 100644 index 00000000..2a45a34c --- /dev/null +++ b/plugins/pidfield/pidfield.install @@ -0,0 +1,39 @@ + array( + // The human-readable label of the field that will be + // seen in the Manage fields screen. + 'label' => t('Fedora PID field'), + // A description of what type of data the field stores. + 'description' => t('Store a reference to a PID in this site\'s Fedora repository.'), + // An icon to use in Panels. + 'content_icon' => 'icon_content_text.png', + ), + ); +} + +/** + * Implementation of hook_field_settings(). + */ +function pidfield_field_settings($op, $field) { + switch ($op) { + // Create the form element to be used on the field + // settings form. Field settings will be the same for + // all shared instances of the same field and should + // define the way the value will be stored + // in the database. + case 'form': + $form = array(); + $form['max_length'] = array( + '#type' => 'textfield', + '#title' => t('Maximum length'), + '#default_value' => is_numeric($field['max_length']) ? $field['max_length'] : 64, + '#required' => FALSE, + + // Use #element_validate to validate the settings. + '#element_validate' => array('_pidfield_length_validate'), + '#description' => t('The maximum length of the field in characters. Must be a number between 1 and 255'), + ); + return $form; + + // Return an array of the names of the field settings + // defined by this module. These are the items that + // CCK will store in the field definition + // and they will be available in the $field array. + // This should match the items defined in 'form' above. + case 'save': + return array('max_length'); + + // Define the database storage for this field using + // the same construct used by schema API. Most fields + // have only one column, but there can be any number + // of different columns. After the schema API values, + // add two optional values to each column, + // 'views', to define a Views field + // 'sortable', to add a Views sort field + case 'database columns': + $columns['value'] = array( + 'type' => 'varchar', + 'length' => is_numeric($field['max_length']) ? $field['max_length'] : 64, + 'not null' => FALSE, + 'sortable' => TRUE, + 'views' => TRUE, + ); + return $columns; + + // Optional: Make changes to the default $data array + // created for Views. Omit this if no changes are + // needed, use it to add a custom handler or make + // other changes. + case 'views data': + // Start with the $data created by CCK + // and alter it as needed. The following + // code illustrates how you would retrieve + // the necessary data. + $data = content_views_field_views_data($field); + $db_info = content_database_info($field); + $table_alias = content_views_tablename($field); + $field_data = $data[$table_alias][$field['field_name'] .'_value']; + // Make changes to $data as needed here. + return $data; + } +} + +/** + * Custom validation of settings values. + * + * Create callbacks like this to do settings validation. + */ +function _pidfield_length_validate($element, &$form_state) { + $value = $form_state['values']['max_length']; + if ($value && !is_numeric($value)|| $value < 1 || $value > 255) { + form_set_error('max_length', t('"Max length" must be a number between 1 and 64.')); + } +} + +/** + * Implementation of hook_field(). + */ +function pidfield_field($op, &$node, $field, &$items, $teaser, $page) { + switch ($op) { + // Do validation on the field values here. The widget + // will do its own validation and you cannot make any + // assumptions about what kind of widget has been used, + // so don't validate widget values, only field values. + case 'validate': + if (is_array($items)) { + foreach ($items as $delta => $item) { + // The error_element is needed so that CCK can + // set an error on the right sub-element when + // fields are deeply nested in the form. + $error_element = isset($item['_error_element']) ? $item['_error_element'] : ''; + if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']); + if (!empty($item['value'])) { + if (!empty($field['max_length']) && drupal_strlen($item['value']) > $field['max_length']) { + form_set_error($error_element, t('%name: the value may not be longer than %max characters.', array('%name' => $field['widget']['label'], '%max' => $field['max_length']))); + } + } + } + } + return $items; + + // This is where you make sure that user-provided + // data is sanitized before being displayed. + case 'sanitize': + foreach ($items as $delta => $item) { + $pid_field_text = check_plain($item['value']); + $items[$delta]['safe'] = $pid_field_text; + } + } +} + +/** + * Implementation of hook_content_is_empty(). + * + * CCK has no way to know if something like a zero is + * an empty value or a valid value, so return + * TRUE or FALSE to a populated field $item array. + * CCK uses this to remove empty multi-value elements + * from forms. + */ +function pidfield_content_is_empty($item, $field) { + if (empty($item['value'])) { + return TRUE; + } + return FALSE; +} + +/** + * Implementation of hook content_generate(). + * + * Optional, provide dummy value for nodes created + * by the Devel Generate module. + */ +function pidfield_content_generate($node, $field) { + $node_field = array(); + // Generate a value that respects max_length. + if (empty($field['max_length'])) { + $field['max_length'] = 12; + } + $node_field['value'] = user_password($field['max_length']); + return $node_field; +} + +/** + * Implementation of hook_token_list() + * and hook_token_values(). + * + * Optional, provide token values for this field. + */ +function pidfield_token_list($type = 'all') { + if ($type == 'field' || $type == 'all') { + $tokens = array(); + + $tokens['pidfield']['raw'] = t('Just the PID itself.'); + $tokens['pidfield']['formatted'] = t('A PID with a hyperlink'); + + return $tokens; + } +} + +function pidfield_token_values($type, $object = NULL) { + if ($type == 'field') { + $item = $object[0]; + + $tokens['raw'] = $item['value']; + $tokens['formatted'] = isset($item['view']) ? $item['view'] : ''; + return $tokens; + } +} + +//==========================================// +// DEFINING A FORMATTER +//==========================================// + +/** + * Implementation of hook_theme(). + */ +function pidfield_theme() { + return array( + // Themes for the formatters. + 'pidfield_formatter_default' => array( + 'arguments' => array('element' => NULL), + ), + 'pidfield_formatter_plain' => array( + 'arguments' => array('element' => NULL), + ), + ); +} + +/** + * Implementation of hook_field_formatter_info(). + * + * All fields should have a 'default' formatter. + * Any number of other formatters can be defined as well. + * It's nice for there always to be a 'plain' option + * for the raw value, but that is not required. + * + */ +function pidfield_field_formatter_info() { + return array( + // The machine name of the formatter. + 'default' => array( + // The human-readable label shown on the Display + // fields screen. + 'label' => t('Default'), + // An array of the field types this formatter + // can be used on. + 'field types' => array('pidfield'), + // CONTENT_HANDLE_CORE: CCK will pass the formatter + // a single value. + // CONTENT_HANDLE_MODULE: CCK will pass the formatter + // an array of all the values. None of CCK's core + // formatters use multiple values, that is an option + // available to other modules that want it. + 'multiple values' => CONTENT_HANDLE_CORE, + ), + 'plain' => array( + 'label' => t('Plain text'), + 'field types' => array('pidfield'), + 'multiple values' => CONTENT_HANDLE_CORE, + ), + ); +} + +/** + * Theme function for 'default' example field formatter. + * + * $element['#item']: the sanitized $delta value for the item, + * $element['#field_name']: the field name, + * $element['#type_name']: the $node->type, + * $element['#formatter']: the $formatter_name, + * $element'#node']: the $node, + * $element['#delta']: the delta of this item, like '0', + * + */ +function theme_pidfield_formatter_default($element) { + //return $element['#item']['safe']; + $pid = $element['#item']['safe']; + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $item = new Fedora_Item($pid); + + return fedora_repository_get_items($pid); + //return $item->objectProfile->objLabel; +} + +/** + * Theme function for 'plain' example field formatter. + */ +function theme_pidfield_formatter_plain($element) { + return strip_tags($element['#item']['safe']); +} + +//==========================================// +// DEFINING A WIDGET +//==========================================// + +/** + * Implementation of hook_widget_info(). + * + * Here we indicate that the content module will handle + * the default value and multiple values for these widgets. + * + * Callbacks can be omitted if default handing is used. + * They're included here just so this module can be used + * as an example for custom modules that might do things + * differently. + */ +function pidfield_widget_info() { + return array( + // The machine name of the widget, no more than 32 + // characters. + 'pidfield_widget' => array( + // The human-readable label of the field that will be + // seen in the Manage fields screen. + 'label' => t('PID Field widget'), + // An array of the field types this widget can be + // used with. + 'field types' => array('pidfield'), + // Who will handle multiple values, default is core. + // 'CONTENT_HANDLE_MODULE' means the module does it. + // See optionwidgets for an example of a module that + // handles its own multiple values. + 'multiple values' => CONTENT_HANDLE_CORE, + 'callbacks' => array( + // Who will create the default value, default is core. + // 'CONTENT_CALLBACK_CUSTOM' means the module does it. + // 'CONTENT_CALLBACK_NONE' means this widget has + // no default value. + 'default value' => CONTENT_CALLBACK_DEFAULT, + ), + ), + ); +} + +/** + * Implementation of hook_widget_settings(). + */ +function pidfield_widget_settings($op, $widget) { + switch ($op) { + // Create the form element to be used on the widget + // settings form. Widget settings can be different + // for each shared instance of the same field and + // should define the way the value is displayed to + // the user in the edit form for that content type. + case 'form': + $form = array(); + $size = (isset($widget['size']) && is_numeric($widget['size'])) ? $widget['size'] : 60; + $form['size'] = array( + '#type' => 'textfield', + '#title' => t('Size of textfield'), + '#default_value' => $size, + '#element_validate' => array('_element_validate_integer_positive'), + '#required' => TRUE, + ); + return $form; + + // Return an array of the names of the widget settings + // defined by this module. These are the items that + // CCK will store in the widget definition and they + // will be available in the $field['widget'] array. + // This should match the items defined in 'form' above. + case 'save': + return array('size'); + } +} + +/** + * Implementation of hook_widget(). + * + * Attach a single form element to the form. + * + * CCK core fields only add a stub element and builds + * the complete item in #process so reusable elements + * created by hook_elements can be plugged into any + * module that provides valid $field information. + * + * Custom widgets that don't care about using hook_elements + * can be built out completely at this time. + * + * If there are multiple values for this field and CCK is + * handling multiple values, the content module will call + * this function as many times as needed. + * + * @param $form + * the entire form array, + * $form['#node'] holds node information + * @param $form_state + * the form_state, + * $form_state['values'][$field['field_name']] + * holds the field's form values. + * @param $field + * the field array + * @param $items + * array of default values for this field + * @param $delta + * the order of this item in the array of + * subelements (0, 1, 2, etc) + * + * @return + * the form item for a single element for this field + */ +function pidfield_widget(&$form, &$form_state, $field, $items, $delta = 0) { + + $element['value'] = array( + '#type' => 'textfield', + '#title' => $field['widget']['label'], + '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL, + '#autocomplete_path' => $element['#autocomplete_path'], + '#size' => !empty($field['widget']['size']) ? $field['widget']['size'] : 60, + '#attributes' => array('class' => 'pidfield'), + '#maxlength' => !empty($field['max_length']) ? $field['max_length'] : NULL, + ); + + // Used so that hook_field('validate') knows where to + // flag an error in deeply nested forms. + if (empty($form['#parents'])) { + $form['#parents'] = array(); + } + $element['_error_element'] = array( + '#type' => 'value', + '#value' => implode('][', array_merge($form['#parents'], array('value'))), + ); + + return $element; +} + +function get_node_references_for_fedora_item($item) { + $result = db_query("SELECT * + FROM {content_node_field} nf + INNER JOIN {content_node_field_instance} ni ON nf.field_name = ni.field_name + WHERE nf.type = 'pidfield'"); + while ($field = db_fetch_array($result)) { + + + $db_info = content_database_info($field); + + + + + + $ids = db_query("SELECT nid FROM {". $db_info['table'] ."} WHERE ". $field['field_name'] ."_value=\"". $item->pid."\""); + + $results = array(); + while ($data = db_fetch_object($ids)) { + //$additions[] = node_load($data->vid); + + $results[] = $data->nid; + + //$referred_node = node_load(array('nid'=>$data->nid) ); + + } + return $results; + } + +} + +function fedora_pidfield_redirect_to_node($item) { + $node_references = get_node_references_for_fedora_item($item); + if (!empty($node_references)) { + if (strstr( drupal_get_destination(), urlencode('fedora/repository'))) { + drupal_goto(drupal_get_path_alias("node/".$node_references[0])); + } + } +} \ No newline at end of file diff --git a/plugins/slide_viewer.inc b/plugins/slide_viewer.inc new file mode 100644 index 00000000..7b14073d --- /dev/null +++ b/plugins/slide_viewer.inc @@ -0,0 +1,63 @@ +pid = $pid; + } + + function showJPG() { + module_load_include('inc', 'fedora_repository', 'plugins/tagging_form'); + module_load_include('inc', 'fedora_repository', 'plugins/ShowStreamsInFieldSets'); + global $base_url; + + $tabset = array(); + + $tabset['my_tabset'] = array( + '#type' => 'tabset', + ); + + global $user; + $qs = ''; + if ($user->uid != 0) { +// $qs = '?uid=' . base64_encode($user->name . ':' . $user->sid); + $qs = '?uid=' . base64_encode($user->name . ':' . $user->pass); + } + + $viewer_url = variable_get('fedora_base_url', 'http://localhost:8080/fedora') . '/get/'. $this->pid . '/ilives:viewerSdef/getViewer'. $qs; + $html = ''; + + drupal_add_css(path_to_theme() . '/header-viewer.css', 'theme'); + + $tabset['my_tabset']['second_tab'] = array( +// $collection_fieldset = array ( + '#type' => 'tabpage', + '#title' => t('Full-size'), + '#content' => $html); + + $tabset['my_tabset']['first_tab'] = array( + // #type and #title are the minimum requirements. + '#type' => 'tabpage', + '#title' => t('View'), + // This will be the content of the tab. + '#content' => ''. '

      '. drupal_get_form('fedora_repository_image_tagging_form', $this->pid) . '

      ', + ); + + $ssifs = new ShowStreamsInFieldSets($this->pid); + $tabset['my_tabset']['third_tab'] = array( + '#type' => 'tabpage', + '#title' => t('Description'), + '#content' => $ssifs->showQdc(), + ); + // Render the tabset. + return tabs_render($tabset); + + return theme('fieldset', $collection_fieldset); +// . (user_access('add fedora datastreams') ? drupal_get_form('fedora_ilives_image_tagging_form', $this->pid) : ''); + } +} diff --git a/plugins/tagging_form.inc b/plugins/tagging_form.inc new file mode 100644 index 00000000..2b374b3c --- /dev/null +++ b/plugins/tagging_form.inc @@ -0,0 +1,122 @@ +tags)) { + $output = "
        "; + foreach ($tags->tags as $tag) { + $output .= "
      • "; + } + return $output; +} + +function fedora_repository_image_tagging_form($form_state, $pid) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'api/dublin_core'); + module_load_include('inc', 'fedora_repository', 'api/tagging'); + global $base_url; + + if (!empty($form_state['post']['pid'])) { + $pid = $form_state['post']['pid']; + } + $obj = new Fedora_Item($pid); + $form['tags-wrapper'] = array( + '#tree' => FALSE, + '#prefix' => '
        ', + '#suffix' => '
        ', + ); + $form['tags-wrapper']['tags'] = array( + '#prefix' => '
          ', + '#suffix' => '
        ', + ); + + // Add the current tags to the form. + $tagset = new TagSet($obj); + foreach ($tagset->tags as $tag) { + $form['tags-wrapper']['tags'][$tag['name']] = array( + '#prefix' => '
      • ', + '#suffix' => '
      • ', + ); + $form['tags-wrapper']['tags'][$tag['name']]['tag'] = array( + '#prefix' => '', + '#value' => $tag['name'], + '#suffix' => '', + ); + if (user_access('modify fedora datastreams') || user_access('add fedora tags')) { + // Delete button for each existing tag. + $form['tags-wrapper']['tags'][$tag['name']]['delete'] = array( + '#type' => 'imagebutton', + '#image' => $base_url . '/'. drupal_get_path('module', 'fedora_repository') . '/images/remove_icon.png', + '#default_value' => $tag['name'], + '#title' => t('Delete this tag'), + ); + } + } + if (user_access('modify fedora datastreams') || user_access('add fedora tags')) { + $form['tags-wrapper']['addtag'] = array( + '#type' => 'textfield', + '#title' => t('New Tag'), + '#size' => 30, + '#description' => t('Add a subject tag to this item.'), + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Add Tag', + '#name' => 'add_tag', + ); + } + $form['pid'] = array( + '#type' => 'hidden', + '#value' => (!empty($form_state['pid']) ? $form_state['pid'] : $pid), + ); + if (empty($form_state['pid'])) { + $form_state['pid'] = $pid; + } + + return $form; +} + +function hook_imagebutton_process($form) { + $form['op_x'] = array( + '#name' => $form['#name'] . '_x', + '#input' => TRUE, + '#button_type' => 'submit', + '#form_submitted' => TRUE, + ); + return $form; +} + +function fedora_repository_image_tagging_form_submit($form, &$form_state) { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'api/tagging'); + global $user; + + $item = new Fedora_Item($form_state['values']['pid']); + $tagset = new TagSet($item); + $addtag = trim($_POST['addtag']); + if (!empty($addtag)) { + array_push($tagset->tags, array('name' => $form_state['values']['addtag'], 'creator' => $user->name)); + } + elseif (!empty($form_state['values']['delete'])) { + for ( $i=0; $i < count($tagset->tags); $i++ ) { + if ($tagset->tags[$i]['name'] == $form_state['clicked_button']['#value']) { + unset($tagset->tags[$i]); + } + } + } + $_SESSION['fedora_tagged_image']['pid'] = $form_state['values']['pid']; + $tagset->save(); +} + diff --git a/policies/noObjectEditPolicy.xml b/policies/noObjectEditPolicy.xml new file mode 100644 index 00000000..992a121f --- /dev/null +++ b/policies/noObjectEditPolicy.xml @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + Allows anyone to view the objects datastreams but only roles and users listed below can edit. + + + + + + + + + + + + + + + + + + urn:fedora:names:fedora:2.1:action:id-ingest + + + + + + urn:fedora:names:fedora:2.1:action:id-modifyDatastreamByReference + + + + + + urn:fedora:names:fedora:2.1:action:id-modifyDatastreamByValue + + + + + + urn:fedora:names:fedora:2.1:action:id-modifyDisseminator + + + + + + urn:fedora:names:fedora:2.1:action:id-modifyDisseminator + + + + + + urn:fedora:names:fedora:2.1:action:id-purgeObject + + + + + + urn:fedora:names:fedora:2.1:action:id-purgeDatastream + + + + + + urn:fedora:names:fedora:2.1:action:id-purgeDisseminator + + + + + + urn:fedora:names:fedora:2.1:action:id-setDatastreamState + + + + + + urn:fedora:names:fedora:2.1:action:id-setDisseminatorState + + + + + + urn:fedora:names:fedora:2.1:action:id-setDatastreamVersionable + + + + + + urn:fedora:names:fedora:2.1:action:id-addDatastream + + + + + + urn:fedora:names:fedora:2.1:action:id-addDisseminator + + + + + + + + + + + + + + + + + + + + + + + + + + + administrator + + + + + + fedoraAdmin + + + + + + + + + + + + + + + + + + + diff --git a/policies/viewANDeditbyrole.xml b/policies/viewANDeditbyrole.xml new file mode 100644 index 00000000..ce75b2f5 --- /dev/null +++ b/policies/viewANDeditbyrole.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + This policy will allow users with the roles listed below to view and edit objects with this policy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + administrator + + + + + + fedoraAdmin + + + + + + + + + + + + + + + + + diff --git a/searchTerms.xml b/searchTerms.xml new file mode 100644 index 00000000..6ab8ac65 --- /dev/null +++ b/searchTerms.xml @@ -0,0 +1,79 @@ + + + + dc.description + 1000 + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.contributor + dc.contributor + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.format + dc.format + + + dc.source + dc.source + + + dc.coverage + dc.coverage + + + dc.relation + dc.relation + + + dc.type + dc.type + + + dsm.text + Full Text + + + + + + + + + + + diff --git a/solrSearchTerms.xml b/solrSearchTerms.xml new file mode 100644 index 00000000..6ab8ac65 --- /dev/null +++ b/solrSearchTerms.xml @@ -0,0 +1,79 @@ + + + + dc.description + 1000 + + dc.title + dc.title + + + dc.creator + dc.creator + + + dc.description + dc.description + + + dc.date + dc.date + + + dc.contributor + dc.contributor + + + dc.identifier + dc.identifier + + + dc.language + dc.language + + + dc.publisher + dc.publisher + + + dc.rights + dc.rights + + + dc.subject + dc.subject + + + dc.format + dc.format + + + dc.source + dc.source + + + dc.coverage + dc.coverage + + + dc.relation + dc.relation + + + dc.type + dc.type + + + dsm.text + Full Text + + + + + + + + + + + diff --git a/tests/README_TESTING.txt b/tests/README_TESTING.txt new file mode 100644 index 00000000..18db5ba8 --- /dev/null +++ b/tests/README_TESTING.txt @@ -0,0 +1,42 @@ +There are a few things to set up to get the Simpletests to run properly. + +Fedora Installation + +The test sets up the fedora_repository module with the default server settings. +This means it will expect a Fedora server to be running on localhost:8080 +with the usual defaults. The tests also expect the Islandora demo objects, i.e., +islandora:top, islandora:demos collections, etc. to be installed. (Go to +Administer -> Site Configuration -> Fedora Colleciton List and click the Install +Demos tab and follow the instructions.) + + +Fedora User + +Add the following entry to the fedora users file located at +$FEDORA_HOME/server/config/fedora-users.xml: + + + + administrator + + + +If you look in the fedora_repository.test file we see that we are creating +a user with a password set to 'simpletestpass'. Fedora requires the hashed +version of this password to do a servlet filter-based authentication. + +Drupal Module Setup + +The Drupal Simpletest module http://drupal.org/project/simpletest requires a +patch be applied to your Drupal core. See the module's README file for +instructions. + +To run the tests go to Administration -> Site Building -> Testing, expand +Fedora Repository and check Fedora Repository, leaving Fedora API unchecked +unless you want to test that as well. The tests as they are right now should +return with 0 Fails and 0 Exceptions. If you add new code or functionality +to the module it is your responsibility to add corresponding tests so that other +people making future changes to the codebase don't break your additions. + +See the SimpleTest Tutorial on Drupal.org here http://drupal.org/simpletest-tutorial +for a good introduction to creating Simpletests. \ No newline at end of file diff --git a/tests/fedora_repository.test b/tests/fedora_repository.test new file mode 100644 index 00000000..216ff4e7 --- /dev/null +++ b/tests/fedora_repository.test @@ -0,0 +1,153 @@ + 'Fedora Repository', + 'description' => t('The Fedora repository content models.'), + 'group' => t('fedora repository'), + ); + } + + function setUp() { + parent::setUp('fedora_repository'); + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + + // Create and login user. + $repository_user = $this->drupalCreateFedoraUser(array('add fedora datastreams', + 'edit fedora meta data', + 'edit tags datastream', + 'ingest new fedora objects', + 'purge objects and datastreams', + 'view fedora collection')); + + + $this->drupalLogin($repository_user); + + } + + /** + * Add an item based on a content model. Initially we will assume that the repository + * will be populated with the default content models and collections that are + * created from the admin settings -> Install Demos page. + * + */ + public function testIngest() { + // Check that the 'Strict PDF' content model exists in the repository. + //$pdf_cm = new Fedora_Item('islandora:strict_pdf'); + + $pid_list = array(); + // Create a collection for ingesting PDF content model objects. + + //$this->drupalGet('fedora/ingestObject/islandora:top/Islandora%20Top-Level%20Collection'); + $ingest_form = array(); + $ingest_form['models'] = 'islandora:collectionCModel/ISLANDORACM'; + + $this->drupalPost('fedora/ingestObject/islandora:top/Islandora%20Top-Level%20Collection', $ingest_form, 'Next'); + + // Add a sample PDF object via the web ingest form. + // Required fields are file location, dc:title and dc:description + $ingest_form_step_2 = array(); + $ingest_form_step_2['dc:title'] = $this->randomName(32); + $ingest_form_step_2['dc:description'] = $this->randomName(256); + + $ingest_form_step_2['files[ingest-file-location]'] = realpath(drupal_get_path('module', 'fedora_repository') . '/tests/test_files/lorem_ipsum.pdf'); + $this->drupalPost(NULL, $ingest_form_step_2, 'Ingest'); + $this->assertText('mimetype (application/pdf) is not associated with this Content Model', 'PDF mime type not accepted in collection content model.', 'message'); + + $this->outputScreenContents('Initial ingest form submit step 2', 'fedora_repository'); + + // Now try ingesting a proper collection policy. + $ingest_form = array(); + $ingest_form['models'] = 'islandora:collectionCModel/ISLANDORACM'; + + $this->drupalPost('fedora/ingestObject/islandora:top/Islandora%20Top-Level%20Collection', $ingest_form, 'Next'); + // Required fields are file location, dc:title and dc:description + $ingest_form_step_2 = array(); + $ingest_form_step_2['dc:title'] = $this->randomName(32); + $ingest_form_step_2['dc:description'] = $this->randomName(256); + $ingest_form_step_2['files[ingest-file-location]'] = realpath(drupal_get_path('module', 'fedora_repository') . '/collection_policies/PDF-COLLECTION POLICY.xml'); + $this->drupalPost(NULL, $ingest_form_step_2, 'Ingest'); + //$this->outputScreenContents('Initial ingest form submit step 2 - PDF collection', 'fedora_repository'); + $this->assertPattern('/Item .* created successfully./', "Verified item created."); + + $pid = $this->getIngestedPid(); + $pid_list[] = $pid; + $this->pass('Now attempting to ingest a PDF into the new collection.'); + // Now try ingesting a PDF + $ingest_form = array(); + $ingest_form['models'] = 'islandora:strict_pdf/ISLANDORACM'; + $this->drupalPost("fedora/ingestObject/$pid/", $ingest_form, 'Next'); + // Required fields are file location, dc:title and dc:description + $ingest_form_step_2 = array(); + $ingest_form_step_2['dc:title'] = "Lorem Ipsum"; + $ingest_form_step_2['dc:description'] = $this->randomName(256); + $ingest_form_step_2['files[ingest-file-location]'] = realpath(drupal_get_path('module', 'fedora_repository') . '/tests/test_files/lorem_ipsum.pdf'); + $this->drupalPost(NULL, $ingest_form_step_2, 'Ingest'); + $pid = $this->getIngestedPid(); + $pid_list[] = $pid; + if (!empty($pid)) { + $this->pass("Successfully ingested PDF object $pid."); + } + $this->cleanUpRepository($pid_list); + } + + private function cleanUpRepository($pid_list = array()) { + $this->pass("This is the PID list to purge: ". implode(", ", $pid_list) ); + foreach ($pid_list as $pid) { + $this->drupalPost("fedora/repository/purgeObject/$pid", array(), 'Purge'); + } + } + + private function getIngestedPid() { + $subject = $this->drupalGetContent(); + $pattern = '/">(.*)<\/a> created successfully./'; + $matches = array(); + $res = preg_match($pattern, $subject, $matches); + return $matches[1]; + } + + private function outputScreenContents($description, $basename) { + // This is a hack to get a directory that won't be cleaned up by SimpleTest. + $file_dir = file_directory_path() . '../simpletest_output_pages'; + if (!is_dir($file_dir)) { + mkdir($file_dir, 0777, TRUE); + } + $output_path = "$file_dir/$basename.". $this->randomName(10) . '.html'; + $rv = file_put_contents($output_path, $this->drupalGetContent()); + $this->pass("$description: Contents of result page are ". l('here', $output_path)); + } + + protected function drupalCreateFedoraUser($permissions = array('access comments', 'access content', 'post comments', 'post comments without approval')) { + // Create a role with the given permission set. + if (!($rid = $this->drupalCreateRole($permissions))) { + return FALSE; + } + + // Create a user assigned to that role. + $edit = array(); + $edit['name'] = 'simpletestuser'; + $edit['mail'] = $edit['name'] . '@example.com'; + $edit['roles'] = array($rid => $rid); + $edit['pass'] = 'simpletestpass'; + $edit['status'] = 1; + + $account = user_save('', $edit); + + $this->assertTrue(!empty($account->uid), t('User created with name %name and pass %pass', array('%name' => $edit['name'], '%pass' => $edit['pass'])), t('User login')); + if (empty($account->uid)) { + return FALSE; + } + + // Add the raw password so that we can log in as this user. + $account->pass_raw = $edit['pass']; + return $account; + } +} diff --git a/tests/test_files/CCITT_5.jp2 b/tests/test_files/CCITT_5.jp2 new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_files/CCITT_5.tiff b/tests/test_files/CCITT_5.tiff new file mode 100644 index 00000000..d52e660d Binary files /dev/null and b/tests/test_files/CCITT_5.tiff differ diff --git a/tests/test_files/CCITT_5_uncompressed.jp2 b/tests/test_files/CCITT_5_uncompressed.jp2 new file mode 100644 index 00000000..32cabf6e Binary files /dev/null and b/tests/test_files/CCITT_5_uncompressed.jp2 differ diff --git a/tests/test_files/CCITT_5_uncompressed.tiff b/tests/test_files/CCITT_5_uncompressed.tiff new file mode 100644 index 00000000..e373aec0 Binary files /dev/null and b/tests/test_files/CCITT_5_uncompressed.tiff differ diff --git a/tests/test_files/lorem_ipsum.pdf b/tests/test_files/lorem_ipsum.pdf new file mode 100644 index 00000000..7d2f1f9e Binary files /dev/null and b/tests/test_files/lorem_ipsum.pdf differ diff --git a/workflow_client/islandora_workflow_client.info b/workflow_client/islandora_workflow_client.info new file mode 100644 index 00000000..3501a8c3 --- /dev/null +++ b/workflow_client/islandora_workflow_client.info @@ -0,0 +1,7 @@ +; $Id$ +name = Islandora Workflow Client +dependencies[] = fedora_repository +description = A STOMP client that listens for JMS messages from Fedora. On receiving a message, it will get the workflow datastream from the updated object and determine if any processes need to be run. Processes must be registered as plugins to this module for them to be updated. Ensure that the apim messages are configured as a QUEUE so that the messages persist when the workflow client is not running. +package = Fedora Repository +version = 6.1dev +core = 6.x diff --git a/workflow_client/islandora_workflow_client.module b/workflow_client/islandora_workflow_client.module new file mode 100644 index 00000000..5ab2be70 --- /dev/null +++ b/workflow_client/islandora_workflow_client.module @@ -0,0 +1,345 @@ + 'Islandora Workflow Client', + 'description' => 'Manage Islandora Workflows', + 'page callback' => 'islandora_workflow_client_manage', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_NORMAL_ITEM + ); + + return $items; +} + + +function islandora_workflow_client_search_submit($form,&$form_state) +{ + if (trim($form['collection_pid']['#value']) !== '') + { + drupal_goto('admin/settings/workflow_client/'.$form['process_name']['#value'].'/'.$form['collection_pid']['#value']); + } else + { + drupal_goto('admin/settings/workflow_client/'.$form['process_name']['#value']); + } +} + +function islandora_workflow_client_search() +{ + module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); + + $form = array(); + $form['process_name'] = array( + '#type' => 'textfield', + '#title' => t('Search by Process Name'), + '#description' => t('Returns a list of objects that match the process name(s) entered. Separate multiple names by spaces.'), + ); + + $form['collection_pid'] = array( + '#type' => 'textfield', + '#title' => t('Search by Collection PID'), + '#description' => t('Returns only objects that match the also match the collection pid(s) entered. Separate multiple PIDs by spaces.'), + ); + + + $form['submit'] = array('#type' => 'submit', '#value' => t('Search')); + + return $form; +} + +function islandora_workflow_client_manage($terms = null, $collection = null, $queue= null, $queueProcess = null) +{ + if ($collection == 'none') + { + $collection = null; + } + + $output = ''; + if (trim($terms) != '') + { + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'islandora_workflow_client', 'workflow'); + + if (module_load_include('php', 'islandora_solr_search', 'Solr/Service') === FALSE) + { + drupal_set_message(t('Error: Islandora_solr_search module is required to search by process.')); + } else + { + $host = variable_get('islandora_solr_search_block_host','localhost'); + $port = variable_get('islandora_solr_search_block_port','8080'); + $appName = variable_get('islandora_solr_search_block_app_name','solr'); + $solr = new Apache_Solr_Service($host, $port, '/'.$appName.'/'); + + try + { + if ($solr->ping()) + { + + $q = preg_split('/\s+/',$terms); + foreach ($q as $key=>$bit) + { + $q[$key]='workflow_process_t:'.htmlentities($bit); + } + $query = join(' OR ',$q); + + if (trim($collection) != '') + { + $q= preg_split('/\s/',$collection); + foreach ($q as $key=>$bit) + { + $q[$key]='related_item_identifier_t:'.htmlentities(preg_replace('/\:/','/',$bit)); + } + $query .= ' AND ('. join(' OR ',$q).')'; + } + + $results = $solr->search($query,0,100); + + $pids=array(); + $processes = array(); + if ($results->response->numFound ==0 ) + { + drupal_set_message(t('No processes found.')); + } else + { + foreach($results->response->docs as $doc) + { + $id = preg_replace('/\//',':',$doc->id); + $collection_pid = preg_replace('/\//',':',$doc->related_item_identifier_t); + + $pids[]=$id; + if (!is_array($doc->workflow_process_t)) + { + if (!is_array($processes[$doc->workflow_process_t])) + $processes[$doc->workflow_process_t]=array($id); + else + $processes[$doc->workflow_process_t][]=$id; + } else + { + foreach ($doc->workflow_process_t as $process) + { + if (!is_array($processes[$process])) + $processes[$process]=array($id); + else + $processes[$process][]=$id; + } + } + } + } + + $workflows=array(); + foreach ($pids as $pid) + { + $workflows[$pid]=Workflow::loadFromObject($pid); + } + + if (count($processes) > 0) + { + $errors=array(); + $headers = array('Process Name', '# Waiting to Run', '# Completed', '# Errors', 'Action'); + $rows=array(); + foreach ($processes as $name=>$pids) + { + $errCount = 0; + $waitCount =0; + $completeCount = 0; + foreach ($pids as $pid) + { + + if ( isset($workflows[$pid]) && $workflows[$pid] !== false ) + { + $procs = $workflows[$pid]->getProcesses(); + $updated = FALSE; + foreach ($procs as $id=>$n) + { + + if ($name == $n) + { + $proc=$workflows[$pid]->getProcess($id); + if (($queue == 'queue'|| ($queue =='errorQueue' && $proc['state'] == 'error')) && $queueProcess == $n) + { + $workflows[$pid]->setState($id,'waiting'); + $updated=TRUE; + } + + + switch ($proc['state']) + { + case 'completed': + $completeCount++; + break; + case 'waiting': + $waitCount++; + break; + case 'error': + $errCount++; + $errors[]=$proc; + break; + } + } + } + if ($updated) + { + $workflows[$pid]->saveToFedora(); + } + } + + } + $rows[]= array($name, $waitCount,$completeCount,$errCount,l('Add All to Queue','admin/settings/workflow_client/'.$terms.'/'.(trim($collection)==''?'none':$collection).'/queue/'.$name).'
        '.l('Add Errors to Queue','admin/settings/workflow_client/'.$terms.'/'.(trim($collection)==''?'none':$collection).'/errorQueue/'.$name)); + } + + if ($queue == 'queue' || $queue == 'errorQueue') + { + drupal_goto('admin/settings/workflow_client/'.$terms.(trim($collection)==''?'/'.$collection:'')); + } + + $output.='

        Search for "'.$terms.'" '.(trim($collection)!=''?'in collection(s) "'.$collection.'" ':'').'returned Processes:

        '; + $output.=theme('table',$headers,$rows); + + if (count ($errors) > 0) + { + $output.='

        Found Errors

        '; + foreach ($errors as $proc) + { + $output.='Process id: '.$proc['id'].'
        '; + $output.='Process name: '.$proc['name'].'
        '; + $output.='# Attempts: '.$proc['attempts'].'
        '; + $output.='Timestamp: '.$proc['timestamp'].'
        '; + $output.='Message: '.$proc['message'].'
        '; + } + } + } + + + } else + { + drupal_set_message(t('Unable to connect to Solr at "%solr" for solr_index process on "%pid".',array('%pid'=>$pid,'%solr'=>$host.':'.$port.'/'.$appName.'/'))); + + } + } catch (Exception $e) + { + drupal_set_message(t('Caught exception from Solr at %solr for solr_index process on "%pid": %msg', array('%pid'=>$pid,'%solr'=>$host.':'.$port.'/'.$appName.'/','%msg'=>$e->getMessage()))); + } + } + + } + $output .= drupal_get_form('islandora_workflow_client_search'); + + return $output; +} + + +function islandora_workflow_client_cron() +{ + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'islandora_workflow_client', 'workflow'); + ob_start(); + echo 'workflow client running'."\n"; + $con = new Stomp(variable_get('fedora_stomp_url', 'tcp://localhost:61613')); + $queue='/queue/fedora.apim.update'; + $con->subscribe($queue); + $messagesToSend=array(); + for ($i=0;$i<50;$i++) { + $msg = $con->readFrame(); + + if ($msg != null) { + $con->ack($msg); + + $xmlobj = simplexml_load_string($msg->body); + $dsid=null; $pid=null; + + + $logMessage = ''; + foreach ($xmlobj->category as $cat) { + switch ($cat['scheme']) { + case 'fedora-types:dsID': + $dsid=(string)$cat['term']; + break; + case 'fedora-types:pid': + $pid=(string)$cat['term']; + break; + case 'fedora-types:logMessage': + $logMessage=(string)$cat['term']; + break; + } + } + echo $pid.' '.$xmlobj->title ."\n"; + if ($pid !== NULL && $xmlobj->title =='purgeObject') { // delete the object from the solr index. + if (module_load_include('php', 'islandora_solr_search', 'Solr/Service') === FAlSE) { + echo t('Unable to load Solr/Service from islandora_solr_search module on "%pid" for process solr_index.', array('%pid' => $pid)).'
        '; + } else { + $host = variable_get('islandora_solr_search_block_host', 'localhost'); + $port = variable_get('islandora_solr_search_block_port', '8080'); + $appName = variable_get('islandora_solr_search_block_app_name', 'solr'); + $solr = new Apache_Solr_Service($host, $port, '/'. $appName .'/'); + + try { + if ($solr->ping()) { + $solr->deleteById($pid); + $solr->commit(); + $solr->optimize(); + } else { + echo t('Unable to connect to Solr at "%solr" for solr_index process on "%pid".', array('%pid' => $pid, '%solr' => $host .':'. $port . '/'. $appName .'/')).'
        '; + } + } + catch (Exception $e) { + echo t('Caught exception from Solr at %solr for solr_index process on "%pid": %msg', array('%pid' => $pid, '%solr' => $host .':'. $port .'/'. $appName .'/', '%msg' => $e->getMessage())).'
        '; + } + } + + } else if ($pid !== NULL && ($wf= Workflow::loadFromObject($pid)) !== FALSE) { + + if (!$wf->validate()) { +// var_dump(Workflow::$errors); + $con->send($queue,$msg->body); + + } else { + + $saveFlag=FALSE; + if ($dsid !== NULL) { + $saveFlag = $wf->resetDependancies($dsid,$logMessage); + } + $procs = $wf->getReadyProcesses(); + + foreach ($procs as $id=>$proc) { + + if (module_load_include('inc','islandora_workflow_client','plugins/'.$proc)!==FALSE && class_exists($proc)) + { + $procClass = new $proc($wf,$id); + $procClass->run(); + $saveFlag = true; + } + } + + // saves the workflow. Note that this will also triger a JMS message so if there are still things + // to do in the workflow, then it will be put back on the queue. + if ($saveFlag) + { +// echo htmlentities($wf->dumpXml()); exit(); + $wf->saveToFedora(); + } else if (count($wf->getReadyProcesses()) > 0) { + // If there is still more to do and we dont need to save the workflow datastream, then + // that means there is a process that does not have a corresponding plugin (perhaps it is handled + // by another client?), so put it back on the queue. + + $messagesToSend[] = $msg->body; + } + } + } + } else { + echo '.'; + } + } + + // Messages to send are sent out after we're done + // so that we dont try and process messages we put back on the queue immediately. + foreach ($messagesToSend as $msg) { + $con->send($queue,$msg); + } + + $dump=ob_get_contents(); + ob_end_clean(); + if (trim($dump) !== '') { + watchdog('workflow','
        '.$dump.'
        ',array(),WATCHDOG_NOTICE); + } +} diff --git a/workflow_client/plugins/create_jp2.inc b/workflow_client/plugins/create_jp2.inc new file mode 100644 index 00000000..f10d7b72 --- /dev/null +++ b/workflow_client/plugins/create_jp2.inc @@ -0,0 +1,83 @@ + 0) { + $this->setMessage(t('Missing parameter(s) "%params" for create_jp2 process on "%pid"', array('%params' => join(',', $missing_params), '%pid' => $pid))); + return FALSE; + } + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + + $item = new fedora_item($pid); + $dslist = $item->get_datastreams_list_as_array(); + if (!isset($dslist[$parameters['dsid']])) { + $this->setMessage(t('Datastream "%dsid" could not be found for create_jp2 process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + + $ds = $dslist[$parameters['dsid']]; + $file = '/tmp/'. $ds['label']; + + $objectHelper = new ObjectHelper(); + $objectHelper->makeObject($pid, $parameters['dsid'], FALSE, NULL, $file); + + $returnValue = TRUE; + $output=array(); + $command='/usr/local/kakadu/kdu_compress -i "'. $file . '" -o "'. $file .'.jp2" -rate 0.5 Clayers=1 Clevels=7 "Cprecincts={256,256},{256,256},{256,256},{128,128},{128,128},{64,64},{64,64},{32,32},{16,16}" "Corder=RPCL" "ORGgen_plt=yes" "ORGtparts=R" "Cblk={32,32}" Cuse_sop=yes -num_threads 2'; + exec($command, $output, $returnValue); + + if (!file_exists($file .'.jp2')) { + $this->setMessage('command failed: '. htmlentities($command ."\n" . join("\n", $output) ."\n return value: $returnValue")); + @unlink($file); + return FALSE; + } + + $returnValue = TRUE; + $output=array(); + $command='/usr/local/kakadu/kdu_compress -i "'. $file . '" -o "'. $file .'_lossless.jp2" -rate -,0.5 Clayers=2 Creversible=yes Clevels=8 "Cprecincts={256,256},{256,256},{128,128}" Corder="RPCL" ORGgen_plt="yes" ORGtparts="R" Cblk="{32,32} -num_threads 2"'; + exec($command, $output, $returnValue); + + if (!file_exists($file .'_lossless.jp2')) { + $this->setMessage('command failed: '. htmlentities($command ."\n". join("\n", $output) ."\n return value: $returnValue")); + @unlink($file); + return FALSE; + } + + if (file_exists($file.'.jp2') && file_exists($file.'_lossless.jp2')) { + + if (isset($dslist['JP2'])) { + $item->purge_datastream('JP2'); + } + if (isset($dslist['LOSSLESS_JP2'])) { + $item->purge_datastream('LOSSLESS_JP2'); + } + + $ret = $item->add_datastream_from_file($file .'.jp2', 'JP2' , $ds['label'] .'.jp2'); + $ret = $ret && $item->add_datastream_from_file($file .'_lossless.jp2', 'LOSSLESS_JP2', $ds['label'] .'_lossless.jp2'); + + + @unlink($file); + @unlink($file .'.jp2'); + @unlink($file .'_lossless.jp2'); + + if (!$ret) { + $this->setMessage(t('Unable to add datastream "%dsid" to "%pid".', array('%dsid' => $dest_ds, '%pid' => $pid))); + return FALSE; + } + + return TRUE; + + } + } +} diff --git a/workflow_client/plugins/image_resize.inc b/workflow_client/plugins/image_resize.inc new file mode 100644 index 00000000..9bbae454 --- /dev/null +++ b/workflow_client/plugins/image_resize.inc @@ -0,0 +1,69 @@ + 0) { + $this->setMessage(t('Missing parameter(s) "%params" for image_resize process on "%pid"', array('%params' => join(',', $missing_params), '%pid' => $pid))); + return FALSE; + } + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + + $item = new fedora_item($pid); + $dslist = $item->get_datastreams_list_as_array(); + if (!isset($dslist[$parameters['dsid']])) { + $this->setMessage(t('Datastream "%dsid" could not be found for image_resize process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + + $ds = $dslist[$parameters['dsid']]; + $file = '/tmp/'. $ds['label']; + $dest_ds = isset($parameters['dest_ds']) ? $parameters['dest_ds'] : 'TN'; + + $objectHelper = new ObjectHelper(); + $objectHelper->makeObject($pid, $parameters['dsid'], FALSE, NULL, $file); + + + $system = getenv('System'); + $file_suffix = '_'. $dest_ds . '.'. $parameters['file_ext']; + $returnValue = TRUE; + $output = array(); + + $command = 'convert -resize '. $parameters['width'] .' -quality 85 '. $file . '[0] -strip '. $file . $file_suffix .' 2>&1 &'; + exec($command, $output, $returnValue); + + if (!file_exists($file . $file_suffix)) { + $this->setMessage('command failed: '. htmlentities($command ."\n". join("\n", $output) ."\n return value: $returnValue")); + @unlink($file); + return FALSE; + } + + if ($returnValue == '0') { + + if (isset($dslist[$dest_ds])) { + $item->purge_datastream($dest_ds); + } + $ret = $item->add_datastream_from_file($file . $file_suffix, $dest_ds, $ds['label'] . $file_suffix); + @unlink($file); + @unlink($file . $file_suffix); + + if (!$ret) { + $this->setMessage(t('Unable to add datastream "%dsid" to "%pid".', array('%dsid' => $dest_ds, '%pid' => $pid))); + return FALSE; + } + + return TRUE; + + } + } +} diff --git a/workflow_client/plugins/jhove.inc b/workflow_client/plugins/jhove.inc new file mode 100644 index 00000000..5f97cfa4 --- /dev/null +++ b/workflow_client/plugins/jhove.inc @@ -0,0 +1,82 @@ + 0) { + $this->setMessage(t('Missing parameter(s) "%params" for image_resize process on "%pid"', array('%params' => join(',', $missing_params), '%pid' => $pid))); + return FALSE; + } + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + module_load_include('inc', 'fedora_repository', 'ObjectHelper'); + + $item = new fedora_item($pid); + $dslist = $item->get_datastreams_list_as_array(); + if (!isset($dslist[$parameters['dsid']])) { + $this->setMessage(t('Datastream "%dsid" could not be found for image_resize process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + + $ds = $dslist[$parameters['dsid']]; + $file = '/tmp/'. $ds['label']; + $dest_ds = isset($parameters['dest_ds']) ? $parameters['dest_ds'] : 'JHOVE'; + + $objectHelper = new ObjectHelper(); + $objectHelper->makeObject($pid, $parameters['dsid'], FALSE, NULL, $file); + + if (!file_exists($file)) { + $this->setMessage('couldnt get datastream '. $parameters['dsid'] .' as '. $file); + return FALSE; + } + + $system = getenv('System'); + $file_suffix = '.jhove.xml'; + $returnValue=TRUE; + $output=array(); + + $command = '/usr/local/jhove/jhove -c /usr/local/jhove/conf/jhove.conf '. $file . ' -h xml -o '. $file . $file_suffix; + exec($command, $output, $returnValue); + + if (!file_exists($file . $file_suffix)) { + $this->setMessage('command failed: '. htmlentities($command ."\n" . join("\n", $output) ."\n return value: $returnValue")); + @unlink($file); + return FALSE; + } + + if ($returnValue == '0') { + if (isset($dslist[$dest_ds])) { + $item->purge_datastream($dest_ds); + } + + $xmlDoc = new DOMDocument(); + $xmlDoc->load($file . $file_suffix); + + $xslDoc = new DOMDocument(); + $xslDoc->load(drupal_get_path('module', 'islandora_workflow_client') .'/xsl/jhove-mix.xsl'); + $proc = new XSLTProcessor(); + $proc->importStylesheet($xslDoc); + + file_put_contents('/tmp/mix.xml', $proc->transformToXML($xmlDoc)); + $ret = $item->add_datastream_from_string($proc->transformToXML($xmlDoc), $dest_ds, $ds['label'] . $file_suffix, 'text/xml', 'X','Added by workflow process jhove.'); + @unlink($file); + @unlink($file . $file_suffix); + + if (!$ret) { + $this->setMessage(t('Unable to add datastream "%dsid" to "%pid".', array('%dsid' => $dest_ds, '%pid' => $pid))); + return FALSE; + } + + return TRUE; + + } + } +} diff --git a/workflow_client/plugins/mods_extend.inc b/workflow_client/plugins/mods_extend.inc new file mode 100644 index 00000000..caf13aff --- /dev/null +++ b/workflow_client/plugins/mods_extend.inc @@ -0,0 +1,123 @@ + 0) { + $this->setMessage(t('Missing parameter(s) "%params" for mods_extend process on "%pid"', array('%params' => join(',', $missing_params), '%pid' => $pid))); + return FALSE; + } + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + + $item = new fedora_item($pid); + $dslist = $item->get_datastreams_list_as_array(); + if (!isset($dslist[$parameters['dsid']])) { + $this->setMessage(t('Datastream "%dsid" could not be found for mods_extend process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + if (!isset($dslist['RELS-EXT'])) { + $this->setMessage(t('Datastream "RELS-EXT" could not be found for mods_extend process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + + $modsDom = DOMDocument::loadXML($item->get_datastream_dissemination($parameters['dsid'])); + $relsExtDom = DOMDocument::loadXML($item->get_datastream_dissemination('RELS-EXT')); + + if ($modsDom === FALSE) { + $this->setMessage(t('Unable to load/interpret MODS Document from "%dsid" for mods_extend process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + + $modsRoot = $modsDom->getElementsByTagNameNS(mods_extend::$MODS_NS, 'mods'); + + if ($modsRoot->length > 0) { + $modsRoot=$modsRoot->item(0); + + /* Remove any pre-existing relatedItems, + physicalDescriptions (mimetypes), or HDL Identifiers + */ + for ($i = $modsRoot->childNodes->length-1; $i >= 0; $i--) { + $node = $modsRoot->childNodes->item($i); + + switch ($node->nodeName) { + case 'mods:relatedItem': + case 'mods:physicalDescription': + $modsRoot->removeChild($node); + break; + case 'mods:identifier': + if ($node->getAttribute('type') == 'hdl') { + $modsRoot->removeChild($node); + } + if ($node->getAttribute('type') == 'pid') { + $modsRoot->removeChild($node); + } + break; + } + } + + $collections= $relsExtDom->getElementsByTagName('isMemberOfCollection'); + for ($i=0; $i < $collections->length; $i++) { + $collection = $collections->item($i); + list(, $ident) = explode('/', $collection->getAttribute('rdf:resource')); + + $collection = new fedora_item($ident); + $dc = new SimpleXMLElement($collection->get_datastream_dissemination('DC'), NULL, FALSE, 'http://purl.org/dc/elements/1.1/'); + + $relatedItem = $modsDom->createElement('mods:relatedItem'); + $relatedItem->setAttribute('type', 'host'); + $titleInfo = $modsDom->createElement('mods:titleInfo'); + $title = $modsDom->createElement('mods:title', $dc->title); + $titleInfo->appendChild($title); + $relatedItem->appendChild($titleInfo); + + $identifier = $modsDom->createElement('mods:identifier', $ident); + $identifier->setAttribute('type', 'pid'); + $relatedItem->appendChild($identifier); + + $ident = preg_replace('/^.*\:/', '10719/', $ident); + + $identifier = $modsDom->createElement('mods:identifier', $ident); + $identifier->setAttribute('type', 'hdl'); + $relatedItem->appendChild($identifier); + + $modsRoot->appendChild($relatedItem); + } + + $identifier = $modsDom->createElement('mods:identifier', $pid); + $identifier->setAttribute('type', 'pid'); + $modsRoot->appendChild($identifier); + + $ident= preg_replace('/^.*\:/', '10719/', $pid); + $identifier = $modsDom->createElement('mods:identifier', $ident); + $identifier->setAttribute('type', 'hdl'); + $modsRoot->appendChild($identifier); + + if (isset($dslist['OBJ']['MIMEType']) && trim($dslist['OBJ']['MIMEType']) != '') { + $physDesc =$modsDom->createElement('mods:physicalDescription'); + $internetMediaType = $modsDom->createElement('mods:internetMediaType', htmlspecialchars(trim($dslist['OBJ']['MIMEType']))); + $physDesc->appendChild($internetMediaType); + $modsRoot->appendChild($physDesc); + } + + // add in record information type? + + $item->modify_datastream_by_value( $modsDom->saveXML(), 'MODS', "MODS Record", 'text/xml',false, 'Modified by workflow process mods_extend.'); + RETURN TRUE; + } + else { + $this->setMessage(t('Could not find MODS root element in "%dsid" for mods_extend process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + } +} diff --git a/workflow_client/plugins/solr_index.inc b/workflow_client/plugins/solr_index.inc new file mode 100644 index 00000000..2c45901d --- /dev/null +++ b/workflow_client/plugins/solr_index.inc @@ -0,0 +1,109 @@ + 0) { + $this->setMessage(t('Missing parameter(s) "%params" for solr_index process on "%pid"', array('%params' => join(',', $missing_params), '%pid' => $pid))); + return FALSE; + } + + if (!isset($parameters['xslt']) && !isset($parameters['xslt_file'])) { + $this->setMessage(t('Must include either "xslt_file" or "xslt" parameter to specify which template to apply on "%pid" for process solr_index.', array('%pid' => $pid))); + return FALSE; + } + + if (module_load_include('php', 'islandora_solr_search', 'Solr/Service') === FAlSE) { + $this->setMessage(t('Unable to load Solr/Service from islandora_solr_search module on "%pid" for process solr_index.', array('%pid' => $pid))); + return FALSE; + } + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $xsltDom = NULL; + if (isset($parameters['xslt'])) { + list($template_pid, $template_dsid) = explode('/', $parameters['xslt']); + + $template_item = new fedora_item($template_pid); + $dslist = $template_item->get_datastreams_list_as_array(); + if (!isset($dslist[$template_dsid])) { + $this->setMessage(t('Datastream "%dsid" for template "%template" could not be found for xslt process on "%pid"', array('%template' => $parameters['xslt'], '%dsid' => $template_dsid, '%pid' => $pid))); + return FALSE; + } + $xsltDom = DOMDocument::loadXML($template_item->get_datastream_dissemination($template_dsid)); + } + else { + $xsltDom = new DOMDocument(); + $xsltDom->load(drupal_get_path('module', 'islandora_workflow_client') .'/xsl/'. trim($parameters['xslt_file'])); + } + + $item = new fedora_item($pid); + $dslist = $item->get_datastreams_list_as_array(); + if (!isset($dslist[$parameters['dsid']])) { + $this->setMessage(t('Datastream "%dsid" could not be found for solr_index process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + + $dom = DOMDocument::loadXML($item->get_datastream_dissemination($parameters['dsid'])); + if ($dom === FALSE) { + $this->setMessage(t('Unable to load/interpret DOM Document from "%dsid" for solr_index process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + + $proc = new XSLTProcessor(); + $proc->importStylesheet($xsltDom); + $solrDoc = $proc->transformToXML($dom); + + $solrDom = DOMDocument::loadXML($solrDoc); + $doc = $solrDom->getElementsByTagName('doc'); + if ($doc->length > 0) { + $doc=$doc->item(0); + $workflow = Workflow::loadFromObject($pid); + $procs= $workflow->getProcesses(); + foreach ($procs as $id => $proc) { + $field=$solrDom->createElement('field', $proc); + $field->setAttribute('name', 'workflow_process_t'); + $doc->appendChild($field); + } + + if (isset($dslist['DC'])) + { + $dc = $item->get_datastream('DC'); + $field=$solrDom->createElement('field',$dc->createDate); + $field->setAttribute('name','created_d'); + $doc->appendChild($field); + } + } + + + + $host = variable_get('islandora_solr_search_block_host', 'localhost'); + $port = variable_get('islandora_solr_search_block_port', '8080'); + $appName = variable_get('islandora_solr_search_block_app_name', 'solr'); + $solr = new Apache_Solr_Service($host, $port, '/'. $appName .'/'); + + try { + if ($solr->ping()) { + $solr->add($solrDom->saveXML()); + $solr->commit(); + $solr->optimize(); + return TRUE; + } + else { + $this->setMessage(t('Unable to connect to Solr at "%solr" for solr_index process on "%pid".', array('%pid' => $pid, '%solr' => $host .':'. $port . '/'. $appName .'/'))); + return FALSE; + } + } + catch (Exception $e) { + $this->setMessage(t('Caught exception from Solr at %solr for solr_index process on "%pid": %msg', array('%pid' => $pid, '%solr' => $host .':'. $port .'/'. $appName .'/', '%msg' => $e->getMessage()))); + return FALSE; + } + } +} diff --git a/workflow_client/plugins/xslt.inc b/workflow_client/plugins/xslt.inc new file mode 100644 index 00000000..f80fd961 --- /dev/null +++ b/workflow_client/plugins/xslt.inc @@ -0,0 +1,67 @@ + 0) { + $this->setMessage(t('Missing parameter(s) "%params" for xslt process on "%pid"', array('%params' => join(',', $missing_params), '%pid' => $pid))); + return FALSE; + } + + if (!isset($parameters['xslt']) && !isset($parameters['xslt_file'])) { + $this->setMessage(t('Must include either "xslt_file" or "xslt" parameter to specify which template to apply on "%pid"', array('%pid' => $pid))); + return FALSE; + } + + + module_load_include('inc', 'fedora_repository', 'api/fedora_item'); + $xsltDom = NULL; + if (isset($parameters['xslt'])) { + list($template_pid, $template_dsid) = explode('/', $parameters['xslt']); + + $template_item = new fedora_item($template_pid); + $dslist = $template_item->get_datastreams_list_as_array(); + if (!isset($dslist[$template_dsid])) { + $this->setMessage(t('Datastream "%dsid" for template "%template" could not be found for xslt process on "%pid"', array('%template' => $parameters['xslt'], '%dsid' => $template_dsid, '%pid' => $pid))); + return FALSE; + } + $xsltDom = DOMDocument::loadXML($template_item->get_datastream_dissemination($template_dsid)); + } + else { + $xsltDom = new DOMDocument(); + $xsltDom->load(drupal_get_path('module', 'islandora_workflow_client') .'/xsl/'. trim($parameters['xslt_file'])); + } + + $item = new fedora_item($pid); + $dslist = $item->get_datastreams_list_as_array(); + + if (!isset($dslist[$parameters['dsid']])) { + $this->setMessage(t('Datastream "%dsid" could not be found for xslt process on "%pid"', array('%dsid' => $parameters['dsid'], '%pid' => $pid))); + return FALSE; + } + + $modsDom = DOMDocument::loadXML($item->get_datastream_dissemination($parameters['dsid'])); + + $proc = new XSLTProcessor(); + $proc->importStylesheet($xsltDom); + + $dc = $proc->transformToXML($modsDom); + if (isset($dslist[$parameters['dest_dsid']])) { + $item->modify_datastream_by_value( $dc, $parameters['dest_dsid'], isset($parameters['dest_label']) ? $parameters['dest_label'] : $dslist[$parameters['dest_dsid']]['label'], 'text/xml',false, 'Modified by workflow process xslt.'); + } + else { + $item->add_datastream_from_string( $dc, $parameters['dest_dsid'], isset($parameters['dest_label']) ? $parameters['dest_label'] : NULL, 'text/xml', 'X','Added by workflow process xslt.'); + } + + } +} diff --git a/workflow_client/process.inc b/workflow_client/process.inc new file mode 100644 index 00000000..1a33744f --- /dev/null +++ b/workflow_client/process.inc @@ -0,0 +1,31 @@ +workflow = &$wf; + $this->process=$wf->getProcess($processId); + } + + public function run() { + $ret = $this->process($this->workflow->pid, $this->process['params']); + $state = ($ret === FALSE) ? 'error' : 'completed'; + $this->workflow->recordAttempt($this->process['id'], $state, $this->message); + + return $ret; + } + + protected function setMessage($msg) { + $this->message = $msg; + } + + abstract protected function process($pid, $parameters); +} diff --git a/workflow_client/send.php b/workflow_client/send.php new file mode 100644 index 00000000..d09d8b62 --- /dev/null +++ b/workflow_client/send.php @@ -0,0 +1,83 @@ + + + urn:uuid:19aab165-c920-40a1-a349-443f60f84567 + 2010-08-08T15:57:08.659Z + + umroymr2 + http://192.168.56.101:8080/fedora + + modifyDatastreamByValue + + + + + + + + + + + uofm:highResImage + 2010-08-08T15:57:08.657Z + + +'; + +$con->send("/queue/fedora.apim.update", $msg); + +#echo "Sent message with body 'test'\n"; +// subscribe to the queue +#$con->subscribe("/topic/fedora.apim.update"); +// receive a message from the queue + +#$msg = $con->readFrame(); + +// do what you want with the message +#if ( $msg != null) { +# echo "Received message with body '$msg->body'\n"; +# // mark the message as received in the queue +# $con->ack($msg); +#} else { +# echo "Failed to receive a message\n"; +#} + +// disconnect +} catch (StompException $e) +{ + echo "StompException!"; + var_dump($e); +} +?> diff --git a/workflow_client/test.php b/workflow_client/test.php new file mode 100644 index 00000000..0cd8a36e --- /dev/null +++ b/workflow_client/test.php @@ -0,0 +1,61 @@ +connect(); +#// send a message to the queue +#$con->send("/topic/fedora.apim.update", "test"); +#echo "Sent message with body 'test'\n"; +// subscribe to the queue +$con->subscribe("/queue/fedora.apim.update"); +// receive a message from the queue +while (true) +{ + $msg = $con->readFrame(); + // do what you want with the message + if ( $msg != null) { + $con->ack($msg); + echo "Received message with body '$msg->body'\n"; + // mark the message as received in the queue + var_dump($msg->headers['pid']); + } else { + echo "Failed to receive a message\n"; + } +} + +// disconnect +#$con->disconnect(); +} catch (StompException $e) +{ + echo "StompException!"; + var_dump($e); +} +?> diff --git a/workflow_client/test.xml b/workflow_client/test.xml new file mode 100644 index 00000000..5ba52846 --- /dev/null +++ b/workflow_client/test.xml @@ -0,0 +1,74 @@ + + + + + FULL_SIZE + + FULL_SIZE + 150 + jpg + + + + + + FULL_SIZE + + FULL_SIZE + JPG + 800 + jpg + + + + + + FULL_SIZE + + FULL_SIZE + + + + + + FULL_SIZE + + FULL_SIZE + ANSI + + + + + + MODS. + + MODS + + + + + + MODS + mods + + MODS + uofm:highResImage/MODS_TO_DC + + + + + + MODS + mods + + MODS + uofm:highResImage/MODS_TO_SOLR + + + + diff --git a/workflow_client/test2.php b/workflow_client/test2.php new file mode 100644 index 00000000..02668215 --- /dev/null +++ b/workflow_client/test2.php @@ -0,0 +1,68 @@ +connect(); +#// send a message to the queue +#$con->send("/topic/fedora.apim.update", "test"); +#echo "Sent message with body 'test'\n"; +// subscribe to the queue +$con = new Stomp("tcp://localhost:61613"); +$con->subscribe("/queue/fedora.apim.update"); + +// receive a message from the queue +while (isset($con)) +{ + + $msg = $con->readFrame(); + + // do what you want with the message + if ( $msg != null) { + echo "Received message with body '$msg->body'\n"; + // mark the message as received in the queue + //$con->ack($msg); + // unset($con); // unset con to return the message to the queue.\ +// $con->ack($msg); + // $con->send('/queue/fedora.apim.update',$msg->body); + + } else { + echo "Failed to receive a message\n"; + } +} + +// disconnect +#$con->disconnect(); +} catch (StompException $e) +{ + echo "StompException!"; + var_dump($e); +} +?> diff --git a/workflow_client/workflow.inc b/workflow_client/workflow.inc new file mode 100644 index 00000000..a91d6128 --- /dev/null +++ b/workflow_client/workflow.inc @@ -0,0 +1,262 @@ +get_datastreams_list_as_array(); + if (isset($datastreams[$dsid])) { + $ds = $fedoraItem->get_datastream_dissemination($dsid); + } + } + + if (!empty($ds)) { + $ret=new Workflow($ds, $pid, $dsid); + } + } + catch (SOAPException $e) { + $ret = FALSE; + } + return $ret; + } + + function resetDependancies($dsid,$logMessage = null) { + $ret = FALSE; + if ($this->validate()) { + $processes = $this->xml->getElementsByTagName('workflow')->item(0)->getElementsByTagName('process'); + for ($i=0; $i < $processes->length; $i++) { + $dependencies = $processes->item($i)->getElementsByTagName('dependant'); + $update = FALSE; + + //check log message to make sure that this process didnt modify the datastream. If this is the case, then dont reset it (prevents loops). + if ($logMessage != null && !preg_match('/'.strtolower(trim($processes->item($i)->getAttribute('name'))).'/',strtolower($logMessage))) + { + for ($j=0; $j < $dependencies->length; $j++) { + if (trim($dependencies->item($j)->nodeValue) == $dsid) { + $update = TRUE; + } + } + } + + if ($update) { + $processes->item($i)->setAttribute('state', 'waiting'); + $ret = TRUE; + } + } + } + + return $ret; + } + + function getProcesses() { + $ret = FALSE; + + if ($this->validate()) { + $processes = $this->xml->getElementsByTagName('workflow')->item(0)->getElementsByTagName('process'); + $ret=array(); + for ($i=0; $i < $processes->length; $i++) { + $id = $processes->item($i)->getAttribute('id'); + $ret[$id]=$processes->item($i)->getAttribute('name'); + } + } + return $ret; + } + + function getReadyProcesses() { + $ret = FALSE; + if ($this->validate()) { + $processes = $this->xml->getElementsByTagName('workflow')->item(0)->getElementsByTagName('process'); + $waitingProcesses = array(); + $completeProcesses = array(); + for ($i=0; $i < $processes->length; $i++) { + $id=$processes->item($i)->getAttribute('id'); + switch (strtolower($processes->item($i)->getAttribute('state'))) { + case 'waiting': + $waitingProcesses[$id]=$processes->item($i); + break; + + case 'completed': + $completeProcesses[$id]=$processes->item($i); + break; + + case 'error': + if (intval($processes->item($i)->getAttribute('attempts')) < Workflow::getMaxAttempts()) { + $waitingProcesses[$id]=$processes->item($i); + } + break; + } + } + + $readyProcesses = array(); + foreach ($waitingProcesses as $id => $proc) { + $prereqs = $proc->getElementsByTagName('prereq'); + $ready = TRUE; + for ($i=0;$ready && $i<$prereqs->length;$i++) { + if (!isset($completeProcesses[trim($prereqs->item($i)->nodeValue)])) { + $ready = FALSE; + } + } + if ($ready) { + $readyProcesses[$id]=$proc->getAttribute('name'); + } + } + $ret = $readyProcesses; + } + return $ret; + } + + function setState($processId, $state) { + $ret = FALSE; + if ($this->validate()) { + $process = FALSE; + $processes = $this->xml->getElementsByTagName('workflow')->item(0)->getElementsByTagName('process'); + for ($i=0; $process === FALSE && $i < $processes->length; $i++) { + if ($processId == $processes->item($i)->getAttribute('id')) { + $process = $processes->item($i); + } + } + + if ($process !== FALSE) { + $process->setAttribute('state', $state); + $process->setAttribute('attempts', 0); + + $msgEl = $process->getElementsByTagName('message'); + if ($msgEl->length > 0) { + $process->removeChild($msgEl->item(0)); + } + } + } + return $ret; + } + + function getProcess($processId) { + $ret = FALSE; + if ($this->validate()) { + $process = FALSE; + $processes = $this->xml->getElementsByTagName('workflow')->item(0)->getElementsByTagName('process'); + for ($i=0; $process === FALSE && $i < $processes->length; $i++) { + if ($processId == $processes->item($i)->getAttribute('id')) { + $process = $processes->item($i); + } + } + + if ($process !== FALSE) { + $attempts = $process->getAttribute('attempts'); + if (!$attempts) { + $attempts = 0; + } + + $msgEl = $process->getElementsByTagName('message'); + $message = ($msgEl->length > 0)? trim($msgEl->item(0)->nodeValue) : ''; + + $params = array(); + $paramEls = $process->getElementsByTagName('parameters'); + if ($paramEls->length > 0) { + $paramEls=$paramEls->item(0)->getElementsByTagName('parameter'); + for ($i=0; $i < $paramEls->length; $i++) { + $params[$paramEls->item($i)->getAttribute('name')] = trim($paramEls->item($i)->nodeValue); + } + } + + $ret=array('name' => $process->getAttribute('name'), + 'id' => $process->getAttribute('id'), + 'state' => $process->getAttribute('state'), + 'timestamp' => $process->getAttribute('timestamp'), + 'attempts' => $attempts, + 'message' => $message, + 'params' => $params + ); + } + + } + return $ret; + } + + function recordAttempt($processId, $state, $message) { + $ret = FALSE; + if ($this->validate()) { + $process = FALSE; + $processes = $this->xml->getElementsByTagName('workflow')->item(0)->getElementsByTagName('process'); + for ($ix= 0; $process === FALSE && $i < $processes->length; $i++) { + if ($processId == $processes->item($i)->getAttribute('id')) { + $process = $processes->item($i); + } + } + + if ($process !== FALSE) { + $process->setAttribute('state', $state); + $attempts = $process->getAttribute('attempts'); + if (!$attempts) { + $attempts = 1; + } + else + $attempts++; + $process->setAttribute('attempts', $attempts); + $process->setAttribute('timestamp', date(DateTime::ATOM)); + + $msgEl = $process->getElementsByTagName('message'); + if (strlen(trim($message)) > 0) { + $newMessage = $this->xml->createElement('message', $message); + if ($msgEl->length > 0) { + $process->replaceChild($newMessage, $msgEl->item(0)); + } + elseif ($process->hasChildNodes()) { + $process->insertBefore($newMessage, $process->childNodes->item(0)); + } + else { + $process->appendChild($newMessage); + } + } + elseif ($msgEl->length > 0) { + $process->removeChild($msgEl->item(0)); + } + + $ret = TRUE; + } + + } + return $ret; + } + + function convertFromOldSchema() { return TRUE; } +} diff --git a/workflow_client/workflow.xsd b/workflow_client/workflow.xsd new file mode 100644 index 00000000..f8735aa1 --- /dev/null +++ b/workflow_client/workflow.xsd @@ -0,0 +1,45 @@ + + + + Islandora Workflow Schema + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/workflow_client/xsl/jhove-mix.xsl b/workflow_client/xsl/jhove-mix.xsl new file mode 100644 index 00000000..e3cdf37d --- /dev/null +++ b/workflow_client/xsl/jhove-mix.xsl @@ -0,0 +1,14 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/workflow_client/xsl/mods-solr.xsl b/workflow_client/xsl/mods-solr.xsl new file mode 100644 index 00000000..aef88d92 --- /dev/null +++ b/workflow_client/xsl/mods-solr.xsl @@ -0,0 +1,790 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + title_sort_s + + + + + + + + id + + + + + + + + + + + + + + + + + + + + + + + genre_t + + + + ; + + + + + + + + genre_facet + + + + + + + + collection_facet + + + + + + + + + + language_t + + + + ; + + + + + + + language_facet + + + + + + + + + + + + + + + + + + + + + + + + note_t + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + alt_title_t + + + + + + uni_title_t + + + + + + abbr_title_t + + + + + + trans_title_t + + + + + + title_t + + + + + + + + ; + + + + ; + + + + + + + + ; + + + + ; + + + + + + + + ; + + + + ; + + + + + + + + + + + identifier_t + + + + + + + + + + + name_organization_t + name_conference_t + name_personal_t + + + + + + + + + + + , + + + + + , + + + + + + + + + + + + , + + + + + + + + + + , + + + + + + + + + + + + , + + + + + + + + + + name_organization_facet + name_conference_facet + name_personal_facet + + + + + + + + + + + , + + + + + , + + + + + + + + + + + + , + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + subject_topic_t + + + subject_topic_facet + + + + + subject_geographic_t + + + subject_geographic_facet + + + + + subject_temporal_t + + + subject_temporal_facet + + + + + subject_name_t + + + subject_name_facet + + + + + genre_t + + + genre_facet + + + + + + + subject_t + + + + + -- + + + + + subject_facet + + + + + -- + + + + + + + + + type_of_resource_t + + + type_of_resource_facet + + + + + + + + + abstract_t + + + + + abstract_t + + + + + + + + + + + + table_of_contents_t + + + + + table_of_contents_t + + + + + + + + + + + toc_t + + + + + target_audience_t + + + + + + + + + related_item_identifier_t + + + related_item_title_t + + + + + + + + location_t + + + + + ; + + + + + + + + + access_condition_t + + + + + + physical_description_t + + + + + ; + + + + + + + + + + + + + + + + + + + + + raw_date + + + + + raw_date + + + + + + raw_date + + + + - + + + + + + + + + + + + raw_date + + + + - + + + + n.d. + + + + + + + + + + + raw_date + + + + - + + + + n.d. + + + + + + + + + + + raw_date + + + + - + + + + n.d. + + + + + + + + + + + + publisher_place_t + + + + + ; + + + + + + + + origin_aspects_t + + + + + ; + + + + + + + + + + + + + + + origin_t + + + + + + + + + + + + + ; + + + + + + + + + , + + + + + + + + + ; + + + + + + + + , + + + + + + + + + ; + + + + + + + ; + + + + + + + + + ; + + + + + + + + , + + + + + + + + ; + + + + + + + + + + + diff --git a/workflow_client/xsl/mods_to_dc.xsl b/workflow_client/xsl/mods_to_dc.xsl new file mode 100644 index 00000000..f5c2da41 --- /dev/null +++ b/workflow_client/xsl/mods_to_dc.xsl @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + : + + + + . + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- + + + + + -- + + + + + + + + + + + + + + + + + + + + + + + + -- + + + + + + + + + + + + + + + - + + + + + + + + + -- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Collection + + + DataSet + + + Service + + + Software + + + Image + + + InteractiveResource + + + MovingImage + + + PhysicalObject + + + Sound + + + StillImage + + + Text + + + Text + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- + + + + + + + + + + + -- + + + + + + + + + + + + + + + + + + + + + + , + + + + , + + + + + ( + + ) + + + ( + + ) + + + + + + + + + - + + + + + - + + + + + + + + + + + + diff --git a/xsl/advanced_search_results.xsl b/xsl/advanced_search_results.xsl new file mode 100644 index 00000000..bb57c47d --- /dev/null +++ b/xsl/advanced_search_results.xsl @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + + + + mnpl_advanced_search + + + + + + + + + + + + + + + + + + + + + + + Total Hits = , + Number of Hits/page = +
        You may not have sufficient privileges to view any or all of the items found. The objects you have rights to view will be shown below. + +
        + + + + + + + + + +
        + +
        + +

        Your search yielded no results

        + +
          +
        • Check if your spelling is correct.
        • + +
        • Remove quotes around phrases to match each word individually: "blue smurf" will match less than blue smurf.
        • +
        • Consider loosening your query with OR: blue smurf will match less than blue OR smurf.
        • +
        + +
        + +
        +
        +
        + + + + + + +
        + + + + + + + + + + + + + + + + + + + + + + + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fedora/repository//-/ + + + + + + + fedora/repository//TN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + + + + + + + + + fedora/repository//-/ + + + +
        +
        + + + Score:() +
        + + + + fedora/repository//-/ + + + + +
        + + +
        + + Text Stream + + + + + +
        + + + + + + + +
        + + +
        + +
        diff --git a/xsl/browseIndexToResultPage.xslt b/xsl/browseIndexToResultPage.xslt new file mode 100644 index 00000000..9d03d470 --- /dev/null +++ b/xsl/browseIndexToResultPage.xslt @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + + + + + + +

        + + + + +

        + +
        + + + + + + +
        +
        +
        + + + + + + + + fedora/ilives_book_search/:"" AND dc.type:collection + + + + +
        +
        + +
        + +
        + + + + + + + + + diff --git a/xsl/convertQDC.xsl b/xsl/convertQDC.xsl new file mode 100644 index 00000000..e7e0d627 --- /dev/null +++ b/xsl/convertQDC.xsl @@ -0,0 +1,33 @@ + + + + + + + + + + +
        + + + + + + + + + + +

        MetaData

        + +
        + = +
        +
        +
        Find Similar by {$FIELD}
        + +
        + + +
        \ No newline at end of file diff --git a/xsl/refworks.xsl b/xsl/refworks.xsl new file mode 100644 index 00000000..2ef0c8df --- /dev/null +++ b/xsl/refworks.xsl @@ -0,0 +1,92 @@ + + + + + + +

        General Information

        + + + + + + + + + + + + + + + +
        Periodical:
        Abbreviation:
        Volume:
        Issue:
        Publisher:
        Place of Publication:
        Edition:
        Year:
        Date:
        Start Page:
        Other Pages:
        ISSN/ISBN:
        Language:
        UL:
        +
        + +

        Titles

        +
          + +
        • +
          +
        +
        + +
          +

          Secondary Titles

          + +
        • +
          +
        +
        + +

        Authors

        +
          + +
        • +
          +
        +
        + + +
          +

          Secondary Authors

          + +
        • +
          +
        +
        + +

        Keywords

        +
          + +
        • +
          +
        +
        + +

        Abstract

        + +
        +
        +
        + +

        Notes

        + +
        +
        +
        + + + + + http://articles.library.upei.ca:7888/godot/hold_tab.cgi?hold_tab_branch=PCU&issn=&date=&volume=&issue=&spage=&atitle=&stitle= + +
        + + + +
        +
        \ No newline at end of file diff --git a/xsl/results.xsl b/xsl/results.xsl new file mode 100644 index 00000000..829822db --- /dev/null +++ b/xsl/results.xsl @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Total Hits = + + , + + Number of Hits/page = + +
        You may not have sufficient privileges to view any or all of the items found. The objects you have rights to view will be shown below. + +
        + + + + + + + + + + + + + + + + + + + + + +
        + +
        + +

        Your search yielded no results

        + +
        +
          +
        • Check if your spelling is correct.
        • + +
        • Remove quotes around phrases to match each word individually: + "blue smurf" will match less than + blue smurf. +
        • +
        • Consider loosening your query with + OR: + blue smurf will match less than + blue OR smurf. +
        • +
        +
        + +
        + +
        +
        +
        + + + + + + + +
        + + + + + + + + + + + + + + + + + + + + + + + +
        +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fedora/repository/ + /-/ + + + + + + fedora/repository/ + /TN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + + + + + + + + + + fedora/repository/ + /-/ + + + + + +
        +
        + + + Score:( + ) + +
        + + + + + fedora/repository/ + /-/ + + + + + +
        + + +
        + + Text Stream + + + + + +
        + + + + + + + +
        + + + +
        + +
        diff --git a/xsl/romeo.xsl b/xsl/romeo.xsl new file mode 100644 index 00000000..8fa02d4e --- /dev/null +++ b/xsl/romeo.xsl @@ -0,0 +1,29 @@ + + + + + + + + + +
        + Journal:
        Published By:
        Publisher Url:
        Prearchiving:
        Postprints:
        +

        Conditions

        +
          + +
        • +
          +
        + + Rights:
        + + + + Romeo Colour:
        +
        + +
        If there are no results from ROMEO shown above you can try searching manually by clicking here.
        +
        +
        +
        \ No newline at end of file diff --git a/xsl/sparql_to_html.xsl b/xsl/sparql_to_html.xsl new file mode 100644 index 00000000..0c037f3e --- /dev/null +++ b/xsl/sparql_to_html.xsl @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        +

        + + + +
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + /fedora/repository//-/ + + + + /fedora/repository//-/ + + + + + + + + + + /fedora/repository//TN + + + +
        + + + + + + + + + + + + + +
        + + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        \ No newline at end of file diff --git a/xsl/specdwc.xsl b/xsl/specdwc.xsl new file mode 100644 index 00000000..84de97d9 --- /dev/null +++ b/xsl/specdwc.xsl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Specimen
        Scientific Name
        Family
        Genus
        Common Name
        Location
        Continent
        Country
        Country Code
        State/Province
        County
        Locality
        Habitat
        Record
        Record Type
        Language-
        Record Basis
        Occurence Remarks
        Occurence ID
        Institution Code
        Collection Code
        Catalog Number
        Recorded By
        Event Date200
        +
        +