Skip to content

Commit

Permalink
Dev main 1.0β38 base (#176)
Browse files Browse the repository at this point in the history
* Center/right alignment (#165)

* Update gdc.gs

Added center/right alignment handling.

* Update html.gs

Added center/right alignment handling for headings. Adds text-align to header tag.

* Update gdc.gs

* Update gdc.gs

Tweaked if statement to allow for Markdown right-alignment.

* Superscript fix (#166)

* Update gdc.gs

Added center/right alignment handling.

* Update html.gs

Added center/right alignment handling for headings. Adds text-align to header tag.

* Update gdc.gs

* Update gdc.gs

Moves closing of styles to the beginning of the loop to close styles before opening new ones. Moves opening superscript later in the loop with the other attributes.

* Update gdc.gs

Updated version info.

---------

Co-authored-by: evbacher <[email protected]>

* Add markdown checkboxes (#167)

* Update gdc.gs

Added center/right alignment handling.

* Update html.gs

Added center/right alignment handling for headings. Adds text-align to header tag.

* Update gdc.gs

* Update gdc.gs

Moves closing of styles to the beginning of the loop to close styles before opening new ones. Moves opening superscript later in the loop with the other attributes.

* Update gdc.gs

Updated version info.

* Update gdc.gs

Added support for Markdown checkboxes.

---------

Co-authored-by: evbacher <[email protected]>

* Target=" blank" (#168)

* Update gdc.gs

Added center/right alignment handling.

* Update html.gs

Added center/right alignment handling for headings. Adds text-align to header tag.

* Update gdc.gs

* Update gdc.gs

Moves closing of styles to the beginning of the loop to close styles before opening new ones. Moves opening superscript later in the loop with the other attributes.

* Update gdc.gs

Updated version info.

* Update gdc.gs

Added support for Markdown checkboxes.

* Update sidebar.html

Add option for target="_blank" to menu

* Update gdc.gs

Adds target="_blank" to links in HTML if target="_blank" is selected in the sidebar.

* Update gdc.gs

Updated version number.

* Update gdc.gs

Add a comment that points to glyph type enum doc in case this ever breaks.

---------

Co-authored-by: evbacher <[email protected]>

* Close <li> tags (#169)

* Update gdc.gs

Added center/right alignment handling.

* Update html.gs

Added center/right alignment handling for headings. Adds text-align to header tag.

* Update gdc.gs

* Update gdc.gs

Moves closing of styles to the beginning of the loop to close styles before opening new ones. Moves opening superscript later in the loop with the other attributes.

* Update gdc.gs

Updated version info.

* Update gdc.gs

Added support for Markdown checkboxes.

* Update sidebar.html

Add option for target="_blank" to menu

* Update gdc.gs

Adds target="_blank" to links in HTML if target="_blank" is selected in the sidebar.

* Update gdc.gs

Updated version number.

* Update gdc.gs

Added list handling to properly close li tags. This makes sure they close at the end of the paragraph.

* Update html.gs

Added extra handling to close li tags. In short, they need to be closed right before opening a new li tag. Otherwise, they should be closed before closing out the whole list.

* Update gdc.gs

Updated files changed.

---------

Co-authored-by: evbacher <[email protected]>

* Remove target="_blank" for now (#171)

* Update gdc.gs

Remove target="_blank" option for now.

* Update sidebar.html

Remove target="_blank" option for now.

* Update appsscript.json 1.0B38 version

Update oauthScopes.

---------

Co-authored-by: sevenshamrocks <[email protected]>
  • Loading branch information
evbacher and sevenshamrocks authored Oct 12, 2024
1 parent 95f0195 commit eca9a00
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 55 deletions.
4 changes: 4 additions & 0 deletions addon/appsscript.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@
"https://www.googleapis.com/auth/script.container.ui"
],
"exceptionLogging": "STACKDRIVER",
"oauthScopes": [
"https://www.googleapis.com/auth/documents.currentonly",
"https://www.googleapis.com/auth/script.container.ui"
],
"runtimeVersion": "DEPRECATED_ES5"
}
119 changes: 78 additions & 41 deletions addon/gdc.gs
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,19 @@ gdc.banner = '<!-- NOTICE: Google recently added tabs to Google Docs: '
var DEBUG = false;
var LOG = false;
var GDC_TITLE = 'Docs to Markdown'; // formerly GD2md-html, formerly gd2md-html
var GDC_VERSION = '1.0β39'; // based on 1.0β38
var GDC_VERSION = '1.0β42'; // based on 1.0β41

// Version notes: significant changes (latest on top). (files changed)
/** - 1.0β40 (12 Oct 2024):
- Close list items before opening a new item. Close at the end of the list. (gdc, html)
- Add support for Markdown checkbox lists. (gdc)
- Fixes handling of superscript/subscript to close old styles before opening new style. Moves opening superscript/subscript later in process. (gdc)
- Added center/right alignment to HTML paragraph and heading handling. Will add text-align: center/right depending on paragraph formatting. (html, gdc)
*/
// - 1.0β39 (12 October 2024): Google Docs recently added a tab interface, which changes the TOC-generated id. This breaks internal links. This release fixes that bug. (gdc, html)
// - 1.0β38 (21 Sept 2024): Italic/bold markup default is now */**: _/__ is now an option. Reckless mode now includes Suppress info comment (removed sidebar option too). Also add a News link to gd2md-html news page in sidebar. (sidebar, gdc)
// - 1.0β37 (31 August 2024): Add a Questions link to gd2md-html Google group in sidebar (no functional changes).
/* - 1.0β36 (26 April 2024): Update required permissions: set explicitly in appsscript.json. No code changes. Using these Oauth scopes:
/** - 1.0β36 (26 April 2024): Update required permissions: set explicitly in appsscript.json. No code changes. Using these Oauth scopes:
"oauthScopes": [
"https://www.googleapis.com/auth/documents.currentonly",
"https://www.googleapis.com/auth/script.container.ui"
Expand Down Expand Up @@ -261,6 +267,7 @@ gdc.mdMarkup = {
olClose: '<newline>',
ulItem: '* ',
olItem: '1. ',
cboxItem: '- [ ] ',
liClose: '',

hr: '<newline><newline>---<newline>',
Expand Down Expand Up @@ -304,6 +311,7 @@ gdc.mixedMarkup = {
olClose: '',
ulItem: '* ',
olItem: '1. ',
cboxItem: '- [ ] ',
liClose: '',

hr: '<newline><newline>---<newline>',
Expand Down Expand Up @@ -346,7 +354,7 @@ gdc.htmlMarkup = {
olClose: '\n</ol>',
ulItem: '\n<li>',
olItem: '\n<li>',
liClose: '\n</li>',
liClose: '</li>',

hr: '\n<hr>',

Expand Down Expand Up @@ -817,19 +825,10 @@ gdc.handleText = function(textElement) {
if (alignment === SUPERSCRIPT) {
superscript = true;
}
if (!gdc.isSubscript && subscript) {
gdc.useHtml();
gdc.isSubscript = true;
gdc.openAttrs.push(gdc.subscript);
gdc.writeStringToBuffer(gdc.markup.subOpen);
}
if (!gdc.isSuperscript && superscript) {
gdc.useHtml();
gdc.isSuperscript = true;
gdc.openAttrs.push(gdc.superscript);
gdc.writeStringToBuffer(gdc.markup.superOpen);
}

var currentAttrs = gdc.getCurrentAttributes(textElement, attrOff);
// Attributes need to close for new text before opening any new attributes. This is for when words run together like italicsSUPERSCRIPT. or BOLDitalics
gdc.maybeCloseAttrs(currentAttrs);

// A philosophical question: should we define gdc.isItalic and friends up
// top in gdc.gs, or just let them be defined here at first use? Might
Expand Down Expand Up @@ -874,14 +873,29 @@ gdc.handleText = function(textElement) {
gdc.openAttrs.push(gdc.strikethrough);
gdc.writeStringToBuffer(gdc.markup.strikethroughOpen);
}
// Open subscript
if (!gdc.isSubscript && subscript) {
gdc.useHtml();
gdc.isSubscript = true;
gdc.openAttrs.push(gdc.subscript);
gdc.writeStringToBuffer(gdc.markup.subOpen);
}
// Open superscript
if (!gdc.isSuperscript && superscript) {
gdc.useHtml();
gdc.isSuperscript = true;
gdc.openAttrs.push(gdc.superscript);
gdc.writeStringToBuffer(gdc.markup.superOpen);
}
// Open underline (uses HTML always). This should really be discouraged!
if (!gdc.isUnderline && underline && !url) {
gdc.isUnderline = true;
gdc.openAttrs.push(gdc.underline);
gdc.writeStringToBuffer(gdc.markup.underlineOpen);
}

gdc.maybeCloseAttrs(currentAttrs);
// Needs to run again to clear any formatting?
// gdc.maybeCloseAttrs(currentAttrs);

// URL handling.

Expand Down Expand Up @@ -919,7 +933,7 @@ gdc.handleText = function(textElement) {
gdc.setWriteBuf();
offset = gdc.writeBuf(textElement, offset, urlEnd);
gdc.writeStringToBuffer('](' + url + ')');
} else { // Must be HTML, write standard link.
} else { // Must be HTML, write standard link.
gdc.writeStringToBuffer('<a href="' + url + '">');
gdc.setWriteBuf();
offset = gdc.writeBuf(textElement, offset, urlEnd);
Expand Down Expand Up @@ -1013,9 +1027,19 @@ gdc.isBullet = function(glyphType) {
if ( glyphType === DocumentApp.GlyphType.BULLET
|| glyphType === DocumentApp.GlyphType.HOLLOW_BULLET
|| glyphType === DocumentApp.GlyphType.SQUARE_BULLET) {
return true;
} else {
return false;
return 'bullet';
} else if (glyphType === null) {
// Since checkboxes currently return null and we know it is a list, this should work to find a checkbox item until Google adds another
// See https://developers.google.com/apps-script/reference/document/glyph-type for glyph enum if this breaks.
return 'checkbox';
// Spelling out ordered list glyphs rather than relying on "everything but null"
// } else if ( glyphType === DocumentApp.GlyphType.NUMBER
// || glyphType === DocumentApp.GlyphType.LATIN_UPPER
// || glyphType === DocumentApp.GlyphType.LATIN_LOWER
// || glyphType === DocumentApp.GlyphType.ROMAN_UPPER
// || glyphType === DocumentApp.GlyphType.ROMAN_LOWER) {
} else {
return 'ordered list';
}
};

Expand Down Expand Up @@ -1224,15 +1248,17 @@ gdc.getUrlEnd = function(textElement, offset) {
gdc.maybeCloseList = function(el) {
// Check to see if we should close this list.
var next = el.getNextSibling();
//var nestingLevel = gdc.nestLevel;
var nestingLevel = el.getNestingLevel();
if (next && next.toString() === "ListItem") {
var nextNestingLevel = next.getNestingLevel();
// Not sure why exactly, but sometimes next is null, breaking the script.
if (!next) { return; }
if (next.getType() == DocumentApp.ElementType.LIST_ITEM) {
// Add one because nesting level starts at 0? Is this the best way of doing this?
var nextNestingLevel = next.getNestingLevel() + 1;

// This is closer to being correct with list closing, but we also need to
// keep state in case there are paragraphs embedded in the list.
if (gdc.isHTML) {
for (var nest = nestingLevel; nest > nextNestingLevel; nest--) {
// Maybe there is a cleaner way to track nesting level. I've found that the document nesting level isn't accurate.
for (var nest = html.listNestingLevel; nest > nextNestingLevel; nest--) {
html.closeList();
}
}
Expand Down Expand Up @@ -1338,6 +1364,8 @@ gdc.maybeCloseAttrs = function(currentAttrs) {
// At the end of a paragraph or list item, we want to close all open attributes.
// This is similar to maybeCloseAttrs, but we want to close all of them in
// the openAttrs list (and we do not have an explicit attribute change here).

// Needs to close when the attribute stops. Not at paragraph/word end.
gdc.closeAllAttrs = function() {
while (gdc.openAttrs.length > 0) {
var a = gdc.openAttrs.pop();
Expand Down Expand Up @@ -1853,8 +1881,7 @@ md.handleParagraph = function(para) {
// blank lines.
html.checkList();


// Check to see if this is a constant-width paragraph (code block signal).
// Check to see if this is a constant-width paragraph (code block signal).
if (gdc.isCodeLine(para) && !gdc.isTable) {
// If we're starting a code block, open it up.
if (!gdc.inCodeBlock) {
Expand Down Expand Up @@ -1908,8 +1935,20 @@ md.handleParagraph = function(para) {
// do nothing: we also want to not add the tablePrefix.
// But check for table cell or definition list.
} else if (!gdc.startingTableCell && !gdc.inDlist) {
gdc.writeStringToBuffer(gdc.markup.pOpen);
}
// This is where we want to check for right/center alignment so that the proper paragraph style can be applied.
if (gdc.isHTML && para.getAlignment() === DocumentApp.HorizontalAlignment.RIGHT && para.isLeftToRight()) {
gdc.writeStringToBuffer('\n<p style="text-align: right">\n');
// Not sure what this does?
gdc.useHtml(); // TODO: check this!
//gdc.isRightAligned = true; // TODO: check this!
} else if (gdc.isHTML && para.getAlignment() === DocumentApp.HorizontalAlignment.CENTER && para.isLeftToRight()) {
gdc.writeStringToBuffer('\n<p style="text-align: center">\n');
gdc.useHtml();
} else {
gdc.writeStringToBuffer(gdc.markup.pOpen);
}
}

// We want paragraphs after the first text in a table cell.
gdc.startingTableCell = false;
}
Expand All @@ -1930,13 +1969,6 @@ md.handleParagraph = function(para) {
}
}

// Check horizontal alignment. We can style right alignment using an HTML paragraph.
if (para.getAlignment() === DocumentApp.HorizontalAlignment.RIGHT && para.isLeftToRight()) {
gdc.writeStringToBuffer('<p style="text-align: right">\n');
gdc.useHtml();
gdc.isRightAligned = true;
}

// Detects text direction.
if (!para.isLeftToRight()) {
gdc.writeStringToBuffer('<p dir="rtl">\n');
Expand All @@ -1953,6 +1985,7 @@ md.handleParagraph = function(para) {
// In case we're in a mixed code span, reset the markup.
gdc.resetMarkup();

// Is this necessary?
if (gdc.isRightAligned) {
gdc.writeStringToBuffer('</p>\n');
gdc.isRightAligned = false;
Expand Down Expand Up @@ -1989,8 +2022,9 @@ md.handleParagraph = function(para) {
gdc.writeStringToBuffer(gdc.markup.pClose);
}
}

//gdc.maybeCloseList(para);

// We also want to check here.
gdc.maybeCloseList(para);
}; // end md.handleParagraph

// Handle the heading type of the paragraph. Fall through for NORMAL.
Expand Down Expand Up @@ -2078,9 +2112,9 @@ md.handleListItem = function(listItem) {
prefix += '<listindent>';
}
// Check for bullet list.
if (gdc.isBullet(glyphType)) {
if (gdc.isBullet(glyphType) === 'bullet') {
prefix += gdc.markup.ulItem;
} else {
} else if (gdc.isBullet(glyphType) === 'ordered list') {
// Ordered list.
var key = listItem.getListId() + '.' + nestLevel;
// Initialize list counter.
Expand All @@ -2090,8 +2124,11 @@ md.handleListItem = function(listItem) {
// Increment ordered list counter.
prefix += counter + '. ';
// Alternative is to use 1. for all ordered list items, but less readable.
//prefix += gdc.markup.olItem;
// prefix += gdc.markup.olItem;
} else if (gdc.isBullet(glyphType) === 'checkbox') { // Maybe it's unecessary to spell out and just leave as an "else" statement.
prefix += gdc.markup.cboxItem
}

gdc.writeStringToBuffer(prefix);

// Prefix set, now deal with the content.
Expand Down
63 changes: 51 additions & 12 deletions addon/html.gs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ var html = html || {

// non-semantic underline, since Docs supports it.
underlineStart: '<span style="text-decoration:underline;">',
underlineEnd: '</span>'
underlineEnd: '</span>',


// I think we need to track these independently because the previous/next sibling won't always be a list item,
// thus not giving reliable nesting level.
listNestingLevel: 0,
// This will also help us know if a list item needs to be closed before opening a new one.
inListItem: false
};

html.tablePrefix = ' ';
Expand Down Expand Up @@ -418,7 +425,17 @@ html.handleHeading = function(heading, para) {
if (id) {
gdc.writeStringToBuffer(' id="' + gdc.headingIds[para.getText()] + '"');
}


// Check for right alignment before closing the tag
if (para.getAlignment() === DocumentApp.HorizontalAlignment.RIGHT && para.isLeftToRight()) {
gdc.writeStringToBuffer(' style="text-align: right"');
}

// Check for center alignment before closing the tag
if (para.getAlignment() === DocumentApp.HorizontalAlignment.CENTER && para.isLeftToRight()) {
gdc.writeStringToBuffer(' style="text-align: center"');
}

// Close the tag.
gdc.writeStringToBuffer('>');
};
Expand Down Expand Up @@ -495,13 +512,11 @@ html.handleListItem = function(listItem) {

html.nestingLevel = listItem.getNestingLevel();

// Check if we're in a code block and end if so.
if (gdc.inCodeBlock) {
gdc.writeStringToBuffer(html.closeCodeBlock);
gdc.inCodeBlock = false;
// Check if a list item is already open, and if so, close it. We will always want to close a listItem before opening a new one.
if (html.inListItem) {
html.closeListItem();
}


gdc.listPrefix = '';
for (var i = 0; i < html.nestingLevel; i++) {
gdc.listPrefix += ' ';
Expand All @@ -521,6 +536,7 @@ html.handleListItem = function(listItem) {
gdc.writeStringToBuffer('\n');
// Note that ulItem, olItem are the same in HTML (<li>).
gdc.writeStringToBuffer(gdc.listPrefix + gdc.htmlMarkup.ulItem);
html.inListItem = true;
md.childLoop(listItem);

// Check to see if we should close this list.
Expand All @@ -537,7 +553,14 @@ html.checkList = function() {
};
// Closes list item. Not necessary for Markdown.
html.closeListItem = function() {
// Check if we're in a code block and end if so. Always close codeblocks before closing list items.
if (gdc.inCodeBlock) {
gdc.writeStringToBuffer(html.closeCodeBlock);
gdc.inCodeBlock = false;
}

gdc.writeStringToBuffer(gdc.markup.liClose);
html.inListItem = false;
};
html.maybeOpenList = function (listItem) {
// Do we need to open a list?
Expand All @@ -548,13 +571,23 @@ html.maybeOpenList = function (listItem) {
}
// Open list if last sibling was not a list item.
if (previousType !== DocumentApp.ElementType.LIST_ITEM) {
html.openList();
} else
// We need to check if a list is already opened first. Is a global variable to track list level the best solution here?
// The previous sibling won't return the list level if it's a paragraph.

// Could we also use:
// if (html.nestingLevel == 0 && gdc.isList == false) {

if (html.nestingLevel >= html.listNestingLevel) {
html.openList();
}
} else if (previousType == DocumentApp.ElementType.LIST_ITEM) {
// Open a new list if nesting level increases.
if (html.nestingLevel > previous.getNestingLevel()) {
html.openList();
if (html.nestingLevel > previous.getNestingLevel()) {
html.openList();
}
}
};

// Open list and save current list type to stack.
html.openList = function() {
gdc.isList = true;
Expand All @@ -571,22 +604,28 @@ html.openList = function() {
gdc.writeStringToBuffer(gdc.listPrefix + gdc.htmlMarkup.olOpen);
html.listStack.unshift(gdc.ol);
}
html.listNestingLevel++;
};

// Close list and remove it's list type from the stack.
html.closeList = function() {
// Close the last item of the list.
// Close the last item of the list. This will always need to be called.
html.closeListItem();

if (html.listStack[0] === gdc.ul) {
gdc.writeStringToBuffer(gdc.listPrefix + gdc.htmlMarkup.ulClose);
html.listNestingLevel--;
}
if (html.listStack[0] === gdc.ol) {
gdc.writeStringToBuffer(gdc.listPrefix + gdc.htmlMarkup.olClose);
html.listNestingLevel--;
}
html.listStack.shift();
if (html.listStack.length === 0) {
gdc.isList = false;
}
};

// But what about a table that's in a list item?
html.closeAllLists = function() {
var list = html.listStack[0];
Expand Down
Loading

0 comments on commit eca9a00

Please sign in to comment.