Skip to content

Commit

Permalink
Merge pull request #57 from UNC-Libraries/vocabularies
Browse files Browse the repository at this point in the history
Vocabularies
  • Loading branch information
lfarrell committed Nov 2, 2015
2 parents 6ddaf0c + 81b00fc commit 0cf7aad
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 12 deletions.
1 change: 1 addition & 0 deletions demo/examples/marc_relators.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[ "Abridger", "Art copyist", "Actor", "Art director", "Adapter", "Author of afterword, colophon, etc.", "Analyst", "Animator", "Annotator", "Bibliographic antecedent", "Appellee", "Appellant", "Applicant", "Author in quotations or text abstracts", "Architect", "Artistic director", "Arranger", "Artist", "Assignee", "Associated name", "Autographer", "Attributed name", "Auctioneer", "Author of dialog", "Author of introduction, etc.", "Screenwriter", "Author", "Binding designer", "Bookjacket designer", "Book designer", "Book producer", "Blurb writer", "Binder", "Bookplate designer", "Broadcaster", "Braille embosser", "Bookseller", "Caster", "Conceptor", "Choreographer", "Client", "Calligrapher", "Colorist", "Collotyper", "Commentator", "Composer", "Compositor", "Conductor", "Cinematographer", "Censor", "Contestant-appellee", "Collector", "Compiler", "Conservator", "Collection registrar", "Contestant", "Contestant-appellant", "Court governed", "Cover designer", "Copyright claimant", "Complainant-appellee", "Copyright holder", "Complainant", "Complainant-appellant", "Creator", "Correspondent", "Corrector", "Court reporter", "Consultant", "Consultant to a project", "Costume designer", "Contributor", "Contestee-appellee", "Cartographer", "Contractor", "Contestee", "Contestee-appellant", "Curator", "Commentator for written text", "Distribution place", "Defendant", "Defendant-appellee", "Defendant-appellant", "Degree granting institution", "Degree supervisor", "Dissertant", "Delineator", "Dancer", "Donor", "Depicted", "Depositor", "Draftsman", "Director", "Designer", "Distributor", "Data contributor", "Dedicatee", "Data manager", "Dedicator", "Dubious author", "Editor of compilation", "Editor of moving image work", "Editor", "Engraver", "Electrician", "Electrotyper", "Engineer", "Enacting jurisdiction", "Etcher", "Event place", "Expert", "Facsimilist", "Film distributor", "Field director", "Film editor", "Film director", "Filmmaker", "Former owner", "Film producer", "Funder", "First party", "Forger", "Geographic information specialist", "Host institution", "Honoree", "Host", "Illustrator", "Illuminator", "Inscriber", "Inventor", "Issuing body", "Instrumentalist", "Interviewee", "Interviewer", "Judge", "Jurisdiction governed", "Laboratory", "Librettist", "Laboratory director", "Lead", "Libelee-appellee", "Libelee", "Lender", "Libelee-appellant", "Lighting designer", "Libelant-appellee", "Libelant", "Libelant-appellant", "Landscape architect", "Licensee", "Licensor", "Lithographer", "Lyricist", "Music copyist", "Metadata contact", "Medium", "Manufacture place", "Manufacturer", "Moderator", "Monitor", "Marbler", "Markup editor", "Musical director", "Metal-engraver", "Minute taker", "Musician", "Narrator", "Opponent", "Originator", "Organizer", "Onscreen presenter", "Other", "Owner", "Panelist", "Patron", "Publishing director", "Publisher", "Project director", "Proofreader", "Photographer", "Platemaker", "Permitting agency", "Production manager", "Printer of plates", "Papermaker", "Puppeteer", "Praeses", "Process contact", "Production personnel", "Presenter", "Performer", "Programmer", "Printmaker", "Production company", "Producer", "Production place", "Production designer", "Printer", "Provider", "Patent applicant", "Plaintiff-appellee", "Plaintiff", "Patent holder", "Plaintiff-appellant", "Publication place", "Rubricator", "Recordist", "Recording engineer", "Addressee", "Radio director", "Redaktor", "Renderer", "Researcher", "Reviewer", "Radio producer", "Repository", "Reporter", "Responsible party", "Respondent-appellee", "Restager", "Respondent", "Restorationist", "Respondent-appellant", "Research team head", "Research team member", "Scientific advisor", "Scenarist", "Sculptor", "Scribe", "Sound designer", "Secretary", "Stage director", "Signer", "Supporting host", "Seller", "Singer", "Speaker", "Sponsor", "Second party", "Surveyor", "Set designer", "Setting", "Storyteller", "Stage manager", "Standards body", "Stereotyper", "Technical director", "Teacher", "Thesis advisor", "Television director", "Television producer", "Transcriber", "Translator", "Type designer", "Typographer", "University place", "Voice actor", "Videographer", "Writer of added commentary", "Writer of added lyrics", "Writer of accompanying material", "Writer of added text", "Woodcutter", "Wood engraver", "Writer of introduction", "Witness", "Writer of preface", "Writer of supplementary textual content" ]
73 changes: 73 additions & 0 deletions demo/relator.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="stylesheets/reset.css" type="text/css" />
<link rel="stylesheet" href="stylesheets/demo.css" type="text/css" />
<link rel="stylesheet" href="../css/jquery.xmleditor.css" type="text/css" />
<script src="../lib/ace/src-min/ace.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../lib/jquery-ui.min.js"></script>
<script src="../lib/json2.js"></script>
<script src="../lib/cycle.js"></script>
<script src="../lib/jquery.autosize-min.js"></script>
<script src="../xsd/xsd2json.js"></script>
<script src="../jquery.xmleditor.js"></script>
<style>
.ui-autocomplete {
width: 200px;
line-height: 24px;
}
</style>
</head>
<body>

