Last active
October 1, 2015 02:37
-
-
Save trevordevore/1903979 to your computer and use it in GitHub Desktop.
Convert LiveCode styledText array to/from XHTML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* \brief Converts a styled text array to XHTML. | |
* | |
* \param pStyledTextA The array to convert. | |
* | |
* \return XHTML | |
*/ | |
function ConvertStyledTextToXHTML pStyledTextA | |
local theXHTML, theRun, theString | |
local theListKey | |
local theClosingListTag, theParaClasses, checkForIndent, theIndentLevel | |
set the wholematches to true | |
repeat with i = 1 to the number of elements of pStyledTextA | |
if pStyledTextA[i] is not an array then next repeat | |
## paragraph level formatting stored in pStyledTextA[i]["style"] | |
## textAlign, listStyle, listDepth, listIndent, firstIndent, leftIndent, rightIndent, | |
## spaceAbove, spaceBelow, tabStops, backgroundColor, borderWidth, borderColor, | |
## hGrid, vGrid, dontWrap and padding. | |
## todo ... | |
########## | |
# Determine paragraph tag | |
########## | |
put DecodeMetaDataArray(pStyledTextA[i]["metadata"]) into theMetaDataA | |
put theMetaDataA["style"] into theParaStyle | |
switch theParaStyle | |
case "code" | |
put "pre" into theParaTag | |
break | |
default | |
if pStyledTextA[i]["style"]["listStyle"] is not empty then | |
########## | |
# NOTE: This code does not support 'skip'. | |
# <ul> | |
# <li>Item | |
# <ol> | |
# <li>Sub item | |
# </ol> | |
# </li> | |
# </ul> | |
########## | |
# Question 1) Are we are at same level and same depth? | |
# Yes: Do nothing | |
# No: Question 2 | |
# Question 2) Is the level increasing? | |
# Yes: Open new list (ul/ol). | |
# No: Do nothing. Already open. | |
# 1) | |
if pStyledTextA[i]["style"]["listStyle"] is not theParaListsA[the number of elements of theParaListsA]["listStyle"] \ | |
OR pStyledTextA[i]["style"]["listDepth"] is not theParaListsA[the number of elements of theParaListsA]["listDepth"] then | |
switch pStyledTextA[i]["style"]["listStyle"] | |
case "disc" | |
case "circle" | |
case "square" | |
put "ul" into theListTag | |
break | |
default | |
put "ol" into theListTag | |
break | |
end switch | |
# 2) | |
if pStyledTextA[i]["style"]["listDepth"] > theParaListsA[the number of elements of theParaListsA]["listDepth"] then | |
put "<" & theListTag & ">" after theXHTML | |
end if | |
# add to nested list | |
put the number of elements of theParaListsA + 1 into theCounter | |
put theListTag into theParaListsA[theCounter]["tag"] | |
put pStyledTextA[i]["style"]["listStyle"] into theParaListsA[theCounter]["listStyle"] | |
put pStyledTextA[i]["style"]["listDepth"] into theParaListsA[theCounter]["listDepth"] | |
end if | |
put "li" into theParaTag | |
else | |
put "p" into theParaTag | |
end if | |
end switch | |
put _DetermineXHTMLClassesForParagraph(pStyledTextA, i) into theParaClasses | |
put "<" & theParaTag after theXHTML | |
if pStyledTextA[i]["style"]["listIndex"] is not empty then | |
put " value=" & quote & pStyledTextA[i]["style"]["listIndex"] & quote after theXHTML | |
end if | |
if theParaClasses is not empty then | |
replace cr with space in theParaClasses | |
put " class=" & quote & theParaClasses & quote after theXHTML | |
end if | |
put ">" after theXHTML | |
put empty into theRun | |
put empty into theString | |
########## | |
# Add text runs to paragraph | |
########## | |
repeat with j = 1 to the number of elements of pStyledTextA[i]["runs"] | |
if pStyledTextA[i]["runs"][j] is not an array then next repeat | |
put empty into theStyles | |
## style: textFont, textSize, textStyle, textColor, backgroundColor, linkText, imageSource | |
-- pStyledTextA[i]["runs"][j]["style"] | |
-- pStyledTextA[i]["runs"][j]["metadata"] | |
-- pStyledTextA[i]["runs"][j]["text"] | |
-- pStyledTextA[i]["runs"][j]["unicodetext"] | |
# Normalize text run: UTF8 | |
if "unicodetext" is among the keys of pStyledTextA[i]["runs"][j] then | |
put unidecode(pStyledTextA[i]["runs"][j]["unicodetext"], "utf8") into theRun | |
else | |
put unidecode(uniencode(pStyledTextA[i]["runs"][j]["text"]), "utf8") into theRun | |
end if | |
put _CleanseNonPrintingCharacters(theRun) into theRun | |
put _EscapePredefinedXMLEntities(theRun) into theRun | |
########## | |
## Get meta data for rest of operations. | |
########## | |
put DecodeMetaDataArray(pStyledTextA[i]["runs"][j]["metadata"]) into theMetaDataA | |
# Modify for "code" style, etc. | |
_UpdateTextBasedOnStyle theParaStyle, theMetaDataA["style"], theRun | |
########## | |
## Define Styles | |
########## | |
if pStyledTextA[i]["runs"][j]["style"]["textColor"] is not empty then | |
put "color: rgb(" & pStyledTextA[i]["runs"][j]["style"]["textColor"] & ")" into line (the number of lines of theStyles + 1) of theStyles | |
end if | |
if "underline" is among the items of pStyledTextA[i]["runs"][j]["style"]["textStyle"] then | |
put "text-decoration:underline" into line (the number of lines of theStyles + 1) of theStyles | |
end if | |
########## | |
## Add in tags and links | |
########## | |
if pStyledTextA[i]["runs"][j]["style"]["linkText"] is not empty then | |
## this is how I stored target info for links | |
## Ensure that "&" in query string is converted to "&" | |
put TextToUTF8(pStyledTextA[i]["runs"][j]["style"]["linkText"]) into pStyledTextA[i]["runs"][j]["style"]["linkText"] | |
put _EscapePredefinedXMLEntities(pStyledTextA[i]["runs"][j]["style"]["linkText"]) into pStyledTextA[i]["runs"][j]["style"]["linkText"] | |
put "<a href=" & quote & pStyledTextA[i]["runs"][j]["style"]["linkText"] & quote into theLink | |
repeat for each key theKey in theMetaDataA | |
if theKey is "href target" then put "target" into theAttr | |
else put theKey into theAttr | |
put space & theAttr & "=" & quote & _EscapePredefinedXMLEntities(theMetaDataA[theKey]) & quote after theLink | |
end repeat | |
put ">" after theLink | |
put theLink before theRun | |
put "</a>" after theRun | |
end if | |
if pStyledTextA[i]["runs"][j]["style"]["textShift"] is an integer then | |
if pStyledTextA[i]["runs"][j]["style"]["textShift"] < 0 then | |
put "<sup>" before theRun | |
put "</sup>" after theRun | |
else if pStyledTextA[i]["runs"][j]["style"]["textShift"] > 0 then | |
put "<sub>" before theRun | |
put "</sub>" after theRun | |
end if | |
end if | |
if "bold" is among the items of pStyledTextA[i]["runs"][j]["style"]["textStyle"] then | |
put "<strong>" before theRun | |
put "</strong>" after theRun | |
end if | |
if "italic" is among the items of pStyledTextA[i]["runs"][j]["style"]["textStyle"] then | |
put "<em>" before theRun | |
put "</em>" after theRun | |
end if | |
########## | |
## Add in spans for styles | |
########## | |
if theStyles is not empty then | |
replace cr with ";" in theStyles | |
## Since each line will get a new <p> tag then we need to apply span to each line. | |
put "<span style=" & quote & theStyles & quote & ">" before theRun | |
put "</span>" after theRun | |
end if | |
put theRun after theString | |
end repeat # Run | |
## Append new string | |
put theString after theXHTML | |
# Close out the paragraph | |
put "</" & theParaTag & ">" & cr after theXHTML | |
########## | |
# Is listStyle changing/ending in next paragraph? Close out the list (ul/ol). | |
########## | |
if theParaListsA is an array then | |
# Question 1: are we at last paragraph? | |
# Yes: Close all open list paragraphs | |
# Question 2: Is depth decreasing in next paragraph or is depth same but style different? | |
# Yes: Close paragraph and then check again. We may be closing out multiple lists. | |
# No: Don't close paragraph. | |
if pStyledTextA[i+1] is not an array then | |
# 1) | |
repeat with theIndex = the number of elements of theParaListsA down to 1 | |
put "</" & theParaListsA[theIndex]["tag"] & ">" & cr after theXHTML | |
delete local theParaListsA[theIndex] | |
end repeat | |
else | |
# 2) | |
repeat with theIndex = the number of elements of theParaListsA down to 1 | |
if pStyledTextA[i+1]["style"]["listDepth"] < theParaListsA[theIndex]["listDepth"] \ | |
OR (pStyledTextA[i+1]["style"]["listDepth"] is theParaListsA[theIndex]["listDepth"] AND \ | |
pStyledTextA[i+1]["style"]["listStyle"] is not theParaListsA[theIndex]["listStyle"]) then | |
put "</" & theParaListsA[theIndex]["tag"] & ">" & cr after theXHTML | |
delete local theParaListsA[theIndex] | |
else | |
exit repeat | |
end if | |
end repeat | |
end if | |
end if | |
end repeat # paragraph | |
if the last char of theXHTML is cr then delete the last char of theXHTML | |
## Livecode has a run for empty paragraphs but XHTML adds spacing automatically. | |
## Get rid of those empty paragraphs. | |
-- replace "</ul><p></p><ul>" with "</ul><ul>" in theXHTML | |
-- replace "</ul><p></p><p>" with "</ul><p>" in theXHTML | |
-- replace "</p><p></p><ul>" with "</p><ul>" in theXHTML | |
-- replace "</p><p></p><p>" with "</p><p>" in theXHTML | |
return theXHTML | |
end ConvertStyledTextToXHTML | |
/** | |
* |brief Inspects a paragraph and determines the XHTML classes to apply to it. | |
* | |
* \param @pStyledTextA the text run. | |
* \param pParaIndex The paragraph to inspect. | |
* | |
* \seealso ConvertStyledTextToXHTML | |
* | |
* \return String of classes, one per line. | |
*/ | |
private function _DetermineXHTMLClassesForParagraph @pStyledTextA, pParaIndex | |
if pStyledTextA[pParaIndex]["runs"] is not an array then return empty | |
local theParaClasses | |
local checkForIndent = "true" | |
local theIndentLevel = 0 | |
repeat with i = 1 to the number of elements of pStyledTextA[pParaIndex]["runs"] | |
# Normalize text so we can inspect. | |
if "unicodetext" is among the keys of pStyledTextA[pParaIndex]["runs"][i] then | |
put unidecode(pStyledTextA[pParaIndex]["runs"][i]["unicodetext"], "utf8") into theRun | |
else | |
put unidecode(uniencode(pStyledTextA[pParaIndex]["runs"][i]["text"]), "utf8") into theRun | |
end if | |
# Look for tabs at start of line. We add a style for indenting: indent1, indent2, etc. | |
if checkForIndent then | |
repeat for each char theChar in theRun | |
if theChar is tab then | |
add 1 to theIndentLevel | |
else | |
put false into checkForIndent | |
exit repeat | |
end if | |
end repeat | |
end if | |
end repeat # Run | |
# add tab indents to class | |
if theIndentLevel > 0 then | |
put "indent" & theIndentLevel into line (the number of lines of theParaClasses + 1) of theParaClasses | |
end if | |
return theParaClasses | |
end _DetermineXHTMLClassesForParagraph | |
/** | |
* |brief Makes any changes to a run based on the paragraph and run style. | |
* | |
* \param pParaStyle The style of the paragraph the run is in. | |
* \param pRunStyle The style of the run. | |
* \param @pText The text to modify. | |
* | |
* \return empty | |
*/ | |
private command _UpdateTextBasedOnStyle pParaStyle, pRunStyle, @pText | |
if pParaStyle is "code" OR pRunStyle is "code" then | |
replace numToChar(11) with cr in pText | |
else | |
replace numToChar(11) with "<br />" in pText | |
end if | |
return empty | |
end _UpdateTextBasedOnStyle | |
local sStyledTextA, sStyledTextIndexPathA | |
local sXMLTreeStateA | |
/** | |
* \brief Converts XHTML to a styled text array. | |
* | |
* \param pXHTML The XHTML to convert. | |
* | |
* \return XHTML | |
*/ | |
function ConvertXHTMLtoStyledText pXHTML | |
local theError, theStyledTextA | |
if pXHTML is not empty then | |
## Strip returns existing after tags. | |
## This keeps unwanted revStartXMLData messages from firing. | |
## No effort made to strip other white space between tags. This type of | |
## white space will fire off unwated revStartXMLData messages so beware. | |
replace ">" & crlf with ">" in pXHTML | |
replace ">" & cr with ">" in pXHTML | |
replace ">" & lf with ">" in pXHTML | |
## Initialize some variables | |
put empty into sXMLTreeStateA["run"]["textStyle"] | |
put empty into sXMLTreeStateA["previous run"]["textStyle"] | |
put qstr("<?xml version=`1.0` encoding=`UTF-8` ?>") into theHeader | |
put revCreateXMLTree(theHeader & cr & "<body>" & pXHTML & "</body>", false, false, true) into theError | |
put item 2 to -1 of theError into theError ## Ditches any numbers of revxmlerr, prefixes. | |
put sStyledTextA into theStyledTextA | |
put empty into sStyledTextA | |
end if | |
if theError is empty then | |
return theStyledTextA | |
else | |
return theError | |
end if | |
end ConvertXHTMLtoStyledText | |
on revXMLStartTree | |
put empty into sStyledTextA | |
end revXMLStartTree | |
/** | |
* \brief | |
* | |
* \param pNodeName The name of the node being parsed. | |
* \param pNodeAttributes One attribute per line. Each attribute name is separated from value by comma. | |
* | |
*/ | |
on revStartXMLNode pNodeName, pNodeAttributes | |
local theParaIndex | |
put pNodeName into line (the number of lines of sXMLTreeStateA["open node"] + 1) of sXMLTreeStateA["open node"] | |
split pNodeAttributes by cr and "," | |
put the number of elements of sStyledTextA into theParaIndex | |
switch pNodeName | |
case "pre" | |
case "p" ## Start a new paragraph entry | |
# TODO: <p> tags within <li> (LiveCode htmltext) are not handled properly. | |
## LiveCode likes an extra run to show paragraph spacing. | |
## Note: removed as we use spaceAbove now. | |
-- if sXMLTreeStateA["block is open"] then | |
-- add 1 to theParaIndex | |
-- put empty into sStyledTextA[theParaIndex]["runs"] | |
-- put false into sXMLTreeStateA["block is open"] | |
-- end if | |
# New paragraph: reset textStyle, textColor, etc. | |
repeat for each key theKey in sXMLTreeStateA["run"] | |
put empty into sXMLTreeStateA["run"][theKey] | |
end repeat | |
repeat for each key theKey in sXMLTreeStateA["previous run"] | |
put empty into sXMLTreeStateA["previous run"][theKey] | |
end repeat | |
add 1 to theParaIndex | |
put empty into sStyledTextA[theParaIndex] | |
if theParaIndex > 1 then | |
put 16 into sStyledTextA[theParaIndex]["style"]["spaceAbove"] ## trigger proper spacing | |
end if | |
switch pNodeName | |
case "pre" | |
put "code" into sStyledTextA[theParaIndex]["metadata"]["style"] | |
break | |
end switch | |
put StringToIndexPath(theParaIndex & ".runs.1") into sStyledTextIndexPathA | |
put empty into sStyledTextA[sStyledTextIndexPathA]["unicodetext"] # default value. If empty <p> tag all settings would be lost otherwise (i.e. spaceAbove). | |
break | |
case "ul" | |
add 1 to sXMLTreeStateA["list depth"] | |
put "disc" into sXMLTreeStateA["list type"][ sXMLTreeStateA["list depth"] ] | |
break | |
case "ol" | |
add 1 to sXMLTreeStateA["list depth"] | |
put "decimal" into sXMLTreeStateA["list type"][ sXMLTreeStateA["list depth"] ] | |
break | |
case "li" | |
# New line: reset textStyle, textColor, etc. | |
repeat for each key theKey in sXMLTreeStateA["run"] | |
put empty into sXMLTreeStateA["run"][theKey] | |
end repeat | |
repeat for each key theKey in sXMLTreeStateA["previous run"] | |
put empty into sXMLTreeStateA["previous run"][theKey] | |
end repeat | |
add 1 to theParaIndex | |
## trigger proper spacing for first line in list | |
if sStyledTextA[theParaIndex - 1]["style"]["listStyle"] is empty then | |
put 16 into sStyledTextA[theParaIndex]["style"]["spaceAbove"] | |
end if | |
put sXMLTreeStateA["list type"][ sXMLTreeStateA["list depth"] ] into sStyledTextA[theParaIndex]["style"]["listStyle"] | |
if pNodeAttributes["value"] is not empty then put pNodeAttributes["value"] into sStyledTextA[theParaIndex]["style"]["listIndex"] | |
put sXMLTreeStateA["list depth"] into sStyledTextA[theParaIndex]["style"]["listDepth"] | |
put StringToIndexPath(theParaIndex & ".runs." & the number of elements of sStyledTextA[theParaIndex]["runs"] + 1) into sStyledTextIndexPathA | |
break | |
case "span" | |
########## | |
## Strip whitespace | |
########## | |
-- text-decoration: underline; something-else: what | |
put pNodeAttributes["style"] into theStyles | |
set the itemDelimiter to ":" | |
repeat with theItemNo = 1 to the number of items of theStyles["style"] | |
put word 1 to -1 of item theItemNo of theStyles["style"] into item theItemNo of theStyles["style"] | |
end repeat | |
set the itemDelimiter to ";" | |
repeat with theItemNo = 1 to the number of items of theStyles["style"] | |
put word 1 to -1 of item theItemNo of theStyles["style"] into item theItemNo of theStyles["style"] | |
end repeat | |
set the itemDelimiter to "," | |
repeat with theItemNo = 1 to the number of items of theStyles["style"] | |
put word 1 to -1 of item theItemNo of theStyles["style"] into item theItemNo of theStyles["style"] | |
end repeat | |
set the wholematches to true | |
split theStyles by ";" and ":" | |
repeat for each key theKey in theStyles | |
put word 1 to -1 of theStyles[theKey] into theStyles[theKey] | |
switch theKey | |
case "text-decoration" | |
if "underline" is among the items of theStyles[theKey] then | |
put _AddToList("underline", sXMLTreeStateA["run"]["textStyle"]) into sXMLTreeStateA["run"]["textStyle"] | |
end if | |
break | |
case "color" | |
if theStyles[theKey] begins with "rgb" then | |
put _StripNonNumericListChars(theStyles[theKey]) into sXMLTreeStateA["run"]["textColor"] | |
else | |
put theStyles[theKey] into sXMLTreeStateA["run"]["textColor"] | |
end if | |
break | |
end switch | |
end repeat | |
break | |
case "a" | |
put _AddToList("link", sXMLTreeStateA["run"]["textStyle"]) into sXMLTreeStateA["run"]["textStyle"] | |
put pNodeAttributes["href"] into sXMLTreeStateA["run"]["linkText"] | |
replace "&" with "&" in sXMLTreeStateA["run"]["linkText"] ## xml parser is converting & to entity number. | |
repeat for each key theKey in pNodeAttributes | |
if theKey is "href" then next repeat | |
if theKey is "target" then put "href target" into theAttr | |
else put theKey into theAttr | |
put pNodeAttributes[theKey] into sXMLTreeStateA["run"]["metadata"][theAttr] | |
end repeat | |
break | |
case "sub" | |
put 4 into sXMLTreeStateA["run"]["textShift"] | |
break | |
case "sup" | |
put -4 into sXMLTreeStateA["run"]["textShift"] | |
break | |
case "b" | |
case "strong" | |
put _AddToList("bold", sXMLTreeStateA["run"]["textStyle"]) into sXMLTreeStateA["run"]["textStyle"] | |
break | |
case "i" | |
case "em" | |
put _AddToList("italic", sXMLTreeStateA["run"]["textStyle"]) into sXMLTreeStateA["run"]["textStyle"] | |
break | |
case "br" | |
put uniencode(numToChar(11)) after sStyledTextA[sStyledTextIndexPathA]["unicodetext"] | |
break | |
end switch | |
end revStartXMLNode | |
/** | |
* \brief Sent when a node has finished being processed. | |
* | |
*/ | |
on revEndXMLNode pNodeName | |
## Remove style from list of active styles. | |
switch pNodeName | |
case "a" | |
put _RemoveFromList("link", sXMLTreeStateA["run"]["textStyle"]) into sXMLTreeStateA["run"]["textStyle"] | |
put empty into sXMLTreeStateA["run"]["linkText"] | |
delete local sXMLTreeStateA["run"]["metadata"]["href target"] | |
break | |
case "sub" | |
case "sup" | |
put empty into sXMLTreeStateA["run"]["textShift"] | |
break | |
case "b" | |
case "strong" | |
put _RemoveFromList("bold", sXMLTreeStateA["run"]["textStyle"]) into sXMLTreeStateA["run"]["textStyle"] | |
break | |
case "i" | |
case "em" | |
put _RemoveFromList("italic", sXMLTreeStateA["run"]["textStyle"]) into sXMLTreeStateA["run"]["textStyle"] | |
break | |
case "span" | |
put _RemoveFromList("underline", sXMLTreeStateA["run"]["textStyle"]) into sXMLTreeStateA["run"]["textStyle"] | |
put empty into sXMLTreeStateA["run"]["textColor"] | |
break | |
case "ul" | |
case "ol" | |
subtract 1 from sXMLTreeStateA["list depth"] | |
break | |
case "p" | |
case "pre" | |
case "li" | |
# encode metadata | |
put the number of elements of sStyledTextA into theParaIndex | |
if sStyledTextA[theParaIndex]["metadata"] is an array then | |
put EncodeMetaDataArray(sStyledTextA[theParaIndex]["metadata"]) into sStyledTextA[theParaIndex]["metadata"] | |
end if | |
break | |
end switch | |
delete line -1 of sXMLTreeStateA["open node"] | |
end revEndXMLNode | |
command revStartXMLData pData | |
## this message can be sent when no node is "open". | |
switch line -1 of sXMLTreeStateA["open node"] | |
case "ul" | |
case "ol" | |
break | |
default | |
## Catch instances where string passed to ConvertXHTMLToStyledText doesn't start with <p> or <ol/ul>. | |
if sStyledTextIndexPathA is not an array then | |
put empty into sStyledTextA[1] | |
put StringToIndexPath("1.runs.1") into sStyledTextIndexPathA | |
end if | |
## If properties are changing on the text then start a new run. | |
if sXMLTreeStateA["run"] is not sXMLTreeStateA["previous run"] then | |
put the number of elements of sStyledTextA into theParaIndex | |
put StringToIndexPath(theParaIndex & ".runs." & the number of elements of sStyledTextA[theParaIndex]["runs"] + 1) into sStyledTextIndexPathA | |
_AddStylesAndColorToRun sStyledTextIndexPathA | |
end if | |
# Check among all lines as a pre may contain a span. | |
if "pre" is among the lines of sXMLTreeStateA["open node"] then | |
-- switch line -1 of sXMLTreeStateA["open node"] | |
-- case "pre" | |
## convert lines to vertical tabs | |
replace crlf with numToChar(11) in pData | |
replace cr with numToChar(11) in pData | |
replace lf with numToChar(11) in pData | |
-- break | |
-- end switch | |
end if | |
## Use after so data isn't lost in situations where white space outside | |
## of tags causes unwanted message to fire. | |
put uniencode(pData, "utf8") after sStyledTextA[sStyledTextIndexPathA]["unicodetext"] | |
-- put pData into sStyledTextA[sStyledTextIndexPathA]["text"] ## for testing | |
## Store run so we can compare next time through | |
put sXMLTreeStateA["run"] into sXMLTreeStateA["previous run"] | |
end switch | |
end revStartXMLData | |
on revXMLEndTree | |
put empty into sXMLTreeStateA | |
put empty into sStyledTextIndexPathA | |
end revXMLEndTree | |
/** | |
* \brief Escapes the predefined XML entities in a string. | |
* | |
* \param pStr The string to escape the characters in. | |
* \param pEscapeApostrophe Pass in true to escape apostrophes. | |
* | |
* \return String | |
*/ | |
private function _EscapePredefinedXMLEntities pStr, pEscapeApostrophe | |
replace "&" with "&" in pStr | |
replace "<" with "<" in pStr | |
replace ">" with ">" in pStr | |
replace quote with """ in pStr | |
if pEscapeApostrophe then | |
replace "'" with "'" in pStr | |
end if | |
return pStr | |
end _EscapePredefinedXMLEntities | |
/** | |
* \brief Cleanses a string of non-printing characters that would mess up XML. | |
* | |
* \param pStr The string to work on. | |
* | |
* \return String | |
*/ | |
private function _CleanseNonPrintingCharacters pStr | |
repeat for each item theNum in "0,1,2,3,4,5,6,7,8" | |
replace numToChar(theNum) with empty in pStr | |
end repeat | |
return pStr | |
end _CleanseNonPrintingCharacters | |
/** | |
* \brief Adds the currently active textStyle and textColor values to a run. | |
* | |
* \param pRunIndexPathA The index path array pointing to the run in the sStyledTextA array. | |
* | |
* \return empty | |
*/ | |
command _AddStylesAndColorToRun pRunIndexPathA | |
if sXMLTreeStateA["run"]["textShift"] is not empty then \ | |
put sXMLTreeStateA["run"]["textShift"] into sStyledTextA[pRunIndexPathA]["style"]["textShift"] | |
if sXMLTreeStateA["run"]["textStyle"] is not empty then \ | |
put sXMLTreeStateA["run"]["textStyle"] into sStyledTextA[pRunIndexPathA]["style"]["textStyle"] | |
if sXMLTreeStateA["run"]["textColor"] is not empty then \ | |
put sXMLTreeStateA["run"]["textColor"] into sStyledTextA[pRunIndexPathA]["style"]["textColor"] | |
if sXMLTreeStateA["run"]["linkText"] is not empty then \ | |
put sXMLTreeStateA["run"]["linkText"] into sStyledTextA[pRunIndexPathA]["style"]["linkText"] | |
if sXMLTreeStateA["run"]["metadata"] is an array then \ | |
put EncodeMetaDataArray(sXMLTreeStateA["run"]["metadata"]) into sStyledTextA[pRunIndexPathA]["metadata"] | |
return empty | |
end _AddStylesAndColorToRun | |
/** | |
* \brief Strips non numeric chars from a string (except commas). Used for converting CSS rgb(x,x,x) to an RGB color that LiveCode likes. | |
* | |
* \param pString The string to strip characters from. | |
* | |
* \return String | |
*/ | |
private function _StripNonNumericListChars pString | |
local i | |
repeat with i = the number of chars of pString down to 1 | |
put char i of pString into theChar | |
if theChar is not an integer AND theChar is not "," then | |
delete char i of pString | |
end if | |
end repeat | |
return pString | |
end _StripNonNumericListChars | |
/** | |
* \brief Adds an item to a list if it does not already exist. | |
* | |
* \param pItem The item to add. | |
* \param pList The list to add the item to. | |
* | |
* \return List | |
*/ | |
private function _AddToList pItem, pList | |
set the wholematches to true | |
if pItem is not among the items of pList then | |
put pItem into item (the number of items of pList + 1) of pList | |
end if | |
return pList | |
end _AddToList | |
/** | |
* \brief Removes an item from a list. | |
* | |
* \param pItem The item to remove. | |
* \param pList The list to remove the item from. | |
* | |
* \return List | |
*/ | |
private function _RemoveFromList pItem, pList | |
set the wholematches to true | |
put itemOffset(pItem, pList) into theItemNo | |
if theItemNo > 0 then delete item theItemNo of pList | |
return pList | |
end _RemoveFromList | |
/** | |
* |brief Encodes an array so it can be stored as the metadata property of a field chunk. | |
* | |
*/ | |
function EncodeMetaDataArray pArrayA | |
if pArrayA is an array then | |
return base64Encode(arrayEncode(pArrayA)) | |
else | |
return pArrayA | |
end if | |
end EncodeMetaDataArray | |
function DecodeMetaDataArray pData | |
try | |
return arrayDecode(base64Decode(pData)) | |
catch e | |
return pData | |
end try | |
end DecodeMetaDataArray |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment