1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873 |
- var Xonomy={
- lang: "", //"en"|"de"|fr"| ...
- mode: "nerd", //"nerd"|"laic"
- };
- Xonomy.setMode=function(mode) {
- if(mode=="nerd" || mode=="laic") Xonomy.mode=mode;
- if(mode=="nerd") $(".xonomy").removeClass("laic").addClass("nerd");
- if(mode=="laic") $(".xonomy").removeClass("nerd").addClass("laic");
- }
- Xonomy.jsEscape=function(str) {
- return String(str)
- .replace(/\"/g, '\\\"')
- .replace(/\'/g, '\\\'')
- };
- Xonomy.xmlEscape=function(str, jsEscape) {
- if(jsEscape) str=Xonomy.jsEscape(str);
- return String(str)
- .replace(/&/g, '&')
- .replace(/"/g, '"')
- .replace(/'/g, ''')
- .replace(/</g, '<')
- .replace(/>/g, '>');
- };
- Xonomy.xmlUnscape=function(value){
- return String(value)
- .replace(/"/g, '"')
- .replace(/'/g, "'")
- .replace(/</g, '<')
- .replace(/>/g, '>')
- .replace(/&/g, '&');
- };
- Xonomy.isNamespaceDeclaration=function(attributeName) {
- //Tells you whether an attribute name is a namespace declaration.
- var ret=false;
- if(attributeName=="xmlns") ret=true;
- if(attributeName.length>=6 && attributeName.substring(0, 6)=="xmlns:") ret=true;
- return ret;
- };
- Xonomy.namespaces={}; //eg. "xmlns:mbm": "http://lexonista.com"
- Xonomy.xml2js=function(xml, jsParent) {
- if(typeof(xml)=="string") xml=$.parseXML(xml);
- if(xml.documentElement) xml=xml.documentElement;
- var js=new Xonomy.surrogate(jsParent);
- js.type="element";
- js.name=xml.nodeName;
- js.htmlID="";
- js.attributes=[];
- for(var i=0; i<xml.attributes.length; i++) {
- var attr=xml.attributes[i];
- if(!Xonomy.isNamespaceDeclaration(attr.nodeName)) {
- if(attr.name!="xml:space") {
- js["attributes"].push({type: "attribute", name: attr.nodeName, value: attr.value, htmlID: "", parent: function(){return js}, });
- }
- } else {
- Xonomy.namespaces[attr.nodeName]=attr.value;
- }
- }
- js.children=[];
- for(var i=0; i<xml.childNodes.length; i++) {
- var child=xml.childNodes[i];
- if(child.nodeType==1) { //element node
- js["children"].push(Xonomy.xml2js(child, js));
- }
- if(child.nodeType==3) { //text node
- js["children"].push({type: "text", value: child.nodeValue, htmlID: "", parent: function(){return js}, });
- }
- }
- js=Xonomy.enrichElement(js);
- return js;
- };
- Xonomy.js2xml=function(js) {
- if(js.type=="text") {
- return Xonomy.xmlEscape(js.value);
- } else if(js.type=="attribute") {
- return js.name+"='"+Xonomy.xmlEscape(js.value)+"'";
- } else if(js.type=="element") {
- var xml="<"+js.name;
- for(var i=0; i<js.attributes.length; i++) {
- var att=js.attributes[i];
- xml+=" "+att.name+"='"+Xonomy.xmlEscape(att.value)+"'";
- }
- if(js.children.length>0) {
- var hasText=false;
- for(var i=0; i<js.children.length; i++) {
- var child=js.children[i];
- if(child.type=="text") hasText=true;
- }
- if(hasText) xml+=" xml:space='preserve'";
- xml+=">";
- for(var i=0; i<js.children.length; i++) {
- var child=js.children[i];
- if(child.type=="text") xml+=Xonomy.xmlEscape(child.value); //text node
- else if(child.type=="element") xml+=Xonomy.js2xml(child); //element node
- }
- xml+="</"+js.name+">";
- } else {
- xml+="/>";
- }
- return xml;
- }
- };
- Xonomy.enrichElement=function(jsElement) {
- jsElement.hasAttribute=function(name) {
- var ret=false;
- for(var i=0; i<this.attributes.length; i++) {
- if(this.attributes[i].name==name) ret=true;
- }
- return ret;
- };
- jsElement.getAttribute=function(name) {
- var ret=null;
- for(var i=0; i<this.attributes.length; i++) {
- if(this.attributes[i].name==name) ret=this.attributes[i];
- }
- return ret;
- };
- jsElement.getAttributeValue=function(name, ifNull) {
- var ret=ifNull;
- for(var i=0; i<this.attributes.length; i++) {
- if(this.attributes[i].name==name) ret=this.attributes[i].value;
- }
- return ret;
- };
- jsElement.hasChildElement=function(name) {
- var ret=false;
- for(var i=0; i<this.children.length; i++) {
- if(this.children[i].name==name) ret=true;
- }
- return ret;
- };
- jsElement.getChildElements=function(name) {
- var ret=[];
- for(var i=0; i<this.children.length; i++) {
- if(this.children[i].type=="element") {
- if(this.children[i].name==name) ret.push(this.children[i]);
- }
- }
- return ret;
- };
- jsElement.getDescendantElements=function(name) {
- var ret=[];
- for(var i=0; i<this.children.length; i++) {
- if(this.children[i].type=="element") {
- if(this.children[i].name==name) ret.push(this.children[i]);
- var temp=this.children[i].getDescendantElements(name);
- for(var t=0; t<temp.length; t++) ret.push(temp[t]);
- }
- }
- return ret;
- };
- jsElement.getText=function(){
- var txt="";
- for(var i=0; i<this.children.length; i++) {
- if(this.children[i].type=="text") txt+=this.children[i].value;
- else if(this.children[i].type=="element") txt+=this.children[i].getText();
- }
- return txt;
- };
- jsElement.hasElements=function(){
- for(var i=0; i<this.children.length; i++) {
- if(this.children[i].type=="element") return true;
- }
- return false;
- };
- jsElement.getPrecedingSibling=function(){
- var parent=this.parent();
- if(parent){
- var lastSibling=null;
- for(var i=0; i<parent.children.length; i++) {
- if(parent.children[i].type=="element" && parent.children[i].htmlID!=this.htmlID) {
- lastSibling=parent.children[i];
- } else if(parent.children[i].htmlID==this.htmlID){
- return lastSibling;
- }
- }
- }
- return null;
- };
- jsElement.getFollowingSibling=function(){
- var parent=this.parent();
- if(parent){
- var seenSelf=false;
- for(var i=0; i<parent.children.length; i++) {
- if(parent.children[i].htmlID==this.htmlID){
- seenSelf=true;
- } else if(parent.children[i].type=="element" && seenSelf) {
- return parent.children[i];
- }
- }
- }
- return null;
- };
- jsElement.setAttribute=function(name, value){
- if(this.hasAttribute(name)){
- this.getAttribute(name).value=value;
- } else {
- this.attributes.push({
- type: "attribute",
- name: name,
- value: value,
- htmlID: null,
- parent: function(){return this;}
- });
- }
- };
- jsElement.addText=function(txt){
- this.children.push({
- type: "text",
- value: txt,
- htmlID: null,
- parent: function(){return this;}
- });
- };
- return jsElement;
- };
- Xonomy.verifyDocSpec=function() { //make sure the docSpec object has everything it needs
- if(!Xonomy.docSpec || typeof(Xonomy.docSpec)!="object") Xonomy.docSpec={};
- if(!Xonomy.docSpec.elements || typeof(Xonomy.docSpec.elements)!="object") Xonomy.docSpec.elements={};
- if(!Xonomy.docSpec.onchange || typeof(Xonomy.docSpec.onchange)!="function") Xonomy.docSpec.onchange=function(){};
- if(!Xonomy.docSpec.validate || typeof(Xonomy.docSpec.validate)!="function") Xonomy.docSpec.validate=function(){};
- };
- Xonomy.asFunction=function(specProperty, defaultValue){
- if(typeof(specProperty)=="function")
- return specProperty;
- else if (typeof(specProperty)==typeof(defaultValue))
- return function() { return specProperty; }
- else
- return function() { return defaultValue };
- }
- Xonomy.verifyDocSpecElement=function(name) { //make sure the DocSpec object has such an element, that the element has everything it needs
- if(!Xonomy.docSpec.elements[name] || typeof(Xonomy.docSpec.elements[name])!="object") {
- if(Xonomy.docSpec.unknownElement) {
- Xonomy.docSpec.elements[name]=(typeof(Xonomy.docSpec.unknownElement)==="function")
- ? Xonomy.docSpec.unknownElement(name)
- : Xonomy.docSpec.unknownElement;
- }
- else Xonomy.docSpec.elements[name]={};
- }
- var spec=Xonomy.docSpec.elements[name];
- if(!spec.attributes || typeof(spec.attributes)!="object") spec.attributes={};
- if(!spec.menu || typeof(spec.menu)!="object") spec.menu=[];
- if(!spec.inlineMenu || typeof(spec.inlineMenu)!="object") spec.inlineMenu=[];
- if(!spec.canDropTo || typeof(spec.canDropTo)!="object") spec.canDropTo=[];
- //if(!spec.mustBeAfter || typeof(spec.mustBeAfter)!="object") spec.mustBeAfter=[];
- //if(!spec.mustBeBefore || typeof(spec.mustBeBefore)!="object") spec.mustBeBefore=[];
- spec.mustBeAfter=Xonomy.asFunction(spec.mustBeAfter, []);
- spec.mustBeBefore=Xonomy.asFunction(spec.mustBeBefore, []);
- spec.oneliner=Xonomy.asFunction(spec.oneliner, false);
- spec.hasText=Xonomy.asFunction(spec.hasText, false);
- spec.collapsible=Xonomy.asFunction(spec.collapsible, true);
- spec.collapsed=Xonomy.asFunction(spec.collapsed, false);
- spec.localDropOnly=Xonomy.asFunction(spec.localDropOnly, false);
- spec.isReadOnly=Xonomy.asFunction(spec.isReadOnly, false);
- spec.isInvisible=Xonomy.asFunction(spec.isInvisible, false);
- spec.backgroundColour=Xonomy.asFunction(spec.backgroundColour, "");
- if(spec.displayName) spec.displayName=Xonomy.asFunction(spec.displayName, "");
- if(spec.title) spec.title=Xonomy.asFunction(spec.title, "");
- for(var i=0; i<spec.menu.length; i++) Xonomy.verifyDocSpecMenuItem(spec.menu[i]);
- for(var i=0; i<spec.inlineMenu.length; i++) Xonomy.verifyDocSpecMenuItem(spec.inlineMenu[i]);
- for(var attributeName in spec.attributes) Xonomy.verifyDocSpecAttribute(name, attributeName);
- };
- Xonomy.verifyDocSpecAttribute=function(elementName, attributeName) { //make sure the DocSpec object has such an attribute, that the attribute has everything it needs
- var elSpec=Xonomy.docSpec.elements[elementName];
- if(!elSpec.attributes[attributeName] || typeof(elSpec.attributes[attributeName])!="object") {
- if(Xonomy.docSpec.unknownAttribute) {
- elSpec.attributes[attributeName]=(typeof(Xonomy.docSpec.unknownAttribute)==="function")
- ? Xonomy.docSpec.unknownAttribute(elementName, attributeName)
- : Xonomy.docSpec.unknownAttribute;
- }
- else elSpec.attributes[attributeName]={};
- }
- var spec=elSpec.attributes[attributeName];
- if(!spec.asker || typeof(spec.asker)!="function") spec.asker=function(){return ""};
- if(!spec.menu || typeof(spec.menu)!="object") spec.menu=[];
- spec.isReadOnly=Xonomy.asFunction(spec.isReadOnly, false);
- spec.isInvisible=Xonomy.asFunction(spec.isInvisible, false);
- spec.shy=Xonomy.asFunction(spec.shy, false);
- if(spec.displayName) spec.displayName=Xonomy.asFunction(spec.displayName, "");
- if(spec.title) spec.title=Xonomy.asFunction(spec.title, "");
- for(var i=0; i<spec.menu.length; i++) Xonomy.verifyDocSpecMenuItem(spec.menu[i]);
- };
- Xonomy.verifyDocSpecMenuItem=function(menuItem) { //make sure the menu item has all it needs
- menuItem.caption=Xonomy.asFunction(menuItem.caption, "?");
- if(!menuItem.action || typeof(menuItem.action)!="function") menuItem.action=function(){};
- if(!menuItem.hideIf) menuItem.hideIf=function(){return false;};
- if(typeof(menuItem.expanded)!="function") menuItem.expanded=Xonomy.asFunction(menuItem.expanded, false);
- };
- Xonomy.nextID=function() {
- return "xonomy"+(++Xonomy.lastIDNum);
- };
- Xonomy.lastIDNum=0;
- Xonomy.docSpec=null;
- Xonomy.refresh=function() {
- $(".xonomy .textnode[data-value='']").each(function(){ //delete empty text nodes if the parent element is not allowed to have text
- var $this=$(this);
- var $parent=$this.closest(".element");
- var parentName=$parent.data("name");
- var elSpec=Xonomy.docSpec.elements[parentName];
- if(elSpec && !elSpec.hasText(Xonomy.harvestElement($parent.toArray()[0]))) {
- $this.remove();
- }
- });
- $(".xonomy .children ").each(function(){ //determine whether each element does or doesn't have children:
- if(this.childNodes.length==0 && !$(this.parentNode).hasClass("hasText")) $(this.parentNode).addClass("noChildren");
- else {
- $(this.parentNode).removeClass("noChildren");
- Xonomy.updateCollapsoid(this.parentNode.id);
- }
- });
- $(".xonomy .element.hasText > .children > .element").each(function () { //determine whether each child element of hasText element should have empty text nodes on either side
- if($(this).prev().length == 0 || !$(this).prev().hasClass("textnode")) {
- $(this).before(Xonomy.renderText({ type: "text", value: "" }));
- }
- if($(this).next().length == 0 || !$(this).next().hasClass("textnode")) {
- $(this).after(Xonomy.renderText({ type: "text", value: "" }));
- }
- });
- var merged=false; while(!merged) { //merge adjacent text nodes
- merged=true; var textnodes=$(".xonomy .textnode").toArray();
- for(var i=0; i<textnodes.length; i++) {
- var $this=$(textnodes[i]);
- if($this.next().hasClass("textnode")) {
- var js1=Xonomy.harvestText($this.toArray()[0]);
- var js2=Xonomy.harvestText($this.next().toArray()[0]);
- js1.value+=js2.value;
- $this.next().remove();
- $this.replaceWith(Xonomy.renderText(js1));
- merged=false;
- break;
- }
- }
- }
- $(".xonomy .attribute ").each(function(){ //reorder attributes if necessary
- var atName=this.getAttribute("data-name");
- var elName=this.parentNode.parentNode.parentNode.getAttribute("data-name");
- var elSpec=Xonomy.docSpec.elements[elName];
- var mustBeAfter=[]; for(var sibName in elSpec.attributes) {
- if(sibName==atName) break; else mustBeAfter.push(sibName);
- }
- var mustBeBefore=[]; var seen=false; for(var sibName in elSpec.attributes) {
- if(sibName==atName) seen=true; else if(seen) mustBeBefore.push(sibName);
- }
- if(mustBeBefore.length>0) { //is it after an attribute it cannot be after? then move it up until it's not!
- var $this=$(this);
- var ok; do {
- ok=true;
- for(var ii=0; ii<mustBeBefore.length; ii++) {
- if( $this.prevAll("*[data-name='"+mustBeBefore[ii]+"']").toArray().length>0 ) {
- $this.prev().before($this);
- ok=false;
- }
- }
- } while(!ok)
- }
- if(mustBeAfter.length>0) { //is it before an attribute it cannot be before? then move it down until it's not!
- var $this=$(this);
- var ok; do {
- ok=true;
- for(var ii=0; ii<mustBeAfter.length; ii++) {
- if( $this.nextAll("*[data-name='"+mustBeAfter[ii]+"']").toArray().length>0 ) {
- $this.next().after($this);
- ok=false;
- }
- }
- } while(!ok)
- }
- });
- $(".xonomy .attributes").each(function(){ //determine whether each attribute list has any shy attributes:
- if($(this).children(".shy").toArray().length==0) {
- $(this.parentNode).children(".rollouter").hide().removeClass("rolledout");
- $(this).removeClass("rolledout").css("display", "");
- } else {
- $(this.parentNode).children(".rollouter").show();
- }
- });
- $(".xonomy .element").each(function(){ //refresh display names, display values and captions:
- var elSpec=Xonomy.docSpec.elements[this.getAttribute("data-name")];
- if(elSpec.displayName) $(this).children(".tag").children(".name").html(Xonomy.textByLang(elSpec.displayName(Xonomy.harvestElement(this))));
- if(elSpec.caption) {
- var jsEl=Xonomy.harvestElement(this);
- $(this).children(".inlinecaption").html(Xonomy.textByLang(elSpec.caption(jsEl)));
- }
- if(elSpec.displayValue) {
- var jsEl=Xonomy.harvestElement(this);
- if(!jsEl.hasElements()) $(this).children(".children").html( Xonomy.textByLang(Xonomy.renderDisplayText(jsEl.getText(), elSpec.displayValue(jsEl))) );
- }
- $(this).children(".tag.opening").children(".attributes").children(".attribute").each(function(){
- var atSpec=elSpec.attributes[this.getAttribute("data-name")];
- if(atSpec.displayName) $(this).children(".name").html(Xonomy.textByLang(atSpec.displayName(Xonomy.harvestAttribute(this))));
- if(atSpec.displayValue) $(this).children(".value").html(Xonomy.textByLang(atSpec.displayValue(Xonomy.harvestAttribute(this))));
- if(atSpec.caption) $(this).children(".inlinecaption").html(" "+Xonomy.textByLang(atSpec.caption(Xonomy.harvestAttribute(this)))+" ");
- });
- });
- };
- Xonomy.harvestCache={};
- Xonomy.harvest=function() { //harvests the contents of an editor
- //Returns xml-as-string.
- var rootElement=$(".xonomy .element").first().toArray()[0];
- var js=Xonomy.harvestElement(rootElement);
- for(var key in Xonomy.namespaces) {
- if(!js.hasAttribute(key)) js.attributes.push({
- type: "attribute",
- name: key,
- value: Xonomy.namespaces[key],
- parent: js
- });
- }
- return Xonomy.js2xml(js);
- }
- Xonomy.harvestElement=function(htmlElement, jsParent) {
- var htmlID=htmlElement.id;
- if(!Xonomy.harvestCache[htmlID]) {
- var js=new Xonomy.surrogate(jsParent);
- js.type="element";
- js.name=htmlElement.getAttribute("data-name");
- js.htmlID=htmlElement.id;
- js.attributes=[];
- var htmlAttributes=$(htmlElement).find(".tag.opening > .attributes").toArray()[0];
- for(var i=0; i<htmlAttributes.childNodes.length; i++) {
- var htmlAttribute=htmlAttributes.childNodes[i];
- if($(htmlAttribute).hasClass("attribute")) js["attributes"].push(Xonomy.harvestAttribute(htmlAttribute, js));
- }
- js.children=[];
- var htmlChildren=$(htmlElement).children(".children").toArray()[0];
- for(var i=0; i<htmlChildren.childNodes.length; i++) {
- var htmlChild=htmlChildren.childNodes[i];
- if($(htmlChild).hasClass("element")) js["children"].push(Xonomy.harvestElement(htmlChild, js));
- else if($(htmlChild).hasClass("textnode")) js["children"].push(Xonomy.harvestText(htmlChild, js));
- }
- js=Xonomy.enrichElement(js);
- Xonomy.harvestCache[htmlID]=js;
- }
- return Xonomy.harvestCache[htmlID];
- };
- Xonomy.harvestAttribute=function(htmlAttribute, jsParent) {
- var htmlID=htmlAttribute.id;
- if(!Xonomy.harvestCache[htmlID]) {
- var js = new Xonomy.surrogate(jsParent);
- js.type = "attribute";
- js.name = htmlAttribute.getAttribute("data-name");
- js.htmlID = htmlAttribute.id;
- js.value = htmlAttribute.getAttribute("data-value");
- Xonomy.harvestCache[htmlID]=js;
- }
- return Xonomy.harvestCache[htmlID];
- }
- Xonomy.surrogate=function(jsParent) {
- this.internalParent=jsParent;
- }
- Xonomy.surrogate.prototype.parent=function() {
- if (!this.internalParent) {
- this.internalParent=Xonomy.harvestParentOf(this);
- }
- return this.internalParent;
- }
- Xonomy.harvestText = function (htmlText, jsParent) {
- var js = new Xonomy.surrogate(jsParent);
- js.type = "text";
- js.htmlID = htmlText.id;
- js.value = htmlText.getAttribute("data-value");
- return js;
- }
- Xonomy.harvestParentOf=function(js) {
- var jsParent=null;
- var $parent=$("#"+js.htmlID).parent().closest(".element");
- if($parent.toArray().length==1) {
- jsParent=Xonomy.harvestElement($parent.toArray()[0]);
- for(var i=0; i<jsParent.attributes.length; i++) if(jsParent.attributes[i].htmlID==js.htmlID) jsParent.attributes[i]=js;
- for(var i=0; i<jsParent.children.length; i++) if(jsParent.children[i].htmlID==js.htmlID) jsParent.children[i]=js;
- }
- return jsParent;
- };
- Xonomy.render=function(data, editor, docSpec) { //renders the contents of an editor
- //The data can be a Xonomy-compliant XML document, a Xonomy-compliant xml-as-string,
- //or a Xonomy-compliant JavaScript object.
- //The editor can be an HTML element, or the string ID of one.
- Xonomy.docSpec=docSpec;
- Xonomy.verifyDocSpec();
- //Clear namespace cache:
- Xonomy.namespaces={};
- //Convert doc to a JavaScript object, if it isn't a JavaScript object already:
- if(typeof(data)=="string") data=$.parseXML(data);
- if(data.documentElement) data=Xonomy.xml2js(data);
- //Make sure editor refers to an HTML element, if it doesn't already:
- if(typeof(editor)=="string") editor=document.getElementById(editor);
- if(!$(editor).hasClass("xonomy")) $(editor).addClass("xonomy"); //make sure it has class "xonomy"
- $(editor).addClass(Xonomy.mode);
- $(editor).hide();
- editor.innerHTML=Xonomy.renderElement(data, editor);
- $(editor).show();
- if(docSpec.allowLayby){
- var laybyHtml="<div class='layby closed empty' onclick='if($(this).hasClass(\"closed\")) Xonomy.openLayby()' ondragover='Xonomy.dragOver(event)' ondragleave='Xonomy.dragOut(event)' ondrop='Xonomy.drop(event)''>";
- laybyHtml+="<span class='button closer' onclick='Xonomy.closeLayby();'> </span>";
- laybyHtml+="<span class='button purger' onclick='Xonomy.emptyLayby()'> </span>";
- laybyHtml+="<div class='content'></div>";
- laybyHtml+="<div class='message'>"+Xonomy.textByLang(docSpec.laybyMessage)+"</div>";
- laybyHtml+="</div>";
- $(laybyHtml).appendTo($(editor));
- }
- if(docSpec.allowModeSwitching){
- $("<div class='modeSwitcher'><span class='nerd'></span><span class='laic'></span></div>").appendTo($(editor)).on("click", function(e){
- if(Xonomy.mode=="nerd") { Xonomy.setMode("laic"); } else { Xonomy.setMode("nerd"); }
- if(docSpec.onModeSwitch) docSpec.onModeSwitch(Xonomy.mode);
- });
- }
- //Make sure the "click off" handler is attached:
- $(document.body).off("click", Xonomy.clickoff);
- $(document.body).on("click", Xonomy.clickoff);
- //Make sure the "drag end" handler is attached:
- $(document.body).off("dragend", Xonomy.dragend);
- $(document.body).on("dragend", Xonomy.dragend);
- Xonomy.refresh();
- Xonomy.validate();
- };
- Xonomy.renderElement=function(element) {
- var htmlID=Xonomy.nextID();
- Xonomy.verifyDocSpecElement(element.name);
- var spec=Xonomy.docSpec.elements[element.name];
- var classNames="element";
- if(spec.canDropTo && spec.canDropTo.length>0) classNames+=" draggable";
- var hasText = spec.hasText(element);
- if(hasText) classNames+=" hasText";
- if(spec.inlineMenu && spec.inlineMenu.length>0) classNames+=" hasInlineMenu";
- if(spec.oneliner(element)) classNames+=" oneliner";
- if(!spec.collapsible(element)) {
- classNames+=" uncollapsible";
- } else {
- if(spec.collapsed(element) && element.children.length>0) classNames+=" collapsed";
- }
- if(spec.isInvisible && spec.isInvisible(element)) { classNames+=" invisible"; }
- if(spec.isReadOnly && spec.isReadOnly(element)) { readonly=true; classNames+=" readonly"; }
- if(spec.menu.length>0) classNames+=" hasMenu"; //not always accurate: whether an element has a menu is actually determined at runtime
- var displayName=element.name;
- if(spec.displayName) displayName=Xonomy.textByLang(spec.displayName(element));
- var title="";
- if(spec.title) title=Xonomy.textByLang(spec.title(element));
- var html="";
- html+='<div data-name="'+element.name+'" id="'+htmlID+'" class="'+classNames+'">';
- html+='<span class="connector">';
- html+='<span class="plusminus" onclick="Xonomy.plusminus(\''+htmlID+'\')"></span>';
- html+='<span class="draghandle" draggable="true" ondragstart="Xonomy.drag(event)"></span>';
- html+='</span>';
- html+='<span class="tag opening focusable" style="background-color: '+spec.backgroundColour(element)+';">';
- html+='<span class="punc"><</span>';
- html+='<span class="warner"><span class="inside" onclick="Xonomy.click(\''+htmlID+'\', \'warner\')"></span></span>';
- html+='<span class="name" title="'+title+'" onclick="Xonomy.click(\''+htmlID+'\', \'openingTagName\')">'+displayName+'</span>';
- html+='<span class="attributes">';
- for(var i=0; i<element.attributes.length; i++) {
- Xonomy.verifyDocSpecAttribute(element.name, element.attributes[i].name);
- html+=Xonomy.renderAttribute(element.attributes[i], element.name);
- }
- html+='</span>';
- html+='<span class="rollouter focusable" onclick="Xonomy.click(\''+htmlID+'\', \'rollouter\')"></span>';
- html+='<span class="punc slash">/</span>';
- html+='<span class="punc">></span>';
- html+='</span>';
- if(spec.caption && !spec.oneliner(element)) html+="<span class='inlinecaption'>"+Xonomy.textByLang(spec.caption(element))+"</span>";
- html+='<span class="childrenCollapsed focusable" onclick="Xonomy.plusminus(\''+htmlID+'\', true)">···</span>';
- html+='<div class="children">';
- if(spec.displayValue && !element.hasElements()) {
- html+=Xonomy.renderDisplayText(element.getText(), spec.displayValue(element));
- } else {
- var prevChildType="";
- if(hasText && (element.children.length==0 || element.children[0].type=="element")) {
- html+=Xonomy.renderText({type: "text", value: ""}); //if inline layout, insert empty text node between two elements
- }
- for(var i=0; i<element.children.length; i++) {
- var child=element.children[i];
- if(hasText && prevChildType=="element" && child.type=="element") {
- html+=Xonomy.renderText({type: "text", value: ""}); //if inline layout, insert empty text node between two elements
- }
- if(child.type=="text") html+=Xonomy.renderText(child); //text node
- else if(child.type=="element") html+=Xonomy.renderElement(child); //element node
- prevChildType=child.type;
- }
- if(hasText && element.children.length>1 && element.children[element.children.length-1].type=="element") {
- html+=Xonomy.renderText({type: "text", value: ""}); //if inline layout, insert empty text node between two elements
- }
- }
- html+='</div>';
- html+='<span class="tag closing focusable" style="background-color: '+spec.backgroundColour(element)+';">';
- html+='<span class="punc"><</span>';
- html+='<span class="punc">/</span>';
- html+='<span class="name" onclick="Xonomy.click(\''+htmlID+'\', \'closingTagName\')">'+displayName+'</span>';
- html+='<span class="punc">></span>';
- html+='</span>';
- if(spec.caption && spec.oneliner(element)) html+="<span class='inlinecaption'>"+Xonomy.textByLang(spec.caption(element))+"</span>";
- html+='</div>';
- element.htmlID = htmlID;
- return html;
- };
- Xonomy.renderAttribute=function(attribute, optionalParentName) {
- var htmlID=Xonomy.nextID();
- classNames="attribute";
- var readonly=false;
- var displayName=attribute.name;
- var displayValue=Xonomy.xmlEscape(attribute.value);
- var caption="";
- var title="";
- if(optionalParentName) {
- var spec=Xonomy.docSpec.elements[optionalParentName].attributes[attribute.name];
- if(spec) {
- if(spec.displayName) displayName=Xonomy.textByLang(spec.displayName(attribute));
- if(spec.displayValue) displayValue=Xonomy.textByLang(spec.displayValue(attribute));
- if(spec.title) title=Xonomy.textByLang(spec.title(attribute));
- if(spec.caption) caption=Xonomy.textByLang(spec.caption(attribute));
- if(spec.isReadOnly && spec.isReadOnly(attribute)) { readonly=true; classNames+=" readonly"; }
- if(spec.isInvisible && spec.isInvisible(attribute)) { classNames+=" invisible"; }
- if(spec.shy && spec.shy(attribute)) { classNames+=" shy"; }
- }
- }
- var html="";
- html+='<span data-name="'+attribute.name+'" data-value="'+Xonomy.xmlEscape(attribute.value)+'" id="'+htmlID+'" class="'+classNames+'">';
- html+='<span class="punc"> </span>';
- var onclick=''; if(!readonly) onclick=' onclick="Xonomy.click(\''+htmlID+'\', \'attributeName\')"';
- html+='<span class="warner"><span class="inside" onclick="Xonomy.click(\''+htmlID+'\', \'warner\')"></span></span>';
- html+='<span class="name attributeName focusable" title="'+title+'"'+onclick+'>'+displayName+'</span>';
- html+='<span class="punc">=</span>';
- var onclick=''; if(!readonly) onclick=' onclick="Xonomy.click(\''+htmlID+'\', \'attributeValue\')"';
- html+='<span class="valueContainer attributeValue focusable"'+onclick+'>';
- html+='<span class="punc">"</span>';
- html+='<span class="value">'+displayValue+'</span>';
- html+='<span class="punc">"</span>';
- html+='</span>';
- if(caption) html+="<span class='inlinecaption'>"+caption+"</span>";
- html+='</span>';
- attribute.htmlID = htmlID;
- return html;
- };
- Xonomy.renderText=function(text) {
- var htmlID=Xonomy.nextID();
- var classNames="textnode focusable";
- if($.trim(text.value)=="") classNames+=" whitespace";
- if(text.value=="") classNames+=" empty";
- var html="";
- html+='<div id="'+htmlID+'" data-value="'+Xonomy.xmlEscape(text.value)+'" class="'+classNames+'">';
- html+='<span class="connector"></span>';
- var txt=Xonomy.chewText(text.value);
- html+='<span class="value" onclick="Xonomy.click(\''+htmlID+'\', \'text\')"><span class="insertionPoint"><span class="inside"></span></span><span class="dots"></span>'+txt+'</span>';
- html+='</div>';
- text.htmlID = htmlID;
- return html;
- }
- Xonomy.renderDisplayText=function(text, displayText) {
- var htmlID=Xonomy.nextID();
- var classNames="textnode";
- if($.trim(displayText)=="") classNames+=" whitespace";
- if(displayText=="") classNames+=" empty";
- var html="";
- html+='<div id="'+htmlID+'" data-value="'+Xonomy.xmlEscape(text)+'" class="'+classNames+'">';
- html+='<span class="connector"></span>';
- html+='<span class="value" onclick="Xonomy.click(\''+htmlID+'\', \'text\')"><span class="insertionPoint"><span class="inside"></span></span><span class="dots"></span>'+Xonomy.textByLang(displayText)+'</span>';
- html+='</div>';
- text.htmlID = htmlID;
- return html;
- }
- Xonomy.chewText=function(txt) {
- var ret="";
- ret+="<span class='word'>"; //start word
- for(var i=0; i<txt.length; i++) {
- if(txt[i]==" ") ret+="</span>"; //end word
- var t=Xonomy.xmlEscape(txt[i])
- if(i==0 && t==" ") t="<span class='space'>·</span>"; //leading space
- if(i==txt.length-1 && t==" ") t="<span class='space'>·</span>"; //trailing space
- var id=Xonomy.nextID();
- ret+="<span id='"+id+"' class='char focusable' onclick='if((event.ctrlKey||event.metaKey) && $(this).closest(\".element\").hasClass(\"hasInlineMenu\")) Xonomy.charClick(this)'>"+t+"<span class='selector'><span class='inside' onclick='Xonomy.charClick(this.parentNode.parentNode)'></span></span></span>";
- if(txt[i]==" ") ret+="<span class='word'>"; //start word
- }
- ret+="</span>"; //end word
- return ret;
- };
- Xonomy.charClick=function(c) {
- Xonomy.clickoff();
- var isReadOnly=( $(c).closest(".readonly").toArray().length>0 );
- if(!isReadOnly) {
- Xonomy.notclick=true;
- if(
- $(".xonomy .char.on").toArray().length==1 && //if there is precisely one previously selected character
- $(".xonomy .char.on").closest(".element").is($(c).closest(".element")) //and if it has the same parent element as this character
- ) {
- var $element=$(".xonomy .char.on").closest(".element");
- var chars=$element.find(".char").toArray();
- var iFrom=$.inArray($(".xonomy .char.on").toArray()[0], chars);
- var iTill=$.inArray(c, chars);
- if(iFrom>iTill) {var temp=iFrom; iFrom=iTill; iTill=temp;}
- for(var i=0; i<chars.length; i++) { //highlight all chars between start and end
- if(i>=iFrom && i<=iTill) $(chars[i]).addClass("on");
- }
- //Save for later the info Xonomy needs to know what to wrap:
- Xonomy.textFromID=$(chars[iFrom]).closest(".textnode").attr("id");
- Xonomy.textTillID=$(chars[iTill]).closest(".textnode").attr("id");
- Xonomy.textFromIndex=$.inArray(chars[iFrom], $("#"+Xonomy.textFromID).find(".char").toArray());
- Xonomy.textTillIndex=$.inArray(chars[iTill], $("#"+Xonomy.textTillID).find(".char").toArray());
- //Show inline menu etc:
- var htmlID=$element.attr("id");
- var content=Xonomy.inlineMenu(htmlID); //compose bubble content
- if(content!="" && content!="<div class='menu'></div>") {
- document.body.appendChild(Xonomy.makeBubble(content)); //create bubble
- Xonomy.showBubble($("#"+htmlID+" .char.on").last()); //anchor bubble to highlighted chars
- }
- Xonomy.clearChars=true;
- } else {
- $(".xonomy .char.on").removeClass("on");
- $(c).addClass("on");
- Xonomy.setFocus(c.id, "char");
- }
- }
- };
- Xonomy.wrap=function(htmlID, param) {
- Xonomy.clickoff();
- Xonomy.destroyBubble();
- var xml=param.template;
- var ph=param.placeholder;
- var jsElement=Xonomy.harvestElement(document.getElementById(htmlID));
- if(Xonomy.textFromID==Xonomy.textTillID) { //abc --> a<XYZ>b</XYZ>c
- var jsOld=Xonomy.harvestText(document.getElementById(Xonomy.textFromID));
- var txtOpen=jsOld.value.substring(0, Xonomy.textFromIndex);
- var txtMiddle=jsOld.value.substring(Xonomy.textFromIndex, Xonomy.textTillIndex+1);
- var txtClose=jsOld.value.substring(Xonomy.textTillIndex+1);
- xml=xml.replace(ph, Xonomy.xmlEscape(txtMiddle));
- var html="";
- html+=Xonomy.renderText({type: "text", value: txtOpen});
- var js=Xonomy.xml2js(xml, jsElement); html+=Xonomy.renderElement(js); var newID=js.htmlID;
- html+=Xonomy.renderText({type: "text", value: txtClose});
- $("#"+Xonomy.textFromID).replaceWith(html);
- window.setTimeout(function(){ Xonomy.setFocus(newID, "openingTagName"); }, 100);
- } else { //ab<...>cd --> a<XYZ>b<...>c</XYZ>d
- var jsOldOpen=Xonomy.harvestText(document.getElementById(Xonomy.textFromID));
- var jsOldClose=Xonomy.harvestText(document.getElementById(Xonomy.textTillID));
- var txtOpen=jsOldOpen.value.substring(0, Xonomy.textFromIndex);
- var txtMiddleOpen=jsOldOpen.value.substring(Xonomy.textFromIndex);
- var txtMiddleClose=jsOldClose.value.substring(0, Xonomy.textTillIndex+1);
- var txtClose=jsOldClose.value.substring(Xonomy.textTillIndex+1);
- xml=xml.replace(ph, Xonomy.xmlEscape(txtMiddleOpen)+ph);
- $("#"+Xonomy.textFromID).nextUntil("#"+Xonomy.textTillID).each(function(){
- if($(this).hasClass("element")) xml=xml.replace(ph, Xonomy.js2xml(Xonomy.harvestElement(this))+ph);
- else if($(this).hasClass("textnode")) xml=xml.replace(ph, Xonomy.js2xml(Xonomy.harvestText(this))+ph);
- });
- xml=xml.replace(ph, Xonomy.xmlEscape(txtMiddleClose));
- $("#"+Xonomy.textFromID).nextUntil("#"+Xonomy.textTillID).remove();
- $("#"+Xonomy.textTillID).remove();
- var html="";
- html+=Xonomy.renderText({type: "text", value: txtOpen});
- var js=Xonomy.xml2js(xml, jsElement); html+=Xonomy.renderElement(js); var newID=js.htmlID;
- html+=Xonomy.renderText({type: "text", value: txtClose});
- $("#"+Xonomy.textFromID).replaceWith(html);
- window.setTimeout(function(){ Xonomy.setFocus(newID, "openingTagName"); }, 100);
- }
- Xonomy.changed();
- };
- Xonomy.unwrap=function(htmlID, param) {
- var parentID=$("#"+htmlID)[0].parentNode.parentNode.id;
- Xonomy.clickoff();
- $("#"+htmlID).replaceWith($("#"+htmlID+" > .children > *"));
- Xonomy.changed();
- window.setTimeout(function(){ Xonomy.setFocus(parentID, "openingTagName"); }, 100);
- };
- Xonomy.plusminus=function(htmlID, forceExpand) {
- var $element=$("#"+htmlID);
- var $children=$element.children(".children");
- if($element.hasClass("collapsed")) {
- $children.hide();
- $element.removeClass("collapsed");
- if($element.hasClass("oneliner")) $children.fadeIn("fast"); else $children.slideDown("fast");
- } else if(!forceExpand) {
- Xonomy.updateCollapsoid(htmlID);
- if($element.hasClass("oneliner")) $children.fadeOut("fast", function(){ $element.addClass("collapsed"); });
- else $children.slideUp("fast", function(){ $element.addClass("collapsed"); });
- }
- window.setTimeout(function(){
- if($("#"+Xonomy.currentHtmlId+" .opening:visible").length>0) {
- Xonomy.setFocus(Xonomy.currentHtmlId, "openingTagName");
- } else {
- Xonomy.setFocus(Xonomy.currentHtmlId, "childrenCollapsed");
- }
- }, 300);
- };
- Xonomy.updateCollapsoid=function(htmlID) {
- var $element=$("#"+htmlID);
- var whisper="";
- var elementName=$element.data("name");
- var spec=Xonomy.docSpec.elements[elementName];
- if(spec.collapsoid) {
- whisper=spec.collapsoid(Xonomy.harvestElement($element.toArray()[0]));
- } else {
- var abbreviated=false;
- $element.find(".textnode").each(function(){
- var txt=Xonomy.harvestText(this).value;
- for(var i=0; i<txt.length; i++) {
- if(whisper.length<35) whisper+=txt[i]; else abbreviated=true;
- }
- whisper+=" ";
- });
- whisper=whisper.replace(/ +/g, " ").replace(/ +$/g, "");
- if(abbreviated && !$element.hasClass("oneliner") && whisper!="...") whisper+="...";
- }
- if(whisper=="" || !whisper) whisper="...";
- $element.children(".childrenCollapsed").html(whisper);
- };
- Xonomy.lastClickWhat="";
- Xonomy.click=function(htmlID, what) {
- if(!Xonomy.notclick) {
- Xonomy.clickoff();
- Xonomy.lastClickWhat=what;
- Xonomy.currentHtmlId=htmlID;
- Xonomy.currentFocus=what;
- $(".xonomy .char.on").removeClass("on");
- var isReadOnly=( $("#"+htmlID).hasClass("readonly") || $("#"+htmlID).closest(".readonly").toArray().length>0 );
- if(!isReadOnly && (what=="openingTagName" || what=="closingTagName") ) {
- $("#"+htmlID).addClass("current"); //make the element current
- var content=Xonomy.elementMenu(htmlID); //compose bubble content
- if(content!="" && content!="<div class='menu'></div>") {
- document.body.appendChild(Xonomy.makeBubble(content)); //create bubble
- if(what=="openingTagName") Xonomy.showBubble($("#"+htmlID+" > .tag.opening > .name")); //anchor bubble to opening tag
- if(what=="closingTagName") Xonomy.showBubble($("#"+htmlID+" > .tag.closing > .name")); //anchor bubble to closing tag
- }
- var surrogateElem = Xonomy.harvestElement(document.getElementById(htmlID));
- $("#"+htmlID).trigger("xonomy-click-element", [surrogateElem]);
- }
- if(!isReadOnly && what=="attributeName") {
- $("#"+htmlID).addClass("current"); //make the attribute current
- var content=Xonomy.attributeMenu(htmlID); //compose bubble content
- if(content!="" && content!="<div class='menu'></div>") {
- document.body.appendChild(Xonomy.makeBubble(content)); //create bubble
- Xonomy.showBubble($("#"+htmlID+" > .name")); //anchor bubble to attribute name
- }
- var surrogateAttr = Xonomy.harvestAttribute(document.getElementById(htmlID));
- $("#"+htmlID).trigger("xonomy-click-attribute", [surrogateAttr]);
- }
- if(!isReadOnly && what=="attributeValue") {
- $("#"+htmlID+" > .valueContainer").addClass("current"); //make attribute value current
- var name=$("#"+htmlID).attr("data-name"); //obtain attribute's name
- var value=$("#"+htmlID).attr("data-value"); //obtain current value
- var elName=$("#"+htmlID).closest(".element").attr("data-name");
- Xonomy.verifyDocSpecAttribute(elName, name);
- var spec=Xonomy.docSpec.elements[elName].attributes[name];
- var content=spec.asker(value, spec.askerParameter, Xonomy.harvestAttribute(document.getElementById(htmlID))); //compose bubble content
- if(content!="" && content!="<div class='menu'></div>") {
- document.body.appendChild(Xonomy.makeBubble(content)); //create bubble
- Xonomy.showBubble($("#"+htmlID+" > .valueContainer > .value")); //anchor bubble to value
- Xonomy.answer=function(val) {
- var obj=document.getElementById(htmlID);
- var html=Xonomy.renderAttribute({type: "attribute", name: name, value: val}, elName);
- $(obj).replaceWith(html);
- Xonomy.changed();
- window.setTimeout(function(){Xonomy.clickoff(); Xonomy.setFocus($(html).prop("id"), what)}, 100);
- };
- }
- }
- if(!isReadOnly && what=="text") {
- $("#"+htmlID).addClass("current");
- var value=$("#"+htmlID).attr("data-value"); //obtain current value
- var elName=$("#"+htmlID).closest(".element").attr("data-name");
- var spec=Xonomy.docSpec.elements[elName];
- if (typeof(spec.asker) != "function") {
- var content=Xonomy.askLongString(value, null, Xonomy.harvestElement($("#"+htmlID).closest(".element").toArray()[0])); //compose bubble content
- } else {
- var content=spec.asker(value, spec.askerParameter, Xonomy.harvestElement($("#"+htmlID).closest(".element").toArray()[0])); //use specified asker
- }
- if(content!="" && content!="<div class='menu'></div>") {
- document.body.appendChild(Xonomy.makeBubble(content)); //create bubble
- Xonomy.showBubble($("#"+htmlID+" > .value")); //anchor bubble to value
- Xonomy.answer=function(val) {
- var obj=document.getElementById(htmlID);
- var jsText = {type: "text", value: val};
- var html=Xonomy.renderText(jsText);
- $(obj).replaceWith(html);
- Xonomy.changed(Xonomy.harvestText(document.getElementById(jsText.htmlID)));
- window.setTimeout(function(){Xonomy.clickoff(); Xonomy.setFocus($(html).prop("id"), what)}, 100);
- };
- }
- }
- if(what=="warner") {
- //$("#"+htmlID).addClass("current");
- var content=""; //compose bubble content
- for(var iWarning=0; iWarning<Xonomy.warnings.length; iWarning++) {
- var warning=Xonomy.warnings[iWarning];
- if(warning.htmlID==htmlID) {
- content+="<div class='warning'>"+Xonomy.formatCaption(Xonomy.textByLang(warning.text))+"</div>";
- }
- }
- document.body.appendChild(Xonomy.makeBubble(content)); //create bubble
- Xonomy.showBubble($("#"+htmlID+" .warner .inside").first()); //anchor bubble to warner
- }
- if(what=="rollouter" && $("#"+htmlID+" > .tag.opening > .attributes").children(".shy").toArray().length>0) {
- if( $("#"+htmlID).children(".tag.opening").children(".rollouter").hasClass("rolledout") ) {
- $("#"+htmlID).children(".tag.opening").children(".rollouter").removeClass("rolledout");
- $("#"+htmlID).children(".tag.opening").children(".attributes").slideUp("fast", function(){
- $(this).removeClass("rolledout").css("display", "");
- })
- } else {
- $("#"+htmlID).children(".tag.opening").children(".rollouter").addClass("rolledout");
- $("#"+htmlID).children(".tag.opening").children(".attributes").addClass("rolledout").hide().slideDown("fast");
- }
- window.setTimeout(function(){Xonomy.setFocus(htmlID, "rollouter")}, 100);
- }
- Xonomy.notclick=true;
- }
- };
- Xonomy.notclick=false; //should the latest click-off event be ignored?
- Xonomy.clearChars=false; //if true, un-highlight any highlighted characters at the next click-off event
- Xonomy.clickoff=function() { //event handler for the document-wide click-off event.
- if(!Xonomy.notclick) {
- Xonomy.currentHtmlId=null;
- Xonomy.currentFocus=null;
- Xonomy.destroyBubble();
- $(".xonomy .current").removeClass("current");
- $(".xonomy .focused").removeClass("focused");
- if(Xonomy.clearChars) {
- $(".xonomy .char.on").removeClass("on");
- Xonomy.clearChars=false;
- }
- }
- Xonomy.notclick=false;
- };
- Xonomy.destroyBubble=function() {
- if(document.getElementById("xonomyBubble")) {
- var bubble=document.getElementById("xonomyBubble");
- $(bubble).find(":focus").blur();
- bubble.parentNode.removeChild(bubble);
- if(Xonomy.keyboardEventCatcher) Xonomy.keyboardEventCatcher.focus();
- }
- };
- Xonomy.makeBubble=function(content) {
- Xonomy.destroyBubble();
- var bubble=document.createElement("div");
- bubble.id="xonomyBubble";
- bubble.className=Xonomy.mode;
- bubble.innerHTML="<div class='inside' onclick='Xonomy.notclick=true;'>"
- +"<div id='xonomyBubbleContent'>"+content+"</div>"
- +"</div>";
- return bubble;
- };
- Xonomy.showBubble=function($anchor) {
- var $bubble=$("#xonomyBubble");
- var offset=$anchor.offset();
- var screenWidth = $("body").width();
- var screenHeight = $(document).height();
- var bubbleHeight = $bubble.outerHeight();
- var width = $anchor.width(); if (width > 40) width = 40;
- var height = $anchor.height(); if (height > 25) height = 25;
- if (Xonomy.mode == "laic") { width = width - 25; height = height + 10; }
- function verticalPlacement() {
- var top = "";
- var bottom = "";
- if (offset.top + height + bubbleHeight <= screenHeight) {
- // enough space - open down
- top = (offset.top + height) + "px";
- } else if (screenHeight - offset.top + 5 + bubbleHeight > 0) {
- // 5px above for some padding. Anchor using bottom so animation opens upwards.
- bottom = (screenHeight - offset.top + 5) + "px";
- } else {
- // neither downwards nor upwards is enough space => center the bubble
- top = (screenHeight - bubbleHeight)/2 + "px";
- }
- return { top: top, bottom: bottom };
- }
- var placement = verticalPlacement();
- if(offset.left<screenWidth/2) {
- placement.left = (offset.left + width - 15) + "px";
- } else {
- $bubble.addClass("rightAnchored");
- placement.right = (screenWidth - offset.left) + "px";
- }
- $bubble.css(placement);
- $bubble.slideDown("fast", function() {
- if(Xonomy.keyNav) $bubble.find(".focusme").first().focus(); //if the context menu contains anything with the class name 'focusme', focus it.
- else $bubble.find("input.focusme, select.focusme, textarea.focusme").first().focus();
- });
- $bubble.on("keyup", function(event){
- if(event.which==27) Xonomy.destroyBubble();
- });
- if(Xonomy.keyNav) {
- $bubble.find("div.focusme").on("keyup", function(event){
- if(event.which==40) { //down key
- var $item=$(event.delegateTarget);
- var $items=$bubble.find(".focusme:visible");
- var $next=$items.eq( $items.index($item[0])+1 );
- $next.focus();
- }
- if(event.which==38) { //up key
- var $item=$(event.delegateTarget);
- var $items=$bubble.find("div.focusme:visible");
- var $next=$items.eq( $items.index($item[0])-1 );
- $next.focus();
- }
- if(event.which==13) { //enter key
- $(event.delegateTarget).click();
- Xonomy.notclick=false;
- }
- });
- }
- };
- Xonomy.askString=function(defaultString, askerParameter, jsMe) {
- var width=($("body").width()*.5)-75
- var html="";
- html+="<form onsubmit='Xonomy.answer(this.val.value); return false'>";
- html+="<input name='val' class='textbox focusme' style='width: "+width+"px;' value='"+Xonomy.xmlEscape(defaultString)+"' onkeyup='Xonomy.notKeyUp=true'/>";
- html+=" <input type='submit' value='OK'>";
- html+="</form>";
- return html;
- };
- Xonomy.askLongString=function(defaultString, askerParameter, jsMe) {
- var width=($("body").width()*.5)-75
- var html="";
- html+="<form onsubmit='Xonomy.answer(this.val.value); return false'>";
- html+="<textarea name='val' class='textbox focusme' spellcheck='false' style='width: "+width+"px; height: 150px;'>"+Xonomy.xmlEscape(defaultString)+"</textarea>";
- html+="<div class='submitline'><input type='submit' value='OK'></div>";
- html+="</form>";
- return html;
- };
- Xonomy.askPicklist=function(defaultString, picklist, jsMe) {
- var html="";
- html+=Xonomy.pickerMenu(picklist, defaultString);
- return html;
- };
- Xonomy.askOpenPicklist=function(defaultString, picklist) {
- var isInPicklist=false;
- var html="";
- html+=Xonomy.pickerMenu(picklist, defaultString);
- html+="<form class='undermenu' onsubmit='Xonomy.answer(this.val.value); return false'>";
- html+="<input name='val' class='textbox focusme' value='"+(!isInPicklist ? Xonomy.xmlEscape(defaultString) : "")+"' onkeyup='Xonomy.notKeyUp=true'/>";
- html+=" <input type='submit' value='OK'>";
- html+="</form>";
- return html;
- };
- Xonomy.askRemote=function(defaultString, param, jsMe) {
- var html="";
- if(param.searchUrl || param.createUrl) {
- html+="<form class='overmenu' onsubmit='return Xonomy.remoteSearch(\""+Xonomy.xmlEscape(param.searchUrl, true)+"\", \""+Xonomy.xmlEscape(param.urlPlaceholder, true)+"\", \""+Xonomy.xmlEscape(Xonomy.jsEscape(defaultString))+"\")'>";
- html+="<input name='val' class='textbox focusme' value=''/>";
- if(param.searchUrl) html+=" <button class='buttonSearch' onclick='return Xonomy.remoteSearch(\""+Xonomy.xmlEscape(param.searchUrl, true)+"\", \""+Xonomy.xmlEscape(param.urlPlaceholder, true)+"\", \""+Xonomy.xmlEscape(Xonomy.jsEscape(defaultString))+"\")'> </button>";
- if(param.createUrl) html+=" <button class='buttonCreate' onclick='return Xonomy.remoteCreate(\""+Xonomy.xmlEscape(param.createUrl, true)+"\", \""+Xonomy.xmlEscape( (param.searchUrl?param.searchUrl:param.url) , true)+"\", \""+Xonomy.xmlEscape(param.urlPlaceholder, true)+"\", \""+Xonomy.xmlEscape(Xonomy.jsEscape(defaultString))+"\")'> </button>";
- html+="</form>";
- }
- html+=Xonomy.wyc(param.url, function(picklist){
- var items=[];
- if(param.add) for(var i=0; i<param.add.length; i++) items.push(param.add[i]);
- for(var i=0; i<picklist.length; i++) items.push(picklist[i]);
- return Xonomy.pickerMenu(items, defaultString);
- });
- Xonomy.lastAskerParam=param;
- return html;
- };
- Xonomy.lastAskerParam=null;
- Xonomy.remoteSearch=function(searchUrl, urlPlaceholder, defaultString){
- var text=$("#xonomyBubble input.textbox").val();
- searchUrl=searchUrl.replace(urlPlaceholder, encodeURIComponent(text));
- $("#xonomyBubble .menu").replaceWith( Xonomy.wyc(searchUrl, function(picklist){
- var items=[];
- if(text=="" && Xonomy.lastAskerParam.add) for(var i=0; i<Xonomy.lastAskerParam.add.length; i++) items.push(Xonomy.lastAskerParam.add[i]);
- for(var i=0; i<picklist.length; i++) items.push(picklist[i]);
- return Xonomy.pickerMenu(items, defaultString);
- }));
- return false;
- };
- Xonomy.remoteCreate=function(createUrl, searchUrl, urlPlaceholder, defaultString){
- var text=$.trim($("#xonomyBubble input.textbox").val());
- if(text!="") {
- createUrl=createUrl.replace(urlPlaceholder, encodeURIComponent(text));
- searchUrl=searchUrl.replace(urlPlaceholder, encodeURIComponent(text));
- $.ajax({url: createUrl, dataType: "text", method: "POST"}).done(function(data){
- if(Xonomy.wycCache[searchUrl]) delete Xonomy.wycCache[searchUrl];
- $("#xonomyBubble .menu").replaceWith( Xonomy.wyc(searchUrl, function(picklist){ return Xonomy.pickerMenu(picklist, defaultString); }) );
- });
- }
- return false;
- };
- Xonomy.pickerMenu=function(picklist, defaultString){
- var html="";
- html+="<div class='menu'>";
- for(var i=0; i<picklist.length; i++) {
- var item=picklist[i];
- if(typeof(item)=="string") item={value: item, caption: ""};
- html+="<div class='menuItem focusme techno"+(item.value==defaultString?" current":"")+"' tabindex='1' onclick='Xonomy.answer(\""+Xonomy.xmlEscape(item.value)+"\")'>";
- var alone=true;
- html+="<span class='punc'>\"</span>";
- if(item.displayValue) {
- html+=Xonomy.textByLang(item.displayValue);
- alone=false;
- } else {
- html+=Xonomy.xmlEscape(item.value);
- if(item.value) alone=false;
- }
- html+="<span class='punc'>\"</span>";
- if(item.caption!="") html+=" <span class='explainer "+(alone?"alone":"")+"'>"+Xonomy.xmlEscape(Xonomy.textByLang(item.caption))+"</span>";
- html+="</div>";
- }
- html+="</div>";
- return html;
- };
- Xonomy.wycLastID=0;
- Xonomy.wycCache={};
- Xonomy.wyc=function(url, callback){ //a "when-you-can" function for delayed rendering: gets json from url, passes it to callback, and delayed-returns html-as-string from callback
- Xonomy.wycLastID++;
- var wycID="xonomy_wyc_"+Xonomy.wycLastID;
- if(Xonomy.wycCache[url]) return callback(Xonomy.wycCache[url]);
- $.ajax({url: url, dataType: "json", method: "POST"}).done(function(data){
- $("#"+wycID).replaceWith(callback(data));
- Xonomy.wycCache[url]=data;
- });
- return "<span class='wyc' id='"+wycID+"'></span>";
- };
- Xonomy.toggleSubmenu=function(menuItem){
- var $menuItem=$(menuItem);
- if($menuItem.hasClass("expanded")){ $menuItem.find(".submenu").first().slideUp("fast", function(){$menuItem.removeClass("expanded");}); }
- else { $menuItem.find(".submenu").first().slideDown("fast", function(){$menuItem.addClass("expanded");}); };
- }
- Xonomy.internalMenu=function(htmlID, items, harvest, getter, indices) {
- indices = indices || [];
- var fragments = items.map(function (item, i) {
- Xonomy.verifyDocSpecMenuItem(item);
- var jsMe=harvest(document.getElementById(htmlID));
- var includeIt=!item.hideIf(jsMe);
- var html="";
- if(includeIt) {
- indices.push(i);
- var icon=""; if(item.icon) icon="<span class='icon'><img src='"+item.icon+"'/></span> ";
- var key=""; if(item.keyTrigger && item.keyCaption) key="<span class='keyCaption'>"+Xonomy.textByLang(item.keyCaption)+"</span>";
- if (item.menu) {
- var internalHtml=Xonomy.internalMenu(htmlID, item.menu, harvest, getter, indices);
- if(internalHtml!="<div class='submenu'></div>") {
- html+="<div class='menuItem"+(item.expanded(jsMe)?" expanded":"")+"'>";
- html+="<div class='menuLabel focusme' tabindex='0' onkeydown='if(Xonomy.keyNav && [37, 39].indexOf(event.which)>-1) Xonomy.toggleSubmenu(this.parentNode)' onclick='Xonomy.toggleSubmenu(this.parentNode)'>"+icon+Xonomy.formatCaption(Xonomy.textByLang(item.caption(jsMe)))+"</div>";
- html+=internalHtml;
- html+="</div>";
- }
- } else {
- html+="<div class='menuItem focusme' tabindex='0' onclick='Xonomy.callMenuFunction("+getter(indices)+", \""+htmlID+"\")'>";
- html+=key+icon+Xonomy.formatCaption(Xonomy.textByLang(item.caption(jsMe)));
- html+="</div>";
- }
- indices.pop();
- }
- return html;
- });
- var cls = !indices.length ? 'menu' : 'submenu';
- return fragments.length
- ? "<div class='"+cls+"'>"+fragments.join("")+"</div>"
- : "";
- };
- Xonomy.attributeMenu=function(htmlID) {
- var name=$("#"+htmlID).attr("data-name"); //obtain attribute's name
- var elName=$("#"+htmlID).closest(".element").attr("data-name"); //obtain element's name
- Xonomy.verifyDocSpecAttribute(elName, name);
- var spec=Xonomy.docSpec.elements[elName].attributes[name];
- function getter(indices) {
- return 'Xonomy.docSpec.elements["'+elName+'"].attributes["'+name+'"].menu['+indices.join('].menu[')+']';
- }
- return Xonomy.internalMenu(htmlID, spec.menu, Xonomy.harvestAttribute, getter);
- };
- Xonomy.elementMenu=function(htmlID) {
- var elName=$("#"+htmlID).attr("data-name"); //obtain element's name
- var spec=Xonomy.docSpec.elements[elName];
- function getter(indices) {
- return 'Xonomy.docSpec.elements["'+elName+'"].menu['+indices.join('].menu[')+']';
- }
- return Xonomy.internalMenu(htmlID, spec.menu, Xonomy.harvestElement, getter);
- };
- Xonomy.inlineMenu=function(htmlID) {
- var elName=$("#"+htmlID).attr("data-name"); //obtain element's name
- var spec=Xonomy.docSpec.elements[elName];
- function getter(indices) {
- return 'Xonomy.docSpec.elements["'+elName+'"].inlineMenu['+indices.join('].menu[')+']';
- }
- return Xonomy.internalMenu(htmlID, spec.inlineMenu, Xonomy.harvestElement, getter);
- };
- Xonomy.callMenuFunction=function(menuItem, htmlID) {
- menuItem.action(htmlID, menuItem.actionParameter);
- };
- Xonomy.formatCaption=function(caption) {
- caption=caption.replace(/\<(\/?)([^\>\/]+)(\/?)\>/g, "<span class='techno'><span class='punc'><$1</span><span class='elName'>$2</span><span class='punc'>$3></span></span>");
- caption=caption.replace(/\@"([^\"]+)"/g, "<span class='techno'><span class='punc'>\"</span><span class='atValue'>$1</span><span class='punc'>\"</span></span>");
- caption=caption.replace(/\@([^ =]+)=""/g, "<span class='techno'><span class='atName'>$1</span><span class='punc'>=\"</span><span class='punc'>\"</span></span>");
- caption=caption.replace(/\@([^ =]+)="([^\"]+)"/g, "<span class='techno'><span class='atName'>$1</span><span class='punc'>=\"</span><span class='atValue'>$2</span><span class='punc'>\"</span></span>");
- caption=caption.replace(/\@([^ =]+)/g, "<span class='techno'><span class='atName'>$1</span></span>");
- return caption;
- };
- Xonomy.deleteAttribute=function(htmlID, parameter) {
- Xonomy.clickoff();
- var obj=document.getElementById(htmlID);
- var parentID=obj.parentNode.parentNode.parentNode.id;
- obj.parentNode.removeChild(obj);
- Xonomy.changed();
- window.setTimeout(function(){ Xonomy.setFocus(parentID, "openingTagName"); }, 100);
- };
- Xonomy.deleteElement=function(htmlID, parameter) {
- Xonomy.clickoff();
- var obj=document.getElementById(htmlID);
- var parentID=obj.parentNode.parentNode.id;
- $(obj).fadeOut(function(){
- var parentNode=obj.parentNode;
- parentNode.removeChild(obj);
- Xonomy.changed();
- if($(parentNode).closest(".layby").length==0) {
- window.setTimeout(function(){ Xonomy.setFocus(parentID, "openingTagName"); }, 100);
- }
- });
- };
- Xonomy.newAttribute=function(htmlID, parameter) {
- Xonomy.clickoff();
- var $element=$("#"+htmlID);
- var html=Xonomy.renderAttribute({type: "attribute", name: parameter.name, value: parameter.value}, $element.data("name"));
- $("#"+htmlID+" > .tag.opening > .attributes").append(html);
- Xonomy.changed();
- //if the attribute we have just added is shy, force rollout:
- if($("#"+htmlID+" > .tag.opening > .attributes").children("[data-name='"+parameter.name+"'].shy").toArray().length>0) {
- if( !$("#"+htmlID).children(".tag.opening").children(".rollouter").hasClass("rolledout") ) {
- $("#"+htmlID).children(".tag.opening").children(".rollouter").addClass("rolledout");
- $("#"+htmlID).children(".tag.opening").children(".attributes").addClass("rolledout").hide().slideDown("fast");
- }
- }
- if(parameter.value=="") Xonomy.click($(html).prop("id"), "attributeValue"); else Xonomy.focus($(html).prop("id"), "attributeValue");
- };
- Xonomy.newElementChild=function(htmlID, parameter) {
- Xonomy.clickoff();
- var jsElement=Xonomy.harvestElement(document.getElementById(htmlID));
- var html=Xonomy.renderElement(Xonomy.xml2js(parameter, jsElement));
- var $html=$(html).hide();
- $("#"+htmlID+" > .children").append($html);
- Xonomy.plusminus(htmlID, true);
- Xonomy.elementReorder($html.attr("id"));
- Xonomy.changed();
- $html.fadeIn();
- window.setTimeout(function(){ Xonomy.setFocus($html.prop("id"), "openingTagName"); }, 100);
- };
- Xonomy.elementReorder=function(htmlID){
- var that=document.getElementById(htmlID);
- var elSpec=Xonomy.docSpec.elements[that.getAttribute("data-name")];
- if(elSpec.mustBeBefore) { //is it after an element it cannot be after? then move it up until it's not!
- var $this=$(that);
- var jsElement=Xonomy.harvestElement(that);
- var mustBeBefore=elSpec.mustBeBefore(jsElement);
- var ok; do {
- ok=true;
- for(var ii=0; ii<mustBeBefore.length; ii++) {
- if( $this.prevAll("*[data-name='"+mustBeBefore[ii]+"']").toArray().length>0 ) {
- $this.prev().before($this);
- ok=false;
- }
- }
- } while(!ok)
- }
- if(elSpec.mustBeAfter) { //is it before an element it cannot be before? then move it down until it's not!
- var $this=$(that);
- var jsElement=Xonomy.harvestElement(that);
- var mustBeAfter=elSpec.mustBeAfter(jsElement);
- var ok; do {
- ok=true;
- for(var ii=0; ii<mustBeAfter.length; ii++) {
- if( $this.nextAll("*[data-name='"+mustBeAfter[ii]+"']").toArray().length>0 ) {
- $this.next().after($this);
- ok=false;
- }
- }
- } while(!ok)
- }
- };
- Xonomy.newElementBefore=function(htmlID, parameter) {
- Xonomy.clickoff();
- var jsElement=Xonomy.harvestElement(document.getElementById(htmlID));
- var html=Xonomy.renderElement(Xonomy.xml2js(parameter, jsElement.parent()));
- var $html=$(html).hide();
- $("#"+htmlID).before($html);
- Xonomy.elementReorder($html.prop("id"));
- Xonomy.changed();
- $html.fadeIn();
- window.setTimeout(function(){ Xonomy.setFocus($html.prop("id"), "openingTagName"); }, 100);
- };
- Xonomy.newElementAfter=function(htmlID, parameter) {
- Xonomy.clickoff();
- var jsElement=Xonomy.harvestElement(document.getElementById(htmlID));
- var html=Xonomy.renderElement(Xonomy.xml2js(parameter, jsElement.parent()));
- var $html=$(html).hide();
- $("#"+htmlID).after($html);
- Xonomy.elementReorder($html.prop("id"));
- Xonomy.changed();
- $html.fadeIn();
- window.setTimeout(function(){ Xonomy.setFocus($html.prop("id"), "openingTagName"); }, 100);
- };
- Xonomy.replace=function(htmlID, jsNode) {
- var what=Xonomy.currentFocus;
- Xonomy.clickoff();
- var html="";
- if(jsNode.type=="element") html=Xonomy.renderElement(jsNode);
- if(jsNode.type=="attribute") html=Xonomy.renderAttribute(jsNode);
- if(jsNode.type=="text") html=Xonomy.renderText(jsNode);
- $("#"+htmlID).replaceWith(html);
- Xonomy.changed();
- window.setTimeout(function(){ Xonomy.setFocus($(html).prop("id"), what); }, 100);
- };
- Xonomy.editRaw=function(htmlID, parameter) {
- var div=document.getElementById(htmlID);
- var jsElement=Xonomy.harvestElement(div);
- if(parameter.fromJs) var txt=parameter.fromJs( jsElement );
- else if(parameter.fromXml) var txt=parameter.fromXml( Xonomy.js2xml(jsElement) );
- else var txt=Xonomy.js2xml(jsElement);
- document.body.appendChild(Xonomy.makeBubble(Xonomy.askLongString(txt))); //create bubble
- Xonomy.showBubble($(div)); //anchor bubble to element
- Xonomy.answer=function(val) {
- var jsNewElement;
- if(parameter.toJs) jsNewElement=parameter.toJs(val, jsElement);
- else if(parameter.toXml) jsNewElement=Xonomy.xml2js(parameter.toXml(val, jsElement), jsElement.parent());
- else jsNewElement=Xonomy.xml2js(val, jsElement.parent());
- var obj=document.getElementById(htmlID);
- var html=Xonomy.renderElement(jsNewElement);
- $(obj).replaceWith(html);
- Xonomy.clickoff();
- Xonomy.changed();
- window.setTimeout(function(){ Xonomy.setFocus($(html).prop("id"), "openingTagName"); }, 100);
- };
- };
- Xonomy.duplicateElement=function(htmlID) {
- Xonomy.clickoff();
- var html=document.getElementById(htmlID).outerHTML.replace(/ id=['"]/g, function(x){return x+"d_"});
- var $html=$(html).hide();
- $("#"+htmlID).after($html);
- Xonomy.changed();
- $html.fadeIn();
- window.setTimeout(function(){ Xonomy.setFocus($html.prop("id"), "openingTagName"); }, 100);
- };
- Xonomy.moveElementUp=function(htmlID){
- Xonomy.clickoff();
- var $me=$("#"+htmlID);
- if($me.closest(".layby > .content").length==0) {
- Xonomy.insertDropTargets(htmlID);
- var $droppers=$(".xonomy .elementDropper").add($me);
- var i=$droppers.index($me[0])-1;
- if(i>=0) {
- $($droppers[i]).replaceWith($me);
- Xonomy.changed();
- $me.hide().fadeIn();
- }
- Xonomy.dragend();
- }
- window.setTimeout(function(){ Xonomy.setFocus(htmlID, "openingTagName"); }, 100);
- };
- Xonomy.moveElementDown=function(htmlID){
- Xonomy.clickoff();
- var $me=$("#"+htmlID);
- if($me.closest(".layby > .content").length==0) {
- Xonomy.insertDropTargets(htmlID);
- var $droppers=$(".xonomy .elementDropper").add($me);
- var i=$droppers.index($me[0])+1;
- if(i<$droppers.length) {
- $($droppers[i]).replaceWith($me);
- Xonomy.changed();
- $me.hide().fadeIn();
- }
- Xonomy.dragend();
- }
- window.setTimeout(function(){ Xonomy.setFocus(htmlID, "openingTagName"); }, 100);
- };
- Xonomy.canMoveElementUp=function(htmlID){
- var ret=false;
- var $me=$("#"+htmlID);
- if($me.closest(".layby > .content").length==0) {
- Xonomy.insertDropTargets(htmlID);
- var $droppers=$(".xonomy .elementDropper").add($me);
- var i=$droppers.index($me[0])-1;
- if(i>=0) ret=true;
- Xonomy.dragend();
- }
- return ret;
- };
- Xonomy.canMoveElementDown=function(htmlID){
- var ret=false;
- var $me=$("#"+htmlID);
- if($me.closest(".layby > .content").length==0) {
- Xonomy.insertDropTargets(htmlID);
- var $droppers=$(".xonomy .elementDropper").add($me);
- var i=$droppers.index($me[0])+1;
- if(i<$droppers.length) ret=true;
- Xonomy.dragend();
- }
- return ret;
- };
- Xonomy.mergeWithPrevious=function(htmlID, parameter){
- var domDead=document.getElementById(htmlID);
- var elDead=Xonomy.harvestElement(domDead);
- var elLive=elDead.getPrecedingSibling();
- Xonomy.mergeElements(elDead, elLive);
- };
- Xonomy.mergeWithNext=function(htmlID, parameter){
- var domDead=document.getElementById(htmlID);
- var elDead=Xonomy.harvestElement(domDead);
- var elLive=elDead.getFollowingSibling();
- Xonomy.mergeElements(elDead, elLive);
- };
- Xonomy.mergeElements=function(elDead, elLive){
- Xonomy.clickoff();
- var domDead=document.getElementById(elDead.htmlID);
- if(elLive && elLive.type=="element") {
- for(var i=0; i<elDead.attributes.length; i++){ //merge attributes
- var atDead=elDead.attributes[i];
- if(!elLive.hasAttribute(atDead.name) || elLive.getAttributeValue(atDead.name)==""){
- elLive.setAttribute(atDead.name, atDead.value);
- if(elLive.hasAttribute(atDead.name)) $("#"+elLive.getAttribute(atDead.name).htmlID).remove();
- $("#"+elLive.htmlID).find(".attributes").first().append($("#"+elDead.attributes[i].htmlID));
- }
- }
- var specDead=Xonomy.docSpec.elements[elDead.name];
- var specLive=Xonomy.docSpec.elements[elLive.name];
- if(specDead.hasText(elDead) || specLive.hasText(elLive)){ //if either element is meant to have text, concatenate their children
- if(elLive.getText()!="" && elDead.getText()!="") {
- elLive.addText(" ");
- $("#"+elLive.htmlID).find(".children").first().append(Xonomy.renderText({type: "text", value: " "}));
- }
- for(var i=0; i<elDead.children.length; i++) {
- elLive.children.push(elDead.children[i]);
- $("#"+elLive.htmlID).find(".children").first().append($("#"+elDead.children[i].htmlID));
- }
- } else { //if no text, merge their children one by one
- for(var i=0; i<elDead.children.length; i++){
- var xmlDeadChild=Xonomy.js2xml(elDead.children[i]);
- var has=false;
- for(y=0; y<elLive.children.length; y++){
- var xmlLiveChild=Xonomy.js2xml(elLive.children[y]);
- if(xmlDeadChild==xmlLiveChild){ has=true; break; }
- }
- if(!has) {
- elLive.children.push(elDead.children[i]);
- $("#"+elLive.htmlID).find(".children").first().append($("#"+elDead.children[i].htmlID));
- Xonomy.elementReorder(elDead.children[i].htmlID);
- }
- }
- }
- domDead.parentNode.removeChild(domDead);
- Xonomy.changed();
- window.setTimeout(function(){ Xonomy.setFocus(elLive.htmlID, "openingTagName"); }, 100);
- } else {
- window.setTimeout(function(){ Xonomy.setFocus(htmlID, "openingTagName"); }, 100);
- }
- };
- Xonomy.insertDropTargets=function(htmlID){
- var $element=$("#"+htmlID);
- $element.addClass("dragging");
- var elementName=$element.attr("data-name");
- var elSpec=Xonomy.docSpec.elements[elementName];
- $(".xonomy .children:visible").append("<div class='elementDropper' ondragover='Xonomy.dragOver(event)' ondragleave='Xonomy.dragOut(event)' ondrop='Xonomy.drop(event)'><div class='inside'></div></div>")
- $(".xonomy .children:visible > .element").before("<div class='elementDropper' ondragover='Xonomy.dragOver(event)' ondragleave='Xonomy.dragOut(event)' ondrop='Xonomy.drop(event)'><div class='inside'></div></div>")
- $(".xonomy .children:visible > .text").before("<div class='elementDropper' ondragover='Xonomy.dragOver(event)' ondragleave='Xonomy.dragOut(event)' ondrop='Xonomy.drop(event)'><div class='inside'></div></div>")
- $(".xonomy .dragging .children:visible > .elementDropper").remove(); //remove drop targets fom inside the element being dragged
- $(".xonomy .dragging").prev(".elementDropper").remove(); //remove drop targets from immediately before the element being dragged
- $(".xonomy .dragging").next(".elementDropper").remove(); //remove drop targets from immediately after the element being dragged
- $(".xonomy .children:visible > .element.readonly .elementDropper").remove(); //remove drop targets from inside read-only elements
- var harvestCache={};
- var harvestElement=function(div){
- var htmlID=$(div).prop("id");
- if(!harvestCache[htmlID]) harvestCache[htmlID]=Xonomy.harvestElement(div);
- return harvestCache[htmlID];
- };
- if(elSpec.localDropOnly(harvestElement($element.toArray()[0]))) {
- if(elSpec.canDropTo) { //remove the drop target from elements that are not the dragged element's parent
- var droppers=$(".xonomy .elementDropper").toArray();
- for(var i=0; i<droppers.length; i++) {
- var dropper=droppers[i];
- if(dropper.parentNode!=ev.target.parentNode.parentNode.parentNode) {
- dropper.parentNode.removeChild(dropper);
- }
- }
- }
- }
- if(elSpec.canDropTo) { //remove the drop target from elements it cannot be dropped into
- var droppers=$(".xonomy .elementDropper").toArray();
- for(var i=0; i<droppers.length; i++) {
- var dropper=droppers[i];
- var parentElementName=$(dropper.parentNode.parentNode).toArray()[0].getAttribute("data-name");
- if($.inArray(parentElementName, elSpec.canDropTo)<0) {
- dropper.parentNode.removeChild(dropper);
- }
- }
- }
- if(elSpec.mustBeBefore) { //remove the drop target from after elements it cannot be after
- var jsElement=harvestElement($element.toArray()[0]);
- var droppers=$(".xonomy .elementDropper").toArray();
- for(var i=0; i<droppers.length; i++) {
- var dropper=droppers[i];
- jsElement.internalParent=harvestElement(dropper.parentNode.parentNode); //pretend the element's parent is the dropper's parent
- var mustBeBefore=elSpec.mustBeBefore(jsElement);
- for(var ii=0; ii<mustBeBefore.length; ii++) {
- if( $(dropper).prevAll("*[data-name='"+mustBeBefore[ii]+"']").toArray().length>0 ) {
- dropper.parentNode.removeChild(dropper);
- }
- }
- }
- }
- if(elSpec.mustBeAfter) { //remove the drop target from before elements it cannot be before
- var jsElement=harvestElement($element.toArray()[0]);
- var droppers=$(".xonomy .elementDropper").toArray();
- for(var i=0; i<droppers.length; i++) {
- var dropper=droppers[i];
- jsElement.internalParent=harvestElement(dropper.parentNode.parentNode); //pretend the element's parent is the dropper's parent
- var mustBeAfter=elSpec.mustBeAfter(jsElement);
- for(var ii=0; ii<mustBeAfter.length; ii++) {
- if( $(dropper).nextAll("*[data-name='"+mustBeAfter[ii]+"']").toArray().length>0 ) {
- dropper.parentNode.removeChild(dropper);
- }
- }
- }
- }
- };
- Xonomy.draggingID=null; //what are we dragging?
- Xonomy.drag=function(ev) { //called when dragging starts
- // Wrapping all the code into a timeout handler is a workaround for a Chrome browser bug
- // (if the DOM is manipulated in the 'dragStart' event then 'dragEnd' event is sometimes fired immediately)
- //
- // for more details @see:
- // http://stackoverflow.com/questions/19639969/html5-dragend-event-firing-immediately
- ev.dataTransfer.effectAllowed="move"; //only allow moving (and not eg. copying]
- var htmlID=ev.target.parentNode.parentNode.id;
- ev.dataTransfer.setData("text", htmlID);
- setTimeout(function() {
- Xonomy.clickoff();
- Xonomy.insertDropTargets(htmlID);
- Xonomy.draggingID=htmlID;
- Xonomy.refresh();
- }, 10);
- };
- Xonomy.dragOver=function(ev) {
- ev.preventDefault();
- ev.dataTransfer.dropEffect="move"; //only allow moving (and not eg. copying]
- if($(ev.currentTarget).hasClass("layby")){
- $(ev.currentTarget).addClass("activeDropper");
- } else {
- $(ev.target.parentNode).addClass("activeDropper");
- }
- };
- Xonomy.dragOut=function(ev) {
- ev.preventDefault();
- if($(ev.currentTarget).hasClass("layby")){
- $(ev.currentTarget).removeClass("activeDropper");
- } else {
- $(".xonomy .activeDropper").removeClass("activeDropper");
- }
- };
- Xonomy.drop=function(ev) {
- ev.preventDefault();
- var node=document.getElementById(Xonomy.draggingID); //the thing we are moving
- if($(ev.currentTarget).hasClass("layby")) {
- $(node).hide();
- $(".xonomy .layby > .content").append(node);
- $(node).fadeIn(function(){ Xonomy.changed(); });
- } else {
- $(node).hide();
- $(ev.target.parentNode).replaceWith(node);
- $(node).fadeIn(function(){ Xonomy.changed(); });
- }
- Xonomy.openCloseLayby();
- Xonomy.recomputeLayby();
- };
- Xonomy.dragend=function(ev) {
- $(".xonomy .attributeDropper").remove();
- $(".xonomy .elementDropper").remove();
- $(".xonomy .dragging").removeClass("dragging");
- Xonomy.refresh();
- $(".xonomy .layby").removeClass("activeDropper");
- };
- Xonomy.openCloseLayby=function(){ //open the layby if it's full, close it if it's empty
- if($(".xonomy .layby > .content > *").length>0){
- $(".xonomy .layby").removeClass("closed").addClass("open");
- } else {
- $(".xonomy .layby").removeClass("open").addClass("closed");
- }
- };
- Xonomy.openLayby=function(){
- $(".xonomy .layby").removeClass("closed").addClass("open");
- };
- Xonomy.closeLayby=function(){
- window.setTimeout(function(){
- $(".xonomy .layby").removeClass("open").addClass("closed");
- }, 10);
- };
- Xonomy.emptyLayby=function(){
- $(".xonomy .layby .content").html("");
- $(".xonomy .layby").removeClass("nonempty").addClass("empty");
- };
- Xonomy.recomputeLayby=function(){
- if($(".xonomy .layby > .content > *").length>0){
- $(".xonomy .layby").removeClass("empty").addClass("nonempty");
- } else {
- $(".xonomy .layby").removeClass("nonempty").addClass("empty");
- }
- }
- Xonomy.changed=function(jsElement) { //called when the document changes
- Xonomy.harvestCache={};
- Xonomy.refresh();
- Xonomy.validate();
- Xonomy.docSpec.onchange(jsElement); //report that the document has changed
- };
- Xonomy.validate=function() {
- var js=Xonomy.harvestElement($(".xonomy .element").toArray()[0], null);
- $(".xonomy .invalid").removeClass("invalid");
- Xonomy.warnings=[];
- Xonomy.docSpec.validate(js); //validate the document
- for(var iWarning=0; iWarning<Xonomy.warnings.length; iWarning++) {
- var warning=Xonomy.warnings[iWarning];
- $("#"+warning.htmlID).addClass("invalid");
- }
- };
- Xonomy.warnings=[]; //array of {htmlID: "", text: ""}
- Xonomy.textByLang=function(str) {
- //str = eg. "en: Delete | de: Löschen | fr: Supprimer"
- if(!str) str="";
- var ret=str;
- var segs=str.split("|");
- for(var i=0; i<segs.length; i++) {
- var seg=$.trim(segs[i]);
- if(seg.indexOf(Xonomy.lang+":")==0) {
- ret=seg.substring((Xonomy.lang+":").length, ret.length);
- }
- }
- ret=$.trim(ret);
- return ret;
- };
- Xonomy.currentHtmlId=null;
- Xonomy.currentFocus=null;
- Xonomy.keyNav=false;
- Xonomy.startKeyNav=function(keyboardEventCatcher, scrollableContainer){
- Xonomy.keyNav=true;
- var $keyboardEventCatcher=$(keyboardEventCatcher); if(!keyboardEventCatcher) $keyboardEventCatcher=$(".xonomy");
- $scrollableContainer=$(scrollableContainer); if(!scrollableContainer) $scrollableContainer=$keyboardEventCatcher;
- $keyboardEventCatcher.attr("tabindex", "0");
- $keyboardEventCatcher.on("keydown", Xonomy.key);
- $(document).on("keydown", function(e) { if([32, 37, 38, 39, 40].indexOf(e.keyCode)>-1 && $("input:focus, select:focus, textarea:focus").length==0) e.preventDefault(); }); //prevent default browser scrolling on arrow keys
- Xonomy.keyboardEventCatcher=$keyboardEventCatcher;
- Xonomy.scrollableContainer=$scrollableContainer;
- };
- Xonomy.setFocus=function(htmlID, what){
- if(Xonomy.keyNav) {
- $(".xonomy .current").removeClass("current");
- $(".xonomy .focused").removeClass("focused");
- if(what=="attributeValue") $("#"+htmlID+" > .valueContainer").addClass("current").addClass("focused");
- else $("#"+htmlID).addClass("current").addClass("focused");
- Xonomy.currentHtmlId=htmlID;
- Xonomy.currentFocus=what;
- if(Xonomy.currentFocus=="openingTagName") $("#"+htmlID+" > .tag.opening").first().addClass("focused");
- if(Xonomy.currentFocus=="closingTagName") $("#"+htmlID+" > .tag.closing").last().addClass("focused");
- if(Xonomy.currentFocus=="childrenCollapsed") $("#"+htmlID+" > .childrenCollapsed").last().addClass("focused");
- if(Xonomy.currentFocus=="rollouter") $("#"+htmlID+" > .tag.opening > .rollouter").last().addClass("focused");
- }
- };
- Xonomy.key=function(event){
- if(!Xonomy.notKeyUp) {
- if(!event.shiftKey && !$("#xonomyBubble").length>0 ) {
- if(event.which==27) { //escape key
- event.preventDefault();
- event.stopImmediatePropagation();
- Xonomy.destroyBubble();
- } else if(event.which==13){ //enter key
- event.preventDefault();
- event.stopImmediatePropagation();
- if(Xonomy.currentFocus=="childrenCollapsed") Xonomy.plusminus(Xonomy.currentHtmlId, true);
- if(Xonomy.currentFocus=="char") {
- Xonomy.charClick($("#"+Xonomy.currentHtmlId)[0]);
- }
- else {
- Xonomy.click(Xonomy.currentHtmlId, Xonomy.currentFocus);
- Xonomy.clickoff();
- }
- } else if((event.ctrlKey || event.metaKey) && event.which==40) { //down key with Ctrl or Cmd (Mac OS)
- event.preventDefault();
- event.stopImmediatePropagation();
- Xonomy.scrollableContainer.scrollTop( Xonomy.scrollableContainer.scrollTop()+60 );
- } else if((event.ctrlKey || event.metaKey) && event.which==38) { //up key with Ctrl or Cmd (Mac OS)
- event.preventDefault();
- event.stopImmediatePropagation();
- Xonomy.scrollableContainer.scrollTop( Xonomy.scrollableContainer.scrollTop()-60 );
- } else if((event.ctrlKey || event.metaKey) && [37, 39].indexOf(event.which)>-1) { //arrow keys with Ctrl or Cmd (Mac OS)
- event.preventDefault();
- event.stopImmediatePropagation();
- var $el=$("#"+Xonomy.currentHtmlId);
- if($el.hasClass("element") && !$el.hasClass("uncollapsible")){
- if(event.which==39 && $el.hasClass("collapsed")) { //expand it!
- Xonomy.plusminus(Xonomy.currentHtmlId);
- }
- if(event.which==37 && !$el.hasClass("collapsed")) { //collapse it!
- Xonomy.plusminus(Xonomy.currentHtmlId);
- }
- }
- } else if([37, 38, 39, 40].indexOf(event.which)>-1 && !event.altKey) { //arrow keys
- event.preventDefault();
- event.stopImmediatePropagation();
- if(!Xonomy.currentHtmlId) { //nothing is current yet
- Xonomy.setFocus($(".xonomy .element").first().prop("id"), "openingTagName");
- } else if($(".xonomy .focused").length==0) { //something is current but nothing is focused yet
- Xonomy.setFocus(Xonomy.currentHtmlId, Xonomy.currentFocus);
- } else { //something is current, do arrow action
- if(event.which==40) Xonomy.goDown(); //down key
- if(event.which==38) Xonomy.goUp(); //up key
- if(event.which==39) Xonomy.goRight(); //right key
- if(event.which==37) Xonomy.goLeft(); //left key
- }
- }
- } else if(!$("#xonomyBubble").length>0) {
- Xonomy.keyboardMenu(event);
- }
- }
- Xonomy.notKeyUp=false;
- };
- Xonomy.keyboardMenu=function(event){
- var $obj=$("#"+Xonomy.currentHtmlId);
- var jsMe=null;
- var menu=null;
- if($obj.hasClass("element")){
- jsMe=Xonomy.harvestElement($obj[0]);
- var elName=$obj.attr("data-name");
- menu=Xonomy.docSpec.elements[elName].menu;
- } else if($obj.hasClass("attribute")) {
- jsMe=Xonomy.harvestAttribute($obj[0]);
- var atName=$obj.attr("data-name");
- var elName=$obj.closest(".element").attr("data-name");
- menu=Xonomy.docSpec.elements[elName].attributes[atName].menu;
- }
- if(menu){
- var findMenuItem=function(menu){
- var ret=null;
- for(var i=0; i<menu.length; i++){
- if(menu[i].menu) ret=findMenuItem(menu[i].menu);
- else if(menu[i].keyTrigger && !menu[i].hideIf(jsMe) && menu[i].keyTrigger(event)) ret=menu[i];
- if(ret) break;
- }
- return ret;
- };
- var menuItem=findMenuItem(menu);
- if(menuItem) {
- Xonomy.callMenuFunction(menuItem, Xonomy.currentHtmlId);
- Xonomy.clickoff();
- return true;
- }
- }
- return false;
- },
- Xonomy.goDown=function(){
- if(Xonomy.currentFocus!="openingTagName" && Xonomy.currentFocus!="closingTagName" && Xonomy.currentFocus!="text" && Xonomy.currentFocus!="char") {
- Xonomy.goRight();
- } else {
- var $el=$("#"+Xonomy.currentHtmlId);
- var $me=$el;
- if(Xonomy.currentFocus=="openingTagName") var $me=$el.find(".tag.opening").first();
- if(Xonomy.currentFocus=="closingTagName") var $me=$el.find(".tag.closing").last();
- var $candidates=$(".xonomy .focusable:visible").not(".attributeName").not(".attributeValue").not(".childrenCollapsed").not(".rollouter");
- $candidates=$candidates.not(".char").add($el);
- if(Xonomy.currentFocus=="openingTagName" && $el.hasClass("oneliner")) $candidates=$candidates.not("#"+Xonomy.currentHtmlId+" .tag.closing").not("#"+Xonomy.currentHtmlId+" .children *");
- if(Xonomy.currentFocus=="openingTagName" && $el.hasClass("oneliner")) $candidates=$candidates.not("#"+Xonomy.currentHtmlId+" .textnode");
- if($el.hasClass("collapsed")) $candidates=$candidates.not("#"+Xonomy.currentHtmlId+" .tag.closing");
- if($el.hasClass("textnode") && $(".xonomy").hasClass("nerd")) var $candidates=$el.closest(".element").find(".tag.closing").last();
- if($el.hasClass("textnode") && $(".xonomy").hasClass("laic")) var $candidates=$el.closest(".element").next().find(".focusable:visible").first();
- var $next=$candidates.eq( $candidates.index($me[0])+1 );
- if($next.hasClass("opening")) Xonomy.setFocus($next.closest(".element").prop("id"), "openingTagName");
- if($next.hasClass("closing")) Xonomy.setFocus($next.closest(".element").prop("id"), "closingTagName");
- if($next.hasClass("textnode")) Xonomy.setFocus($next.prop("id"), "text");
- }
- };
- Xonomy.goUp=function(){
- if(Xonomy.currentFocus!="openingTagName" && Xonomy.currentFocus!="closingTagName" && Xonomy.currentFocus!="char" && Xonomy.currentFocus!="text") {
- Xonomy.goLeft();
- } else {
- var $el=$("#"+Xonomy.currentHtmlId);
- var $me=$el;
- if(Xonomy.currentFocus=="openingTagName") var $me=$el.find(".tag.opening").first();
- if(Xonomy.currentFocus=="closingTagName") var $me=$el.find(".tag.closing").last();
- var $candidates=$(".xonomy .focusable:visible").not(".attributeName").not(".attributeValue").not(".childrenCollapsed").not(".rollouter");
- $candidates=$candidates.not(".element .oneliner .tag.closing");
- $candidates=$candidates.not(".element .oneliner .textnode");
- $candidates=$candidates.not(".element .collapsed .tag.closing");
- $candidates=$candidates.not(".char");
- if($el.hasClass("char")) var $candidates=$el.closest(".textnode").first().add($el);
- if($el.hasClass("textnode")) var $candidates=$el.closest(".element").find(".tag.opening").first().add($el);
- if($me.hasClass("closing") && $el.hasClass("hasText")) $candidates=$candidates.not("#"+Xonomy.currentHtmlId+" .children *:not(:first-child)");
- if($me.hasClass("opening") && $el.closest(".element").prev().hasClass("hasText")) {
- var siblingID=$el.closest(".element").prev().prop("id");
- $candidates=$candidates.not("#"+siblingID+" .children *:not(:first-child)");
- }
- if($candidates.index($me[0])>0) {
- var $next=$candidates.eq( $candidates.index($me[0])-1 );
- if($next.hasClass("opening")) Xonomy.setFocus($next.closest(".element").prop("id"), "openingTagName");
- if($next.hasClass("closing")) Xonomy.setFocus($next.closest(".element").prop("id"), "closingTagName");
- if($next.hasClass("textnode")) Xonomy.setFocus($next.prop("id"), "text");
- }
- }
- };
- Xonomy.goRight=function(){
- var $el=$("#"+Xonomy.currentHtmlId);
- var $me=$el;
- if(Xonomy.currentFocus=="openingTagName") var $me=$el.find(".tag.opening").first();
- if(Xonomy.currentFocus=="closingTagName") var $me=$el.find(".tag.closing").last();
- if(Xonomy.currentFocus=="attributeName") var $me=$el.find(".attributeName").first();
- if(Xonomy.currentFocus=="attributeValue") var $me=$el.find(".attributeValue").first();
- if(Xonomy.currentFocus=="childrenCollapsed") var $me=$el.find(".childrenCollapsed").first();
- if(Xonomy.currentFocus=="rollouter") var $me=$el.find(".rollouter").first();
- var $candidates=$(".xonomy .focusable:visible");
- $candidates=$candidates.not(".char").add(".hasInlineMenu > .children > .textnode .char:visible");
- var $next=$candidates.eq( $candidates.index($me[0])+1 );
- if($next.hasClass("attributeName")) Xonomy.setFocus($next.closest(".attribute").prop("id"), "attributeName");
- if($next.hasClass("attributeValue")) Xonomy.setFocus($next.closest(".attribute").prop("id"), "attributeValue");
- if($next.hasClass("opening")) Xonomy.setFocus($next.closest(".element").prop("id"), "openingTagName");
- if($next.hasClass("closing")) Xonomy.setFocus($next.closest(".element").prop("id"), "closingTagName");
- if($next.hasClass("textnode")) Xonomy.setFocus($next.prop("id"), "text");
- if($next.hasClass("childrenCollapsed")) Xonomy.setFocus($next.closest(".element").prop("id"), "childrenCollapsed");
- if($next.hasClass("rollouter")) Xonomy.setFocus($next.closest(".element").prop("id"), "rollouter");
- if($next.hasClass("char")) Xonomy.setFocus($next.prop("id"), "char");
- };
- Xonomy.goLeft=function(){
- var $el=$("#"+Xonomy.currentHtmlId);
- var $me=$el;
- if(Xonomy.currentFocus=="openingTagName") var $me=$el.find(".tag.opening").first();
- if(Xonomy.currentFocus=="closingTagName") var $me=$el.find(".tag.closing").last();
- if(Xonomy.currentFocus=="attributeName") var $me=$el.find(".attributeName").first();
- if(Xonomy.currentFocus=="attributeValue") var $me=$el.find(".attributeValue").first();
- if(Xonomy.currentFocus=="childrenCollapsed") var $me=$el.find(".childrenCollapsed").first();
- if(Xonomy.currentFocus=="rollouter") var $me=$el.find(".rollouter").first();
- var $candidates=$(".xonomy .focusable:visible");
- $candidates=$candidates.not(".char").add(".hasInlineMenu > .children > .textnode .char:visible");
- var $next=$candidates.eq( $candidates.index($me[0])-1 );
- if($next.hasClass("attributeName")) Xonomy.setFocus($next.closest(".attribute").prop("id"), "attributeName");
- if($next.hasClass("attributeValue")) Xonomy.setFocus($next.closest(".attribute").prop("id"), "attributeValue");
- if($next.hasClass("opening")) Xonomy.setFocus($next.closest(".element").prop("id"), "openingTagName");
- if($next.hasClass("closing")) Xonomy.setFocus($next.closest(".element").prop("id"), "closingTagName");
- if($next.hasClass("textnode")) Xonomy.setFocus($next.prop("id"), "text");
- if($next.hasClass("childrenCollapsed")) Xonomy.setFocus($next.closest(".element").prop("id"), "childrenCollapsed");
- if($next.hasClass("rollouter")) Xonomy.setFocus($next.closest(".element").prop("id"), "rollouter");
- if($next.hasClass("char")) Xonomy.setFocus($next.prop("id"), "char");
- };
|