<div id="xml_editor">
&lt;mods xmlns=&quot;http://www.loc.gov/mods/v3&quot;&gt;
&lt;name&gt;
&lt;role&gt;
&lt;roleTerm /&gt;
&lt;/role&gt;
&lt;/name&gt;
&lt;/mods&gt;
</div>
<script>
$(function() {
var availableTags = "examples/marc_relators.json";
var extractor = new Xsd2Json("mods-3-4.xsd", {
"schemaURI" : "examples/mods-3-4/"
});
$("#xml_editor").xmlEditor(
{
schema : extractor.getSchema(),
vocabularyConfigs : {
vocabularies : {
"marcRelators" : {
"url" : "examples/marc_relators.json"
},
"departments" : {
"values" : ["blah", "Department of Sonoeland Studies"]
}/*,
"fast" : {
url : "example.com",
type : "query",
keypress : function(input) {
}
}*/
},
xpathSelectors: {
"mods:mods/mods:name//mods:roleTerm" : "marcRelators"
},
xpathNamespaces: {
"mods" : "http://www.loc.gov/mods/v3"
}
/*cssSelectors: {
"roleTerm": availableTags
}*/
}
});
});
</script>
</body>
</html>
106 changes: 100 additions & 6 deletions jquery.xmleditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,9 @@ $.widget( "xml.xmlEditor", {
});
}

// Load any external vocabularies
this.loadVocabularies(this.options.vocabularyConfigs);

// Start loading the document for editing
this.loadDocument(this.options.ajaxOptions, localXMLContent);
},
Expand Down Expand Up @@ -416,6 +419,37 @@ $.widget( "xml.xmlEditor", {
}
},

loadVocabularies : function(vocabularyConfigs) {
var self = this;
this.loadingVocabs = 0;

if (!this.options.vocabularyConfigs || !this.options.vocabularyConfigs.vocabularies) {
return;
}

$.each(this.options.vocabularyConfigs.vocabularies, function(vocabName, vocabInfo) {
if ("url" in vocabInfo) {
self.loadingVocabs++;
}
});

$.each(this.options.vocabularyConfigs.vocabularies, function(vocabName, vocabInfo) {
if ("url" in vocabInfo) {
$.ajax({
url : vocabInfo["url"],
type : "GET",
dataType : "json"
}).done(function(data){
vocabInfo.values = data;
self.loadingVocabs--;
if (self.loadingVocabs == 0) {
self._everythingReady();
}
});
}
});
},

