4989 lines
223 KiB
JavaScript
4989 lines
223 KiB
JavaScript
|
||
editorLog = console.log;
|
||
// editorLog = function(){};
|
||
debugLog = function(){};
|
||
// debugLog = console.log;
|
||
//parseLog = function(){};
|
||
parseLog = console.log;
|
||
errorLog = console.log;
|
||
|
||
/* the structure of each object, and its realization as PreTeXt source or in HTML,
|
||
is recorded in the objectStructure dictionary.
|
||
|
||
{"xml:id": new_id, "sourcetag": new_tag, "parent": parent_description, "title": ""}
|
||
|
||
In pretext, pieces are of the form ["piecename", "tag"], while
|
||
in source, pieces are of the form ["piecename", "required_component"], while
|
||
|
||
*/
|
||
|
||
editing_mode = 0;
|
||
|
||
current_page = location.host+location.pathname;
|
||
debugLog("current_page", current_page);
|
||
chosen_edit_option_key = "edit_option".concat(current_page);
|
||
chosen_edit_option = readCookie(chosen_edit_option_key) || "";
|
||
editing_mode = chosen_edit_option; /* delete one of those variables */
|
||
debugLog("chosen_edit_option", chosen_edit_option, "chosen_edit_option", chosen_edit_option > 0);
|
||
|
||
|
||
objectStructure = {
|
||
"type": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="type"', 'data-parent_id="<&>xml:id<;>"', 'data-editable="70XX"', 'tabindex="-1"'],
|
||
"pieces": [["(capitalize,sourcetag)", ""]]
|
||
}
|
||
},
|
||
"type-child": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="type"', 'data-editable="70YY"', 'tabindex="-1"'],
|
||
"pieces": [["(capitalize,sourcetag)", ""]]
|
||
// "pieces": [["(capitalize,type-contained)", ""]]
|
||
}
|
||
},
|
||
"type-proof": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="type"', 'data-editable="70YY"', 'tabindex="-1"'],
|
||
"pieces": [["(literal,Proof)", ""]]
|
||
// "pieces": [["(capitalize,type-contained)", ""]]
|
||
}
|
||
},
|
||
"sectiontype": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="type"'], // the type of a section is not editable?
|
||
"pieces": [["(capitalize,sourcetag)", ""]]
|
||
}
|
||
},
|
||
"codenumber": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="codenumber"'],
|
||
"pieces": [["(codenumber,)", ""]] // maybe () was a bad idea? do we need a triple?
|
||
}
|
||
},
|
||
"period": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="period"'],
|
||
"pieces": [["(period,)", ""]]
|
||
}
|
||
},
|
||
"comma": { // used in bibliography
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="comma"'],
|
||
"pieces": [["(comma,)", ""]]
|
||
}
|
||
},
|
||
"titleperiod": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="period"'],
|
||
"pieces": [["(titleperiod,)", ""]]
|
||
}
|
||
},
|
||
"space": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="space"'],
|
||
"pieces": [["(space,)", ""]]
|
||
}
|
||
},
|
||
"title": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="title"', 'data-editable="70"', 'tabindex="-1"'],
|
||
"pieces": [["title", ""]]
|
||
}
|
||
},
|
||
"nbsp": {
|
||
"html": {
|
||
"tag": "",
|
||
"pieces": [["(literal, )", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "nbsp",
|
||
"pieces": []
|
||
},
|
||
"source": {
|
||
"pieces": []
|
||
}
|
||
},
|
||
"idx": {
|
||
"html": {
|
||
"tag": "",
|
||
"pieces": [],
|
||
},
|
||
"pretext": {
|
||
"tag": "idx",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"h": {
|
||
"html": {
|
||
"tag": "",
|
||
"pieces": [],
|
||
},
|
||
"pretext": {
|
||
"tag": "h",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
|
||
"theorem_like_heading": {
|
||
"html": {
|
||
"tag": "h4",
|
||
"cssclass": "heading",
|
||
"attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'],
|
||
"pieces": [["{type}", ""], ["{space}", ""], ["{codenumber}", ""], ["{period}", ""], ["{space}", ""], ["{title}", ""], ["{titleperiod}", ""]]
|
||
// * means editable piece
|
||
}
|
||
},
|
||
"proof_like_heading": {
|
||
"html": {
|
||
"tag": "h5",
|
||
"cssclass": "heading",
|
||
"attributes": ['class="<&>{cssclass}<;>"', 'xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["{type-child}", ""], ["{period}", ""]]
|
||
}
|
||
},
|
||
"proof_heading": {
|
||
"html": {
|
||
"tag": "h5",
|
||
"cssclass": "heading",
|
||
"attributes": ['class="<&>{cssclass}<;>"', 'xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["{type-proof}", ""], ["{period}", ""]]
|
||
}
|
||
},
|
||
"section_like_heading": {
|
||
"html": {
|
||
"tag": "h2",
|
||
"cssclass": "heading hide-type",
|
||
"attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'],
|
||
"pieces": [["{sectiontype}", ""], ["{codenumber}", ""], ["{space}", ""], ["{title}", ""]]
|
||
}
|
||
},
|
||
"title_heading": {
|
||
"html": {
|
||
"tag": "h2",
|
||
"cssclass": "heading",
|
||
"attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'],
|
||
"pieces": [["{title}", ""], ["{period}", ""]]
|
||
}
|
||
},
|
||
"task_like_heading": {
|
||
"html": {
|
||
"tag": "h6",
|
||
"cssclass": "heading",
|
||
"attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'],
|
||
"pieces": [["{codenumber}", ""], ["{space}", ""], ["{title}", ""]]
|
||
}
|
||
},
|
||
"caption_like_heading": {
|
||
"html": {
|
||
"tag": "h5",
|
||
"cssclass": "captionheading",
|
||
"attributes": ['class="<&>{cssclass}<;>"', 'data-parent_id="<&>xml:id<;>"'],
|
||
"pieces": [["{type}", ""], ["{space}", ""], ["{codenumber}", ""], ["{period}", ""], ["{space}", ""]]
|
||
}
|
||
},
|
||
"xref": {
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['class="ref tmp"', 'id="<&>xml:id<;>"', 'ref="<&>ref<;>"'],
|
||
"pieces": [["(literal,REFERENCE)", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "xref",
|
||
"attributes": ['ref="<&>ref<;>"', 'text="<&>text<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]],
|
||
"attributes": [["ref", "*"], ["text", ""],["detail",""],["first",""],["last",""]]
|
||
}
|
||
},
|
||
"introduction": {
|
||
"html": {
|
||
"tag": "section",
|
||
"attributes": ['class="introduction"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'],
|
||
"pieces": [["content", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "introduction",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", "*"], ["content", "p"]]
|
||
}
|
||
},
|
||
"conclusion": {
|
||
"html": {
|
||
"tag": "section",
|
||
"attributes": ['class="conclusion"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'],
|
||
"pieces": [["{proof_like_heading}", ""], ["content", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "conclusion",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", "*"], ["content", "p"]]
|
||
}
|
||
},
|
||
|
||
"worksheet": {
|
||
"html": {
|
||
"tag": "section",
|
||
"attributes": ['class="worksheet"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'],
|
||
"pieces": [["{section_like_heading}", ""], ["content", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "worksheet",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", "*"], ["content", "p"]]
|
||
}
|
||
},
|
||
"section": {
|
||
"html": {
|
||
"tag": "section",
|
||
"attributes": ['class="section"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'],
|
||
"pieces": [["{section_like_heading}", ""], ["content", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "section",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", "*"], ["content", "p"]]
|
||
}
|
||
},
|
||
"subsection": {
|
||
"html": {
|
||
"tag": "section",
|
||
"attributes": ['class="subsection"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'],
|
||
"pieces": [["{section_like_heading}", ""], ["content", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "subsection",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", "*"], ["content", "p"]]
|
||
}
|
||
},
|
||
"paragraphs": {
|
||
"html": {
|
||
"tag": "section",
|
||
"attributes": ['class="paragraphs"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'],
|
||
"pieces": [["{title_heading}", ""], ["content", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "paragraphs",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", "*"], ["content", "p"]]
|
||
}
|
||
},
|
||
"exercises": {
|
||
"html": {
|
||
"tag": "section",
|
||
"attributes": ['class="exercises"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'],
|
||
"pieces": [["{section_like_heading}", ""], ["content", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "exercises",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", "*"], ["content", "p"]]
|
||
}
|
||
},
|
||
"exercisegroup": {
|
||
"html": {
|
||
"tag": "section",
|
||
"attributes": ['class="exercisegroup"', 'id="<&>xml:id<;>"', 'data-editable="XYX"', 'tabindex="-1"'],
|
||
"pieces": [["{section_like_heading}", ""], ["content", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "exercisegroup",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", "*"], ["content", "p"]]
|
||
}
|
||
},
|
||
|
||
|
||
"page": {
|
||
"html": {
|
||
"tag": "section",
|
||
"attributes": ['class="onepage"', 'id="<&>xml:id<;>"', 'data-editable="PPP"', 'tabindex="-1"'],
|
||
"pieces": [["content", ""]],
|
||
},
|
||
"pretext": {
|
||
"tag": "page",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", "p"]]
|
||
}
|
||
},
|
||
"objectives": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "objectives",
|
||
"pieces": [["{proof_like_heading}", ""], ["content",""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"data_editable": "160"
|
||
},
|
||
"pretext": {
|
||
"tag": "objectives",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", "p"]]
|
||
}
|
||
},
|
||
|
||
|
||
|
||
"p": {
|
||
"html": {
|
||
"tag": "p",
|
||
"pieces": [["content", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "99"
|
||
},
|
||
"pretext": {
|
||
"tag": "p",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
/* probably there is a better way to do it, but we have separate elements for p
|
||
that occur in
|
||
text // ip
|
||
math
|
||
text // mp
|
||
math
|
||
text // mp
|
||
math
|
||
text // fp
|
||
*/
|
||
"ip": {
|
||
"html": {
|
||
"tag": "p",
|
||
"pieces": [["content", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "99"
|
||
},
|
||
"pretext": {
|
||
"tag_opening": "\n<p", // note the slimy way of including attributes
|
||
"tag_closing": "",
|
||
"attributes": ['xml:id="<&>xml:id<;>">\n'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"mp": {
|
||
"html": {
|
||
"tag": "p",
|
||
"pieces": [["content", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="mp"'],
|
||
"data_editable": "99"
|
||
},
|
||
"pretext": {
|
||
"tag_opening": "",
|
||
"tag_closing": "",
|
||
"attributes": [],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"fp": {
|
||
"html": {
|
||
"tag": "p",
|
||
"pieces": [["content", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="fp"'],
|
||
"data_editable": "99"
|
||
},
|
||
"pretext": {
|
||
"tag_opening": "",
|
||
"tag_closing": "\n</p>\n",
|
||
"attributes": [],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
|
||
"li": {
|
||
"html": {
|
||
"tag": "li",
|
||
"pieces": [["content", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"'],
|
||
"data_editable": "98aZ"
|
||
},
|
||
"pretext": {
|
||
"tag": "li",
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["content", "p"]]
|
||
}
|
||
},
|
||
|
||
"blockquote": {
|
||
"html": {
|
||
"tag": "blockquote",
|
||
"pieces": [["content", ""], ["attribution", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"cssclass": "blockquote",
|
||
"data_editable": "44?"
|
||
},
|
||
"pretext": {
|
||
"tag": "blockquote",
|
||
"pieces": [["content", ""], ["attribution", "attribution"]],
|
||
},
|
||
"source": {
|
||
"pieces": [["content", "p"], ["attribution", ""]] // attribution can contain a "line". come back to that
|
||
}
|
||
},
|
||
|
||
"list": {
|
||
"html": {
|
||
"tag": "ol",
|
||
"pieces": [["content", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'list-style-type="a"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "AAA"
|
||
},
|
||
"pretext": {
|
||
"tag": "ol",
|
||
"pieces": [["content", ""]],
|
||
"attributes": ['label="A"']
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["content", "li"]],
|
||
"attributes": [["label", "A"]]
|
||
}
|
||
},
|
||
|
||
"figure": {
|
||
"html": {
|
||
"tag": "figure",
|
||
"pieces": [["content",""],["{caption}", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"data_editable": "32",
|
||
"cssclass": "figure figure-like"
|
||
},
|
||
"pretext": {
|
||
"tag": "figure",
|
||
"pieces": [["content"], ["{caption}"]],
|
||
"attributes": ['xml:id="<&>xml:id<;>"']
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""], ["captiontext", ""]],
|
||
"attributes": []
|
||
}
|
||
},
|
||
|
||
"image": {
|
||
"html": {
|
||
"tag": "div",
|
||
"pieces": [["{bareimage}",""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"', 'style="width: <&>width<;>%; margin-right: <&>marginright<;>%; margin-left: <&>marginleft<;>%"'],
|
||
"data_editable": "31",
|
||
"cssclass": "image-box"
|
||
},
|
||
"pretext": {
|
||
"tag": "image",
|
||
"pieces": [],
|
||
"attributes": ['xml:id="<&>xml:id<;>"', 'source="<&>source<;>"', 'alt="<&>alt<;>"', 'width="<&>width<;>%"', 'margins="<&>marginleft<;>% <&>marginright<;>%"']
|
||
},
|
||
"source": {
|
||
"pieces": [["",""]],
|
||
"attributes": [["source", ""], ["width", "40"], ["marginleft", "20"], ["marginright", "40"], ["alt", ""]]
|
||
}
|
||
},
|
||
|
||
"bareimage": {
|
||
"html": {
|
||
"tag": "img",
|
||
"pieces": [],
|
||
"attributes": ['src="<&>source<;>"', 'alt="<&>alt<;>"', 'class="contained"'],
|
||
}
|
||
},
|
||
|
||
"sidebyside": {
|
||
"html": {
|
||
"tag": "div",
|
||
"pieces": [["{sbsrow}",""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="<&>{cssclass}<;>"'],
|
||
"cssclass": "sidebyside"
|
||
},
|
||
"pretext": {
|
||
"tag": "sidebyside",
|
||
"pieces": [["content", ""]],
|
||
"attributes": ['xml:id="<&>xml:id<;>"', 'margins="<&>marginleft<;>% <&>marginright<;>%"', 'width="<&>(percentlist,widths)<;>"'],
|
||
},
|
||
"source": {
|
||
"pieces": [["content",""]],
|
||
"attributes": [["marginleft", ""], ["marginright", ""], ["widths", ""]]
|
||
}
|
||
},
|
||
"sbsrow": {
|
||
"html": {
|
||
"tag": "div",
|
||
"pieces": [["content",""]], // ????
|
||
"attributes": ['class="<&>{cssclass}<;>"', 'style="margin-right: <&>marginright<;>%; margin-left: <&>marginleft<;>%"'],
|
||
"data_editable": "89",
|
||
"cssclass": "sbsrow"
|
||
},
|
||
"pretext": {
|
||
"tag": "",
|
||
"pieces": [["content",""]],
|
||
"attributes": []
|
||
},
|
||
"source": {
|
||
"pieces": [["content",""]],
|
||
"attributes": [["marginleft", "20"], ["marginright", "40"]]
|
||
}
|
||
},
|
||
"sbspanel": {
|
||
"html": {
|
||
"tag": "div",
|
||
"pieces": [["content",""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="<&>{cssclass}<;>"', 'style="width:<&>(nthitem,widths)<;>%"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "90",
|
||
"cssclass": "sbspanel"
|
||
},
|
||
"pretext": {
|
||
"tag": "stack",
|
||
"pieces": [["content", ""]],
|
||
"attributes": ['xml:id="<&>xml:id<;>"']
|
||
},
|
||
"source": {
|
||
"pieces": [["content",""]]
|
||
}
|
||
},
|
||
|
||
"proof": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "proof",
|
||
"pieces": [["{proof_heading}", ""], ["proof",""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"data_editable": "60"
|
||
},
|
||
"pretext": {
|
||
"tag": "proof",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["proof", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", "p"]]
|
||
}
|
||
},
|
||
"proof-standalone": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "proof",
|
||
"pieces": [["{XXXXXnorbeingusedXXXXXXX_proof_heading}", ""], ["content",""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"data_editable": "60"
|
||
},
|
||
"pretext": {
|
||
"tag": "proof",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", "p"]]
|
||
}
|
||
},
|
||
|
||
"caption": {
|
||
"html": {
|
||
"tag": "figcaption",
|
||
"data_editable": "321",
|
||
// "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"attributes": ['id="<&>xml:id<;>"'],
|
||
"pieces": [["{caption_like_heading}", ""], ["{captiontext}",""]]
|
||
// "pieces": [["(literal, caption goes here)",""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "caption",
|
||
"attributes": [],
|
||
"pieces": [["captiontext", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"captiontext": { /* not used */
|
||
"html": {
|
||
"tag": "p",
|
||
"data_editable": "321",
|
||
// "attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
// do it like editabe title?
|
||
"attributes": ['data-source_id="<&>xml:id<;>"', 'data-component="caption"', 'class="caption"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"pieces": [["captiontext",""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "",
|
||
"attributes": [],
|
||
"pieces": [["captiontext", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["captiontext", ""]]
|
||
}
|
||
},
|
||
|
||
"references": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "bib",
|
||
"data_editable": "33",
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"pieces": [["{section_like_heading}", ""], ["content",""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "references",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", ""], ["content",""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["content",""]]
|
||
}
|
||
},
|
||
|
||
/* biblio, the items directly following it, and the refrences above,
|
||
are not usable at this time. references have to be handled in
|
||
a text editor. 3 Dec 2021
|
||
*/
|
||
"biblio": {
|
||
"html": {
|
||
"tag": "div",
|
||
"cssclass": "bibentry",
|
||
"data_editable": "333",
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"pieces": [["{bib-title}", ""], ["{journal}",""], ["{volume}",""], ["{number}",""], ["{author}",""], ["{pages}",""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "biblio",
|
||
"attributes": ['xml:id="<&>xml:id<;>"', 'type="raw"'],
|
||
"pieces": [["title", ""], ["journal",""], ["volume",""], ["number",""], ["author",""], ["pages",""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["journal",""], ["volume",""], ["number",""], ["author",""], ["pages",""]]
|
||
}
|
||
},
|
||
|
||
"bib-title": {
|
||
"html": {
|
||
"tag": "i",
|
||
"pieces": [["title", "zz"]]
|
||
}
|
||
},
|
||
"author": {
|
||
"html": {
|
||
"tag": "",
|
||
"pieces": [["author", ""], ["{comma}", ""]]
|
||
}
|
||
},
|
||
"journal": {
|
||
"html": {
|
||
"tag": "",
|
||
"pieces": [["journal", ""]]
|
||
}
|
||
},
|
||
"volume": {
|
||
"html": {
|
||
"tag": "b",
|
||
"pieces": [["volume", ""]]
|
||
}
|
||
},
|
||
"pages": {
|
||
"html": {
|
||
"tag": "jjj",
|
||
"pieces": [["pages", ""]]
|
||
}
|
||
},
|
||
"number": {
|
||
"html": {
|
||
"tag_opening": "no. ",
|
||
"tag_closing": " ",
|
||
"pieces": [["number", ""]]
|
||
}
|
||
},
|
||
|
||
"remark-like": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "remark-like",
|
||
"data_editable": "92",
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"pieces": [["{theorem_like_heading}", ""], ["statement",""]]
|
||
},
|
||
"pretext": {
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["statement", "statement"]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["statement", "p"]]
|
||
}
|
||
},
|
||
|
||
"project-like-tasks": {
|
||
"html": {
|
||
"tag": "article",
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"cssclass": "project-like",
|
||
"data_editable": "194",
|
||
"pieces": [["{theorem_like_heading}", ""], ["content",""], ["tasks", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "sourcetag",
|
||
"pieces": [["title", "title"], ["content", ""], ["tasks", ""]],
|
||
"attributes": ['xml:id="<&>xml:id<;>"']
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["content", "p"], ["tasks", ""]]
|
||
// "attributes": [["workspace", "0"]]
|
||
}
|
||
},
|
||
"project-like": {
|
||
"html": {
|
||
"tag": "article",
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"cssclass": "project-like",
|
||
"data_editable": "94",
|
||
"pieces": [["{theorem_like_heading}", ""], ["statement",""], ["%hint%", "hint"], ["%answer%", "answer"], ["%solution%", "solution"], ["{workspace}", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "sourcetag",
|
||
"pieces": [["title", "title"], ["statement", "statement"], ["hint", "hint"], ["answer", "answer"], ["solution", "solution"]],
|
||
"attributes": ['xml:id="<&>xml:id<;>"', 'workspace="<&>workspace<;>"']
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["statement", "p"], ["hint", ""], ["answer", ""], ["solution", ""]],
|
||
"attributes": [["workspace", "0"]]
|
||
}
|
||
},
|
||
|
||
"definition-like": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "definition-like",
|
||
"data_editable": "95a",
|
||
"pieces": [["{theorem_like_heading}", ""], ["statement", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"']
|
||
},
|
||
"pretext": {
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["statement", "statement"]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["statement", "p"]]
|
||
}
|
||
},
|
||
|
||
"theorem-like": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "theorem-like",
|
||
"data_editable": "93",
|
||
"pieces": [["{theorem_like_heading}", ""], ["statement", ""], ["{proof}", ""]],
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"']
|
||
},
|
||
"pretext": {
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["statement", "statement"], ["{proof}", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["statement", "p"], ["proof", ""]]
|
||
}
|
||
},
|
||
|
||
"task": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "exercise-like task",
|
||
"data_editable": "94ZZZA",
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"pieces": [["{task_like_heading}", ""], ["statement",""], ["%hint%", "hint"], ["%answer%", "answer"], ["%solution%", "solution"], ["{workspace}", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "task",
|
||
"pieces": [["title", "title"], ["statement", "statement"], ["hint", ""], ["answer", ""], ["solution", ""]],
|
||
"attributes": ['workspace="<&>workspace<;>"']
|
||
},
|
||
"source": {
|
||
"pieces": [["title", ""], ["statement", "p"], ["hint", ""], ["answer", ""], ["solution", ""]],
|
||
"attributes": [["workspace", "0"]]
|
||
}
|
||
},
|
||
|
||
/* consolidate H/A/S */
|
||
"hint": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "solution-like hint",
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"pieces": [["{proof_like_heading}", ""], ["content",""]],
|
||
// go back and make the lack of data_editable automatically make the contained p editable
|
||
/* "data_editable": "454", */
|
||
"data_editable": "hhhh"
|
||
},
|
||
"pretext": {
|
||
"tag": "hint",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", "p"]]
|
||
}
|
||
},
|
||
"answer": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "solution-like answer",
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"pieces": [["{proof_like_heading}", ""], ["content",""]],
|
||
// go back and make the lack of data_editable automatically make the contained p editable
|
||
/* "data_editable": "454", */
|
||
"data_editable": "hhhh"
|
||
},
|
||
"pretext": {
|
||
"tag": "answer",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", "p"]]
|
||
}
|
||
},
|
||
"solution": {
|
||
"html": {
|
||
"tag": "article",
|
||
"cssclass": "solution-like solution",
|
||
"attributes": ['id="<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"pieces": [["{proof_like_heading}", ""], ["content",""]],
|
||
// go back and make the lack of data_editable automatically make the contained p editable
|
||
/* "data_editable": "454", */
|
||
"data_editable": "hhhh"
|
||
},
|
||
"pretext": {
|
||
"tag": "solution",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["title", "title"], ["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", "p"]]
|
||
}
|
||
},
|
||
|
||
"workspace": {
|
||
"html": {
|
||
"tag": "div",
|
||
"cssclass": "workspace",
|
||
"data_editable": "WwW",
|
||
"attributes": ['data-parent_id="<&>xml:id<;>"', 'data-space="<&>workspace<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"', 'class="<&>{cssclass}<;>"'],
|
||
"pieces": []
|
||
}
|
||
},
|
||
|
||
"term": { // need to mark it as inline
|
||
"html": {
|
||
"tag": "dfn",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="terminology"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "ttt",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "term",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
|
||
"em": { // need to mark it as inline
|
||
"html": {
|
||
"tag": "em",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="emphasis"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "eemm",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "em",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"fn": { // need to mark it as inline
|
||
"html": {
|
||
"tag": "a",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="id-ref fn-knowl original"', 'data-knowl=" "', 'href=" "', 'data-refid="hk-<&>xml:id<;>"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "fnfnfn",
|
||
// "pieces": [["content", "sup"]]
|
||
"pieces": [["(literal,footnote)", "sup"]]
|
||
},
|
||
"pretext": {
|
||
"tag": "fn",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"alert": { // need to mark it as inline
|
||
"html": {
|
||
"tag": "em",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="alert"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "aall",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "alert",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"init": { // need to mark it as inline
|
||
"html": {
|
||
"tag": "abbr",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="initialism"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "iinniitt",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "init",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"c": { // need to mark it as inline
|
||
"html": {
|
||
"tag": "code",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="code-inline tex2jax_ignore"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "ccoo",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "c",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
|
||
"ellipsis": { // need to mark it as inline
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="abbrev"', 'contenteditable="false"'],
|
||
"data_editable": "abbr",
|
||
"pieces": [["(literal,…)", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "ellipsis",
|
||
"pieces": []
|
||
},
|
||
"source": {
|
||
}
|
||
},
|
||
"etc": { // need to mark it as inline
|
||
"html": {
|
||
"tag": "span",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="abbrev"', 'contenteditable="false"'],
|
||
"pieces": [["(literal,etc)", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "etc",
|
||
"pieces": []
|
||
},
|
||
"source": {
|
||
}
|
||
},
|
||
|
||
"q": { // need to mark it as inline
|
||
"html": {
|
||
"tag": "q",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="quote"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "qqq",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "q",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
|
||
"m": { // need to mark it as inline
|
||
"html": {
|
||
"tag_opening": "<span class='process-math'>\\(",
|
||
"tag_closing": "\\)</span>",
|
||
// "tag": "script",
|
||
// "attributes": ['type="math/tex"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "m",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
|
||
"me": {
|
||
"html": {
|
||
"tag": "div",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="displaymath process-math"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "42",
|
||
"pieces": [["{me_raw}", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "me",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"men": {
|
||
"html": {
|
||
"tag": "div",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="displaymath process-math"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "42",
|
||
"pieces": [["{me_raw}", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "men",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"md": {
|
||
"html": {
|
||
"tag": "div",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="displaymath process-math"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "42",
|
||
"pieces": [["{md_raw}", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "md",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"mdn": {
|
||
"html": {
|
||
"tag": "div",
|
||
"attributes": ['id="<&>xml:id<;>"', 'class="displaymath process-math"', 'data-editable="<&>{data_editable}<;>"', 'tabindex="-1"'],
|
||
"data_editable": "42",
|
||
"pieces": [["{me_raw}", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "mdn",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"me_raw": {
|
||
"html": {
|
||
"tag_opening": "\\begin{equation*}",
|
||
"tag_closing": "\\end{equation*}",
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
"md_raw": {
|
||
"html": {
|
||
"tag_opening": "\\begin{align*}",
|
||
"tag_closing": "\\end{align*}",
|
||
"pieces": [["content", ""]]
|
||
}
|
||
},
|
||
// check if mrow is actually used
|
||
"mrow": {
|
||
"html": {
|
||
"tag_opening": "",
|
||
"tag_closing": "\\cr",
|
||
"data_editable": "422",
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"pretext": {
|
||
"tag": "mrow",
|
||
"attributes": ['xml:id="<&>xml:id<;>"'],
|
||
"pieces": [["content", ""]]
|
||
},
|
||
"source": {
|
||
"pieces": [["content", ""]]
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
var environment_instances = {
|
||
"definition-like": ["definition", "conjecture", "axiom", "principle", "heuristic", "hypothesis", "assumption"],
|
||
"theorem-like": ["lemma", "proposition", "theorem", "corollary", "claim", "fact", "identity", "algorithm"],
|
||
"remark-like": ["remark", "warning", "note", "observation", "convention", "insight"],
|
||
"project-like-tasks": ["investigation", "exploration", "project"],
|
||
"project-like": ["exercise", "activity"]
|
||
}
|
||
|
||
for (const [owner, instances] of Object.entries(environment_instances)) {
|
||
var data_editable_base = objectStructure[owner].html.data_editable;
|
||
var cssclass_base = objectStructure[owner].html.cssclass;
|
||
var source_pieces = objectStructure[owner].source.pieces;
|
||
var pretext_pieces = objectStructure[owner].pretext.pieces;
|
||
var pretext_attributes = (objectStructure[owner].pretext.attributes || []);
|
||
var source_attributes = (objectStructure[owner].source.attributes || []);
|
||
for (var j=0; j < instances.length; ++j) {
|
||
var this_tag = instances[j];
|
||
objectStructure[this_tag] = {
|
||
"owner": owner,
|
||
"html": {
|
||
"tag": objectStructure[owner].html.tag,
|
||
"pieces": objectStructure[owner].html.pieces,
|
||
"attributes": objectStructure[owner].html.attributes,
|
||
"cssclass": cssclass_base + " " + this_tag,
|
||
"data_editable": data_editable_base + j.toString(),
|
||
"heading": objectStructure[owner].html.heading
|
||
},
|
||
"pretext": {
|
||
"tag": this_tag,
|
||
"pieces": pretext_pieces,
|
||
"attributes": pretext_attributes
|
||
},
|
||
"source": {
|
||
"tag": this_tag,
|
||
"pieces": source_pieces,
|
||
"attributes": source_attributes
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
editorLog('objectStructure["exercise"]', objectStructure["exercise"]);
|
||
|
||
var sidebyside_instances = {
|
||
"sbs": [["2 panels", "sbs2"], ["3 panels", "sbs3"], ["4 panels", "sbs4"]],
|
||
//"sbs2": [["full across XX", "sbs2_0_50_50_0"], ["gap but no margin", "sbs2_0_40_40_0"], ["spaced equally", "sbs2_5_40_40_5"]],
|
||
"sbs2": [["full across", "sbs_0_50_50_0"], ["gap but no margin", "sbs_0_45_45_0"], ["spaced equally", "sbs_5_40_40_5"]],
|
||
"sbs3": [["full across", "sbs_0_34_32_34_0"], ["gap but no margin", "sbs_0_28_28_38_0"], ["spaced equally", "sbs_5_25_26_25_5"]],
|
||
"sbs4": [["full across", "sbs_0_25_25_25_25_0"], ["gap but no margin", "sbs_0_20_20_20_20_0"], ["spaced equally", "sbs_3_18_18_18_18_3"]]
|
||
}
|
||
|
||
Object.assign(objectStructure, sidebyside_instances);
|
||
|
||
// shoudl we distinguish empty tags by format?
|
||
var always_empty_tags = ["img", "image", "xref"];
|
||
// eventially xref will move to allowed_empty_tags
|
||
var allowed_empty_tags = ["div", "span", "p", "stack"];
|
||
var tag_display = { /* the default is "block" */
|
||
"inline": ["m", "em", "ellipsis", "span", "term", "dfn", "q", "c", "code", "alert", "nbsp", "xref", "idx", "h", "init"],
|
||
"title": ["title", "idx", "h1", "h2", "h3", "h4", "h5", "h6", "div", "usage", "image"],
|
||
"block-tight": [] // ["mp", "mrow"]
|
||
}
|
||
|
||
inline_tags = tag_display["inline"];
|
||
inline_math = ["m"];
|
||
inline_abbrev = ["ellipsis", "ie", "eg", "etc"];
|
||
|
||
// contained_objects are a componnet of another object, not just buried in content
|
||
var contained_objects =["title", "statement", "caption", "captiontext", "proof",
|
||
"author", "journal", "volume", "number", "pages"];
|
||
|
||
function tag_type(tag) {
|
||
var this_type;
|
||
|
||
if (["p", "ip", "mp", "fp"].includes(tag)) { this_type = "p" }
|
||
else if (["me", "men", "md", "mdn"].includes(tag)) { this_type = "md" }
|
||
else { this_type = tag }
|
||
|
||
return this_type
|
||
}
|
||
|
||
function process_value_from_source(fcn, piece, src) {
|
||
|
||
editorLog(fcn, "process_value_from_source", piece, "in", src);
|
||
var content_raw = "";
|
||
if (["literal", "codenumber", "period", "titleperiod", "space"].includes(fcn)) {
|
||
content_raw = piece;
|
||
} else {
|
||
if (piece in src) {
|
||
content_raw = src[piece]
|
||
} else {
|
||
if ("parent" in src) {
|
||
var parent_src = internalSource[src["parent"][0]];
|
||
if (piece in parent_src) {
|
||
content_raw = parent_src[piece]
|
||
} else {
|
||
errorLog("Error: piece", piece, "fcn", fcn, "from", parent_src, "not in src or parent_src")
|
||
}
|
||
} else {
|
||
errorLog("at the top, or else there is an error")
|
||
}
|
||
}
|
||
} /* fcn != literal */
|
||
|
||
/*
|
||
if (typeof myVar == 'string') {
|
||
content_raw = content_raw.replace(/-standalone$/, "") // hack because we need alternate to sourcetag
|
||
}
|
||
*/
|
||
if (fcn == "capitalize") {
|
||
content = content_raw.charAt(0).toUpperCase() + content_raw.slice(1);
|
||
} else if (fcn == "literal") {
|
||
editorLog("literally", piece);
|
||
// alert(piece);
|
||
content = piece
|
||
} else if (fcn == "space") {
|
||
content = content_raw + " "
|
||
} else if (fcn == "period") {
|
||
content = content_raw + "."
|
||
} else if (fcn == "comma") {
|
||
content = content_raw + ","
|
||
} else if (fcn == "titleperiod") {
|
||
if (src.title && !(/[!?]$/.test(src.title))) {
|
||
content = content_raw + "."
|
||
}
|
||
} else if (fcn == "percentlist") {
|
||
if (content_raw) {
|
||
content = content_raw.join("% ") + "%"
|
||
} else {
|
||
content = "MISSING" + "%"
|
||
}
|
||
} else if (fcn == "nthitem") {
|
||
|
||
editorLog("calculating nthitem", piece, "from ", content_raw, "within", src);
|
||
var item_index = 0; // need to be its location among siblings
|
||
content = content_raw[item_index];
|
||
} else if (fcn == "codenumber") {
|
||
editorLog(" CODENUMBER", src);
|
||
content = internalSource.root_data.number_base;
|
||
if (src["xml:id"] == top_level_id) {
|
||
// no need to add locan number
|
||
} else {
|
||
content += ".N"
|
||
}
|
||
} else {
|
||
content = content_raw
|
||
}
|
||
|
||
return content
|
||
}
|
||
|
||
$(".autopermalink > a").attr("tabindex", -1);
|
||
|
||
var editable_objects = [["p", 99], ["ol", 97], ["ul", 96], ["article", 95], ["blockquote", 80], ["section", 66],
|
||
["title", 20], ["caption", 890]];
|
||
for(var j=0; j < editable_objects.length; ++j) {
|
||
$(editable_objects[j][0]).attr("data-editable", editable_objects[j][1]);
|
||
$(editable_objects[j][0]).attr("tabindex", -1);
|
||
}
|
||
|
||
/* the code */
|
||
|
||
editorLog(" enabling edit");
|
||
|
||
user_level = "novice";
|
||
|
||
// we have to keep track of multiple consecutive carriage returns
|
||
this_char = "";
|
||
prev_char = "";
|
||
prev_prev_char = "";
|
||
|
||
// for resizing and layout changes
|
||
// clobal variables so we can adjust them dynamically
|
||
move_scale = 1;
|
||
magnify_scale = 1;
|
||
|
||
final_added_object = "";
|
||
previous_added_object = "";
|
||
|
||
// sometimes we have to prevent Tab from changing focus
|
||
this_focused_element = "";
|
||
prev_focused_element = "";
|
||
prev_prev_focused_element = "";
|
||
|
||
var menu_neutral_background = "#ddb";
|
||
var menu_active_background = "#fdd";
|
||
|
||
var recent_editing_actions = []; // we unshift to this, so most recent edit is first.
|
||
// currently just a human-readable list
|
||
var ongoing_editing_actions = [];
|
||
var old_content = {}; // to hold old versions of changed materials
|
||
|
||
// what will happen with internationalization?
|
||
var keyletters = ["KeyA", "KeyB", "KeyC", "KeyD", "KeyE", "KeyF", "KeyG", "KeyH", "KeyI", "KeyJ", "KeyK", "KeyL", "KeyM", "KeyN", "KeyO", "KeyP", "KeyQ", "KeyR", "KeyS", "KeyT", "KeyU", "KeyV", "KeyW", "KeyX", "KeyY", "KeyZ"];
|
||
|
||
var movement_location_options = [];
|
||
var movement_location = 0;
|
||
var first_move = true; // used when starting to move, because object no longer occupies its original location
|
||
|
||
Storage.prototype.setObject = function(key, value) {
|
||
// this.setItem(key, JSON.stringify(value));
|
||
this.setItem(key, JSON.stringify(value, function(key, val) {
|
||
// console.log("key", key, "value", value, "val", val);
|
||
return val.toFixed ? Number(val.toFixed(3)) : val;
|
||
}));
|
||
}
|
||
|
||
Storage.prototype.getObject = function(key) {
|
||
var value = this.getItem(key);
|
||
return value && JSON.parse(value);
|
||
}
|
||
|
||
function randomstring(len) {
|
||
if (!len) { len = 10 }
|
||
return "tMP" + (Math.random() + 1).toString(36).substring(2,len)
|
||
}
|
||
|
||
function removeItemFromList(lis, value) {
|
||
var index = lis.indexOf(value);
|
||
if (index > -1) {
|
||
lis.splice(index, 1);
|
||
}
|
||
return lis;
|
||
}
|
||
|
||
function rescale(width, max, margin_left, margin_right) {
|
||
var available_width = max - parseFloat(margin_left) - parseFloat(margin_right);
|
||
return width * 100 / available_width
|
||
}
|
||
|
||
function spacemath_to_tex(text) {
|
||
thetext = text;
|
||
|
||
thetext = thetext.replace(/ d([a-zA-Z])(\s|$)/, " \\,d$1$2");
|
||
thetext = thetext.replace(/ *< */, " < ");
|
||
|
||
return thetext
|
||
}
|
||
|
||
function split_paragraphs(paragraph_content) {
|
||
|
||
// does the textbox contain more than one paragraph?
|
||
var paragraph_content_list = paragraph_content.split("<div><br></div>");
|
||
editorLog("there were", paragraph_content_list.length, "paragraphs, but some may be empty");
|
||
for (var j=0; j < paragraph_content_list.length; ++j) {
|
||
editorLog("paragraph", j, "begins", paragraph_content_list[j].substring(0,20))
|
||
}
|
||
|
||
var paragraph_content_list_trimmed = [];
|
||
|
||
for (var j=0; j < paragraph_content_list.length; ++j) {
|
||
// probably each paragraph is wrapped in meaningless div tags
|
||
var this_paragraph_contents_raw = paragraph_content_list[j];
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<\/div><div>/g, "\n");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<div>/g, "");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<\/div>/g, "");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/ /g, " ");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/ +<br>/g, "\n");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<br>/g, "\n");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.trim();
|
||
if (!this_paragraph_contents_raw) { editorLog("empty paragraph") }
|
||
else { paragraph_content_list_trimmed.push(this_paragraph_contents_raw) }
|
||
editorLog("this_paragraph_contents_raw", this_paragraph_contents_raw);
|
||
}
|
||
|
||
if (!paragraph_content_list_trimmed.length ) {
|
||
// empty, so insert it and delete it later
|
||
paragraph_content_list_trimmed = [""];
|
||
}
|
||
|
||
return paragraph_content_list_trimmed
|
||
}
|
||
|
||
var submenu_options = { // revise as these are handled previously
|
||
"math-like": [["me"], ["chem"], ["code"]],
|
||
"image-like": [["image"], ["video"], ["audio"]],
|
||
"aside-like": [["aside"], ["historical"], ["biographical"]],
|
||
"list-like": [["itemized list", "list"], ["dictionary list", "dl"], ["table"]],
|
||
"layout-like": [["side-by-side panels", "sbs"], ["assemblage"], ["biographical aside"], ["titled paragraph", "paragraphs"]],
|
||
"section-like": ["section", "subsection", "paragraphs", "rq", "exercises"],
|
||
"sbs": [["2 panels", "sbs2"], ["3 panels", "sbs3"], ["4 panels", "sbs4"]],
|
||
"list-like": [["itemized list", "list"], ["dictionary list", "dl"], ["table"]],
|
||
"example-like": ["example", "question", "problem"]
|
||
}
|
||
|
||
Object.assign(submenu_options, sidebyside_instances);
|
||
|
||
Object.assign(submenu_options, environment_instances); // wrong because string not list
|
||
// or not wrong, if the code is more clever
|
||
|
||
/* need to distinguish between the list of objects of a type,
|
||
and the list of types that can go in a location.
|
||
OR, is it okay that these are all in one list?
|
||
It seems to not be okay, because the "blockquote" entry
|
||
says that only a "p" can go in a blockquote. But blockquote
|
||
is an entry under "quoted".
|
||
*/
|
||
base_menu_for = {
|
||
"section": [["paragraph", "p"],
|
||
["display math/chemistry/code", "math-like", "c"],
|
||
["list or table", "list-like"],
|
||
["example-like", "example-like"],
|
||
["definition-like", "definition-like"],
|
||
["theorem-like", "theorem-like"],
|
||
["remark-like"],
|
||
["project/exercise-like", "project-like", "j"],
|
||
["image/video/sound", "image-like", "v"],
|
||
["blockquote/poem/music/etc", "quoted"],
|
||
["aside-like", "aside-like", "d"],
|
||
["interactives"],
|
||
["proof", "proof-standalone", "o"],
|
||
["layout-like"],
|
||
["section-like"],
|
||
// ["Save", "save"],
|
||
["PreTeXt source", "source"]],
|
||
// need to unify section with paragraphs (when sections are managed by the CAT)
|
||
"paragraphs": [["paragraph", "p"],
|
||
["display math/chemistry/code", "math-like", "c"],
|
||
["list or table", "list-like"],
|
||
["example-like", "example-like"],
|
||
["definition-like", "definition-like"],
|
||
["theorem-like", "theorem-like"],
|
||
["remark-like"],
|
||
["project/exercise-like", "project-like", "j"],
|
||
["image/video/sound", "image-like", "v"],
|
||
["blockquote/poem/music/etc", "quoted"],
|
||
["aside-like", "aside-like", "d"],
|
||
["interactives"],
|
||
["proof", "proof-standalone", "o"],
|
||
["layout-like"],
|
||
// ["Save", "save"],
|
||
["PreTeXt source", "source"]],
|
||
"blockquote": [["paragraph", "p"]],
|
||
// "ol": [["list item", "li"]],
|
||
"article": [["paragraph", "p"], // this is for theorem-like and similar
|
||
["math/chemistry/code", "math-like", "c"],
|
||
["list or table", "list-like"],
|
||
["image/video/sound", "image-like", "v"]],
|
||
"li": [["new list item", "li", "i"],
|
||
["paragraph", "p"],
|
||
["list or table", "list-like"],
|
||
["math/chemistry/code", "math-like", "c"],
|
||
["image/video/sound", "image-like", "v"]],
|
||
"p": [["emphasis-like"], ["formula"], ["abbreviation"], ["symbol"], ["ref or link", "ref"]]
|
||
}
|
||
base_menu_for["proof"] = base_menu_for["article"];
|
||
base_menu_for["page"] = base_menu_for["section"];
|
||
|
||
|
||
// not currently used
|
||
function past_edits() {
|
||
|
||
var the_past_edits = [];
|
||
if(recent_editing_actions.length) {
|
||
the_past_edits = recent_editing_actions.map(x => [x.join(" ")])}
|
||
else { the_past_edits = [["no chnages yet"]] }
|
||
|
||
return the_past_edits
|
||
}
|
||
|
||
// this should be created from inner_menu_for
|
||
editing_container_for = { "p": 1, "ip": 1, "mp": 1, "fp": 1,
|
||
"theorem-like": ["theorem", "proposition", "lemma", "corollary", "claim", "fact", "identity", "algorithm"],
|
||
"definition-like": ["definition", "conjecture", "axiom", "hypothesis", "principle", "heuristic", "assumption"],
|
||
"remark-like": ["remark", "warning", "note", "observation", "convention", "insight"],
|
||
"example-like": ["example", "question", "problem"],
|
||
"exercise-like": ["exercise"],
|
||
"ol": ["item"],
|
||
"li": [""],
|
||
"list": [""],
|
||
"image": [""],
|
||
"sbs2": [""],
|
||
"sbs3": [""],
|
||
"sbs4": [""],
|
||
"source": 1,
|
||
"proof-standalone": [""], //just a guess
|
||
"proof": [""] //just a guess
|
||
}
|
||
|
||
function make_current_editing_tree_from_id(theid) {
|
||
|
||
//current_editing keeps track of where we are in the tree. maybe need a better name?
|
||
|
||
editorLog(" OOOOO make_current_editing_tree_from_id", theid);
|
||
editorLog(" which has internalSource", internalSource[theid]);
|
||
editorLog(" within", internalSource);
|
||
editorLog(" and the DOM object is", document.getElementById(theid));
|
||
// the existing current_editing know the top level id
|
||
// var top_id = current_editing["tree"][0][0].id;
|
||
var top_id = top_level_id;
|
||
|
||
// but now we need to start over and go bottom-up
|
||
current_editing = {
|
||
"level": -1,
|
||
"location": [],
|
||
"tree": [ ]
|
||
}
|
||
|
||
var current_id = theid;
|
||
var current_element = document.getElementById(current_id);
|
||
console.log("current_id", current_id, "current_element", current_element);
|
||
var selectable_parent, current_element_siblings, selectable_parent_id;
|
||
var ct=0;
|
||
while (current_id != top_id && ct < 10) {
|
||
ct += 1;
|
||
editorLog("ct", ct);
|
||
editorLog("looking to match current_element", current_element, "until we hit", top_id);
|
||
selectable_parent = current_element.parentElement.closest("[data-editable]");
|
||
current_element_siblings = next_editable_of(selectable_parent, "children");
|
||
current_id = selectable_parent.id;
|
||
editorLog("current_id", current_id);
|
||
current_editing["tree"].unshift(current_element_siblings);
|
||
editorLog("looking for", current_element, "in", current_element_siblings);
|
||
for (var j=0; j < current_element_siblings.length; ++j) {
|
||
if (current_element == current_element_siblings[j]) {
|
||
current_editing["level"] += 1;
|
||
current_editing["location"].unshift(j);
|
||
editorLog("this is item", j);
|
||
break
|
||
} else {
|
||
editorLog(current_element == current_element_siblings[j], "aaa", current_element,"zzz", current_element_siblings[j])
|
||
}
|
||
}
|
||
current_element = selectable_parent
|
||
}
|
||
current_editing["level"] += 1;
|
||
current_editing["location"].unshift(0);
|
||
current_editing["tree"].unshift([document.getElementById(top_id)]);
|
||
|
||
editorLog("built current_editing after", ct, "levels");
|
||
editorLog("current_editing[level]", current_editing["level"]);
|
||
editorLog("current_editing[location]", current_editing["location"]);
|
||
editorLog("current_editing[tree]", current_editing["tree"])
|
||
|
||
editorLog(" OOOOO done with make_current_editing_tree_from_id", theid, document.getElementById(theid));
|
||
|
||
}
|
||
|
||
function standard_title_form(object_id) {
|
||
var the_object = internalSource[object_id];
|
||
var the_title = the_object.title;
|
||
|
||
var title_form = '<span id="actively_editing" class="starting_point_for_editing" data-source_id="' + object_id + '" data-component="' + 'title' + '" contenteditable="true">' + the_title + '</span>';
|
||
|
||
return title_form
|
||
}
|
||
function standard_caption_form(object_id) {
|
||
var the_object = internalSource[object_id];
|
||
editorLog("editing caption of object_id", object_id, "which contains", the_object);
|
||
var the_caption = the_object.caption;
|
||
|
||
var caption_form = '<span id="actively_editing" class="starting_point_for_editing" data-source_id="' + object_id + '" data-component="' + 'caption' + '" contenteditable="true">' + the_caption + '</span>';
|
||
|
||
return caption_form
|
||
}
|
||
|
||
|
||
function menu_options_for(object_id, component_type, level) {
|
||
// this should be a function of the object, not just its tag
|
||
// p in li vs p child of section, for example
|
||
var menu_for;
|
||
|
||
if (!component_type) { component_type = internalSource[object_id]["sourcetag"] }
|
||
editorLog("component_tag", component_type);
|
||
if (level == "base") {
|
||
menu_for = base_menu_for
|
||
} else if (level == "move-or-delete") {
|
||
editorLog("C0 menu options for", component_type);
|
||
var m_d_options;
|
||
var component_parent = internalSource[object_id]["parent"][0];
|
||
var component_parent_tag = internalSource[component_parent]["sourcetag"];
|
||
if (component_type == "p" && component_parent_tag == "li") {
|
||
m_d_options = [
|
||
["move-local-p", "Move these words within this page"],
|
||
["move-local-li", "Move this list item within this page"],
|
||
["move-global", "Move this another page (not implemented yet)"],
|
||
["delete", "Delete"] // does it matter whether there are other p in this li?
|
||
];
|
||
} else if(tag_type(component_type) == "p") {
|
||
m_d_options = [
|
||
["move-local-p", "Move this text within this page"],
|
||
["move-global", "Move to another page (not implemented yet)"],
|
||
["delete", "Delete"]
|
||
];
|
||
} else {
|
||
m_d_options = [
|
||
["move-local", "Move within this page"],
|
||
["move-global", "Move to another page (not implemented yet)"],
|
||
["delete", "Delete"]
|
||
];
|
||
}
|
||
var this_menu = "";
|
||
for (var i=0; i < m_d_options.length; ++i) {
|
||
this_menu += '<li tabindex="-1" data-action="' + m_d_options[i][0] + '"';
|
||
if (i==0) { this_menu += ' id="choose_current"'}
|
||
this_menu += '>';
|
||
this_menu += m_d_options[i][1]
|
||
this_menu += '</li>';
|
||
}
|
||
editorLog("made this_menu", this_menu);
|
||
return this_menu
|
||
} else if (level == "modify") {
|
||
editorLog("CZ menu options for", component_type);
|
||
var m_d_options;
|
||
var component_parent = internalSource[object_id]["parent"][0];
|
||
var component_parent_tag = internalSource[component_parent]["sourcetag"];
|
||
if (component_type == "image") {
|
||
m_d_options = [
|
||
["modify", "enlarge", "make larger"],
|
||
["modify", "shrink", "make smaller"],
|
||
["modify", "left", "shift left"],
|
||
["modify", "right", "shift right"],
|
||
["modify", "arrows", "use arrow keys (not implemented yet)"],
|
||
["modify", "done", "done modifying"]
|
||
];
|
||
} else if (component_type == "sbspanel") {
|
||
m_d_options = [
|
||
["modify", "enlarge", "make this panel wider"],
|
||
["modify", "shrink", "make this panel narrower"],
|
||
["modify", "enlargeall", "make all panels wider"],
|
||
["modify", "shrinkall", "make all panels narrower"],
|
||
["modify", "leftminus", "decrease left margin"],
|
||
["modify", "leftplus", "increase left margin"],
|
||
["modify", "rightminus", "decrease right margin"],
|
||
["modify", "rightplus", "increase right margin"],
|
||
["modify", "done", "done modifying"]
|
||
];
|
||
} else if (environment_instances["project-like"].includes(component_type) || component_type == "task") {
|
||
// needs to also include exercise-like
|
||
m_d_options = [
|
||
["modify", "enlarge", "more space"],
|
||
["modify", "shrink", "less space"],
|
||
["modify", "enlargeslightly", "slightly more space"],
|
||
["modify", "shrinkslightly", "slightly less space"],
|
||
["modify", "done", "done adjusting"]
|
||
];
|
||
} else {
|
||
alert("don;t know how to make that menu")
|
||
m_d_options = []
|
||
}
|
||
var this_menu = "";
|
||
for (var i=0; i < m_d_options.length; ++i) {
|
||
this_menu += '<li tabindex="-1" data-action="' + m_d_options[i][0] + '" data-modifier="' + m_d_options[i][1] + '"';
|
||
if (i==0) { this_menu += ' id="choose_current"'}
|
||
this_menu += '>';
|
||
this_menu += m_d_options[i][2]
|
||
this_menu += '</li>';
|
||
}
|
||
editorLog("made this_menu", this_menu);
|
||
return this_menu
|
||
} else if (level == "change") {
|
||
editorLog("C1 menu options for", component_type);
|
||
objectclass = objectStructure[component_type].owner;
|
||
editorLog("which has class",objectclass);
|
||
var equivalent_objects = environment_instances[objectclass].slice();
|
||
var replacement_list = removeItemFromList(equivalent_objects, component_type);
|
||
editorLog("equivalent_objects", equivalent_objects);
|
||
var this_menu = "";
|
||
for (var i=0; i < replacement_list.length; ++i) {
|
||
this_menu += '<li tabindex="-1" data-action="change-env-to" data-env="' + replacement_list[i] + '"';
|
||
if (i==0) { this_menu += ' id="choose_current"'}
|
||
this_menu += '>';
|
||
this_menu += replacement_list[i];
|
||
this_menu += '</li>';
|
||
}
|
||
editorLog("made this_menu", this_menu);
|
||
return this_menu
|
||
// } else { menu_for = inner_menu_for() }
|
||
} else { menu_for = submenu_options }
|
||
editorLog("C2 in menu options for", component_type, "or", object_id);
|
||
editorLog("menu_for", menu_for);
|
||
if (component_type in menu_for) {
|
||
component_items = menu_for[component_type]
|
||
} else {
|
||
// is this a reasonable default for what can go anywhere?
|
||
editorLog("default menu for" + component_type);
|
||
component_items = [["paragraph", "p"],
|
||
["math/chemistry/code", "math-like", "c"],
|
||
["list or table", "list-like"],
|
||
["image/video/sound", "image-like", "v"]]
|
||
}
|
||
|
||
this_menu = "";
|
||
for (var i=0; i < component_items.length; ++i) {
|
||
this_item = component_items[i];
|
||
|
||
if (typeof this_item == "string") {
|
||
this_item_name = this_item;
|
||
this_item_label = this_item;
|
||
this_item_shortcut = "";
|
||
} else { // list
|
||
this_item_name = this_item[0];
|
||
this_item_label = this_item_name;
|
||
this_item_shortcut = "";
|
||
if (this_item.length == 3) {
|
||
this_item_label = this_item[1];
|
||
this_item_shortcut = this_item[2];
|
||
} else if (this_item.length == 2) {
|
||
this_item_label = this_item[1];
|
||
}
|
||
}
|
||
this_menu += '<li tabindex="-1" data-env="' + this_item_label + '"';
|
||
this_menu += ' data-env-parent="' + component_type + '"';
|
||
if (this_item_shortcut) {
|
||
this_menu += ' data-jump="' + this_item_name.charAt(0) + ' ' + this_item_shortcut + '"';
|
||
if (this_item_name.match(/^[a-z]/i)) {
|
||
this_item_name = this_item_name.replace(this_item_shortcut, '<b>' + this_item_shortcut + '</b>');
|
||
}
|
||
} else {
|
||
this_menu += 'data-jump="' + this_item_name.charAt(0) + '"';
|
||
}
|
||
if (i==0) { this_menu += ' id="choose_current"'}
|
||
this_menu += '>';
|
||
|
||
if (this_item_name.match(/^[a-z]/i)) {
|
||
first_character = this_item_name.charAt(0);
|
||
this_item_name = this_item_name.replace(first_character, "<b>" + first_character + "</b>");
|
||
}
|
||
|
||
this_menu += this_item_name
|
||
// little right triangle if there is a submenu
|
||
// if (this_item_label in inner_menu_for()) { this_menu += '<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div>' }
|
||
if (this_item_label in submenu_options) { this_menu += '<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div>' }
|
||
this_menu += '</li>';
|
||
}
|
||
|
||
return this_menu
|
||
}
|
||
|
||
function top_menu_options_for(this_obj) {
|
||
editorLog("top menu options for aa", this_obj);
|
||
var this_id = this_obj.id;
|
||
|
||
// maybe the "classList" in this function shoudl instead look at the internalSource?
|
||
|
||
var this_list = "";
|
||
|
||
if (this_obj.classList.contains("heading")) {
|
||
var this_obj_parent = this_obj.parentElement;
|
||
editorLog("heading options for bbb", this_obj_parent);
|
||
var this_obj_parent_id = this_obj_parent.id;
|
||
var this_obj_parent_source = internalSource[this_obj_parent_id];
|
||
var this_obj_environment = this_obj_parent_source["sourcetag"];
|
||
|
||
editorLog("this_obj_environment", this_obj_environment);
|
||
|
||
this_list = '<li tabindex="-1" id="choose_current" data-env="p" data-action="edit">Change the title</li>';
|
||
this_list += '<li tabindex="-1" data-action="change-env">Change "' + this_obj_environment + '" to <div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
} else {
|
||
var this_object_type = this_obj.tagName; // needs to examine other attributes and then look up a reasonable name
|
||
//consolidate this redundancy
|
||
this_obj_id = this_obj.id;
|
||
if (!this_obj_id) {
|
||
this_obj_id=this_obj.getAttribute("data-parent_id")
|
||
editorLog("now has id", this_obj_id);
|
||
}
|
||
this_obj_source = internalSource[this_obj_id];
|
||
editorLog("this_obj_source", this_obj_source);
|
||
editorLog("this_obj", this_obj, "classList", this_obj.classList, "T/F", this_obj.classList.contains("image-box"));
|
||
this_obj_environment = this_obj_source["sourcetag"];
|
||
if (this_object_type == "P" || this_obj.classList.contains("displaymath")) {
|
||
this_list = '<li tabindex="-1" id="choose_current" data-env="p" data-action="edit">Edit ' + this_obj_environment + '</li>';
|
||
var editable_children = next_editable_of(this_obj, "children");
|
||
editorLog("editable_children", editable_children);
|
||
if (editable_children.length && !(this_object_type == "P")) {
|
||
this_list += '<li tabindex="-1" data-env="' + this_object_type + '" data-location="enter">Enter ' + this_obj_environment + '</li>';
|
||
}
|
||
if (editable_children.length > 2 && (this_object_type == "SECTION")) {
|
||
this_list += '<li tabindex="-1" data-env="' + this_object_type + '" data-location="end">Go to end of ' + this_obj_environment + '</li>';
|
||
}
|
||
} else if (this_obj.classList.contains("image-box")) {
|
||
editorLog("found an image-box");
|
||
this_list = '<li tabindex="-1" id="choose_current" data-env="imagebox" data-action="modify">Modify layout<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
} else if (this_obj.classList.contains("sbspanel")) {
|
||
this_list = '<li tabindex="-1" id="choose_current" data-env="sbspanel" data-action="modify">Modify layout<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
} else {
|
||
this_list += '<li tabindex="-1" id="choose_current" data-env="' + this_object_type + '" data-location="enter">Enter ' + this_obj_environment + '</li>';
|
||
if (this_object_type == "SECTION") {
|
||
this_list += '<li tabindex="-1" data-env="' + this_object_type + '" data-location="end">Go to end of ' + this_obj_environment + '</li>';
|
||
}
|
||
}
|
||
|
||
if (this_obj.classList.contains("sbspanel")) {
|
||
this_list += '<li tabindex="-1" data-env="' + 'sbspanel' + '" data-location="afterbegin">Insert in panel<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
}
|
||
|
||
if (this_obj.classList.contains("project-like")) {
|
||
this_list += '<li tabindex="-1" data-env="' + 'task' + '">Add a task</li>';
|
||
}
|
||
|
||
if (this_id != top_level_id) {
|
||
this_list += '<li tabindex="-1" data-env="' + this_object_type + '" data-location="beforebegin">Insert before<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
this_list += '<li tabindex="-1" data-env="' + this_object_type + '" data-location="afterend">Insert after<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
|
||
this_list += '<li tabindex="-1" data-action="move-or-delete">Move or delete<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
}
|
||
this_list += '<li tabindex="-1" data-env="' + "metaadata" + '">Metadata<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
if (this_id != top_level_id) {
|
||
this_list += '<li tabindex="-1" data-env="' + "undo" + '">Revert<div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
}
|
||
if (previous_editing() && this_id == top_level_id) {
|
||
this_list += '<li tabindex="-1" data-action="' + "resume" + '">Resume previous editing</li>';
|
||
}
|
||
this_list += '<li tabindex="-1" data-action="' + "save" + '">Save</li>';
|
||
this_list += '<li tabindex="-1" data-action="' + "stop_editing" + '">Stop editing</li>';
|
||
}
|
||
return this_list
|
||
}
|
||
|
||
function edit_menu_from_current_editing(motion) {
|
||
// obviously we need to think a bit about current_editing and how it is used
|
||
var object_of_interest = current_editing["tree"][ current_editing["level"] ][ current_editing["location"][ current_editing["level"] ] ];
|
||
edit_menu_for(object_of_interest, motion);
|
||
}
|
||
|
||
function edit_menu_for(this_obj_or_id, motion) {
|
||
editorLog("make edit menu", motion, "for", this_obj_or_id);
|
||
|
||
// delete the old menu, if it exists
|
||
if (document.getElementById('edit_menu_holder')) {
|
||
var current_menu = document.getElementById('edit_menu_holder');
|
||
editorLog("current_menu", current_menu);
|
||
editorLog("this_choice", document.getElementById('enter_choice'));
|
||
if (this_choice = document.getElementById('enter_choice')) {
|
||
if (this_choice.getAttribute("data-location") == "stay") {
|
||
current_menu.previousSibling.classList.remove("may_leave")
|
||
} else {
|
||
current_menu.parentElement.classList.remove("may_select");
|
||
current_menu.parentElement.classList.remove("may_enter");
|
||
}
|
||
}
|
||
current_menu.parentElement.classList.remove("may_select");
|
||
current_menu.parentElement.classList.remove("may_enter");
|
||
current_menu.remove();
|
||
}
|
||
|
||
if (!this_obj_or_id) {
|
||
errorLog("error: empty this_obj_or_id", motion);
|
||
return ""
|
||
} else {
|
||
editorLog("this_obj_or_id", this_obj_or_id, "string?", typeof this_obj_or_id === 'string');
|
||
editorLog("which has parent", this_obj_or_id.parentElement)
|
||
}
|
||
|
||
console.log("this_obj_or_id", this_obj_or_id, typeof this_obj_or_id);
|
||
if (typeof this_obj_or_id === 'string') {
|
||
this_obj = document.getElementById(this_obj_or_id)
|
||
} else {
|
||
this_obj = this_obj_or_id
|
||
}
|
||
console.log("this_obj", this_obj);
|
||
var this_id = this_obj.id;
|
||
// this_obj = document.getElementById(this_obj); // because is is an id? Maybe need cases here
|
||
|
||
if (motion == "entering") {
|
||
menu_location = "afterbegin";
|
||
this_obj.classList.remove("may_leave");
|
||
if (next_editable_of(this_obj, "children").length && !(this_obj.tagName == "P")) {
|
||
this_obj.classList.add("may_enter");
|
||
} else {
|
||
this_obj.classList.add("may_select");
|
||
}
|
||
if (inline_tags.includes(this_obj.tagName.toLowerCase())) {
|
||
this_obj.classList.add("inline");
|
||
}
|
||
} else { menu_location = "afterend";
|
||
this_obj.classList.remove("may_select");
|
||
this_obj.classList.remove("may_enter");
|
||
this_obj.classList.add("may_leave");
|
||
editorLog("added may_leave to", this_obj)
|
||
} // when motion is 'leaving'
|
||
|
||
var edit_menu_holder = document.createElement('div');
|
||
edit_menu_holder.setAttribute('id', 'edit_menu_holder');
|
||
edit_menu_holder.setAttribute('class', 'edit_menu_holder');
|
||
edit_menu_holder.setAttribute('tabindex', '-1');
|
||
editorLog("adding menu for", this_obj_or_id, "menu_location", menu_location);
|
||
editorLog("which has tag", this_obj.tagName);
|
||
editorLog("does", this_obj.classList, "include type", this_obj.classList.contains("type"));
|
||
|
||
this_obj.insertAdjacentElement(menu_location, edit_menu_holder);
|
||
editorLog("added edit_menu_holder", document.getElementById("edit_menu_holder"), motion);
|
||
|
||
var edit_option = document.createElement('span');
|
||
edit_option.setAttribute('id', 'enter_choice');
|
||
|
||
if (motion == "entering") {
|
||
editorLog("inline_tags", inline_tags, "tag", this_obj.tagName.toLowerCase());
|
||
editorLog("next_editable_of(this_obj, children)", next_editable_of(this_obj, "children"));
|
||
if (false && inline_tags.includes(this_obj.tagName.toLowerCase())) {
|
||
edit_option.innerHTML = "change this?";
|
||
edit_option.setAttribute('data-location', 'inline');
|
||
} else if (this_obj.classList.contains("type")) {
|
||
// e.g., changing "proposition" to "theorem"
|
||
// need to code this better: over-writing edit_option
|
||
edit_option = document.createElement('ol');
|
||
edit_option.setAttribute('id', 'edit_menu');
|
||
edit_option.setAttribute('class', 'edit_menu');
|
||
this_obj_parent_id = this_obj.parentElement.parentElement.id;
|
||
this_obj_environment = internalSource[this_obj_parent_id]["sourcetag"];
|
||
edit_option.innerHTML = '<li id="choose_current" tabindex="-1" data-action="change-env">Change "' + this_obj_environment + '" to <div class="wrap_to_submenu"><span class="to_submenu">▻</span></div></li>';
|
||
edit_option.setAttribute('data-location', 'inline');
|
||
} else if (this_obj.classList.contains("image-box")) {
|
||
edit_option.innerHTML = "<b>modify</b> this image layout, or add near here?";
|
||
} else if (this_obj.classList.contains("sbspanel")) {
|
||
edit_option.innerHTML = "<b>modify</b> this panel layout, or change panel contents?";
|
||
} else if (this_obj.classList.contains("title") || this_obj.classList.contains("caption")) {
|
||
var this_contained_type = "title";
|
||
if (this_obj.classList.contains("caption")) { this_contained_type = "caption" }
|
||
edit_option = document.createElement('ol');
|
||
edit_option.setAttribute('id', 'edit_menu');
|
||
edit_option.setAttribute('class', 'edit_menu');
|
||
editorLog("this_obj", this_obj);
|
||
editorLog("this_obj.innerHTML", this_obj.innerHTML);
|
||
editorLog("menu only?", this_obj.innerHTML == '<div id="edit_menu_holder" class="edit_menu_holder" tabindex="-1"></div>');
|
||
this_obj_parent_id = this_obj.parentElement.parentElement.id;
|
||
this_obj_environment = internalSource[this_obj_parent_id]["sourcetag"];
|
||
if (this_obj.innerHTML == '<div id="edit_menu_holder" class="edit_menu_holder" tabindex="-1"></div>') {
|
||
edit_option.innerHTML = '<li id="choose_current" tabindex="-1" data-action="change-' + this_contained_type + '">Add a ' + this_contained_type + '</li>';
|
||
} else {
|
||
edit_option.innerHTML = '<li id="choose_current" tabindex="-1" data-action="change-' + this_contained_type + '">Change ' + this_contained_type + '</li>';
|
||
}
|
||
edit_option.setAttribute('data-location', 'inline');
|
||
} else if ((this_obj.classList.contains("placeholder") && (this_obj.classList.contains("hint") ||
|
||
this_obj.classList.contains("answer") ||
|
||
this_obj.classList.contains("solution") ||
|
||
this_obj.classList.contains("proof")) ) ) {
|
||
var theverb = "add"
|
||
var thenoun = this_obj.getAttribute("data-HAS");
|
||
edit_option.setAttribute('id', 'choose_current');
|
||
edit_option.setAttribute('data-env', thenoun);
|
||
edit_option.setAttribute('data-parent_id', this_obj.getAttribute("data-parent_id"));
|
||
edit_option.innerHTML = "<b>" + theverb + "</b>" + " " + thenoun;
|
||
} else if (this_obj.classList.contains('workspace')) {
|
||
edit_option.setAttribute('id', 'choose_current');
|
||
edit_option.setAttribute('data-env', 'workspace');
|
||
edit_option.setAttribute('data-action', 'modify');
|
||
edit_option.setAttribute('data-parent_id', this_obj.getAttribute("data-parent_id"));
|
||
|
||
edit_option.innerHTML = "<b>" + "adjust" + "</b>" + " " + "workspace";
|
||
} else {
|
||
if (next_editable_of(this_obj, "children").length && this_obj.tagName != "P") {
|
||
editorLog("this_obj", this_obj);
|
||
if (this_id == top_level_id) {
|
||
edit_option.innerHTML = "<b>enter</b> this " + internalSource[this_obj.id]["sourcetag"] + "?";
|
||
} else {
|
||
edit_option.innerHTML = "<b>enter</b> this " + internalSource[this_obj.id]["sourcetag"] + ", or add near here?";
|
||
}
|
||
} else {
|
||
edit_option.innerHTML = "<b>edit</b> this passage, or add near here?";
|
||
}
|
||
edit_option.setAttribute('data-location', 'next');
|
||
}
|
||
} else {
|
||
edit_option.setAttribute('data-location', 'stay');
|
||
edit_option.innerHTML = "continue editing this " + internalSource[this_obj.id]["sourcetag"];
|
||
}
|
||
editorLog("edit_option", edit_option);
|
||
document.getElementById("edit_menu_holder").insertAdjacentElement("afterbegin", edit_option);
|
||
document.getElementById('edit_menu_holder').focus();
|
||
}
|
||
|
||
function next_editable_of(obj, relationship) {
|
||
var next_to_edit;
|
||
editorLog("finding", relationship, "editable of", obj);
|
||
if (relationship == "children") {
|
||
next_to_edit = $(obj).find(' > [data-editable], > .sidebyside > .sbsrow > [data-editable], > li > [data-editable], > .heading > [data-editable], > .hint > [data-editable], > .answer > [data-editable]')
|
||
} else if (relationship == "outer-block") { // for example, a direct child of a section
|
||
next_to_edit = $(obj).find(' > [data-editable]')
|
||
} else if (relationship == "inner-block") { // typically a paragraph
|
||
next_to_edit = $(obj).find('section > [data-editable], [data-editable="99"], [data-editable="42"]')
|
||
} else if (relationship == "li-only") { // typically a paragraph
|
||
next_to_edit = $(obj).find('li')
|
||
} else {
|
||
editorLog("unimplemented next_editable_of")
|
||
}
|
||
|
||
editorLog("next_to_edit", next_to_edit);
|
||
return next_to_edit
|
||
}
|
||
|
||
function create_new_internal_object(new_tag, new_id, parent_description) {
|
||
|
||
var new_source = {"xml:id": new_id, "sourcetag": new_tag, "parent": parent_description, "title": ""}
|
||
|
||
editorLog("create new internal object", new_tag, "new_id", new_id, "parent_description", parent_description);
|
||
editorLog("within", internalSource[parent_description[0]]);
|
||
if (new_tag.startsWith("sbs")) { // creating an sbs, which contains one sbsrow, which contains several sbspanels
|
||
new_source.sourcetag = "sidebyside";
|
||
var sbs_layout = new_tag.split("_");
|
||
var [margin_left, margin_right] = [sbs_layout[1], sbs_layout[sbs_layout.length - 1]];
|
||
editorLog("sbs side margins", margin_left, "jj", margin_right);
|
||
new_source.marginleft = margin_left;
|
||
new_source.marginright = margin_right;
|
||
|
||
var col_content = "";
|
||
var widths = [];
|
||
for (var j=2; j <= sbs_layout.length - 2; ++j) {
|
||
widths.push(sbs_layout[j]);
|
||
var new_col_id = randomstring();
|
||
col_content += "<&>" + new_col_id + "<;>";
|
||
internalSource[new_col_id] = {"xml:id": new_col_id, "sourcetag": "sbspanel",
|
||
"content": "", "parent": [new_id, "content"]}
|
||
}
|
||
new_source.widths = widths;
|
||
new_source.content = col_content;
|
||
|
||
editorLog("new sbs", new_source);
|
||
|
||
} else {
|
||
|
||
editorLog("new_tag", new_tag);
|
||
var thisstructure = objectStructure[new_tag];
|
||
var thisownersourcestructure = {};
|
||
if (!thisstructure) { errorLog(new_tag + " not implemented yet"); return "" }
|
||
if ("owner" in thisstructure) {
|
||
var thisownerstructure = objectStructure[thisstructure.owner];
|
||
thisownersourcestructure = thisownerstructure.source;
|
||
}
|
||
var thissourcestructure = Object.assign({},thisownersourcestructure, thisstructure.source);
|
||
|
||
editorLog("thissourcestructure", thissourcestructure);
|
||
|
||
if ("attributes" in thissourcestructure) {
|
||
these_source_attributes = thissourcestructure.attributes;
|
||
for (var j=0; j < these_source_attributes.length; ++j) {
|
||
editorLog("adding", j, "attribute", these_source_attributes[j]);
|
||
new_source[these_source_attributes[j][0]] = these_source_attributes[j][1]
|
||
}
|
||
}
|
||
|
||
/* here need to also use the owner structure */
|
||
var these_source_pieces = thissourcestructure.pieces;
|
||
for (var j=0; j < these_source_pieces.length; ++j) {
|
||
editorLog("adding a piece", these_source_pieces[j]);
|
||
var [this_piece, this_piece_contains] = these_source_pieces[j];
|
||
|
||
if (this_piece_contains) {
|
||
var new_child_id = randomstring();
|
||
new_source[this_piece] = "<&>" + new_child_id + "<;>";
|
||
create_new_internal_object(this_piece_contains, new_child_id, [new_id, this_piece]);
|
||
} else {
|
||
new_source[this_piece] = ""
|
||
}
|
||
}
|
||
}
|
||
|
||
editorLog("made the new_source", new_source);
|
||
|
||
internalSource[new_id] = new_source;
|
||
|
||
editorLog("parent_description", parent_description, "new_tag", new_tag, "new_id", new_id);
|
||
editorLog("internalSource", internalSource);
|
||
if (new_tag == "list") {
|
||
// do nothing, because it is the child "li" which we are really creating
|
||
// chack that: maybe do add, if the stack is in the proper order
|
||
} else if (tag_type(new_tag) == "p"){
|
||
// p is the default, so no need to keep track of it
|
||
} else if (new_tag == "source"){
|
||
// not really a tag
|
||
} else if (new_tag.startsWith("sbs")){
|
||
ongoing_editing_actions.push(["new", "sbs", new_id]);
|
||
} else {
|
||
ongoing_editing_actions.push(["new", new_tag, new_id]);
|
||
}
|
||
return new_tag
|
||
}
|
||
|
||
function show_source(sibling, relative_placement) {
|
||
// var current_source = document.getElementById("newpretextsource");
|
||
// if (current_source) { editorLog("curr sou", current_source); alert("curr sour"); current_source.remove() }
|
||
var edit_placeholder = document.createElement("span");
|
||
edit_placeholder.setAttribute('id', "newsource");
|
||
sibling.insertAdjacentElement(relative_placement, edit_placeholder);
|
||
|
||
editorLog("just added", edit_placeholder);
|
||
|
||
var the_pretext_source = output_from_id("", top_level_id, "pretext");
|
||
|
||
the_pretext_source = the_pretext_source.replace(/\n\n/g, '\n');
|
||
|
||
// remove temporary ids
|
||
the_pretext_source = the_pretext_source.replace(/ xml:id="tMP[0-9a-z]+"/g, '');
|
||
the_pretext_source = the_pretext_source.replace(/^ +$/mg, ''); // m = multiline
|
||
|
||
// var the_old_source = document.getElementById("newsource");
|
||
// if (the_old_source) { the_old_source.remove() }
|
||
edit_placeholder.insertAdjacentHTML('afterend', '<textarea id="newpretextsource" style="width: 100%; height:30em">' + the_pretext_source + '</textarea>');
|
||
}
|
||
|
||
// unify with show_source, and maybe make the clean up part of output_from_id
|
||
function save_source() {
|
||
// var current_source = document.getElementById("newpretextsource");
|
||
// if (current_source) { editorLog("curr sou", current_source); alert("curr sour"); current_source.remove() }
|
||
editorLog(" QQ saving");
|
||
|
||
var the_pretext_source = output_from_id("", top_level_id, "pretext");
|
||
|
||
the_pretext_source = the_pretext_source.replace(/\n\n/g, '\n');
|
||
// remove temporary ids
|
||
the_pretext_source = the_pretext_source.replace(/ xml:id="tMP[0-9a-z]+"/g, '');
|
||
the_pretext_source = the_pretext_source.replace(/^ +$/mg, ''); // m = multiline
|
||
|
||
editorLog(" RR saving", top_level_id, "which begins", the_pretext_source.substring(0,50));
|
||
parent.save_file(top_level_id, the_pretext_source)
|
||
}
|
||
|
||
function create_object_to_edit(new_tag, new_objects_sibling, relative_placement) {
|
||
|
||
// when relative_placement is "afterbegin", the new_objects_sibling is actually its parent
|
||
editorLog("create object to edit", new_tag, new_objects_sibling, relative_placement);
|
||
// first insert a placeholder to edit-in-place
|
||
var new_id = randomstring();
|
||
recent_editing_actions.push(["new", new_tag, new_id]);
|
||
// we won;t need all of these, so re-think when these are created
|
||
var edit_placeholder = document.createElement("span");
|
||
edit_placeholder.setAttribute('id', new_id);
|
||
|
||
// when adding an li, you are actually focused on somethign inside an li
|
||
// but, maybe that distinction shoud be mede before calling create object to edit ?
|
||
if (new_tag == "li") { new_objects_sibling = new_objects_sibling.parentElement }
|
||
|
||
var sibling_id, parent_description, object_neighbor;
|
||
|
||
if (["hint", "answer", "solution", "proof"].includes(new_tag)) { // this is only for the case that a solution does not already exist
|
||
// create_new
|
||
|
||
sibling_id = new_objects_sibling.parentElement.id;
|
||
parent_description = [sibling_id, new_tag]
|
||
|
||
editorLog(new_tag, "parent_description", parent_description);
|
||
object_neighbor = "" ; // will not be used
|
||
|
||
} else if(new_objects_sibling.classList.contains("sbspanel")) { //bad hack! use internalCOntents!
|
||
sibling_id = new_objects_sibling.id;
|
||
editorLog("special case for empty sbspanel",sibling_id);
|
||
// alert("special sbspanel case");
|
||
parent_description = [sibling_id, "content"]
|
||
object_neighbor = "" ; // will not be used???
|
||
} else {
|
||
// and describe where it goes
|
||
editorLog("new_objects_sibling",new_objects_sibling);
|
||
sibling_id = new_objects_sibling.id;
|
||
parent_description = internalSource[sibling_id]["parent"];
|
||
object_neighbor = new RegExp('(<&>' + sibling_id + '<;>)');
|
||
}
|
||
|
||
if (relative_placement == "afterbegin" && new_tag != "image") { // when adding to a sbs panel
|
||
// redo the condition so that it explicitly uses sbs
|
||
// redundant with the "special case" above?
|
||
// parent_description = [new_id, "content"];
|
||
}
|
||
var object_neighbor = new RegExp('(<&>' + sibling_id + '<;>)');
|
||
if (new_tag == "task" && !(new_objects_sibling.classList.contains("task"))) {
|
||
// when task is being added by selecting from the parent exercise
|
||
relative_placement = "atend";
|
||
parent_description = [sibling_id, "tasks"];
|
||
}
|
||
if (["hint", "answer", "solution", "proof"].includes(new_tag)) { // this is only for the case that a solution does not already exist
|
||
relative_placement = "replace";
|
||
}
|
||
editorLog(new_tag, "parent_description", parent_description);
|
||
|
||
// then create the empty internalSource for the new object
|
||
var new_obj = create_new_internal_object(new_tag, new_id, parent_description);
|
||
if (!new_obj) { return "" }
|
||
|
||
// we have made the new object, but we still have to put it in the correct location
|
||
|
||
var the_current_arrangement = internalSource[parent_description[0]][parent_description[1]];
|
||
editorLog(" the_current_arrangement", the_current_arrangement);
|
||
editorLog(" from parent_description", parent_description, "internalSource[parent_description[0]]", internalSource[parent_description[0]]);
|
||
editorLog(" current_editing", current_editing);
|
||
|
||
// maybe the changes to current_editing is different for lists?
|
||
|
||
var neighbor_with_new = '';
|
||
var current_level = current_editing["level"];
|
||
var current_location = current_editing["location"][current_level];
|
||
editorLog(" UUU current_editing", current_editing["level"], current_editing["location"].length, current_editing["tree"].length, current_editing["tree"][current_editing["level"]])
|
||
if (relative_placement == "beforebegin" || relative_placement == "afterbegin") {
|
||
neighbor_with_new = '<&>' + new_id + '<;>' + '$1';
|
||
}
|
||
else if (relative_placement == "afterend" || relative_placement == "beforeend"){
|
||
neighbor_with_new = '$1' + '<&>' + new_id + '<;>'
|
||
current_location += 1
|
||
}
|
||
editorLog("makking new_arrangement from", object_neighbor, "by", neighbor_with_new);
|
||
|
||
if (relative_placement == "atend" || relative_placement == "replace" ) {
|
||
// this is not quire gight, but it works for hint/answer/solution
|
||
new_arrangement = the_current_arrangement + '<&>' + new_id + '<;>';
|
||
} else if(the_current_arrangement) {
|
||
new_arrangement = the_current_arrangement.replace(object_neighbor, neighbor_with_new);
|
||
} else {
|
||
new_arrangement = '<&>' + new_id + '<;>';
|
||
}
|
||
editorLog("which became", new_arrangement);
|
||
// alert("here");
|
||
internalSource[parent_description[0]][parent_description[1]] = new_arrangement;
|
||
if (new_tag == "list") {
|
||
// current_editing["level"] += 1;
|
||
// current_editing["location"].push(0);
|
||
// current_editing["tree"].push([document.getElementById(new_p_id)])
|
||
} else {
|
||
current_editing["location"][current_level] = current_location;
|
||
}
|
||
editorLog(" new_arrangement", new_arrangement);
|
||
editorLog("tried to insert", new_id, "next to", sibling_id, "in", the_current_arrangement)
|
||
editorLog(" updated current_editing", current_editing);
|
||
editorLog(" VVV current_editing", current_editing["level"], current_editing["location"].length, current_editing["tree"].length, current_editing["tree"][current_editing["level"]])
|
||
editorLog("relative_placement", relative_placement, "edit_placeholder", edit_placeholder);
|
||
|
||
if (relative_placement == "atend") {
|
||
new_objects_sibling.insertAdjacentElement("beforeend", edit_placeholder);
|
||
} else if (relative_placement == "replace") {
|
||
new_objects_sibling.replaceWith(edit_placeholder);
|
||
} else {
|
||
new_objects_sibling.insertAdjacentElement(relative_placement, edit_placeholder);
|
||
}
|
||
|
||
return edit_placeholder
|
||
}
|
||
|
||
function edit_in_place(obj, oldornew) {
|
||
// currentlt old_or_new is onlu use as "new" for a new li, so that we know
|
||
// to immediately make a new li to edit
|
||
// previous comment probebly wrong/out of date
|
||
|
||
var thisID;
|
||
editorLog("in edit in place", obj);
|
||
if (thisID = obj.getAttribute("id")) {
|
||
editorLog("will edit in place id", thisID, "which is", obj);
|
||
thisTagName = obj.tagName.toLowerCase();
|
||
} else { // editing somethign without an id, so probably is a title or caption
|
||
if (obj.classList.contains("heading")) {
|
||
editorLog("changing a heading");
|
||
editorLog("except we don;t know how to do that")
|
||
} else {
|
||
errorLog("error: I don't know how to edit", obj)
|
||
}
|
||
return ""
|
||
}
|
||
|
||
// this only works for paragraphs,
|
||
// which may be right, because existing content is mostly titles and paragraphs
|
||
if ( internalSource[thisID] ) {
|
||
var new_tag = internalSource[thisID]["sourcetag"];
|
||
var new_id = thisID; // track down why new_id is in the code
|
||
editorLog("new_tag is", new_tag, "from thisID", thisID, "from", internalSource[thisID]);
|
||
if (tag_type(new_tag) == "p" || tag_type(new_tag) == "md") { // make into a category?
|
||
var this_content_container = document.createElement('div');
|
||
this_content_container.setAttribute('id', "actively_editing");
|
||
this_content_container.setAttribute('data-age', oldornew);
|
||
editorLog("thing with thisID", thisID, "is",document.getElementById(thisID));
|
||
$("#" + thisID).replaceWith(this_content_container);
|
||
|
||
var idOfEditText = 'editing' + '_input_text';
|
||
var paragraph_editable = document.createElement('div');
|
||
paragraph_editable.setAttribute('contenteditable', 'true');
|
||
if (tag_type(new_tag) == "md") {
|
||
paragraph_editable.setAttribute('class', 'text_source displaymath_input');
|
||
} else {
|
||
paragraph_editable.setAttribute('class', 'text_source paragraph_input');
|
||
}
|
||
paragraph_editable.setAttribute('id', idOfEditText);
|
||
paragraph_editable.setAttribute('data-source_id', thisID);
|
||
paragraph_editable.setAttribute('data-parent_id', internalSource[thisID]["parent"][0]);
|
||
paragraph_editable.setAttribute('data-parent_component', internalSource[thisID]["parent"][1]);
|
||
|
||
document.getElementById('actively_editing').insertAdjacentElement("afterbegin", paragraph_editable);
|
||
|
||
editorLog("setting", $('#' + idOfEditText), "to have contents", internalSource[thisID]["content"]);
|
||
|
||
// from https://stackoverflow.com/questions/21257688/paste-rich-text-into-content-editable-div-and-only-keep-bold-and-italics-formatt
|
||
|
||
// figure out better how to do this as needed.
|
||
$('[contenteditable]').on('paste',function(e) {
|
||
e.preventDefault();
|
||
var text = (e.originalEvent || e).clipboardData.getData('text/plain') || prompt('Paste something..');
|
||
document.execCommand('insertText', false, text);
|
||
});
|
||
the_contents = internalSource[thisID]["content"];
|
||
the_contents = expand_condensed_source_html(the_contents, "edit");
|
||
the_contents = the_contents.replace(/\\cr/g, "<div><br></div>");
|
||
$('#' + idOfEditText).html(the_contents);
|
||
document.getElementById(idOfEditText).focus();
|
||
editorLog("made edit box for", thisID);
|
||
editorLog("which is", document.getElementById(idOfEditText));
|
||
editorLog("Whth content CC" + document.getElementById(idOfEditText).innerHTML + "DD");
|
||
editorLog("Whth content EE" + document.getElementById(idOfEditText).innerText + "FF");
|
||
editorLog("Whth content GG" + document.getElementById(idOfEditText).textContent + "HH");
|
||
this_char = "";
|
||
prev_char = "";
|
||
|
||
} else if (new_tag == "image") {
|
||
var this_content_container = document.createElement('div');
|
||
this_content_container.setAttribute('id', "actively_editing");
|
||
this_content_container.setAttribute('data-age', oldornew);
|
||
this_content_container.setAttribute('style', "width:50%; margin-left:auto; margin-right: auto; padding: 2em 3em 3em 3em; background: #fed");
|
||
$("#" + thisID).replaceWith(this_content_container);
|
||
|
||
var idOfEditText = 'editing' + '_input_image';
|
||
var image_editable = document.createElement('div');
|
||
image_editable.setAttribute('contenteditable', 'true');
|
||
image_editable.setAttribute('class', 'image_source');
|
||
image_editable.setAttribute('id', idOfEditText);
|
||
image_editable.setAttribute('style', "background: #fff");
|
||
image_editable.setAttribute('data-source_id', thisID);
|
||
image_editable.setAttribute('data-parent_id', internalSource[thisID]["parent"][0]);
|
||
image_editable.setAttribute('data-parent_component', internalSource[thisID]["parent"][1]);
|
||
|
||
document.getElementById('actively_editing').insertAdjacentElement("afterbegin", image_editable);
|
||
|
||
var edit_instructions = document.createElement('span');
|
||
edit_instructions.setAttribute('style', "font-size: 90%");
|
||
edit_instructions.innerHTML = "URL of image:"
|
||
document.getElementById('actively_editing').insertAdjacentElement("afterbegin", edit_instructions);
|
||
|
||
document.getElementById(idOfEditText).focus();
|
||
editorLog("made edit box for", thisID);
|
||
editorLog("which is", document.getElementById(idOfEditText));
|
||
editorLog("Whth content CC" + document.getElementById(idOfEditText).innerHTML + "DD");
|
||
editorLog("Whth content EE" + document.getElementById(idOfEditText).innerText + "FF");
|
||
editorLog("Whth content GG" + document.getElementById(idOfEditText).textContent + "HH");
|
||
this_char = "";
|
||
prev_char = "";
|
||
|
||
} else {
|
||
|
||
editorLog(new_tag, "create the object, then edit p in place", obj);
|
||
|
||
var this_object = html_from_internal_id(new_id, "");
|
||
var where_it_goes = document.getElementById(thisID);
|
||
where_it_goes.insertAdjacentHTML('afterend', this_object[0]);
|
||
where_it_goes.remove();
|
||
var where_it_is = document.getElementById(thisID);
|
||
|
||
|
||
editorLog("added this_object", this_object);
|
||
editorLog("where it is", where_it_is);
|
||
|
||
var this_source = internalSource[thisID];
|
||
if (this_source.sourcetag == "sidebyside") { // generalize to container was added
|
||
editorLog("added an sbs", document.getElementById(thisID));
|
||
editorLog("its .firstChild", document.getElementById(thisID).firstElementChild);
|
||
editorLog("its .firstChild.firstchild", document.getElementById(thisID).firstElementChild.firstElementChild);
|
||
var first_panel_id = document.getElementById(thisID).firstElementChild.firstElementChild.id;
|
||
editorLog("first_panel_id", first_panel_id, document.getElementById(first_panel_id));
|
||
make_current_editing_tree_from_id(first_panel_id);
|
||
edit_menu_from_current_editing("entering");
|
||
} else {
|
||
var empty_p_child = $(where_it_is).find("p");
|
||
if (empty_p_child[0]) {
|
||
editorLog("found the empty p", empty_p_child);
|
||
editorLog("found the empty p[0]", empty_p_child[0]);
|
||
edit_in_place(empty_p_child[0], "new");
|
||
} else {
|
||
errorLog("error: no empty p to edit")
|
||
}
|
||
}
|
||
}
|
||
|
||
} else {
|
||
editorLog("Error: edit in place of object that is not already known", obj);
|
||
editorLog("What is known:", internalSource)
|
||
}
|
||
}
|
||
|
||
function resume_editing() {
|
||
internalSource = previous_editing();
|
||
replace_by_id(internalSource["root_data"]["id"], "html");
|
||
edit_menu_for(top_level_id, "entering");
|
||
console.log("editing resumed");
|
||
}
|
||
|
||
function replace_by_id(theid, format) {
|
||
|
||
if (format != "html") { return "" }
|
||
|
||
var this_object_new = output_from_id("",theid, format);
|
||
|
||
console.log("id", theid);
|
||
// GO BACK AND REVISIT THE NEXT 3 LINES
|
||
// document.getElementById(theid).setAttribute("id", "delete_me");
|
||
// document.getElementById("delete_me").insertAdjacentHTML('beforebegin', this_object_new);
|
||
// document.getElementById("delete_me").remove();
|
||
|
||
// need to also work with MJ3
|
||
// MathJax.Hub.Queue(['Typeset', MathJax.Hub, document.getElementById(theid)]);
|
||
console.log("MathJax on", theid, document.getElementById(theid));
|
||
// MathJax.typesetPromise(document.getElementById(theid));
|
||
MathJax.typesetPromise();
|
||
|
||
console.log("adjusting workspace");
|
||
window.setTimeout(adjustWorkspace, 1000);
|
||
}
|
||
|
||
// temporary: need to unify img and sbs layout
|
||
function modify_by_id(theid, modifier) {
|
||
editorLog("modifying by id", theid);
|
||
if (internalSource[theid]["sourcetag"] == "sbspanel") {
|
||
modify_by_id_sbs(theid, modifier)
|
||
} else if (environment_instances["project-like"].includes(internalSource[theid]["sourcetag"])
|
||
|| internalSource[theid]["sourcetag"] == "task") {
|
||
modify_by_id_workspace(theid, modifier)
|
||
} else {
|
||
modify_by_id_image(theid, modifier)
|
||
}
|
||
save_edits()
|
||
}
|
||
|
||
function modify_by_id_workspace(theid, modifier) {
|
||
|
||
var the_height = internalSource[theid]["workspace"];
|
||
editorLog("the_height", the_height, "from", internalSource[theid]);
|
||
|
||
//modify: enlarge, shrink, enlargeslightly, shrinkslightly, done
|
||
|
||
the_height = parseInt(the_height);
|
||
editorLog('the_height, ', the_height);
|
||
|
||
if (modifier == "enlarge") { the_height += 10 }
|
||
else if (modifier == "shrink") { the_height -= 10 }
|
||
else if (modifier == "enlargeslightly") { the_height += 1 }
|
||
else if (modifier == "shrinkslightly") { the_height -= 1 }
|
||
|
||
if (the_height < 0) { the_height = 0 }
|
||
|
||
internalSource[theid]["workspace"] = the_height;
|
||
editorLog("the_height is now", the_height);
|
||
|
||
var this_workspace = document.getElementById(theid).querySelector(".workspace");
|
||
this_workspace.setAttribute("style", "height:" + the_height*10 + "px");
|
||
this_workspace.setAttribute("data-space", the_height);
|
||
}
|
||
|
||
function modify_by_id_image(theid, modifier) {
|
||
|
||
var width = internalSource[theid]["width"];
|
||
var marginleft = internalSource[theid]["marginleft"];
|
||
var marginright = internalSource[theid]["marginright"];
|
||
editorLog('width, , marginright, , marginleft', width, "mr", marginright, "ml", marginleft);
|
||
width = parseInt(width);
|
||
marginright = parseInt(marginright);
|
||
marginleft = parseInt(marginleft);
|
||
|
||
var scale_direction = 1;
|
||
var moving_direction = 1;
|
||
if (modifier == "shrink") { scale_direction = -1 }
|
||
else if (modifier == "left") { moving_direction = -1 }
|
||
if ("enlarge shrink".includes(modifier)) {
|
||
if ((width >= 100 && scale_direction == 1) || (width <= 0 && scale_direction == -1)) {
|
||
editorLog("can't go above 100 or below 0");
|
||
return
|
||
} else {
|
||
width += 2*scale_direction*magnify_scale;
|
||
}
|
||
if (marginleft > 0 && marginright > 0) {
|
||
marginleft += -1*scale_direction*magnify_scale;
|
||
marginright += -1*scale_direction*magnify_scale;
|
||
} else if (marginleft > 0) {
|
||
marginleft += -2*scale_direction*magnify_scale;
|
||
} else if (marginright > 0) {
|
||
marginright += -2*scale_direction*magnify_scale;
|
||
} else if (scale_direction < 0) { // applies when we shrink a 100 width image
|
||
marginleft += -1*scale_direction*magnify_scale;
|
||
marginright += -1*scale_direction*magnify_scale;
|
||
} else {
|
||
// do nothing: this is a placeholder which is reached when both margins are 0
|
||
editorLog("already have no margins, width is", width);
|
||
}
|
||
} else if ("left right".includes(modifier)) {
|
||
editorLog("marginleft*moving_direction", marginleft*moving_direction, "marginright*moving_direction", marginright*moving_direction);
|
||
if ((marginleft > 0 && marginright > 0) || (marginright*moving_direction > 0) || (marginleft*moving_direction < 0)) {
|
||
marginleft += moving_direction*move_scale;
|
||
marginright += -1*moving_direction*move_scale;
|
||
} else {
|
||
// do nothing: this is a placeholder which is reached when both margins are 0
|
||
// we choose to prioritize scale, so a 100% image cannot be shifted
|
||
editorLog("already at 100%, width is", width);
|
||
}
|
||
}
|
||
|
||
var the_new_sizes = "width: " + width + "%;";
|
||
the_new_sizes += "margin-right: " + marginright + "%;";
|
||
the_new_sizes += "margin-left: " + marginleft + "%;";
|
||
|
||
internalSource[theid]["width"] = width;
|
||
internalSource[theid]["marginleft"] = marginleft;
|
||
internalSource[theid]["marginright"] = marginright;
|
||
|
||
document.getElementById(theid).setAttribute("style", the_new_sizes);
|
||
}
|
||
|
||
function modify_by_id_sbs(theid, modifier) {
|
||
|
||
var this_panel_source = internalSource[theid];
|
||
// var this_width = this_panel_source["width"];
|
||
var this_sbs_id = this_panel_source["parent"][0];
|
||
var this_sbs_source = internalSource[this_sbs_id];
|
||
editorLog("this_sbs_source", this_sbs_source);
|
||
var marginleft = parseInt(this_sbs_source["marginleft"]);
|
||
var marginright = parseInt(this_sbs_source["marginright"]);
|
||
var these_siblings = this_sbs_source["content"];
|
||
these_siblings = these_siblings.replace(/^\s*<&>\s*/, "");
|
||
these_siblings = these_siblings.replace(/\s*<;>\s*$/, "");
|
||
these_siblings = these_siblings.replace(/>\s*</g, "><");
|
||
editorLog("these_siblings", these_siblings);
|
||
var these_siblings_list = these_siblings.split("<;><&>");
|
||
var this_panel_index = these_siblings_list.indexOf(theid);
|
||
editorLog("this panel", theid, "is", this_panel_index, "within", these_siblings_list);
|
||
var these_panel_widths = this_sbs_source.widths;
|
||
var this_width = parseInt(these_panel_widths[this_panel_index]);
|
||
var total_width = 0;
|
||
editorLog("these html siblings",document.getElementById(these_siblings_list[0])," and ", document.getElementById(these_siblings_list[1]))
|
||
editorLog("these siblings source", internalSource[these_siblings_list[0]], "and", internalSource[these_siblings_list[1]]);
|
||
for(var j=0; j < these_siblings_list.length; ++j) {
|
||
// var t_wid = parseInt(internalSource[these_siblings_list[j]]["width"]);
|
||
var t_wid = parseInt(these_panel_widths[j]);
|
||
these_panel_widths[j] = t_wid; // put it back as an integer
|
||
editorLog("adding width", t_wid);
|
||
total_width += t_wid;
|
||
// these_panel_widths.push(t_wid);
|
||
}
|
||
// if (this_width != these_panel_widths[this_panel_index]) {
|
||
// errorLog("error: width", this_width, "not on list", these_panel_widths)
|
||
// } else {
|
||
// editorLog("width", this_width, "on list", these_panel_widths)
|
||
// }
|
||
|
||
editorLog("occ", marginleft, "u", total_width, "pi", marginright, "total", marginleft + total_width + marginright, "ratio", marginright/total_width)
|
||
var remaining_space = 100 - (marginleft + total_width + marginright);
|
||
editorLog("remaining_space", remaining_space);
|
||
|
||
//modify: enlarge, shrink, left, right, ??? done
|
||
|
||
// make the data structure better, then delete this comment
|
||
// currently style looks like "width: 66%; margin-right: 17%; margin-left: 17%"
|
||
editorLog('width', this_width, "mr", marginright, "ml", marginleft);
|
||
|
||
editorLog("modifier", modifier);
|
||
|
||
var scale_direction = 1;
|
||
var moving_direction = 1;
|
||
|
||
if (modifier == "enlargeall") {
|
||
editorLog("enlarging all", "remaining space", remaining_space);
|
||
if (remaining_space >= these_panel_widths.length) {
|
||
for (var j=0; j < these_panel_widths.length; ++j) {
|
||
these_panel_widths[j] += 1
|
||
}
|
||
// probablu the next case handles the first case
|
||
} else if (remaining_space + marginleft + marginright >= these_panel_widths.length) {
|
||
for (var j=0; j < these_panel_widths.length; ++j) {
|
||
these_panel_widths[j] += 1
|
||
}
|
||
var missing_length = these_panel_widths.length - remaining_space;
|
||
while (missing_length) {
|
||
missing_length -= 1;
|
||
if (missing_length % 2) {
|
||
if (marginleft) { marginleft -= 1 }
|
||
else { marginright -= 1 }
|
||
} else {
|
||
if (marginright) { marginright -= 1 }
|
||
else { marginleft -= 1 }
|
||
}
|
||
}
|
||
} else {
|
||
editorLog("Problem: not implemented yet")
|
||
}
|
||
} else if (modifier == "shrinkall") {
|
||
for (var j=0; j < these_panel_widths.length; ++j) {
|
||
if (these_panel_widths[j]) { these_panel_widths[j] -= 1 }
|
||
}
|
||
} else if (modifier == "enlarge") {
|
||
editorLog("enlarging one");
|
||
if (remaining_space) { these_panel_widths[this_panel_index] += 1 }
|
||
} else if (modifier == "shrink") {
|
||
editorLog("shrinking one");
|
||
if (these_panel_widths[this_panel_index]) { these_panel_widths[this_panel_index] -= 1 }
|
||
} else if (modifier == "leftplus") {
|
||
if (remaining_space) { marginleft += 1 }
|
||
} else if (modifier == "leftminus") {
|
||
if (marginleft) { marginleft -= 1 }
|
||
} else if (modifier == "rightplus") {
|
||
if (remaining_space) { marginright += 1 }
|
||
} else if (modifier == "rightminus") {
|
||
if (marginright) { marginright -= 1 }
|
||
}
|
||
editorLog("now these_panel_widths", these_panel_widths);
|
||
|
||
// missing cases??
|
||
|
||
internalSource[this_sbs_id]["marginleft"] = marginleft;
|
||
internalSource[this_sbs_id]["marginright"] = marginright;
|
||
internalSource[this_sbs_id]["widths"] = these_panel_widths;
|
||
|
||
// next is wrong, becuase the sbsrow does not have an id
|
||
/*
|
||
document.getElementById(this_sbs_id).style.marginLeft = marginleft + "%";
|
||
document.getElementById(this_sbs_id).style.marginRight = marginright + "%";
|
||
*/
|
||
document.getElementById(theid).parentElement.style.marginLeft = marginleft + "%";
|
||
document.getElementById(theid).parentElement.style.marginRight = marginright + "%";
|
||
|
||
for (var j=0; j < these_siblings_list.length; ++j) {
|
||
var this_id = these_siblings_list[j];
|
||
// internalSource[this_id]["width"] = these_panel_widths[j];
|
||
var width = rescale(these_panel_widths[j], 100, marginleft, marginright)
|
||
// document.getElementById(this_id).style.width = these_panel_widths[j] + "%";
|
||
document.getElementById(this_id).style.width = width + "%";
|
||
}
|
||
editorLog("NOW these html siblings",document.getElementById(these_siblings_list[0])," and ", document.getElementById(these_siblings_list[1]))
|
||
editorLog("NOW these siblings source", internalSource[these_siblings_list[0]], "and", internalSource[these_siblings_list[1]]);
|
||
editorLog("and internalSource[this_id]", internalSource[this_id]);
|
||
editorLog("and also internalSource[this_sbs_id]", internalSource[this_sbs_id]);
|
||
}
|
||
|
||
function move_by_id_local(theid, thehandleid) {
|
||
// when moving an object within a page, we create a phantomobject that is manipulated
|
||
// the actual movement is handled by move_object(e)
|
||
|
||
first_move = true;
|
||
|
||
document.getElementById("edit_menu_holder").remove()
|
||
document.getElementById(theid).classList.remove("may_select");
|
||
|
||
moved_content = internalSource[theid];
|
||
moved_content_tag = moved_content["sourcetag"];
|
||
ongoing_editing_actions.push(["moved", moved_content_tag, theid]);
|
||
moved_parent_and_location = moved_content["parent"];
|
||
editorLog("moving", theid);
|
||
editorLog("moved_parent_and_location", moved_parent_and_location);
|
||
// code duplicated elsewhere
|
||
var where_it_was = internalSource[moved_parent_and_location[0]][ moved_parent_and_location[1] ];
|
||
editorLog("where_it_was", where_it_was);
|
||
var object_in_parent = '<&>' + theid + '<;>';
|
||
var where_it_is = where_it_was.replace(object_in_parent, "");
|
||
editorLog("where_it_is ZZ" + where_it_is + "EE");
|
||
internalSource[moved_parent_and_location[0]][ moved_parent_and_location[1] ] = where_it_is;
|
||
|
||
// but first, remember the initial location of the object
|
||
|
||
moving_object = document.getElementById(theid);
|
||
editorLog("moving", moving_object, "within this page");
|
||
editorLog("moving_id", theid);
|
||
editorLog("current_editing[tree][0]", current_editing["tree"][0]);
|
||
if (moved_content_tag == "li") {
|
||
movement_location_neighbors = next_editable_of(current_editing["tree"][0][0], "li-only");
|
||
} else if (tag_type(moved_content_tag) == "p") {
|
||
movement_location_neighbors = next_editable_of(current_editing["tree"][0][0], "inner-block");
|
||
} else {
|
||
movement_location_neighbors = next_editable_of(current_editing["tree"][0][0], "outer-block");
|
||
}
|
||
editorLog("movement_location_neighbors", movement_location_neighbors);
|
||
var foundit = false;
|
||
var movement_location_tmp = 0;
|
||
for (var j=0; j < movement_location_neighbors.length; ++j) {
|
||
if (movement_location_neighbors[j] == moving_object) {
|
||
movement_location_tmp = j;
|
||
// delete the one which is being moved, because
|
||
// we are making a list of slots to place it, and its slot will still be there
|
||
// isn't there a better way to delete one item from a list?
|
||
movement_location_neighbors.splice(j, 1);
|
||
foundit = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!foundit) { errorLog("serious error: trying to move an object that is not movable", theid) }
|
||
|
||
editorLog("movement_location_tmp", movement_location_tmp);
|
||
// a paragraph by itself in an item or a statement can have a new paragraph before or after it
|
||
movement_location_options = [[movement_location_neighbors[0], "beforebegin"],
|
||
[movement_location_neighbors[0], "afterend"]];
|
||
movement_location = 0;
|
||
var movement_location_ct = 1;
|
||
for (var j=1; j < movement_location_neighbors.length; ++j) {
|
||
if (movement_location_tmp == j) { movement_location = movement_location_ct }
|
||
movement_location_ct += 1;
|
||
if (movement_location_neighbors[j-1].parentElement == movement_location_neighbors[j].parentElement) {
|
||
movement_location_options.push([movement_location_neighbors[j], "afterend"])
|
||
} else {
|
||
movement_location_ct += 1;
|
||
movement_location_options.push([movement_location_neighbors[j], "beforebegin"])
|
||
movement_location_options.push([movement_location_neighbors[j], "afterend"])
|
||
}
|
||
}
|
||
editorLog("movement_location_ct", movement_location_ct);
|
||
editorLog("movement_location", movement_location);
|
||
|
||
editorLog("made", movement_location_options.length, "movement_location_options", movement_location_options);
|
||
editorLog("from", movement_location_neighbors.length, "movement_location_neighbors", movement_location_neighbors);
|
||
|
||
var the_phantomobject = document.createElement('div');
|
||
the_phantomobject.setAttribute("id", "phantomobject");
|
||
the_phantomobject.setAttribute("data-moving_id", theid);
|
||
the_phantomobject.setAttribute("data-handle_id", thehandleid);
|
||
the_phantomobject.setAttribute("class", "phantomobject move");
|
||
the_phantomobject.setAttribute("tabindex", "-1");
|
||
var these_instructions = '<div class="movearrow"><span class="arrow">↑</span><p class="up">"shift-tab", or "up arrow", to move up</p></div>';
|
||
these_instructions += '<div class="movearrow"><p class="done">"return" or "escape" to set in place </p></div>';
|
||
these_instructions += '<div class="movearrow"><span class="arrow">↓</span><p class="down">"tab" or "down arrow" to move down</p></div>';
|
||
the_phantomobject.innerHTML = these_instructions;
|
||
// if we are moving a p which has parent li, and it is the only p there, then delete the parent li
|
||
// note: this will be wrong if there is other non-p siblings inside the li
|
||
var moving_object_replace = moving_object;
|
||
if (tag_type(moved_content_tag) == "p" && internalSource[moved_parent_and_location[0]]["sourcetag"] == "li") {
|
||
// check if that p is the only thing inside the li (so the li is empty when we move the p), and if so,
|
||
// remove that li from internalSource and also the HTML, and the reverence to it in internalSource
|
||
if (moving_object.parentElement.getElementsByTagName("p").length == 1) {
|
||
moving_object_replace = moving_object.parentElement
|
||
var now_empty_li_id = moved_parent_and_location[0];
|
||
editorLog("list item now empty:", now_empty_li_id);
|
||
var now_empty_li_parent_and_location = internalSource[now_empty_li_id]["parent"];
|
||
var where_it_was = internalSource[now_empty_li_parent_and_location[0]][ now_empty_li_parent_and_location[1] ];
|
||
var object_in_parent = '<&>' + now_empty_li_id + '<;>';
|
||
var where_it_is = where_it_was.replace(object_in_parent, "");
|
||
delete internalSource[now_empty_li_id];
|
||
editorLog("where_it_is II" + where_it_is + "OO");
|
||
internalSource[now_empty_li_parent_and_location[0]][ now_empty_li_parent_and_location[1] ] = where_it_is;
|
||
}
|
||
}
|
||
moving_object_replace.replaceWith(the_phantomobject)
|
||
document.getElementById("phantomobject").focus();
|
||
}
|
||
|
||
function move_object(e) {
|
||
// we have alread set movement_location_options and movement_location
|
||
editorLog("movement_location",movement_location);
|
||
if ((e.code == "Tab" && e.shiftKey) || e.code == "ArrowUp") { // Shift-Tab up the page
|
||
e.preventDefault();
|
||
if (movement_location == 0) {
|
||
alert("can't move past the top")
|
||
} else {
|
||
if (first_move) { first_move = false; }
|
||
movement_location -= 1
|
||
}
|
||
} else if ((e.code == "Tab" || e.code == "ArrowDown") && !e.shiftKey) {
|
||
e.preventDefault();
|
||
if (first_move) { first_move = false; editorLog("did first move") }
|
||
if (movement_location == movement_location_options.length - 1) {
|
||
alert("can't move past the bottom")
|
||
} else {
|
||
movement_location += 1
|
||
}
|
||
} else if (e.code == "Escape" || e.code == "Enter" || e.code == "ArrowRight") {
|
||
e.preventDefault();
|
||
editorLog(" decided where to put moving_object", moving_object);
|
||
var id_of_moving_object = document.getElementById('phantomobject').getAttribute("data-moving_id");
|
||
editorLog("moving object started as", internalSource[id_of_moving_object]);
|
||
var handle_of_moving_object = document.getElementById('phantomobject').getAttribute("data-handle_id");
|
||
document.getElementById('phantomobject').remove();
|
||
var new_anchor_and_position = movement_location_options[movement_location]
|
||
editorLog("new_location_anchor",new_anchor_and_position);
|
||
new_anchor_and_position[0].insertAdjacentElement(new_anchor_and_position[1], moving_object);
|
||
|
||
// the html appears to be updated, but we still need to update both the internal source:
|
||
var new_neighbor_id = new_anchor_and_position[0].id;
|
||
editorLog("new_neighbor_id", new_neighbor_id);
|
||
editorLog("which has source", internalSource[new_neighbor_id]);
|
||
var new_neighbor_rel_pos = new_anchor_and_position[1];
|
||
var [new_neighbor_parent, new_neighbor_location] = internalSource[new_neighbor_id]["parent"];
|
||
var new_neighbor_in_context = internalSource[new_neighbor_parent][new_neighbor_location];
|
||
editorLog("new_neighbor_in_context was", new_neighbor_in_context);
|
||
var neighbor_tag = '<&>' + new_neighbor_id + '<;>';
|
||
var neighbor_tag_re = new RegExp(neighbor_tag);
|
||
|
||
var moving_object_tag = '<&>' + id_of_moving_object + '<;>';
|
||
if (new_neighbor_rel_pos == "beforebegin") {
|
||
// new_neighbor_in_context.replace(neighbor_tag, moving_object_tag + "\n" + neighbor_tag)
|
||
// RegExp
|
||
new_neighbor_in_context = new_neighbor_in_context.replace(neighbor_tag_re, moving_object_tag + "\n" + neighbor_tag)
|
||
} else {
|
||
new_neighbor_in_context = new_neighbor_in_context.replace(neighbor_tag_re, neighbor_tag + "\n" + moving_object_tag)
|
||
}
|
||
editorLog("new_neighbor_in_context is", new_neighbor_in_context);
|
||
internalSource[new_neighbor_parent][new_neighbor_location] = new_neighbor_in_context;
|
||
internalSource[id_of_moving_object]["parent"] = [new_neighbor_parent, new_neighbor_location];
|
||
editorLog("moving object ended as", internalSource[id_of_moving_object]);
|
||
|
||
save_edits();
|
||
|
||
// and the navigation information
|
||
make_current_editing_tree_from_id(handle_of_moving_object);
|
||
|
||
var most_recent_edit = ongoing_editing_actions.pop();
|
||
recent_editing_actions.unshift(most_recent_edit);
|
||
|
||
edit_menu_from_current_editing("entering");
|
||
return
|
||
|
||
} else {
|
||
editorLog("don't know how to move with", e.code)
|
||
}
|
||
|
||
editorLog("now movement_location", movement_location);
|
||
var the_phantomobject = document.getElementById('phantomobject');
|
||
movement_location_options[movement_location][0].insertAdjacentElement(movement_location_options[movement_location][1], the_phantomobject);
|
||
document.getElementById("phantomobject").focus();
|
||
}
|
||
|
||
function delete_by_id(theid, thereason) {
|
||
// reasons to delete something: author wants it deleted, it is empty, ...
|
||
// first delete the specific object
|
||
final_added_object = "";
|
||
editorLog("deleting by theid", theid, "with content", internalSource[theid]);
|
||
var deleted_content = internalSource[theid];
|
||
var parent_and_location = deleted_content["parent"];
|
||
delete internalSource[theid];
|
||
editorLog("deleted", theid, "so", theid in internalSource, "now", internalSource);
|
||
// and save what was deleted
|
||
if (theid in old_content) {
|
||
old_content[theid].push(deleted_content)
|
||
} else {
|
||
old_content[theid] = [deleted_content]
|
||
}
|
||
if (thereason != "newempty") { // not sure newempty can still happen
|
||
ongoing_editing_actions.push(["deleted ", deleted_content["sourcetag"], theid]);
|
||
}
|
||
// update the parent of the object
|
||
var current_level = current_editing["level"];
|
||
var where_it_was = internalSource[parent_and_location[0]][ parent_and_location[1] ];
|
||
var object_in_parent = '<&>' + theid + '<;>';
|
||
var where_it_is = where_it_was.replace(object_in_parent, "");
|
||
editorLog("where_it_is ZZ" + where_it_is + "EE");
|
||
internalSource[parent_and_location[0]][ parent_and_location[1] ] = where_it_is;
|
||
// if the parent is empty, delete it
|
||
if (!(where_it_is.trim()) && (parent_and_location[1] == "content" || parent_and_location[1] == "statement")) {
|
||
editorLog(" deleted from within", internalSource[parent_and_location[0]]);
|
||
document.getElementById(theid).removeAttribute("data-editable"); // so it is invisible to next-editable-of as we delete its parent
|
||
if (internalSource[parent_and_location[0]][ "sourcetag" ] == "li") {
|
||
editorLog("not going up a level, because it is a list element")
|
||
} else {
|
||
current_editing["level"] -= 1;
|
||
}
|
||
delete_by_id(parent_and_location[0], thereason)
|
||
} else { // else, because the parent is going to be deleted, so no need to delete the child
|
||
// delete from the html
|
||
var current_index = current_editing["location"][current_level] + 1; // +1 because the deleted item is still in the current_editing tree
|
||
if (thereason == "empty" || thereason == "newempty") {
|
||
editorLog("removing from DOM", document.getElementById(theid));
|
||
document.getElementById(theid).remove();
|
||
current_index -= 1;
|
||
editorLog("current_index", current_index, "current_level", current_level);
|
||
editorLog(current_editing["tree"][ current_level ]);
|
||
// hack because adding a list (inside a defn?) is not updating the tree properly
|
||
if (current_index > current_editing["tree"][ current_level ].length - 1) {
|
||
current_index = current_editing["tree"][ current_level ].length - 1
|
||
}
|
||
if (current_editing["tree"][ current_level ][ current_index ].id == theid) {
|
||
current_editing["tree"][ current_level ].splice(current_index, 1)
|
||
}
|
||
editorLog("empty or newempty", thereason)
|
||
} else {
|
||
editorLog("deleting for another reason", thereason)
|
||
document.getElementById("edit_menu_holder").remove()
|
||
document.getElementById(theid).setAttribute("id", "deleting");
|
||
document.getElementById("deleting").removeAttribute("data-editable"); // so it is invisible to next-editable-of
|
||
setTimeout(() => { document.getElementById("deleting").remove(); }, 600);
|
||
}
|
||
|
||
if (current_index >= current_editing["tree"][ current_level ].length) {
|
||
current_index = current_editing["tree"][ current_level ].length - 2;
|
||
}
|
||
editorLog("current_index", current_index, "in", current_editing["tree"][ current_level ]);
|
||
editorLog("object of interest", current_editing["tree"][ current_level ][ current_index ]);
|
||
editorLog("current_level", current_level, "on", current_editing["tree"]);
|
||
make_current_editing_tree_from_id(current_editing["tree"][ current_level ][ current_index].id);
|
||
edit_menu_from_current_editing("entering");
|
||
}
|
||
save_edits()
|
||
}
|
||
|
||
|
||
var internalSource = { // currently the key is the HTML id
|
||
"root_data": {"id": "page-1", "number_base": "0.1" }
|
||
}
|
||
|
||
/* top_level_id is a mistake: just use internalSource.root_data.id */
|
||
var top_level_id = internalSource["root_data"]["id"];
|
||
|
||
var current_editing = {
|
||
"level": 0,
|
||
"location": [0],
|
||
"tree": [ [document.getElementById(top_level_id)] ]
|
||
}
|
||
|
||
|
||
function create_local_menu() {
|
||
|
||
// this does not work, but local menu navigator would not have worked either
|
||
|
||
editorLog("make local edit menu for", this_obj_id);
|
||
var local_menu_holder = document.createElement('div');
|
||
local_menu_holder.setAttribute('id', 'local_menu_holder');
|
||
local_menu_holder.setAttribute('tabindex', '-1');
|
||
editorLog("adding local menu for", this_obj_id);
|
||
document.getElementById(this_obj_id).insertAdjacentElement("afterbegin", local_menu_holder);
|
||
|
||
var enter_option = document.createElement('ol');
|
||
enter_option.setAttribute('id', 'edit_menu');
|
||
enter_option.setAttribute('class', 'edit_menu');
|
||
|
||
enter_option.innerHTML = menu_options_for(this_obj_id, "XunusedX", "base");
|
||
|
||
document.getElementById("local_menu_holder").insertAdjacentElement("afterbegin", enter_option);
|
||
|
||
}
|
||
|
||
function extract_internal_contents(some_text) {
|
||
|
||
// some_text must be a paragraph with mixed content only contining
|
||
// non-nested tags
|
||
the_text = some_text;
|
||
editorLog(" xxxxxxxxxx the_text is", the_text);
|
||
editorLog("extract_internal_contents");
|
||
|
||
// delete class information
|
||
the_text = the_text.replace(/ class="[^"]"/g, "");
|
||
|
||
// inline from previous editing
|
||
editorLog("extracting where 'data-editable...'");
|
||
the_text = the_text.replace(/<([^<]+) data-editable="[^"]+" tabindex="-1">(.*?)<[^<]+>/g, save_internal_cont);
|
||
editorLog("extracting where 'contenteditable...'");
|
||
the_text = the_text.replace(/<([^<]+) contenteditable="false">(.*?)<[^<]+>/g, save_internal_cont);
|
||
// new $math$
|
||
editorLog("extracting new $math$");
|
||
the_text = the_text.replace(/(^|\s)\$([^\$]+)\$(\s|$|[.,!?;:])/mg, extract_new_math);
|
||
// new \\(math\\)
|
||
editorLog("extracting new \\(math\\)");
|
||
the_text = the_text.replace(/(^|.)\\\(([^\$]+)\\\)(.|$)/g, extract_new_math);
|
||
// new <m>math</m>
|
||
editorLog("extracting new <m>math</m>");
|
||
the_text = the_text.replace(/(^|.)<m>(.*?)<\/m>(.|$)/g, extract_new_math);
|
||
|
||
// "..." to <ellipsis/>, which will then be processed
|
||
the_text = the_text.replace(/\.\.\./g, '<ellipsis\/>');
|
||
// same for etc
|
||
the_text = the_text.replace(/(\s)etc\.?([^a-zA-Z])/g, '$1<etc\/>$2');
|
||
|
||
for (var j=0; j < inline_abbrev.length; ++j) {
|
||
var this_tag = inline_abbrev[j];
|
||
editorLog("this_tag", this_tag);
|
||
var this_tag_search = "<(" + this_tag + ")\\/>";
|
||
editorLog("searching for", this_tag_search);
|
||
var this_tag_search_re = new RegExp(this_tag_search,"g");
|
||
the_text = the_text.replace(this_tag_search_re, extract_new_inline)
|
||
}
|
||
|
||
// "quote" to <q>quote</q>, which will then be processed
|
||
the_text = the_text.replace(/(^|\s)"([^"]+)"(\s|$|[.,!?;:])/g, '$1<q>$2<\/q>$3');
|
||
the_text = the_text.replace(/(^|\s)“([^”]+)”(\s|$|[.,!?;:])/g, '$1<q>$2<\/q>$3');
|
||
the_text = the_text.replace(/(^|\s)‘([^’]+)’(\s|$|[.,!?;:])/g, '$1<q>$2<\/q>$3');
|
||
|
||
for (var j=0; j < inline_tags.length; ++j) {
|
||
var this_tag = inline_tags[j];
|
||
editorLog("this_tag", this_tag);
|
||
var this_tag_search = "<(" + this_tag + ") *>" + "(.*?)" + "<\\/" + this_tag + ">";
|
||
editorLog("searching for", this_tag_search);
|
||
var this_tag_search_re = new RegExp(this_tag_search,"g");
|
||
the_text = the_text.replace(this_tag_search_re, extract_new_inline)
|
||
}
|
||
|
||
return the_text
|
||
}
|
||
|
||
function extract_new_math(match, sp_before, math_content, sp_after) {
|
||
var new_math_id = randomstring();
|
||
internalSource[new_math_id] = { "xml:id": new_math_id, "sourcetag": "m",
|
||
"content": math_content}
|
||
return sp_before + "<&>" + new_math_id + "<;>" + sp_after
|
||
}
|
||
function extract_new_inline(match, the_tag, the_content) {
|
||
var new_id = randomstring();
|
||
editorLog("extracting", the_content, "inside", the_tag);
|
||
internalSource[new_id] = { "xml:id": new_id, "sourcetag": the_tag,
|
||
"content": the_content};
|
||
return "<&>" + new_id + "<;>"
|
||
}
|
||
function extract_new_abbrev(match, the_tag) {
|
||
var new_id = randomstring();
|
||
editorLog("extracting", the_content, "inside", the_tag);
|
||
internalSource[new_id] = { "xml:id": new_id, "sourcetag": the_tag};
|
||
return "<&>" + new_id + "<;>"
|
||
}
|
||
|
||
// rename this next function
|
||
function save_internal_cont(match, contains_id, the_contents) {
|
||
this_id = contains_id.replace(/.*id="(.+?)".*/, '$1');
|
||
|
||
editorLog("id", this_id, "now has contents", the_contents);
|
||
if ("content" in internalSource[this_id]) { // not all objects have content
|
||
internalSource[this_id]["content"] = the_contents;
|
||
} else if (internalSource[this_id]["sourcetag"] == "xref") {
|
||
// this needs work once we have text="custom" references
|
||
internalSource[this_id]["ref"] = the_contents;
|
||
}
|
||
editorLog("all of it is now", internalSource[this_id]);
|
||
return "<&>" + this_id + "<;>"
|
||
}
|
||
function assemble_internal_version_changes(object_being_edited) {
|
||
editorLog("in assemble_internal_version_changes");
|
||
editorLog("current active element to be saved", object_being_edited);
|
||
editorLog("which has parent", object_being_edited.parentElement);
|
||
editorLog("whose age is", object_being_edited.parentElement.getAttribute("data-age"));
|
||
|
||
var oldornew = object_being_edited.parentElement.getAttribute("data-age");
|
||
if (!oldornew) { oldornew = object_being_edited.getAttribute("data-age") }
|
||
editorLog(" OLDorNEW", oldornew);
|
||
|
||
var possibly_changed_ids_and_entry = [];
|
||
var nature_of_the_change = "";
|
||
|
||
// var object_being_edited = document.activeElement;
|
||
var location_of_change = object_being_edited.parentElement;
|
||
var this_arrangement_of_objects = "";
|
||
|
||
if (object_being_edited.classList.contains("paragraph_input")) {
|
||
editorLog("found paragraph_input");
|
||
nature_of_the_change = "replace";
|
||
var paragraph_content = object_being_edited.innerHTML;
|
||
// editorLog("paragraph_content from innerHTML", paragraph_content);
|
||
paragraph_content = paragraph_content.trim();
|
||
|
||
var cursor_location = object_being_edited.selectionStart;
|
||
|
||
editorLog("cursor_location", cursor_location, "out of", paragraph_content.length, "paragraph_content", paragraph_content);
|
||
|
||
var parent_and_location = [object_being_edited.getAttribute("data-parent_id"), object_being_edited.getAttribute("data-parent_component")];
|
||
editorLog("parent_and_location", parent_and_location);
|
||
editorLog("of ", object_being_edited);
|
||
|
||
var prev_id = object_being_edited.getAttribute("data-source_id");
|
||
editorLog("prev_id", prev_id);
|
||
editorLog("which contains", internalSource[prev_id]);
|
||
|
||
// need to replace the below by split_paragraphs
|
||
|
||
// does the textbox contain more than one paragraph?
|
||
var paragraph_content_list = paragraph_content.split("<div><br></div>");
|
||
editorLog("there were", paragraph_content_list.length, "paragraphs, but some may be empty");
|
||
for (var j=0; j < paragraph_content_list.length; ++j) {
|
||
editorLog("paragraph", j, "begins", paragraph_content_list[j].substring(0,20))
|
||
}
|
||
|
||
var paragraph_content_list_trimmed = [];
|
||
|
||
for (var j=0; j < paragraph_content_list.length; ++j) {
|
||
// probably each paragraph is wrapped in meaningless div tags
|
||
var this_paragraph_contents_raw = paragraph_content_list[j];
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<\/div><div>/g, "\n");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<div>/g, "");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<\/div>/g, "");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/ /g, " ");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/ +<br>/g, "\n");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.replace(/<br>/g, "\n");
|
||
this_paragraph_contents_raw = this_paragraph_contents_raw.trim();
|
||
if (!this_paragraph_contents_raw) { editorLog("empty paragraph") }
|
||
else { paragraph_content_list_trimmed.push(this_paragraph_contents_raw) }
|
||
// editorLog("this_paragraph_contents_raw", this_paragraph_contents_raw);
|
||
editorLog("done transforming paragraph", j, "with object_being_edited",object_being_edited);
|
||
editorLog("which has contents", this_paragraph_contents_raw)
|
||
}
|
||
|
||
if (!paragraph_content_list_trimmed.length ) {
|
||
// empty, so insert it and delete it later
|
||
paragraph_content_list_trimmed = [""];
|
||
}
|
||
|
||
for (var j=0; j < paragraph_content_list_trimmed.length; ++j) {
|
||
editorLog("_trimmed paragraph", j, "begins", paragraph_content_list_trimmed[j].substring(0,20))
|
||
}
|
||
for (var j=0; j < paragraph_content_list_trimmed.length; ++j) {
|
||
var this_paragraph_contents = paragraph_content_list_trimmed[j];
|
||
editorLog("this_paragraph_contents", this_paragraph_contents.substring(0,20));
|
||
if (j == 0 && prev_id) {
|
||
if (prev_id in internalSource) {
|
||
// the content is referenced, so we update the referenced content
|
||
// need to check internal content, such as em or math
|
||
this_paragraph_contents = extract_internal_contents(this_paragraph_contents);
|
||
if (internalSource[prev_id]["content"] != this_paragraph_contents) {
|
||
if (internalSource[prev_id]["content"]) {
|
||
ongoing_editing_actions.push(["changed", "p", prev_id]);
|
||
} else if (this_paragraph_contents) {
|
||
ongoing_editing_actions.push(["new", "p", prev_id]);
|
||
}
|
||
internalSource[prev_id]["content"] = this_paragraph_contents;
|
||
editorLog("changed content of", prev_id)
|
||
} else if (!this_paragraph_contents) { // adding an empty paragraph
|
||
ongoing_editing_actions.push(["empty", "p", prev_id]);
|
||
} else {
|
||
// this means the contents are nonempty and unchanged, so don't record is as a change
|
||
}
|
||
possibly_changed_ids_and_entry.push([prev_id, "content", oldornew]);
|
||
this_arrangement_of_objects = internalSource[parent_and_location[0]][parent_and_location[1]];
|
||
} else {
|
||
errorLog("error: existing tag from input", prev_id, "not in internalSource")
|
||
}
|
||
} else { // a newly created paragraph
|
||
var this_object_internal = {"sourcetag": "p", "title": ""}; //p don't have title
|
||
this_object_label = randomstring();
|
||
this_object_internal["xml:id"] = this_object_label;
|
||
this_object_internal["parent"] = parent_and_location;
|
||
|
||
// put the new p after the previous p in the string describing the neighboring contents
|
||
var object_before = new RegExp('(<&>' + prev_id + '<;>)');
|
||
this_arrangement_of_objects = this_arrangement_of_objects.replace(object_before, '$1' + '\n<&>' + this_object_label + '<;>');
|
||
prev_id = this_object_label;
|
||
|
||
this_paragraph_contents = extract_internal_contents(this_paragraph_contents);
|
||
this_object_internal["content"] = this_paragraph_contents;
|
||
internalSource[this_object_label] = this_object_internal
|
||
editorLog("just inserted at label", this_object_label, "content starting", this_paragraph_contents.substring(0,11), "which is now", internalSource[this_object_label]);
|
||
ongoing_editing_actions.push(["added", "p", this_object_label]);
|
||
// here is where we can record that somethign is empty, hence should be deleted
|
||
possibly_changed_ids_and_entry.push([this_object_label, "content", "new"]);
|
||
}
|
||
}
|
||
editorLog("parent_and_location", parent_and_location);
|
||
editorLog("this_arrangement_of_objects was", internalSource[parent_and_location[0]][parent_and_location[1]]);
|
||
internalSource[parent_and_location[0]][parent_and_location[1]] = this_arrangement_of_objects;
|
||
editorLog("this_arrangement_of_objects is", this_arrangement_of_objects);
|
||
} else if (object_being_edited.classList.contains("displaymath_input")) {
|
||
editorLog("found displaymath_input");
|
||
nature_of_the_change = "replace";
|
||
var paragraph_content = object_being_edited.innerHTML;
|
||
// editorLog("paragraph_content from innerHTML", paragraph_content);
|
||
paragraph_content = paragraph_content.trim();
|
||
|
||
var cursor_location = object_being_edited.selectionStart;
|
||
|
||
editorLog("cursor_location", cursor_location, "out of", paragraph_content.length, "paragraph_content", paragraph_content);
|
||
|
||
var parent_and_location = [object_being_edited.getAttribute("data-parent_id"), object_being_edited.getAttribute("data-parent_component")];
|
||
|
||
editorLog("parent_and_location", parent_and_location);
|
||
editorLog("of ", object_being_edited);
|
||
|
||
var prev_id = object_being_edited.getAttribute("data-source_id");
|
||
editorLog("prev_id", prev_id);
|
||
editorLog("which contains", internalSource[prev_id]);
|
||
|
||
// textbox may contain more than one paragraph
|
||
var paragraph_content_list = split_paragraphs(paragraph_content);
|
||
var this_paragraph_contents = paragraph_content_list.join("\n\\cr\n");
|
||
this_paragraph_contents = extract_internal_contents(this_paragraph_contents);
|
||
|
||
if (!internalSource[prev_id]["content"]) {
|
||
ongoing_editing_actions.push(["new", "md", prev_id]);
|
||
} else {
|
||
ongoing_editing_actions.push(["changed", "md", prev_id]);
|
||
}
|
||
|
||
internalSource[prev_id]["content"] = this_paragraph_contents
|
||
possibly_changed_ids_and_entry.push([prev_id, "content", oldornew]);
|
||
|
||
} else if (object_being_edited.getAttribute('data-component') == "title" ||
|
||
object_being_edited.getAttribute('data-component') == "caption") {
|
||
|
||
var this_content_type = object_being_edited.getAttribute('data-component');
|
||
nature_of_the_change = "replace";
|
||
var line_being_edited = object_being_edited;
|
||
var line_content = line_being_edited.innerHTML;
|
||
line_content = line_content.trim();
|
||
editorLog("the content (is it a title or caption?) is", line_content);
|
||
var owner_of_change = object_being_edited.getAttribute("data-source_id");
|
||
var component_being_changed = object_being_edited.getAttribute("data-component");
|
||
editorLog("component_being_changed", component_being_changed, "within", owner_of_change);
|
||
if (internalSource[owner_of_change][component_being_changed]) {
|
||
ongoing_editing_actions.push(["changed", this_content_type, owner_of_change]);
|
||
} else {
|
||
ongoing_editing_actions.push(["added", this_content_type, owner_of_change]);
|
||
}
|
||
// update the title of the object
|
||
internalSource[owner_of_change][component_being_changed] = line_content;
|
||
possibly_changed_ids_and_entry.push([owner_of_change, this_content_type]);
|
||
|
||
} else if (object_being_edited.classList.contains("image_source")) {
|
||
// currently this only handles images by URL.
|
||
// later do the case of uploading an image.
|
||
var image_src = object_being_edited.innerHTML;
|
||
|
||
// what is the right way to do this?
|
||
image_src = image_src.replace(/<div>/g, "");
|
||
image_src = image_src.replace(/<\/div>/g, "");
|
||
image_src = image_src.trim();
|
||
editorLog("changing image src to", image_src);
|
||
|
||
var image_being_changed = object_being_edited.getAttribute("data-source_id");
|
||
editorLog("image_being_changed ", image_being_changed);
|
||
|
||
if (internalSource[image_being_changed]["source"]) {
|
||
ongoing_editing_actions.push(["changed", "source", image_being_changed]);
|
||
} else {
|
||
ongoing_editing_actions.push(["added", "source", image_being_changed]);
|
||
}
|
||
internalSource[image_being_changed]["source"] = image_src;
|
||
editorLog("image being changed is", internalSource[image_being_changed]);
|
||
// possibly_changed_ids_and_entry.push([owner_of_change, "image"]);
|
||
possibly_changed_ids_and_entry.push([image_being_changed, "image"]);
|
||
|
||
|
||
} else if (inline_tags.includes(object_being_edited.tagName.toLowerCase())) {
|
||
editorLog(object_being_edited, "is inline, so processing parent");
|
||
return assemble_internal_version_changes(object_being_edited.parentElement)
|
||
} else if (object_being_edited.classList.contains("edit_math_row")) {
|
||
nature_of_the_change = "replace";
|
||
var line_being_edited = object_being_edited;
|
||
var line_content = line_being_edited.innerHTML;
|
||
line_content = line_content.trim();
|
||
editorLog("the content (is it a title?) is", line_content);
|
||
var owner_of_change = object_being_edited.getAttribute("id");
|
||
// var component_being_changed = object_being_edited.getAttribute("data-component");
|
||
var component_being_changed = "content";
|
||
editorLog("component_being_changed", component_being_changed, "within", owner_of_change);
|
||
// update the title of the object
|
||
if (internalSource[owner_of_change][component_being_changed]) {
|
||
ongoing_editing_actions.push(["changed", "mrow", owner_of_change]);
|
||
} else {
|
||
ongoing_editing_actions.push(["added", "mrow", owner_of_change]);
|
||
}
|
||
internalSource[owner_of_change][component_being_changed] = line_content;
|
||
possibly_changed_ids_and_entry.push([owner_of_change, "mrow"]);
|
||
|
||
} else {
|
||
errorLog("trouble editing", object_being_edited, "AAA", object_being_edited.tagName.toLowerCase(), "not in", inline_tags);
|
||
alert("don;t know how to assemble internal_version_changes of " + object_being_edited.tagName)
|
||
}
|
||
editorLog("finished assembling internal version, which is now:",internalSource);
|
||
editorLog(" NUMBER of things chagnged:", possibly_changed_ids_and_entry.length);
|
||
return [nature_of_the_change, location_of_change, possibly_changed_ids_and_entry]
|
||
}
|
||
|
||
function wrap_tag(tag, content, attribute_values) {
|
||
// tag is either an XML tag name, or [opening_tag, closing_tag]
|
||
|
||
// layout: inline or block or title
|
||
// is this the right place to handle empty content?
|
||
// editorLog("calling wrap_tag", "tag", tag, "content", content, "attribute_values", attribute_values);
|
||
if (!content && !tag) { return "" }
|
||
if (!content && !always_empty_tags.includes(tag) && !allowed_empty_tags.includes(tag)) { return "" }
|
||
if (!tag) { return content }
|
||
|
||
var opening_tag = closing_tag = "";
|
||
|
||
if (typeof tag == "string") {
|
||
if (tag) {
|
||
opening_tag = "<" + tag;
|
||
for (var j=0; j < attribute_values.length; ++j) {
|
||
opening_tag += ' ' + attribute_values[j]
|
||
}
|
||
closing_tag = "</" + tag + ">";
|
||
}
|
||
if (!content && (always_empty_tags.includes(tag) || allowed_empty_tags.includes(tag))) {
|
||
opening_tag += "/>";
|
||
closing_tag = "";
|
||
} else {
|
||
opening_tag += ">";
|
||
}
|
||
|
||
if (tag_display["inline"].includes(tag)) {
|
||
// do nothing
|
||
} else if (tag_display["title"].includes(tag)) {
|
||
opening_tag = "\n" + opening_tag;
|
||
closing_tag = closing_tag + "\n"
|
||
} else if (tag_display["block-tight"].includes(tag)) {
|
||
// do nothing
|
||
} else { //the default
|
||
opening_tag = "\n" + opening_tag + "\n";
|
||
if (closing_tag) {
|
||
closing_tag = "\n" + closing_tag + "\n"
|
||
}
|
||
}
|
||
} else if (tag) {
|
||
[opening_tag, closing_tag] = tag
|
||
for (var j=0; j < attribute_values.length; ++j) {
|
||
opening_tag += ' ' + attribute_values[j]
|
||
}
|
||
} else {
|
||
opening_tag = "";
|
||
closing_tag = "";
|
||
}
|
||
if (!opening_tag) { opening_tag = "" }
|
||
if (!closing_tag) { closing_tag = "" }
|
||
|
||
if (content.includes("N.m")) { editorLog("3 ----- content",content); editorLog("opening_tag", opening_tag) }
|
||
|
||
if (opening_tag.startsWith("<p") && !content) {
|
||
alert("empty p")
|
||
}
|
||
|
||
return opening_tag + content.trim() + closing_tag
|
||
}
|
||
|
||
function output_from_source(the_object, output_structure, format) {
|
||
|
||
if (!the_object) { return ""}
|
||
if (!output_structure) { return "MISSING STRUCTURE"}
|
||
|
||
editorLog("calling output from_source", "the_object", the_object, "output_structure", output_structure, "format", format);
|
||
// format: html, pretext (or source?)
|
||
var the_answer = "";
|
||
var output_tag = output_structure.tag;
|
||
if (!output_tag) {
|
||
output_tag = [output_structure.tag_opening, output_structure.tag_closing]
|
||
}
|
||
|
||
var output_attributes = [];
|
||
if ("attributes" in output_structure && output_structure.attributes) {
|
||
output_attributes = output_structure.attributes;
|
||
} else {
|
||
output_attributes = []
|
||
}
|
||
var output_attributes_values = [];
|
||
for (var j=0; j < output_attributes.length; ++j) {
|
||
var attr_name = output_attributes[j];
|
||
// var attr_val = the_object[attr_name];
|
||
var attr_val = attr_name;
|
||
editorLog("attr_val", attr_val);
|
||
attr_val = attr_val.replace(/<&>(.*?)<;>/g, function (match, newid) {
|
||
if (newid.startsWith("{")) {
|
||
newid = newid.slice(1,-1);
|
||
if (newid in output_structure) {
|
||
return output_structure[newid]
|
||
} else { // don't want to return 'undefined'
|
||
return ""
|
||
}
|
||
} else if (newid.startsWith("(")) {
|
||
var this_piece = newid.slice(1,-1);
|
||
var this_fcn;
|
||
[this_fcn, this_piece] = this_piece.split(",");
|
||
return process_value_from_source(this_fcn, this_piece, the_object)
|
||
} else {
|
||
if (newid in the_object) {
|
||
return the_object[newid]
|
||
} else {
|
||
return ""
|
||
}
|
||
}
|
||
});
|
||
editorLog(" attr_val", attr_val);
|
||
if (attr_val && !attr_val.includes('""')) {
|
||
output_attributes_values.push(attr_val)
|
||
}
|
||
}
|
||
|
||
editorLog("output_structure", output_tag, "is", output_structure);
|
||
editorLog("output_attributes_values", output_attributes_values);
|
||
editorLog("output_structure.pieces", output_structure.pieces);
|
||
for (var j=0; j < output_structure.pieces.length; ++j) {
|
||
var this_piece_output = "";
|
||
var [this_piece, this_tag] = output_structure.pieces[j];
|
||
editorLog("output_structure", output_structure);
|
||
// when this_piece is provisional, then this_tag is actually the key for the required content
|
||
editorLog(j, "this_piece", this_piece, "this_tag", this_tag, "output_tag", output_tag);
|
||
if (this_piece.startsWith("{")) {
|
||
this_piece = this_piece.slice(1,-1);
|
||
this_piece_output += output_from_source(the_object, objectStructure[this_piece][format], format);
|
||
editorLog("wrapping in bracketed tag", this_tag);
|
||
the_answer += wrap_tag(this_tag, this_piece_output, [])
|
||
} else if (this_piece.startsWith("%")) {
|
||
// need to distinguish between the case where this object exists,
|
||
// and when it does not exist and we want a placeholder
|
||
this_piece = this_piece.slice(1,-1);
|
||
editorLog("% % % % % % % % % ", this_piece, "this_tag", this_tag, "the_object", the_object);
|
||
editorLog("% % % % % % % % % ", the_object[this_piece]);
|
||
editorLog("% % % % % % % % % ", the_object[this_tag]);
|
||
if (the_object[this_tag]) {
|
||
// var sub_object = {};
|
||
|
||
// Object.assign(sub_object, the_object);
|
||
|
||
// sub_object['type-contained'] = this_tag;
|
||
// editorLog("sub_object", sub_object);
|
||
// this_piece_output = output_from_source(sub_object, objectStructure[this_piece][format], format);
|
||
this_piece_output = expand_condensed_source_html(the_object[this_tag],"html?");
|
||
// this_piece_output = output_from_source(sub_object, objectStructure[this_piece][format], format);
|
||
the_answer += this_piece_output;
|
||
editorLog("this piece exists", this_piece, "this_piece_output", this_piece_output)
|
||
} else {
|
||
editorLog("making placeholder for", this_piece);
|
||
the_answer += wrap_tag("div", "", ['class="placeholder ' + this_piece + '"', 'data-parent_id="' + the_object['xml:id'] + '"', 'data-has="' + this_piece + '"', 'tabindex="-1"', 'data-editable="123456"', 'data-placeholder=""'])
|
||
}
|
||
} else if (this_piece.startsWith("(")) {
|
||
editorLog("whole this_piece", this_piece);
|
||
this_piece = this_piece.slice(1,-1);
|
||
var this_fcn;
|
||
[this_fcn, this_piece] = this_piece.split(",");
|
||
var this_content = process_value_from_source(this_fcn, this_piece, the_object)
|
||
editorLog(j, "parenthesized content", this_content, "this_piece", this_piece, "XX", this_tag)
|
||
the_answer += wrap_tag(this_tag, this_content, [])
|
||
} else if (this_piece in the_object) {
|
||
this_piece_output = output_from_text(the_object[this_piece], format);
|
||
if (format == "pretext" && output_tag == "md" && this_piece == "content") {
|
||
// convert \cr to mrow
|
||
this_piece_output = this_piece_output.replace(/\s*\\cr\b\s*/g, "</mrow>\n<mrow>\n");
|
||
this_piece_output = "<mrow>\n" + this_piece_output + "\n</mrow>";
|
||
}
|
||
the_answer += wrap_tag(this_tag, this_piece_output, [])
|
||
} else {
|
||
editorLog("missing piece:", this_tag, "with no", this_piece)
|
||
}
|
||
}
|
||
|
||
// pretty print the output
|
||
if (format == "pretext" && !(inline_tags.includes(output_tag)) && !(inline_math.includes(output_tag))) {
|
||
the_answer = the_answer.replace(/(^|\n)( *(\w|<))/g, "$1 $2");
|
||
}
|
||
the_answer = wrap_tag(output_tag, the_answer, output_attributes_values)
|
||
// editorLog("now the answer is", the_answer);
|
||
|
||
return the_answer
|
||
}
|
||
|
||
function output_from_text(text, format) {
|
||
editorLog("output_from_text of ", text, "with format", format);
|
||
if (text.includes("<&>")) {
|
||
// return text.replace(/\s*<&>(.*?)<;>\s*/g, function (match, newid) { return output_from_id(match, newid, format)})
|
||
return text.replace(/<&>(.*?)<;>/g, function (match, newid) { return output_from_id(match, newid, format)})
|
||
} else {
|
||
return text
|
||
}
|
||
}
|
||
|
||
function output_from_id(match, the_id, format) {
|
||
var the_answer = "";
|
||
editorLog("expanding the_id", the_id);
|
||
debugLog("expanding the_id", the_id);
|
||
var the_object = internalSource[the_id];
|
||
if (!the_object) {
|
||
errorLog("error: no content for", the_id);
|
||
return the_id
|
||
}
|
||
var src_tag = the_object.sourcetag;
|
||
editorLog("the_object",the_object);
|
||
var output_structure;
|
||
if (src_tag in objectStructure) {
|
||
output_structure = objectStructure[src_tag][format];
|
||
} else {
|
||
errorLog("error: unknown structure:", src_tag);
|
||
// so make reasonable assumptions about the structure
|
||
output_structure = {
|
||
"tag": src_tag,
|
||
"pieces": [["content", ""]]
|
||
}
|
||
}
|
||
|
||
editorLog("output_structure", output_structure);
|
||
// var output_tag = output_structure.tag;
|
||
|
||
the_answer = output_from_source(the_object, output_structure, format);
|
||
|
||
return the_answer
|
||
}
|
||
|
||
function expand_condensed_source_html(text, context) {
|
||
editorLog("iiiiiii in expand_condensed_source_html");
|
||
if (text.includes("<&>")) {
|
||
editorLog(" qqqqq expand_condensed_source_html", text);
|
||
if (context == "edit") {
|
||
return text.replace(/<&>(.*?)<;>/g,expand_condensed_src_edit)
|
||
} else {
|
||
return text.replace(/<&>(.*?)<;>/g,expand_condensed_src_html)
|
||
}
|
||
} else {
|
||
editorLog("returning text XX" + text.substring(0,17) + "YY");
|
||
editorLog("returning from expand_condensed_source_html");
|
||
return text
|
||
}
|
||
}
|
||
function expand_condensed_src_html(match, the_id) {
|
||
return html_from_internal_id(the_id, "inner")
|
||
}
|
||
function expand_condensed_src_edit(match, the_id) {
|
||
return html_from_internal_id(the_id, "edit")
|
||
}
|
||
|
||
function html_from_internal_id(the_id, is_inner) {
|
||
// the outer element needs to be constructed as document.createElement
|
||
// but the inner content is just plain text
|
||
// maybe saying it better: sometimes we want to create an object and
|
||
// insert it into the DOM. Other times we just want to construct the
|
||
// HTML markup fo rthe object and return that.
|
||
var the_object = internalSource[the_id];
|
||
editorLog("making html of", the_object, "is_inner", is_inner, "the_id", the_id);
|
||
var sourcetag = the_object["sourcetag"];
|
||
editorLog("which has tag", sourcetag);
|
||
|
||
editorLog("m in inline_math", inline_math.includes("m"));
|
||
|
||
var html_of_this_object;
|
||
var the_html_objects = [];
|
||
|
||
if (sourcetag == "image") {
|
||
html_of_this_object = output_from_id("", the_id, "html");
|
||
editorLog("html_of_this_object", html_of_this_object);
|
||
the_html_objects.push(html_of_this_object);
|
||
} else if (tag_type(sourcetag) == "p") {
|
||
html_of_this_object = output_from_id("", the_id, "html");
|
||
editorLog("html_of_this_object", html_of_this_object);
|
||
the_html_objects.push(html_of_this_object);
|
||
} else if (inline_math.includes(sourcetag) && is_inner == "edit") {
|
||
// here we are assuming the tag is 'm'
|
||
var opening_tag = '<span class="edit_inline_math"';
|
||
var closing_tag = '</span>';
|
||
opening_tag += ' id="' + the_id + '"data-editable="44" tabindex="-1">';
|
||
return opening_tag + spacemath_to_tex(the_object["content"]) + closing_tag
|
||
} else if (["me","men"].includes(sourcetag) && is_inner == "edit") {
|
||
var opening_tag = '<div class="edit_display_math"';
|
||
var closing_tag = '</div>';
|
||
opening_tag += ' id="' + the_id + '"data-editable="44" tabindex="-1">';
|
||
return opening_tag + spacemath_to_tex(the_object["content"]) + closing_tag
|
||
} else if (["md","mdn"].includes(sourcetag) && is_inner == "edit") {
|
||
var opening_tag = '<div class="edit_multiline_math"';
|
||
var closing_tag = '</div>';
|
||
opening_tag += ' id="' + the_id + '"data-editable="44" tabindex="-1">';
|
||
this_content = the_object["content"].replace(/<&>(.*?)<;>/g,expand_condensed_src_edit);
|
||
this_content = this_content.replace("MROWsepARATOR", "\n yyyy \n");
|
||
return opening_tag + this_content + closing_tag
|
||
} else if (["mrow"].includes(sourcetag) && is_inner == "edit") {
|
||
var opening_tag = '<div class="edit_math_row"';
|
||
var closing_tag = '</div>';
|
||
opening_tag += ' id="' + the_id + '"data-editable="44" tabindex="-1">';
|
||
return opening_tag + "MROW" + spacemath_to_tex(the_object["content"]) + closing_tag
|
||
} else if (sourcetag == "xref" && is_inner == "edit") {
|
||
// here we are assuming the tag is 'm'
|
||
var opening_tag = '<span class="edit_reference"';
|
||
var closing_tag = '</span>';
|
||
opening_tag += ' id="' + the_id + '"data-editable="44" tabindex="-1">';
|
||
return opening_tag + the_object["ref"] + closing_tag
|
||
} else {
|
||
html_of_this_object = output_from_id("", the_id, "html");
|
||
editorLog("html_of_this_object", html_of_this_object);
|
||
the_html_objects.push(html_of_this_object);
|
||
|
||
}
|
||
|
||
editorLog(" RRRR returning the_html_objects", the_html_objects);
|
||
|
||
// the_html_objects = the_html_objects.replace("MROWsepARATOR", "\n\\cr\n");
|
||
return the_html_objects
|
||
}
|
||
|
||
function insert_html_version(these_changes) {
|
||
|
||
var nature_of_the_change = these_changes[0];
|
||
var location_of_change = these_changes[1];
|
||
var possibly_changed_ids_and_entry = these_changes[2];
|
||
|
||
editorLog("nature_of_the_change", nature_of_the_change);
|
||
editorLog("location_of_change", location_of_change);
|
||
editorLog("possibly_changed_ids_and_entry", possibly_changed_ids_and_entry);
|
||
|
||
if (!possibly_changed_ids_and_entry.length) {
|
||
editorLog("nothing to change");
|
||
// return ""
|
||
}
|
||
// we make HTML version of the objects with ids possibly_changed_ids_and_entry,
|
||
// and then insert those into the page.
|
||
|
||
// here is where we detect deleting?
|
||
// or is that after this function is done?
|
||
if (nature_of_the_change != "replace") {
|
||
editorLog("should be replace, since it is the edit form we are replacing");
|
||
}
|
||
|
||
var object_as_html = "";
|
||
var this_object_id, this_object_entry, this_object_oldornew, this_object;
|
||
|
||
editorLog(" there are", possibly_changed_ids_and_entry.length, "items to process");
|
||
|
||
for (var j=0; j < possibly_changed_ids_and_entry.length; ++j) {
|
||
this_object_id = possibly_changed_ids_and_entry[j][0];
|
||
this_object_entry = possibly_changed_ids_and_entry[j][1];
|
||
this_object_oldornew = possibly_changed_ids_and_entry[j][2];
|
||
editorLog("j=", j, "this thing", possibly_changed_ids_and_entry[j]);
|
||
this_object = internalSource[this_object_id];
|
||
editorLog(j, "this_object", this_object);
|
||
if (tag_type(this_object["sourcetag"]) == "p" || this_object["sourcetag"] == "li" || tag_type(this_object["sourcetag"]) == "md") {
|
||
|
||
var this_new_object = html_from_internal_id(this_object_id);
|
||
editorLog("inserting",this_new_object,"before",location_of_change);
|
||
location_of_change.insertAdjacentHTML('beforebegin', this_new_object[0]);
|
||
object_as_html = document.getElementById(this_object_id);
|
||
|
||
} else if (this_object_entry == "title") {
|
||
var object_as_html = document.createElement('span');
|
||
object_as_html.setAttribute("class", "title");
|
||
object_as_html.setAttribute('data-editable', 20);
|
||
object_as_html.setAttribute('tabindex', -1);
|
||
// next line should apply a transform to the source
|
||
object_as_html.innerHTML = this_object[this_object_entry];
|
||
editorLog("inserting",object_as_html,"before",location_of_change);
|
||
// location_of_change is the .header . We want it to be the .title
|
||
location_of_change = location_of_change.querySelector("#actively_editing");
|
||
editorLog("now location_of_change",location_of_change);
|
||
location_of_change.insertAdjacentElement('beforebegin', object_as_html);
|
||
} else if (this_object_entry == "caption") {
|
||
console.log("Error: don't know what to do with 'caption'")
|
||
} else if (this_object_entry == "image") {
|
||
editorLog("image, this_object", this_object);
|
||
var this_new_object = html_from_internal_id(this_object_id);
|
||
editorLog("inserting",this_new_object,"before",location_of_change);
|
||
location_of_change.insertAdjacentHTML('beforebegin', this_new_object[0]);
|
||
object_as_html = document.getElementById(this_object_id);
|
||
|
||
} else {
|
||
editorLog("trouble making", this_object);
|
||
}
|
||
MathJax.typesetPromise();
|
||
// MathJax.Hub.Queue(['Typeset', MathJax.Hub, this_object_id]);
|
||
}
|
||
location_of_change.remove();
|
||
|
||
editorLog("returning from insert html version", object_as_html);
|
||
// call mathjax, in case the new content contains math
|
||
return object_as_html // the most recently added object, which we may want to
|
||
// do something, like add an editing menu
|
||
} // insert html version
|
||
|
||
function save_edits() {
|
||
|
||
var currentState = internalSource;
|
||
|
||
editorLog("saving", currentState);
|
||
localStorage.setObject("savededits", currentState);
|
||
return "";
|
||
}
|
||
|
||
function previous_editing() {
|
||
var old_internal_source = localStorage.getObject("savededits");
|
||
return (old_internal_source || "")
|
||
}
|
||
|
||
function local_editing_action(e) {
|
||
editorLog("in local editing action for" ,e.code);
|
||
var most_recent_edit;
|
||
if (e.code == "Escape" || e.code == "Enter") {
|
||
editorLog("I saw a Rettttt");
|
||
if (document.activeElement.getAttribute('data-component') == "title" ||
|
||
document.activeElement.getAttribute('data-component') == "caption") {
|
||
editorLog("probably saving a ", document.activeElement.getAttribute('data-component'));
|
||
e.preventDefault();
|
||
these_changes = assemble_internal_version_changes(document.activeElement);
|
||
final_added_object = insert_html_version(these_changes);
|
||
most_recent_edit = ongoing_editing_actions.pop();
|
||
recent_editing_actions.unshift(most_recent_edit);
|
||
editorLog("most_recent_edit should be title change", most_recent_edit);
|
||
editorLog("final_added_object", final_added_object);
|
||
this_char = "";
|
||
prev_char = "";
|
||
save_edits();
|
||
|
||
// .title is in a .heading, and neither have an id
|
||
make_current_editing_tree_from_id(final_added_object.parentElement.parentElement.id);
|
||
edit_menu_from_current_editing("entering");
|
||
|
||
// editing_input_image
|
||
} else if (e.code == "Escape" || (prev_char.code == "Enter" && prev_prev_char.code == "Enter") || document.getElementById("editing_input_image")) {
|
||
editorLog("need to save");
|
||
editorLog(" HHH current_editing", current_editing, "with active element", document.activeElement);
|
||
|
||
e.preventDefault();
|
||
this_char = "";
|
||
prev_char = "";
|
||
these_changes = assemble_internal_version_changes(document.activeElement);
|
||
editorLog(" CCC these_changes", these_changes);
|
||
editorLog(" CCC0 these_changes[0]", these_changes[0]);
|
||
editorLog("ongoing_editing_actions", ongoing_editing_actions);
|
||
editorLog("actively_editing", document.getElementById("actively_editing"));
|
||
editorLog(" III current_editing", current_editing, current_editing["tree"][current_editing["level"]]);
|
||
previous_added_object = final_added_object;
|
||
final_added_object = insert_html_version(these_changes);
|
||
editorLog("final_added_object, previous_added_object", final_added_object, previous_added_object);
|
||
editorLog(" LLL current_editing", current_editing, current_editing["tree"][current_editing["level"]]);
|
||
editorLog("the final_added_object", final_added_object);
|
||
editorLog("the actively_editing", document.getElementById("actively_editing"));
|
||
editorLog("OO", ongoing_editing_actions.length, " ongoing_editing_actions", ongoing_editing_actions);
|
||
/*
|
||
editorLog("ongoing_editing_actions[0]", ongoing_editing_actions[0]);
|
||
editorLog("ongoing_editing_actions[0][2]", ongoing_editing_actions[0][2]);
|
||
*/
|
||
// maybe this next if only handles when we delete by removing the letters in a p?
|
||
if (these_changes[0] == "empty") {
|
||
editorLog("NN", ongoing_editing_actions.length, " ongoing_editing_actions", ongoing_editing_actions);
|
||
editorLog("ongoing_editing_actions[0]", ongoing_editing_actions[0]);
|
||
editorLog("ongoing_editing_actions[0][2]", ongoing_editing_actions[0][2]);
|
||
editorLog(" going to delete", these_changes[2][0]);
|
||
// this is sort-of a hack to detext the end of inserting li
|
||
if (ongoing_editing_actions.length == 2 &&
|
||
ongoing_editing_actions[1][0] == "empty" &&
|
||
ongoing_editing_actions[1][1] == "p" &&
|
||
ongoing_editing_actions[0][0] == "new" &&
|
||
ongoing_editing_actions[0][1] == "li") {
|
||
ongoing_editing_actions.pop(); // content was empty, so there is no editing action
|
||
ongoing_editing_actions.pop();
|
||
delete_by_id(these_changes[2][0][0], "newempty");
|
||
current_editing["location"][current_editing["level"]] -= 1
|
||
final_added_object = previous_added_object; // this approach makes the updating of current_editing moot?
|
||
} else {
|
||
delete_by_id(these_changes[2][0][0], "empty");
|
||
}
|
||
editorLog("MM", ongoing_editing_actions.length, " ongoing_editing_actions", ongoing_editing_actions);
|
||
for (var j=0; j<ongoing_editing_actions.length; ++j ) {
|
||
editorLog(j, "ongoing_editing_actions[j]", ongoing_editing_actions[j]);
|
||
}
|
||
editorLog("PP", ongoing_editing_actions.length, " ongoing_editing_actions", ongoing_editing_actions);
|
||
}
|
||
if (final_added_object) { // && document.getElementById("actively_editing"))
|
||
|
||
if(document.getElementById("actively_editing")) {
|
||
editorLog(" SSS current_editing", current_editing, current_editing["tree"][current_editing["level"]]);
|
||
|
||
var editing_placeholder = document.getElementById("actively_editing");
|
||
editorLog("still editing", editing_placeholder, "which contains", final_added_object);
|
||
var this_parent = internalSource[final_added_object.id]["parent"];
|
||
editorLog("final_added_object parent", this_parent);
|
||
var the_whole_object = html_from_internal_id(this_parent[0]);
|
||
editorLog("the_whole_object", the_whole_object);
|
||
if (internalSource[this_parent[0]]["sourcetag"] == "proof") { // insert the theorem-like statement
|
||
alert("something about a proof");
|
||
var the_parent_object = html_from_internal_id(internalSource[this_parent[0]]["parent"][0]);
|
||
the_whole_object = the_parent_object.concat(the_whole_object)
|
||
}
|
||
for (var j = the_whole_object.length - 1; j >= 0; --j) {
|
||
editorLog(" X", j, "the_whole_object[j]", the_whole_object[j]);
|
||
document.getElementById("actively_editing").insertAdjacentElement("afterend", the_whole_object[j])
|
||
MathJax.typesetPromise();
|
||
// MathJax.Hub.Queue(['Typeset', MathJax.Hub, the_whole_object[j]]);
|
||
}
|
||
|
||
editorLog("here is where we need to update current_editing", "parent:", this_parent,"which is",document.getElementById(this_parent[0]), "level:", current_editing["level"], "loation:", current_editing["location"], "tree:", current_editing["tree"]);
|
||
$("#actively_editing").remove();
|
||
|
||
editorLog(" DDD current_editing", current_editing, current_editing["tree"][current_editing["level"]]);
|
||
|
||
}
|
||
|
||
most_recent_edit = ["","",""];
|
||
while (ongoing_editing_actions.length) {
|
||
most_recent_edit = ongoing_editing_actions.pop();
|
||
recent_editing_actions.unshift(most_recent_edit);
|
||
editorLog(" most_recent_edit", most_recent_edit);
|
||
}
|
||
editorLog(" 8888 final_added_object", final_added_object);
|
||
|
||
save_edits()
|
||
|
||
// is this in the right place?
|
||
editorLog("most_recent_edit", most_recent_edit);
|
||
|
||
// sometimes, such as when adding items to a list, you want to
|
||
// automatically start adding something else.
|
||
// maybe refactor theorem to add proof after?
|
||
if (most_recent_edit[1] == "li") { // added to a list, so try adding again
|
||
// note that when adding an li, the neichbor is a p within the actual li neighbor
|
||
var new_obj = create_object_to_edit("li", document.getElementById(most_recent_edit[2]).firstElementChild, "afterend")
|
||
edit_in_place(new_obj, "new");
|
||
editorLog("now editing the assumed new li");
|
||
editorLog(" GGG current_editing", current_editing, current_editing["tree"][current_editing["level"]]);
|
||
|
||
} else {
|
||
|
||
editorLog("re-making the tree from final_added_object", final_added_object);
|
||
make_current_editing_tree_from_id(final_added_object.id);
|
||
editorLog("and then adding a menu");
|
||
edit_menu_from_current_editing("entering");
|
||
}
|
||
|
||
} else if ( document.getElementById("actively_editing")) {
|
||
document.getElementById("actively_editing").remove();
|
||
// were actively editing, and now just re-making the menu
|
||
edit_menu_from_current_editing("entering");
|
||
} else {
|
||
// default makng the menu
|
||
edit_menu_from_current_editing("entering");
|
||
}
|
||
} // esc or enter enter enter
|
||
editorLog ("processed an enter");
|
||
} // esc or enter
|
||
else {
|
||
editorLog("e.code was not one of those we were looking for", e)
|
||
}
|
||
editorLog("leaving local editing action")
|
||
}
|
||
|
||
function main_menu_navigator(e) { // we are not currently editing
|
||
// so we are building the menu, and possibly moving aroung the document,
|
||
//for the user to decide what/how to edit
|
||
|
||
// There are 3 modes:
|
||
// #enter_choice, data-location="next"
|
||
// #enter_choice, data-location="stay"
|
||
// above means we are deciding whenter to edit/enter/leave and object, or to move on
|
||
// #choose_current
|
||
// 3rd option means we already have a menu
|
||
|
||
if (document.getElementById("enter_choice")) {
|
||
theEnterChoice = document.getElementById("enter_choice");
|
||
editorLog("enter_choice", e);
|
||
var theMotion = theEnterChoice.getAttribute("data-location");
|
||
var object_of_interest;
|
||
if (theMotion == "stay") {
|
||
object_of_interest = theEnterChoice.parentElement.previousSibling;
|
||
} else {
|
||
object_of_interest = theEnterChoice.parentElement.parentElement;
|
||
}
|
||
editorLog(" MMN: want to", theMotion, "on", object_of_interest, "from", theEnterChoice)
|
||
|
||
editorLog("current_editing", current_editing);
|
||
editorLog("theEnterChoice", theEnterChoice);
|
||
var current_level = current_editing["level"];
|
||
var current_location = current_editing["location"][current_level];
|
||
var current_siblings = current_editing["tree"][current_level];
|
||
editorLog("current_level", current_level, "current_location", current_location, "current_siblings", current_siblings);
|
||
|
||
if ((e.code == "Tab" || e.code == "ArrowDown") && !e.shiftKey) {
|
||
e.preventDefault();
|
||
if (current_level == 0) { // at the top, so no "next" object
|
||
return ""
|
||
}
|
||
// go to next sibling, or stage to exit if on last sibling
|
||
if (current_location == (current_siblings.length - 1)) { // on last sibling
|
||
editorLog("on last sibling, level was", current_level,"siblings was", current_siblings, "tree", current_editing["tree"]);
|
||
editorLog("current_location was", current_location);
|
||
current_level -= 1;
|
||
current_location = current_editing["location"][current_level];
|
||
current_editing["level"] = current_level;
|
||
current_editing["location"][current_level] = current_location;
|
||
current_siblings = current_editing["tree"][current_level];
|
||
editorLog("current_location is", current_location);
|
||
editorLog("stay menu A");
|
||
object_of_interest.classList.remove("may_leave");
|
||
object_of_interest.classList.remove("may_elect");
|
||
edit_menu_from_current_editing("leaving")
|
||
} else {
|
||
editorLog("moving to the next editable sibling");
|
||
editorLog("level was", current_level,"siblings was", current_siblings, "tree", current_editing["tree"]);
|
||
editorLog("current_location was", current_location);
|
||
editorLog(current_location, "was", current_editing);
|
||
current_location += 1;
|
||
object_of_interest.classList.remove("may_leave");
|
||
object_of_interest.classList.remove("may_elect");
|
||
editorLog("current_location is", current_location);
|
||
editorLog("stay menu B");
|
||
current_editing["location"][current_level] = current_location;
|
||
editorLog(current_location, "is", current_editing);
|
||
edit_menu_from_current_editing("entering")
|
||
}
|
||
} else if ((e.code == "Tab" && e.shiftKey) || e.code == "ArrowUp") { // Shift-Tab to prevous object
|
||
e.preventDefault();
|
||
// go to previous sibling, or up one if on first sibling
|
||
editorLog("Arrow Up:", "current_location", current_location, "current_level", current_level);
|
||
if (theMotion == "stay") { // about to leave, to return to the top of that region
|
||
edit_menu_from_current_editing("entering")
|
||
} else if (current_location == 0) {
|
||
if (!current_level) { // already at the top, so nowhere to go, so do nothing
|
||
editorLog("at the top, so can't go up");
|
||
return ""
|
||
}
|
||
current_level -= 1;
|
||
current_editing["level"] = current_level;
|
||
current_location = current_editing["location"][current_level];
|
||
editorLog("AA new current_location", current_location, " current_editing['tree']", current_editing["tree"]);
|
||
editorLog(" current_editing['tree'][0]", current_editing["tree"][0]);
|
||
current_siblings = current_editing["tree"][current_level];
|
||
editorLog("current_siblings", current_siblings);
|
||
edit_menu_from_current_editing("entering")
|
||
} else {
|
||
current_location -= 1;
|
||
current_editing["location"][current_level] = current_location;
|
||
editorLog("current_siblings", current_siblings);
|
||
editorLog("BB new current_location", current_location, "at level", current_level, " current_editing['tree']", current_editing["tree"]);
|
||
edit_menu_from_current_editing("entering")
|
||
}
|
||
} else if (e.code == "Escape" || e.code == "ArrowLeft") {
|
||
e.preventDefault();
|
||
if (current_level == 0) { return "" } // already at the top, so nowhere to go, so do nothing
|
||
// copied from A1
|
||
editorLog("At ArrowLeft, level was", current_level, "with location", current_editing["location"], "and tree", current_editing["tree"][current_level]);
|
||
current_level -= 1;
|
||
current_editing["level"] = current_level;
|
||
current_location = current_editing["location"][current_level];
|
||
current_siblings = current_editing["tree"][current_level];
|
||
editorLog("now level id", current_level, "with location", current_editing["location"], "and tree", current_editing["tree"][current_level]);
|
||
edit_menu_from_current_editing("entering")
|
||
} else if (e.code == "Enter" || e.code == "ArrowRight") {
|
||
e.preventDefault();
|
||
if (theMotion == "stay") {
|
||
edit_menu_from_current_editing("entering");
|
||
return ""
|
||
}
|
||
var edit_submenu = document.createElement('ol');
|
||
edit_submenu.setAttribute('id', 'edit_menu');
|
||
edit_submenu.setAttribute('class', 'edit_menu');
|
||
|
||
var to_be_edited = object_of_interest;
|
||
editorLog("to_be_edited", to_be_edited);
|
||
edit_submenu.innerHTML = top_menu_options_for(to_be_edited);
|
||
$("#enter_choice").replaceWith(edit_submenu);
|
||
document.getElementById('choose_current').focus();
|
||
}
|
||
editorLog(" Just handled the case of enter_choice");
|
||
return ""
|
||
|
||
} else if (document.getElementById("choose_current")) {
|
||
var theChooseCurrent = document.getElementById("choose_current");
|
||
var dataLocation = theChooseCurrent.getAttribute("data-location"); // may be null
|
||
var dataAction = theChooseCurrent.getAttribute("data-action"); // may be null
|
||
var dataModifier = theChooseCurrent.getAttribute("data-modifier"); // may be null
|
||
var dataEnv = theChooseCurrent.getAttribute("data-env"); // may be null
|
||
// a hack because of how the menus were originally set up
|
||
if (dataEnv == "save") { dataAction = "save" }
|
||
var dataEnvParent = theChooseCurrent.getAttribute("data-env-parent"); // may be null
|
||
var object_of_interest;
|
||
if (document.getElementById("edit_menu_holder")) {
|
||
object_of_interest = document.getElementById("edit_menu_holder").parentElement
|
||
} else if (document.getElementById("local_menu_holder")) {
|
||
object_of_interest = document.getElementById("local_menu_holder").parentElement
|
||
} else {
|
||
editorLog("something is confused: should be a menu, but isn't");
|
||
if (theChooseCurrent.id) {
|
||
make_current_editing_tree_from_id(theChooseCurrent.id);
|
||
object_of_interest = theChooseCurrent
|
||
} else {
|
||
make_current_editing_tree_from_id(theChooseCurrent.parentElement.id);
|
||
object_of_interest = theChooseCurrent.parentElement
|
||
}
|
||
editorLog("made entering menu for", object_of_interest);
|
||
edit_menu_from_current_editing("entering")
|
||
}
|
||
current_level = current_editing["level"];
|
||
current_location = current_editing["location"][current_level];
|
||
current_siblings = current_editing["tree"][current_level];
|
||
editorLog("in choose_current", dataLocation, "of", object_of_interest);
|
||
editorLog("dataAction ", dataAction);
|
||
editorLog("dataLocation ", dataLocation);
|
||
// we have an active menu, and have selected an item
|
||
// there are three main sub-cases, depending on whether there is a data-location attribute,
|
||
// a data-action attribute, or a data-env attribute.
|
||
// That is the primary order in which those attributes are considered
|
||
// however, some actions (such as Tab and shift-Tab) are the same
|
||
// in each sub-case (because all we are doing is moving up and down the
|
||
// current list of options), so we handle those first.
|
||
|
||
if ((e.code == "Tab" || e.code == "ArrowDown") && !e.shiftKey) {
|
||
e.preventDefault();
|
||
next_menu_item = theChooseCurrent.nextSibling;
|
||
editorLog("theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item);
|
||
if (!next_menu_item) { next_menu_item = theChooseCurrent.parentNode.firstChild }
|
||
editorLog("theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item);
|
||
if (theChooseCurrent == next_menu_item) { //only one item on menu, so Tab shold move to the next editable item
|
||
// if last editable child, go up one
|
||
if (current_location == (current_siblings.length - 1)) {
|
||
current_level -= 1;
|
||
current_location = current_editing["location"][current_level];
|
||
current_editing["level"] = current_level;
|
||
current_editing["location"][current_level] = current_location;
|
||
edit_menu_from_current_editing("leaving")
|
||
} else {
|
||
current_location += 1;
|
||
editorLog("single item menu, current_location now", current_location);
|
||
current_editing["location"][current_level] = current_location;
|
||
edit_menu_from_current_editing("entering");
|
||
}
|
||
}
|
||
theChooseCurrent.removeAttribute("id");
|
||
editorLog("theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item);
|
||
next_menu_item.setAttribute("id", "choose_current");
|
||
editorLog("setting focus on",next_menu_item);
|
||
next_menu_item.focus();
|
||
} // Tab
|
||
else if ((e.code == "Tab" && e.shiftKey) || e.code == "ArrowUp") { // Shift-Tab to prevous object
|
||
e.preventDefault();
|
||
editorLog("just saw a", e.code);
|
||
editorLog("focus is on", $(":focus"));
|
||
editorLog("saw an",e.code);
|
||
next_menu_item = theChooseCurrent.previousSibling;
|
||
editorLog("W1 theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item);
|
||
if (!next_menu_item) { next_menu_item = theChooseCurrent.parentNode.lastChild }
|
||
editorLog("W2 theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item);
|
||
if (theChooseCurrent == next_menu_item) { //only one item on menu, so Shift-Tab shold move to previous or up one level
|
||
if (current_editing["location"][ current_editing["level"] ] == 0) {
|
||
current_editing["level"] -= 1;
|
||
} else {
|
||
current_editing["location"][ current_editing["level"] ] -= 1;
|
||
}
|
||
editorLog("single item menu, current_level now", current_level);
|
||
edit_menu_from_current_editing("entering");
|
||
} else {
|
||
theChooseCurrent.removeAttribute("id");
|
||
editorLog("W3 theChooseCurrent", theChooseCurrent, "next_menu_item", next_menu_item);
|
||
theChooseCurrent.classList.remove("chosen");
|
||
next_menu_item.setAttribute("id", "choose_current");
|
||
editorLog("setting focus on",next_menu_item);
|
||
next_menu_item.focus();
|
||
}
|
||
}
|
||
else if (e.code == "Escape" || e.code == "ArrowLeft") {
|
||
editorLog("processing ESC");
|
||
editorLog("At ArrowLeft, level was", current_level, "xx", current_editing["level"], "with location", current_editing["location"], "and tree", current_editing["tree"][current_level]);
|
||
// I think the next if can never be true, because of how to route keystrokes
|
||
if (document.getElementById("local_menu_holder")) { // hack for when the interface gets confused
|
||
document.getElementById("local_menu_holder").remove()
|
||
} else {
|
||
editorLog("W4 theChooseCurrent", theChooseCurrent);
|
||
// need to go up one level in the menu
|
||
var previous_menu_item = theChooseCurrent.parentElement.parentElement; // li > ol > li
|
||
if (previous_menu_item.id == "edit_menu_holder") {
|
||
var thenewchoice = '<span id="enter_choice" data-location="next">';
|
||
thenewchoice += 'edit or add nearby';
|
||
thenewchoice += '</span>';
|
||
previous_menu_item.innerHTML = thenewchoice
|
||
} else {
|
||
theChooseCurrent.parentElement.remove();
|
||
previous_menu_item.classList.remove('chosen');
|
||
previous_menu_item.parentElement.classList.remove('past');
|
||
previous_menu_item.setAttribute("id", "choose_current");
|
||
previous_menu_item.focus();
|
||
}
|
||
}
|
||
}
|
||
else if (keyletters.includes(e.code)) {
|
||
key_hit = e.code.toLowerCase().substring(3); // remove forst 3 characters, i.e., "key"
|
||
editorLog("key_hit", key_hit);
|
||
theChooseCurrent = document.getElementById('choose_current');
|
||
editorLog('theChooseCurrent', theChooseCurrent );
|
||
editorLog( $(theChooseCurrent) );
|
||
// there can be multiple data-jump, so use ~= to find if the one we are looking for is there
|
||
// and start from the beginning in case the match is earlier (make the second selector better)
|
||
if ((next_menu_item = $(theChooseCurrent).nextAll('[data-jump~="' + key_hit + '"]:first')[0]) ||
|
||
(next_menu_item = $(theChooseCurrent).prevAll('[data-jump~="' + key_hit + '"]:last')[0])) { // check there is a menu item with that key
|
||
theChooseCurrent.removeAttribute("id", "choose_current");
|
||
next_menu_item.setAttribute("id", "choose_current");
|
||
next_menu_item.focus();
|
||
} else {
|
||
// not sure what to do if an irrelevant key was hit
|
||
editorLog("that key does not match any option")
|
||
}
|
||
}
|
||
|
||
// Now only Enter and ArrowRight are meaningful in this context.
|
||
// The effect will depend on the other attributes of #choose_current:
|
||
// dataLocation, dataAction, dataEnv
|
||
|
||
else if (e.code == "Enter" || e.code == "ArrowRight") {
|
||
e.preventDefault();
|
||
if (dataLocation) {
|
||
if (dataLocation == "enter") { // we are moving down into an object
|
||
|
||
editorLog("theChooseCurrent", theChooseCurrent);
|
||
var object_to_be_entered = object_of_interest;
|
||
editorLog("object_to_be_entered", object_to_be_entered);
|
||
object_to_be_entered.classList.remove("may_select");
|
||
object_to_be_entered.classList.remove("may_enter");
|
||
object_to_be_entered.classList.remove("may_leave");
|
||
editorLog('next_editable_of(object_to_be_entered, "children")');
|
||
editableChildren = next_editable_of(object_to_be_entered, "children");
|
||
current_level += 1;
|
||
current_editing["level"] = current_level;
|
||
current_editing["location"][current_level] = 0;
|
||
current_editing["tree"][current_level] = editableChildren;
|
||
editorLog("current_editing", current_editing);
|
||
|
||
editorLog("object_to_be_entered", object_to_be_entered);
|
||
editorLog("with some children", editableChildren);
|
||
// put menu on the item at the top of the block_we_are_reentering
|
||
// this is a repeat of a Tab case, so consolidate
|
||
editorLog("menu place 10");
|
||
editorLog("document.activeElement", document.activeElement);
|
||
|
||
editorLog("menu on", editableChildren[0]);
|
||
edit_menu_for(editableChildren[0], "entering");
|
||
|
||
return ""
|
||
// combine the next with previous, because the ony difference is which object receives focus
|
||
} else if (dataLocation == "end") { // move to the end of an object
|
||
|
||
editorLog("theChooseCurrent", theChooseCurrent);
|
||
var object_to_be_entered = object_of_interest;
|
||
editorLog("object_to_be_entered", object_to_be_entered);
|
||
object_to_be_entered.classList.remove("may_select");
|
||
object_to_be_entered.classList.remove("may_enter");
|
||
object_to_be_entered.classList.remove("may_leave");
|
||
editorLog('next_editable_of(object_to_be_entered, "children")');
|
||
editableChildren = next_editable_of(object_to_be_entered, "children");
|
||
var num_editableChildren = editableChildren.length;
|
||
current_level += 1;
|
||
current_editing["level"] = current_level;
|
||
// current_editing["location"][current_level] = 0;
|
||
current_editing["location"][current_level] = num_editableChildren - 1;
|
||
current_editing["tree"][current_level] = editableChildren;
|
||
editorLog("current_editing", current_editing);
|
||
|
||
editorLog("object_to_be_entered", object_to_be_entered);
|
||
editorLog("with some children", editableChildren);
|
||
// put menu on the item at the top of the block_we_are_reentering
|
||
// this is a repeat of a Tab case, so consolidate
|
||
editorLog("menu place 10end");
|
||
editorLog("document.activeElement", document.activeElement);
|
||
|
||
editorLog("menu on", editableChildren[num_editableChildren - 1]);
|
||
edit_menu_for(editableChildren[num_editableChildren - 1], "entering");
|
||
|
||
return ""
|
||
} else if ((dataLocation == "beforebegin") || (dataLocation == "afterend") || (dataLocation == "afterbegin")) { // should be the only other options
|
||
theChooseCurrent.parentElement.classList.add("past");
|
||
theChooseCurrent.removeAttribute("id");
|
||
theChooseCurrent.classList.add("chosen");
|
||
|
||
var parent_id = document.getElementById('edit_menu_holder').parentElement.parentElement.id;
|
||
if (!parent_id) {
|
||
editorLog(document.getElementById('edit_menu_holder').parentElement.parentElement, "has no id, so going down one level");
|
||
parent_id = document.getElementById('edit_menu_holder').parentElement.id;
|
||
}
|
||
editorLog("making a menu for", parent_id);
|
||
var edit_submenu = document.createElement('ol');
|
||
edit_submenu.innerHTML = menu_options_for(parent_id, "", "base");
|
||
editorLog("just inserted inner menu_options_for(" + parent_id + ")", menu_options_for(parent_id, "", "base"));
|
||
theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu);
|
||
document.getElementById('choose_current').focus();
|
||
editorLog("focus is on", $(":focus"));
|
||
|
||
return ""
|
||
} else {
|
||
editorLog("Error: unknown dataLocation:", dataLocation)
|
||
}
|
||
} // dataLocation
|
||
|
||
else if (dataAction) {
|
||
if (dataAction == "edit") {
|
||
editorLog("going to edit", object_of_interest);
|
||
edit_in_place(object_of_interest, "old");
|
||
} else if (dataAction == "replace") { // no longer used?
|
||
editorLog("replace", object_of_interest, "by id", object_of_interest.id);
|
||
replace_by_id(object_of_interest.id, "html")
|
||
} else if (dataAction == "stop_editing") {
|
||
editorLog("stop_editing", object_of_interest, "by id", object_of_interest.id);
|
||
replace_by_id(object_of_interest.id, "html")
|
||
eraseCookie(chosen_edit_option_key)
|
||
} else if (dataAction == "save") {
|
||
save_source();
|
||
edit_menu_from_current_editing("entering");
|
||
} else if (dataAction == "resume") {
|
||
editorLog("resuming previous editing session");
|
||
resume_editing()
|
||
} else if (dataAction == "change-env-to") {
|
||
// shoudl use dataEnv ?
|
||
var new_env = theChooseCurrent.getAttribute("data-env");
|
||
editorLog("changing environment to", new_env);
|
||
// #edit_menu_holder is in span.type, inside .heading, inside article
|
||
to_be_edited = document.getElementById('edit_menu_holder').parentElement.parentElement.parentElement;
|
||
editorLog("to_be_edited", to_be_edited);
|
||
var id_of_object = to_be_edited.id;
|
||
var this_object_source = internalSource[id_of_object];
|
||
editorLog("current envoronemnt", this_object_source);
|
||
var old_env = internalSource[id_of_object]["sourcetag"];
|
||
internalSource[id_of_object]["sourcetag"] = new_env;
|
||
recent_editing_actions.push([old_env, new_env, id_of_object]);
|
||
editorLog("the change was", "changed " + old_env + " to " + new_env + " " + id_of_object);
|
||
var the_whole_object = html_from_internal_id(id_of_object);
|
||
editorLog("B: the_whole_object", the_whole_object);
|
||
$("#" + id_of_object).replaceWith(the_whole_object[0]); // later handle multiple additions
|
||
editorLog("just edited", $("#" + id_of_object));
|
||
// since we changed an object which is in
|
||
editorLog("curent_editing level", current_editing["level"], "with things", current_editing["tree"][current_editing["level"]]);
|
||
current_editing["level"] -= 1;
|
||
current_editing["tree"][current_editing["level"]] = next_editable_of(document.getElementById(id_of_object).parentElement, "children");
|
||
editorLog("now curent_editing level", current_editing["level"], "with things", current_editing["tree"][current_editing["level"]]);
|
||
edit_menu_from_current_editing("entering");
|
||
return ""
|
||
|
||
} else if (dataAction == 'change-env') {
|
||
// #edit_menu_holder is in span.type, inside .heading, inside article
|
||
current_env = document.getElementById('edit_menu_holder').parentElement.parentElement.parentElement;
|
||
current_env_id = current_env.id;
|
||
|
||
theChooseCurrent.parentElement.classList.add("past");
|
||
theChooseCurrent.removeAttribute("id");
|
||
theChooseCurrent.classList.add("chosen");
|
||
|
||
var edit_submenu = document.createElement('ol');
|
||
editorLog("J1 lookinh for menu options for", current_env_id);
|
||
edit_submenu.innerHTML = menu_options_for(current_env_id, "", "change");
|
||
editorLog("just inserted inner menu_options_for(parent_type)", menu_options_for(current_env_id, "", "change"));
|
||
theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu);
|
||
document.getElementById('choose_current').focus();
|
||
editorLog("focus is on", $(":focus"));
|
||
} else if (dataAction == 'modify') {
|
||
// #edit_menu_holder is in span.type, inside .heading, inside article
|
||
current_env = document.getElementById('edit_menu_holder').parentElement;
|
||
current_env_id = current_env.id;
|
||
|
||
if (!dataModifier) {
|
||
theChooseCurrent.parentElement.classList.add("past");
|
||
theChooseCurrent.removeAttribute("id");
|
||
theChooseCurrent.classList.add("chosen");
|
||
|
||
var edit_submenu = document.createElement('ol');
|
||
// this may only hapen when adjusting workspace:
|
||
if (!current_env_id) {
|
||
edit_submenu.setAttribute('id', 'edit_menu');
|
||
edit_submenu.setAttribute('class', 'edit_menu');
|
||
current_env_id = current_env.getAttribute("data-parent_id");
|
||
editorLog("current_env_id", current_env_id);
|
||
}
|
||
editorLog("J2a looking for menu options for", current_env_id);
|
||
edit_submenu.innerHTML = menu_options_for(current_env_id, "", "modify");
|
||
editorLog("just inserted inner menu_options_for(parent_type)", menu_options_for(current_env_id, "", "modify"));
|
||
if (theChooseCurrent.tagName == "SPAN") { // when adjusting workspace
|
||
theChooseCurrent.replaceWith(edit_submenu);
|
||
} else {
|
||
theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu);
|
||
}
|
||
document.getElementById('choose_current').focus();
|
||
editorLog("focus is on", $(":focus"));
|
||
} else if (dataModifier == "done") {
|
||
edit_menu_from_current_editing("entering");
|
||
} else if (dataModifier == "arrows") {
|
||
// setup_arrow_modify() // is different for images and SBSs
|
||
} else {
|
||
// this may only hapen when adjusting workspace:
|
||
if (!current_env_id) {
|
||
current_env_id = current_env.getAttribute("data-parent_id");
|
||
editorLog("current_env_id from parent", current_env_id);
|
||
}
|
||
modify_by_id(current_env_id, dataModifier)
|
||
}
|
||
} else if (dataAction == "move-or-delete") {
|
||
// almost all repeats from dataAction == 'change-env'
|
||
// except for current_env and menu options for. Consolidate
|
||
// maybe also separate actions which give anotehr menu, from actions which change content
|
||
current_env = document.getElementById('edit_menu_holder').parentElement;
|
||
editorLog("current_env", current_env);
|
||
current_env_id = current_env.id;
|
||
|
||
theChooseCurrent.parentElement.classList.add("past");
|
||
theChooseCurrent.removeAttribute("id");
|
||
theChooseCurrent.classList.add("chosen");
|
||
|
||
var edit_submenu = document.createElement('ol');
|
||
editorLog("J3 looking for menu options for", current_env_id);
|
||
edit_submenu.innerHTML = menu_options_for(current_env_id, "", "move-or-delete");
|
||
editorLog("just inserted inner menu_options_for(parent_type)", menu_options_for(current_env_id, "", "move-or-delete"));
|
||
theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu);
|
||
document.getElementById('choose_current').focus();
|
||
editorLog("focus is on", $(":focus"));
|
||
} else if (dataAction == "delete") {
|
||
current_env = document.getElementById('edit_menu_holder').parentElement;
|
||
editorLog("current_env", current_env);
|
||
current_env_id = current_env.id;
|
||
delete_by_id(current_env_id, "choice")
|
||
} else if (["move-local", "move-local-p", "move-local-li"].includes(dataAction)) {
|
||
current_env = document.getElementById('edit_menu_holder').parentElement;
|
||
current_env_id = current_env.id;
|
||
handle_env_id = current_env_id; // we were focused on that p, even though
|
||
// we are moving an li. Later refocus on p
|
||
if (dataAction == "move-local-li") {
|
||
current_env.classList.remove("may_select");
|
||
current_env = current_env.parentElement;
|
||
current_env.classList.add("may_select");
|
||
current_env_id = current_env.id;
|
||
}
|
||
editorLog("current_env", current_env);
|
||
move_by_id_local(current_env_id, handle_env_id)
|
||
} else if (dataAction == "change-title") {
|
||
var this_heading = document.getElementById('edit_menu_holder').parentElement.parentElement;
|
||
var this_env_id = this_heading.getAttribute("data-parent_id");
|
||
var new_title_form = standard_title_form(this_env_id);
|
||
document.getElementById('edit_menu_holder').parentElement.insertAdjacentHTML("afterend",new_title_form);
|
||
document.getElementById('edit_menu_holder').parentElement.remove();
|
||
editorLog("change-title in progress")
|
||
document.getElementById('actively_editing').focus();
|
||
} else if (dataAction == "change-caption") {
|
||
alert("editing captions not implemented yet");
|
||
return ;
|
||
var this_caption = document.getElementById('edit_menu_holder').parentElement;
|
||
var this_env_id = this_caption.getAttribute("data-source_id");
|
||
var new_title_form = standard_caption_form(this_env_id);
|
||
document.getElementById('edit_menu_holder').parentElement.insertAdjacentHTML("afterend",new_title_form);
|
||
document.getElementById('edit_menu_holder').parentElement.remove();
|
||
editorLog("change-caption in progress")
|
||
document.getElementById('actively_editing').focus();
|
||
} else {
|
||
editorLog("unknown dataAction", dataAction);
|
||
alert("I don;t know what to do llllllll dataAction " + dataAction)
|
||
}
|
||
} // dataAction
|
||
else if (dataEnv) { // this has to come after dataAction, because if both occur,
|
||
// dataAction says to do something, and dataEnv says what to do
|
||
e.preventDefault(); // was this handled earlier?
|
||
editorLog("in dataEnv", dataEnv);
|
||
editorLog("selected a menu item with no action and no location");
|
||
$("#choose_current").parent().addClass("past");
|
||
editorLog("apparently selected", theChooseCurrent);
|
||
theChooseCurrent.removeAttribute("id");
|
||
theChooseCurrent.setAttribute('class', 'chosen');
|
||
|
||
// if (dataEnv in inner_menu_for()) { // object names a collection, so make submenu
|
||
if (dataEnv in submenu_options) { // object names a collection, so make submenu
|
||
editorLog("making a menu for", dataEnv);
|
||
var edit_submenu = document.createElement('ol');
|
||
edit_submenu.innerHTML = menu_options_for("", dataEnv, "inner");
|
||
theChooseCurrent.insertAdjacentElement("beforeend", edit_submenu);
|
||
document.getElementById('choose_current').focus();
|
||
|
||
// determine whether both of these next cases can occur
|
||
} else if (dataEnv in objectStructure || dataEnvParent in objectStructure) {
|
||
// we just selected an action, so do it
|
||
// that probably involves adding something before or after a given object
|
||
editorLog("making a new", dataEnv, "within", dataEnvParent);
|
||
|
||
var before_after = $("#edit_menu_holder > #edit_menu > .chosen").attr("data-location");
|
||
|
||
if (dataEnv == "source") {
|
||
alert(" making source");
|
||
show_source(object_of_interest, before_after);
|
||
edit_menu_from_current_editing("entering");
|
||
return
|
||
// } else if (dataEnv == "save") {
|
||
// save_source();
|
||
// edit_menu_from_current_editing("entering");
|
||
}
|
||
editorLog("create object to edit",dataEnv, object_of_interest, before_after);
|
||
var new_obj = create_object_to_edit(dataEnv, object_of_interest, before_after);
|
||
if (!new_obj) { edit_menu_from_current_editing("entering"); return "" }
|
||
editorLog("new_obj", new_obj);
|
||
edit_in_place(new_obj, "new");
|
||
var new_obj_id = new_obj.id;
|
||
editorLog("are we editing id", new_obj_id);
|
||
editorLog("are we editing", new_obj);
|
||
editorLog(" JJJ current_editing", current_editing["level"], current_editing["location"].length, current_editing["tree"].length, current_editing["tree"][current_editing["level"]]);
|
||
editorLog(" current_editing", current_editing);
|
||
object_of_interest.classList.remove("may_select");
|
||
object_of_interest.classList.remove("may_enter");
|
||
if (tmp = document.getElementById('edit_menu_holder')) { tmp.remove() }
|
||
if (dataEnv.startsWith("sbs")) {
|
||
editorLog("added sbs, now add to it", new_obj_id);
|
||
editorLog("document.getElementById(new_obj_id)", document.getElementById(new_obj_id));
|
||
var first_panel_id = document.getElementById(new_obj_id).firstElementChild.firstElementChild.id;
|
||
editorLog("first_panel_id", first_panel_id, document.getElementById(first_panel_id));
|
||
make_current_editing_tree_from_id(first_panel_id);
|
||
edit_menu_from_current_editing("entering");
|
||
}
|
||
} else {
|
||
editorLog("Error: unknown dataEnv", dataEnv);
|
||
editorLog("Or maybe unknown dataEnvParent", dataEnvParent);
|
||
editorLog("moving up the menu -- not");
|
||
alert("Sorry, not implemented yet!");
|
||
theChooseCurrent.classList.remove("chosen");
|
||
theChooseCurrent.parentElement.classList.remove("past");
|
||
theChooseCurrent.setAttribute("id", "choose_current");
|
||
}
|
||
}
|
||
} // // dataEnv
|
||
else {
|
||
editorLog("key that is not meaningful when navigating a menu:", e.code)
|
||
}
|
||
}
|
||
} // main menu navigator
|
||
|
||
editorLog("adding tab listener");
|
||
|
||
document.addEventListener('keydown', logKeyDown);
|
||
|
||
function logKeyDown(e) {
|
||
if (e.code == "ShiftLeft" || e.code == "ShiftRight" || e.code == "Shift") { return }
|
||
prev_prev_char = prev_char;
|
||
prev_char = this_char;
|
||
this_char = e;
|
||
editorLog("logKey",e,"XXX",e.code);
|
||
editorLog("are we editing", document.getElementById('actively_editing'));
|
||
editorLog("is there already an edit menu?", document.getElementById('edit_menu_holder'));
|
||
|
||
var input_region = document.activeElement;
|
||
editorLog("input_region", input_region);
|
||
// if we are writing something, keystrokes usually are just text input
|
||
if (document.getElementById('actively_editing')) {
|
||
editorLog(" we are actively editing");
|
||
|
||
if (e.code == "Tab" && !document.getElementById('local_menu_holder')) {
|
||
// disabled for now
|
||
e.preventDefault();
|
||
return ""
|
||
create_local_menu()
|
||
} else if (document.getElementById('local_menu_holder')) {
|
||
main_menu_navigator(e);
|
||
} else {
|
||
local_editing_action(e)
|
||
}
|
||
|
||
} else if (document.getElementById('phantomobject')) {
|
||
var the_phantomobject = document.getElementById('phantomobject');
|
||
|
||
if (the_phantomobject.classList.contains('move')) {
|
||
move_object(e)
|
||
} else {
|
||
alert("do not know what to do with that")
|
||
}
|
||
} else {
|
||
main_menu_navigator(e);
|
||
}
|
||
}
|
||
|
||
document.addEventListener('focus', function() {
|
||
// editorLog('focused:', document.activeElement)
|
||
// editorLog('which has content XX' + document.activeElement.innerHTML + "VV")
|
||
prev_prev_focused_element = prev_focused_element;
|
||
prev_focused_element = this_focused_element;
|
||
this_focused_element = document.activeElement;
|
||
$('.in_edit_tree').removeClass('in_edit_tree');
|
||
// $(':focus').parent().addClass('in_edit_tree');
|
||
$('#edit_menu_holder:first-child').parent().addClass('in_edit_tree');
|
||
$('#edit_menu_holder').prev().addClass('in_edit_tree');
|
||
/*
|
||
var edit_tree = $(':focus').parents();
|
||
// put little lines on teh right, to show the local heirarchy
|
||
for (var i=0; i < edit_tree.length; ++i) {
|
||
if (edit_tree[i].getAttribute('id') == "content") { break }
|
||
edit_tree[i].classList.add('in_edit_tree')
|
||
}
|
||
*/
|
||
}, true);
|
||
|
||
function initialize_editing(xml_st) {
|
||
|
||
createCookie(chosen_edit_option_key,1,0.01);
|
||
// console.log("QQQQQQQQ", xml_st, "PPPPPPPPPP");
|
||
// Space Math uses a blank line to indicate mrows
|
||
xml_st = xml_st.replace(/<\/mrow>\s*<mrow>/g, " \n\\cr\n ");
|
||
xml_st = xml_st.replace(/<mrow>/g, " ");
|
||
xml_st = xml_st.replace(/<\/mrow>/g, " ");
|
||
|
||
xmlToObject(xml_st);
|
||
record_children(sourceobj);
|
||
internalSource = re_transform_source();
|
||
|
||
console.log("mostly done initializing");
|
||
console.log(internalSource);
|
||
|
||
current_editing = {
|
||
"level": 0,
|
||
"location": [0],
|
||
// "tree": [ [document.getElementById(top_level_id)] ]
|
||
"tree": [ [internalSource.root_data.id] ]
|
||
}
|
||
console.log("initial current_editing", current_editing);
|
||
|
||
e_tree = current_editing["tree"];
|
||
editorLog("e_tree", e_tree);
|
||
e_level = current_editing["level"];
|
||
editorLog("e_level", e_level);
|
||
e_location = current_editing["location"];
|
||
editorLog("e_location", e_location);
|
||
console.log(" making the initial menu for", e_tree[e_level][e_location]);
|
||
|
||
// document.getElementById("content").firstElementChild.setAttribute("id", internalSource.root_data.id);
|
||
|
||
console.log("replacing by id", internalSource.root_data.id);
|
||
replace_by_id(internalSource.root_data.id, "html");
|
||
|
||
edit_menu_for(e_tree[e_level][e_location], "entering")
|
||
|
||
console.log("internalSource internalSource internalSource internalSource internalSource internalSource", internalSource);
|
||
|
||
// done rebulding HTML, so now process math
|
||
// NOT CURRENTLY DOING ANYTHING????
|
||
console.log("ready to edit, so typeset the math");
|
||
document.getElementById("content").classList.add("canedit");
|
||
MathJax.typesetPromise();
|
||
}
|
||
|
||
var this_source_txt;
|
||
var source_url = window.location.href;
|
||
source_url = source_url.replace(/(#|\?).*/, "");
|
||
source_url = source_url.replace(/html$/, "ptx");
|
||
fetch(source_url).then(
|
||
function(u){ return u.text();}
|
||
).then(
|
||
function(text){
|
||
this_source_txt = text;
|
||
// console.log("ppppppppppp this_source_txt",this_source_txt)
|
||
if (this_source_txt.includes("404 Not")) {
|
||
console.log("Error: source unavailable")
|
||
} else if (this_source_txt.includes("<biblio ")) {
|
||
console.log("Editing bibliographies not implemented")
|
||
} else if( false && editing_mode) {
|
||
initialize_editing(this_source_txt)
|
||
} else {
|
||
console.log("editing_mode", editing_mode)
|
||
edit_choice = document.createElement('span');
|
||
edit_choice.setAttribute("class", "login-link");
|
||
// edit_choice.innerHTML = "<span id='edit_choice'>Edit this page</span>";
|
||
// document.getElementById("content").insertAdjacentElement("afterbegin", edit_choice);
|
||
if(editing_mode) {
|
||
initialize_editing(this_source_txt)
|
||
// edit_choice.innerHTML = "<span id='edit_choice'>Stop editing this page</span>";
|
||
edit_choice.innerHTML = "";
|
||
} else {
|
||
edit_choice.innerHTML = "<span id='edit_choice'>Edit this page</span>";
|
||
}
|
||
document.getElementById("ptx-content").insertAdjacentElement("beforeend", edit_choice);
|
||
console.log("editing choice enabled")
|
||
$("#edit_choice").on("click", function(event){
|
||
console.log("apparently you want to edit");
|
||
initialize_editing(this_source_txt)
|
||
document.getElementById("edit_choice").remove();
|
||
});
|
||
}
|
||
}
|
||
);
|
||
|
||
console.log("fetched source");
|
||
|
||
|
||
// make the top level menu
|
||
/* make a function which is called after the source is imported
|
||
|
||
e_tree = current_editing["tree"];
|
||
editorLog("e_tree", e_tree);
|
||
e_level = current_editing["level"];
|
||
editorLog("e_level", e_level);
|
||
e_location = current_editing["location"];
|
||
editorLog("e_location", e_location);
|
||
console.log(" making the initial menu for", e_tree[e_level][e_location]);
|
||
edit_menu_for(e_tree[e_level][e_location], "entering")
|
||
*/
|
||
|
||
function xml_id_of(xml) {
|
||
var this_id = "";
|
||
if (xml.attributes.length > 0) {
|
||
// bad code because I dopied and was too lazy to rewrite
|
||
parseLog(xml.nodeName, "has attributes", xml.attributes);
|
||
for (var j = 0; j < xml.attributes.length; j++) {
|
||
var attribute = xml.attributes.item(j);
|
||
if (attribute.nodeName == "permid") { this_id = attribute.nodeValue }
|
||
// these look backward, but that seems to be how PTX does it currently
|
||
if (!this_id && attribute.nodeName == "xml:id") { this_id = attribute.nodeValue }
|
||
}
|
||
}
|
||
if (!this_id) {
|
||
this_id = randomstring()
|
||
}
|
||
return this_id
|
||
}
|
||
|
||
var sourceobj = {};
|
||
var new_top_id = "";
|
||
|
||
function xmlToObject(xml_st) {
|
||
var xml;
|
||
if (typeof xml_st == "string") {
|
||
// parseLog("xml starts", xml_st.slice(0,50));
|
||
parser = new DOMParser();
|
||
xml = parser.parseFromString(xml_st, "text/xml");
|
||
// xml = $.parseXML(xml_st);
|
||
} else {
|
||
xml = xml_st
|
||
}
|
||
|
||
parseLog("xml", xml);
|
||
parseLog("xml.nodeName", xml.nodeName, "xml.nodeType", xml.nodeType);
|
||
// var obj = {};
|
||
var this_id = "";
|
||
var this_node_content = xml.nodeValue;
|
||
|
||
if (xml.nodeType == 9) { // document
|
||
xml = xml.documentElement;
|
||
}
|
||
|
||
parseLog("this_node_content", this_node_content);
|
||
|
||
if (xml.nodeType == 1) { // element
|
||
this_id = xml_id_of(xml);
|
||
if (!new_top_id) {
|
||
new_top_id = this_id;
|
||
top_level_id = new_top_id;
|
||
sourceobj["root_data"] = {"id": new_top_id, "number_base": "X.Y"}
|
||
}
|
||
parseLog("found this_id", this_id);
|
||
var this_entry = {};
|
||
this_entry["xml:id"] = this_id;
|
||
if (["ol", "ul", "dl"].includes(xml.nodeName)) {
|
||
this_entry["sourcetag"] = "list"
|
||
/*
|
||
} else if (["me", "men"].includes(xml.nodeName)){
|
||
this_entry["sourcetag"] = "displaymath"
|
||
*/
|
||
} else {
|
||
this_entry["sourcetag"] = xml.nodeName;
|
||
}
|
||
|
||
this_node_content = "";
|
||
if (xml.hasChildNodes()) {
|
||
for (var i = 0; i < xml.childNodes.length; i++) {
|
||
var item = xml.childNodes.item(i);
|
||
if (item.nodeType == 8) {
|
||
//comment, so skip
|
||
} else if (item.nodeType == 3) { // text
|
||
this_node_content += item.nodeValue
|
||
} else if (item.nodeType == 1) { // element
|
||
var sub_node_id = xmlToObject(item); // the contents, in certain cases
|
||
if (contained_objects.includes(item.nodeName)) {
|
||
this_entry[item.nodeName] = sub_node_id
|
||
} else {
|
||
this_node_content += "<&>" + sub_node_id + "<;>"
|
||
}
|
||
} else {
|
||
parseLog("what to do with this node?", item)
|
||
}
|
||
}
|
||
}
|
||
if (this_node_content) {
|
||
this_entry["content"] = this_node_content.trim();
|
||
}
|
||
|
||
if (xml.attributes.length > 0) {
|
||
// parseLog(xml.nodeName, "has attributes", xml.attributes);
|
||
for (var j = 0; j < xml.attributes.length; j++) {
|
||
var attribute = xml.attributes.item(j);
|
||
if (attribute.nodeName == "source") { this_entry["source"] = attribute.nodeValue }
|
||
else if (attribute.nodeName == "ref") { this_entry["ref"] = attribute.nodeValue }
|
||
else if (attribute.nodeName == "text") { this_entry["text"] = attribute.nodeValue }
|
||
// width for images, widths for sbs
|
||
else if (attribute.nodeName == "width") {
|
||
var widthvalue = attribute.nodeValue;
|
||
if (widthvalue.endsWith("%")) { widthvalue = widthvalue.slice(0,-1); }
|
||
this_entry["width"] = widthvalue
|
||
} else if (attribute.nodeName == "margins") {
|
||
var marginsvalues = attribute.nodeValue.split(' ');
|
||
if (marginsvalues.length == 1) {
|
||
var margin = marginsvalues[0];
|
||
if (margin.endsWith("%")) { margin = margin.slice(0,-1); }
|
||
this_entry["marginleft"] = margin;
|
||
this_entry["marginright"] = margin;
|
||
} else if (marginsvalues.length == 2) {
|
||
var [marginleft, marginright] = marginsvalues;
|
||
if (marginleft.endsWith("%")) { marginleft = marginleft.slice(0,-1); }
|
||
if (marginright.endsWith("%")) { marginright = marginright.slice(0,-1); }
|
||
this_entry["marginleft"] = marginleft;
|
||
this_entry["marginright"] = marginright;
|
||
} else {
|
||
console.log("Error: too many margins in", xml)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// The CAT expects a width and margins on an image, but those myght not be
|
||
// specified in the source. So add those if not present.
|
||
if (xml.nodeName == "image") {
|
||
console.log("image attributes", xml.attributes, "ddd", xml.attributes["source"]);
|
||
if (!xml.attributes["width"]) {
|
||
console.log("no width");
|
||
this_entry["width"] = 100;
|
||
}
|
||
if (!xml.attributes["margins"]) {
|
||
console.log("no margins");
|
||
this_entry["marginleft"] = 0;
|
||
this_entry["marginright"] = 0;
|
||
}
|
||
}
|
||
|
||
if (xml.attributes) {
|
||
parseLog(xml, "has attributes", xml.attributes)
|
||
}
|
||
// parseLog("item", item);
|
||
if (contained_objects.includes(xml.nodeName)) {
|
||
return this_node_content
|
||
} else {
|
||
sourceobj[this_id] = this_entry
|
||
return this_id
|
||
}
|
||
} else if (xml.nodeType == 8) {
|
||
// comment node, so do nothing
|
||
this_node_content = ""
|
||
} else if (xml.nodeType == 3) { // text
|
||
// can this, or the previous case, actually happen?
|
||
} else {
|
||
console.log("failed to deal with", xml)
|
||
}
|
||
}
|
||
|
||
function record_children(internal_src) {
|
||
for (key in internal_src) {
|
||
var this_item = internal_src[key];
|
||
if ("content" in this_item) { // skip empty tags
|
||
var this_content = this_item["content"];
|
||
parseLog("this_content", this_content);
|
||
var child_items = this_content.match(/<&>.*?<;>/g) || "";
|
||
for (var j=0; j < child_items.length; ++j) {
|
||
var this_child = child_items[j].slice(3,-3);
|
||
parseLog("this_child", this_child, "has a parent", key);
|
||
internal_src[this_child]["parent"] = [key, "content"]
|
||
}
|
||
}
|
||
// need to handle content and statement better
|
||
if ("statement" in this_item) { // skip empty tags
|
||
var this_statement = this_item["statement"];
|
||
// parseLog("this_statement", this_statement);
|
||
var child_items = this_statement.match(/<&>.*?<;>/g) || "";
|
||
for (var j=0; j < child_items.length; ++j) {
|
||
var this_child = child_items[j].slice(3,-3);
|
||
// parseLog("this_child", this_child, "has a parent", key);
|
||
internal_src[this_child]["parent"] = [key, "statement"]
|
||
}
|
||
}
|
||
if ("proof" in this_item) { // skip empty tags
|
||
var this_proof = this_item["proof"];
|
||
// parseLog("this_statement", this_statement);
|
||
var child_items = this_proof.match(/<&>.*?<;>/g) || "";
|
||
for (var j=0; j < child_items.length; ++j) {
|
||
var this_child = child_items[j].slice(3,-3);
|
||
// parseLog("this_child", this_child, "has a parent", key);
|
||
internal_src[this_child]["parent"] = [key, "proof"]
|
||
}
|
||
}
|
||
}
|
||
return internal_src
|
||
}
|
||
|
||
// transofrm again, to un-wrap list in p
|
||
|
||
/* rewrite with sourceobj not global */
|
||
function re_transform_source() {
|
||
var ids_to_delete = [];
|
||
for (var id in sourceobj) {
|
||
var this_item = sourceobj[id];
|
||
if (this_item["sourcetag"] == "list") {
|
||
// I think this takes the list out of its parent p,
|
||
// but I forgot to write this comment when I first wrote the code.
|
||
parseLog("found a list", this_item);
|
||
var [parent_id, parent_content] = this_item["parent"];
|
||
parseLog("with parent", sourceobj[parent_id]);
|
||
if (sourceobj[parent_id]["sourcetag"] == "p") {
|
||
var [parent_parent_id, parent_parent_content] = sourceobj[parent_id]["parent"];
|
||
parseLog("with parents parent", sourceobj[parent_parent_id]);
|
||
// need to skip the intermediate parent
|
||
var old_p_p_content = sourceobj[parent_parent_id][parent_parent_content];
|
||
var new_p_p_content = old_p_p_content.replace("<&>" + parent_id + "<;>", "<&>" + id + "<;>");
|
||
sourceobj[parent_parent_id][parent_parent_content] = new_p_p_content;
|
||
sourceobj[id]["parent"] = [parent_parent_id, parent_parent_content];
|
||
// then eliminate the intermediate parent
|
||
parseLog("deleting", parent_id);
|
||
// delete sourceobj[parent_id];
|
||
ids_to_delete.push(parent_id);
|
||
parseLog("now sourceobj[parent_parent_id]", sourceobj[parent_parent_id])
|
||
}
|
||
} else if (this_item["sourcetag"] == "image") {
|
||
if ("width" in this_item && !("marginleft" in this_item)) {
|
||
parseLog("no width in" + this_item["xml:id"])
|
||
var width = parseInt(this_item["width"]);
|
||
var margins = (100 - width)*0.5;
|
||
this_item["marginleft"] = margins;
|
||
this_item["marginright"] = margins;
|
||
}
|
||
} else if (["md", "mdn", "me", "men"].includes(this_item["sourcetag"])) {
|
||
// to handle the case of more than one displaymath in a p,
|
||
// we do it in two passes. First we just record the ids of the me/men's.
|
||
// Then we simplify the problem by handling the displaymath in the
|
||
// order they occur.
|
||
parseLog("found displaymath", this_item);
|
||
parseLog("with parent", sourceobj[this_item["parent"][0]]);
|
||
var displaymath_id= this_item["xml:id"];
|
||
if ("includedmath" in sourceobj[this_item["parent"][0]]) {
|
||
sourceobj[this_item["parent"][0]]["includedmath"].push("<&>" + displaymath_id + "<;>")
|
||
} else {
|
||
sourceobj[this_item["parent"][0]]["includedmath"] = ["<&>" + displaymath_id + "<;>"]
|
||
}
|
||
} else if (["caption"].includes(this_item["sourcetag"])) {
|
||
parseLog("found a caption", this_item);
|
||
var [parent_id, parent_content] = this_item["parent"];
|
||
parseLog("with parent", sourceobj[parent_id]);
|
||
if (sourceobj[parent_id]["sourcetag"] == "figure") {
|
||
var old_p_content = sourceobj[parent_id][parent_content];
|
||
var new_p_content = old_p_content.replace("<&>" + id + "<;>", "");
|
||
sourceobj[parent_id][parent_content] = new_p_content;
|
||
sourceobj[parent_id]["captiontext"] = sourceobj[id]["content"];
|
||
// then eliminate the caption object, because now it is an attribute of a figure
|
||
// delete sourceobj[id];
|
||
ids_to_delete.push(id);
|
||
parseLog("now sourceobj[parent_id]", sourceobj[parent_id])
|
||
alert("testing")
|
||
} else { alert("error: caption not in figure") }
|
||
}
|
||
}
|
||
// now go through and fix the "p" containing displaymath
|
||
for (var id in sourceobj) {
|
||
var this_item = sourceobj[id];
|
||
if (this_item["sourcetag"] == "p") {
|
||
if ("includedmath" in this_item) {
|
||
console.log("found includedmath", this_item);
|
||
var outer_parent = this_item["parent"];
|
||
var context_of_outer_parent = sourceobj[outer_parent[0]][outer_parent[1]];
|
||
console.log("this item id", id, "with parent", outer_parent, "in context", context_of_outer_parent);
|
||
var these_includedmath = this_item["includedmath"];
|
||
var this_content = this_item["content"];
|
||
var these_includedmath_index = [];
|
||
for (var j=0; j < these_includedmath.length; ++j) {
|
||
var this_math_tag = these_includedmath[j];
|
||
these_includedmath_index.push([this_content.indexOf(this_math_tag),this_math_tag]);
|
||
console.log("this_math_tag", this_math_tag, "has index", this_content.indexOf(this_math_tag))
|
||
}
|
||
these_includedmath_index.sort();
|
||
parseLog("sorted list", these_includedmath_index)
|
||
|
||
// var displaymath_parent_original_content = sourceobj[outer_parent[0]]["content"];
|
||
parseLog("ocntent before splitting up", context_of_outer_parent);
|
||
this_math_tag = these_includedmath_index[0][1];
|
||
parseLog("this_math_tag", this_math_tag);
|
||
var this_math_id = this_math_tag.slice(3,-3);
|
||
parseLog("this_math_id", this_math_id);
|
||
parseLog("with source", sourceobj[this_math_id]);
|
||
// move punctuation inside the display math
|
||
// (for easier editing. move it back out later)
|
||
var find_char_after = new RegExp('^(.*' + this_math_tag + ")(.)\s*(.*)$", "s");
|
||
var char_after = this_content.replace(find_char_after, "$2");
|
||
if ([".", ",", ";", ":"].includes(char_after)) {
|
||
console.log("found punctuation", char_after);
|
||
this_content = this_content.replace(find_char_after, "$1$3"); // go back an omit white space
|
||
sourceobj[this_math_id]["content"] += char_after
|
||
}
|
||
// the original p ends at the first displaymath
|
||
var displaymath_id_and_before = new RegExp('^.*' + this_math_tag, "s"); // s = dotAll
|
||
var displaymath_id_and_after = new RegExp(this_math_tag + '.*$', "s");
|
||
sourceobj[id]["content"] =
|
||
this_content.replace(displaymath_id_and_after, "");
|
||
sourceobj[id]["sourcetag"] = "ip"
|
||
this_content = this_content.replace(displaymath_id_and_before, "");
|
||
parseLog("updated this_content", this_content);
|
||
// the first displaymath now has a different parent
|
||
sourceobj[this_math_id]["parent"] = outer_parent;
|
||
// that parent needs to know where to put the first displaymath
|
||
context_of_outer_parent = context_of_outer_parent.replace("<&>" + id + "<;>", "<&>" + id + "<;>" + "\n" + this_math_tag);
|
||
parseLog("updated context_of_outer_parent", context_of_outer_parent);
|
||
sourceobj[outer_parent[0]][outer_parent[1]] = context_of_outer_parent;
|
||
// here need to check if this_content is nonempty (after removing trailing white space
|
||
var new_id = "XXXX" + randomstring();
|
||
sourceobj[new_id] = {"xml:id":new_id, "sourcetag": "mp"};
|
||
sourceobj[new_id]["content"] = this_content;
|
||
sourceobj[new_id]["parent"] = outer_parent;
|
||
context_of_outer_parent = context_of_outer_parent.replace(this_math_tag, this_math_tag + "\n" + "<&>" + new_id + "<;>");
|
||
sourceobj[outer_parent[0]][outer_parent[1]] = context_of_outer_parent;
|
||
for (var j=1; j < these_includedmath_index.length; ++j) {
|
||
this_math_tag = these_includedmath_index[j][1];
|
||
this_math_id = this_math_tag.slice(3,-3);
|
||
|
||
// move punctuation inside the display math
|
||
// (for easier editing. move it back out later)
|
||
var find_char_after = new RegExp('^(.*' + this_math_tag + ")(.)\s*(.*)$", "s");
|
||
var char_after = this_content.replace(find_char_after, "$2");
|
||
if ([".", ",", ";", ":"].includes(char_after)) {
|
||
console.log("found punctuation", char_after);
|
||
this_content = this_content.replace(find_char_after, "$1$3"); // go back an omit white space
|
||
sourceobj[this_math_id]["content"] += char_after
|
||
}
|
||
|
||
displaymath_id_and_before = new RegExp('^.*' + this_math_tag, "s"); // s = dotAll
|
||
displaymath_id_and_after = new RegExp(this_math_tag + '.*$', "s");
|
||
sourceobj[new_id]["content"] = this_content.replace(displaymath_id_and_after, "");
|
||
this_content = this_content.replace(displaymath_id_and_before, "");
|
||
// this displaymath now has a different parent
|
||
sourceobj[this_math_id]["parent"] = outer_parent;
|
||
// that parent needs to know where to put the first displaymath
|
||
context_of_outer_parent = context_of_outer_parent.replace("<&>" + new_id + "<;>", "<&>" + new_id + "<;>" + "\n" + this_math_tag);
|
||
sourceobj[outer_parent[0]][outer_parent[1]] = context_of_outer_parent;
|
||
// omit next if this_content is only white space
|
||
new_id = "XXXX" + randomstring();
|
||
sourceobj[new_id] = {"xml:id":new_id, "sourcetag": "mp"};
|
||
sourceobj[new_id]["content"] = this_content;
|
||
sourceobj[new_id]["parent"] = outer_parent;
|
||
context_of_outer_parent = context_of_outer_parent.replace(this_math_tag, this_math_tag + "\n" + "<&>" + new_id + "<;>");
|
||
sourceobj[outer_parent[0]][outer_parent[1]] = context_of_outer_parent;
|
||
}
|
||
sourceobj[new_id]["sourcetag"] = "fp"
|
||
}
|
||
}
|
||
}
|
||
// trim leading white space in paragraph content
|
||
for (var id in sourceobj) {
|
||
var this_item = sourceobj[id];
|
||
if (["p", "ip", "mp", "fp"].includes(this_item["sourcetag"])) {
|
||
var this_content = sourceobj[id]["content"];
|
||
this_content = this_content.replace(/\n +/g, "\n");
|
||
sourceobj[id]["content"] = this_content;
|
||
} else if (["me", "men", "md", "mdn"].includes(this_item["sourcetag"])) {
|
||
var this_content = sourceobj[id]["content"];
|
||
this_content = this_content.replace(/\n +/g, "\n ");
|
||
sourceobj[id]["content"] = this_content;
|
||
}
|
||
// next also needs table (or whatever it is that has a caption)
|
||
if (["figure"].includes(this_item["sourcetag"])) {
|
||
editorLog("adjusting a figure", this_item);
|
||
// ??? next line should involve captiontext instead of caption ?
|
||
var this_caption = sourceobj[id]["caption"];
|
||
this_caption = this_caption.replace(/\n +/g, "\n");
|
||
sourceobj[id]["captiontext"] = this_caption;
|
||
}
|
||
}
|
||
|
||
for (var j=1; j < ids_to_delete.length; ++j) {
|
||
// delete sourceobj[ids_to_delete[j]]
|
||
}
|
||
|
||
return sourceobj;
|
||
}
|
||
|