_templating : function() {
var dialog;
var self = this;
Expand All @@ -434,7 +468,7 @@ $.widget( "xml.xmlEditor", {
this.undoHistory.setStateChangeEvent(function() {
self.refreshDisplay();
});
this._documentAndSchemaReady();
this._everythingReady();
},

// Schema object loaded event
Expand All @@ -444,14 +478,14 @@ $.widget( "xml.xmlEditor", {
}
this.schemaTree = new SchemaTree(this.schema);
this.schemaTree.build();
this._documentAndSchemaReady();
this._everythingReady();
},

// Performs initialization of editor after rejoining document and schema loading workflows
// to support asychronous/multithreaded loading
_documentAndSchemaReady : function() {
_everythingReady : function() {
// Join back up asynchronous loading of document and schema
if (!this.schemaTree || !this.xmlState)
if (!this.schemaTree || !this.xmlState || this.loadingVocabs != 0)
return;

this.targetPrefix = this.xmlState.namespaces.getNamespacePrefix(this.options.targetNS);
Expand Down Expand Up @@ -1165,6 +1199,58 @@ $.widget( "xml.xmlEditor", {
$("#" + xmlMenuHeaderPrefix + this.toString()).removeClass("disabled").data("menuItemData").enabled = true;
else $("#" + xmlMenuHeaderPrefix + this.toString()).addClass("disabled").data("menuItemData").enabled = false;
});
},

// Finds the associated vocabulary for an xml element
getVocabulary: function(xmlElement) {
if (!this.options.vocabularyConfigs) {
return null;
}
var self = this;
var matchingVocab = null;
var xmlDocument = this.xmlState.xml;
if (this.options.vocabularyConfigs.cssSelectors) {
$.each(this.options.vocabularyConfigs.cssSelectors, function(selector, vocabulary){
// find elements in xml document that match this vocabulary's selector
var matches = $(selector, xmlDocument);

// Check to see if our xmlElement was in the matching list
for (var i = 0; i < matches.length; i++) {
if (xmlElement.xmlNode[0] === matches[i]) {
matchingVocab = vocabulary;
return false;
}
}
});
}

var nsResolver = function nsResolver(prefix) {
return self.options.vocabularyConfigs.xpathNamespaces[prefix] || null;
};
nsResolver.lookupNamespaceURI = nsResolver;

if (this.options.vocabularyConfigs.xpathSelectors) {
$.each(this.options.vocabularyConfigs.xpathSelectors, function(selector, vocabulary){
// find elements in xml document that match this vocabulary's selector
var matchesIterate = xmlDocument[0].evaluate(selector, xmlDocument[0], nsResolver, null, null);

// Check to see if our xmlElement was in the matching 0list
var match = matchesIterate.iterateNext()
while (match) {
if (xmlElement.xmlNode[0] === match) {
matchingVocab = vocabulary;
return false;
}
match = matchesIterate.iterateNext();
}
});
}

if (!matchingVocab || !(matchingVocab in this.options.vocabularyConfigs.vocabularies)) {
return null;
}

return this.options.vocabularyConfigs.vocabularies[matchingVocab];
}
});
function AbstractXMLObject(objectType, editor) {
Expand Down Expand Up @@ -4397,7 +4483,9 @@ XMLElement.prototype.renderChild = function(childNode, recursive) {
};

XMLElement.prototype.renderText = function(childNode, prepend) {
var textNode = new XMLTextNode(childNode, this.objectType.type, this.editor);
var vocabulary = this.editor.getVocabulary(this);

var textNode = new XMLTextNode(childNode, this.objectType.type, this.editor, vocabulary);
textNode.render(this, prepend);

this.nodeCount++;
Expand Down Expand Up @@ -5064,14 +5152,15 @@ XMLTemplates.prototype.loadEvents = function(dialog) {
self.processForm();
});
};
function XMLTextNode(textNode, dataType, editor) {
function XMLTextNode(textNode, dataType, editor, vocabulary) {
var textType = {
text : true,
type : dataType
};

this.textNode = textNode;
this.xmlNode = $(textNode);
this.vocabulary = vocabulary;

AbstractXMLObject.call(this, textType, editor);

Expand Down Expand Up @@ -5133,6 +5222,11 @@ XMLTextNode.prototype.render = function(parentElement, prepend) {
this.textInput = AbstractXMLObject.prototype.createElementInput.call(this,
this.domNodeID + "_text", textValue, inputColumn);
this.textInput.addClass('element_text');
if (this.vocabulary && this.vocabulary.values) {
this.textInput.autocomplete({
source : this.vocabulary.values
});
}

this.deleteButton = document.createElement('div');
this.deleteButton.className = 'xml_delete';
Expand Down
94 changes: 90 additions & 4 deletions src/jquery.xmleditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,9 @@ $.widget( "xml.xmlEditor", {
});
}

// Load any external vocabularies
this.loadVocabularies(this.options.vocabularyConfigs);

// Start loading the document for editing
this.loadDocument(this.options.ajaxOptions, localXMLContent);
},
Expand Down Expand Up @@ -416,6 +419,37 @@ $.widget( "xml.xmlEditor", {
}
},

loadVocabularies : function(vocabularyConfigs) {
var self = this;
this.loadingVocabs = 0;

if (!this.options.vocabularyConfigs || !this.options.vocabularyConfigs.vocabularies) {
return;
}

$.each(this.options.vocabularyConfigs.vocabularies, function(vocabName, vocabInfo) {
if ("url" in vocabInfo) {
self.loadingVocabs++;
}
});

$.each(this.options.vocabularyConfigs.vocabularies, function(vocabName, vocabInfo) {
if ("url" in vocabInfo) {
$.ajax({
url : vocabInfo["url"],
type : "GET",
dataType : "json"
}).done(function(data){
vocabInfo.values = data;
self.loadingVocabs--;
if (self.loadingVocabs == 0) {
self._everythingReady();
}
});
}
});
},

_templating : function() {
var dialog;
var self = this;
Expand All @@ -434,7 +468,7 @@ $.widget( "xml.xmlEditor", {
this.undoHistory.setStateChangeEvent(function() {
self.refreshDisplay();
});
this._documentAndSchemaReady();
this._everythingReady();
},

// Schema object loaded event
Expand All @@ -444,14 +478,14 @@ $.widget( "xml.xmlEditor", {
}
this.schemaTree = new SchemaTree(this.schema);
this.schemaTree.build();
this._documentAndSchemaReady();
this._everythingReady();
},

// Performs initialization of editor after rejoining document and schema loading workflows
// to support asychronous/multithreaded loading
_documentAndSchemaReady : function() {
_everythingReady : function() {
// Join back up asynchronous loading of document and schema
if (!this.schemaTree || !this.xmlState)
if (!this.schemaTree || !this.xmlState || this.loadingVocabs != 0)
return;

this.targetPrefix = this.xmlState.namespaces.getNamespacePrefix(this.options.targetNS);
Expand Down Expand Up @@ -1165,5 +1199,57 @@ $.widget( "xml.xmlEditor", {
$("#" + xmlMenuHeaderPrefix + this.toString()).removeClass("disabled").data("menuItemData").enabled = true;
else $("#" + xmlMenuHeaderPrefix + this.toString()).addClass("disabled").data("menuItemData").enabled = false;
});
},

// Finds the associated vocabulary for an xml element
getVocabulary: function(xmlElement) {
if (!this.options.vocabularyConfigs) {
return null;
}
var self = this;
var matchingVocab = null;
var xmlDocument = this.xmlState.xml;
if (this.options.vocabularyConfigs.cssSelectors) {
$.each(this.options.vocabularyConfigs.cssSelectors, function(selector, vocabulary){
// find elements in xml document that match this vocabulary's selector
var matches = $(selector, xmlDocument);

// Check to see if our xmlElement was in the matching list
for (var i = 0; i < matches.length; i++) {
if (xmlElement.xmlNode[0] === matches[i]) {
matchingVocab = vocabulary;
return false;
}
}
});
}

var nsResolver = function nsResolver(prefix) {
return self.options.vocabularyConfigs.xpathNamespaces[prefix] || null;
};
nsResolver.lookupNamespaceURI = nsResolver;

if (this.options.vocabularyConfigs.xpathSelectors) {
$.each(this.options.vocabularyConfigs.xpathSelectors, function(selector, vocabulary){
// find elements in xml document that match this vocabulary's selector
var matchesIterate = xmlDocument[0].evaluate(selector, xmlDocument[0], nsResolver, null, null);

// Check to see if our xmlElement was in the matching 0list
var match = matchesIterate.iterateNext()
while (match) {
if (xmlElement.xmlNode[0] === match) {
matchingVocab = vocabulary;
return false;
}
match = matchesIterate.iterateNext();
}
});
}

if (!matchingVocab || !(matchingVocab in this.options.vocabularyConfigs.vocabularies)) {
return null;
}

return this.options.vocabularyConfigs.vocabularies[matchingVocab];
}
});
4 changes: 3 additions & 1 deletion src/xml_element.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,9 @@ XMLElement.prototype.renderChild = function(childNode, recursive) {
};

XMLElement.prototype.renderText = function(childNode, prepend) {
var textNode = new XMLTextNode(childNode, this.objectType.type, this.editor);
var vocabulary = this.editor.getVocabulary(this);

var textNode = new XMLTextNode(childNode, this.objectType.type, this.editor, vocabulary);
textNode.render(this, prepend);

this.nodeCount++;
Expand Down
Loading

0 comments on commit 0cf7aad

Please sign in to comment.