(* ::Package:: *) (************************************************************************************************ This package defines a set of functions that facilitates notebook-to-HTML-webpage export. Version 1.5.x by ~sh, 2025-06-22 1.5.0: new function amendHTML added; renaming *.html to index.html moved from amendCSS to amendHTML. 1.5.1: linking real author photo added to amendHTML. Version 1.7.x by ~sh, 2025-10-05--2025-10-19 1.7.0: two new functions exportAsWebPage and deleteWebFiles added. 1.7.1: default value of the "Viewport" option changed from "width=device-width, initial-scale=1" to "". 1.7.2: 3rd argument (tabsty) added in amendCSS; linking the oersonal URLs added in amendHTML. 1.7.3: amendHTML now adds target="_blank" for both tags. ************************************************************************************************) BeginPackage["WebUtils`"]; Unprotect["WebUtils`*"]; ClearAll["WebUtils`*"]; (**************** lastUpdate: ****************) lastUpdate::usage = "\ lastUpdate[\!\(\* StyleBox[\"str\", \"TI\"]\)] creates \"last update\" banner showing message given by string \!\(\* StyleBox[\"str\", \"TI\"]\). \"Helvetica\" font and default eye-catcher image will be used. lastUpdate[\!\(\* StyleBox[\"str\", \"TI\"]\), \!\(\* StyleBox[\"font\", \"TI\"]\)] same as above, but font given by string \!\(\* StyleBox[\"font\", \"TI\"]\) will be used. lastUpdate[\!\(\* StyleBox[\"str\", \"TI\"]\), \!\(\* StyleBox[\"font\", \"TI\"]\), \!\(\* StyleBox[\"img\", \"TI\"]\)] same as above, but eye-catcher image \!\(\* StyleBox[\"img\", \"TI\"]\) will be used."; (**************** insertImage: ****************) insertImage::usage = "\ insertImage[\!\(\* StyleBox[\"dir\", \"TI\"]\), \!\(\* StyleBox[\"file\", \"TI\"]\)] imports single raster image specified by directory string \!\(\* StyleBox[\"dir\", \"TI\"]\) (built with FileNameJoin, relative to notebook directory, regression to be specified by \"..\" designations) and file name string \!\(\* StyleBox[\"file\", \"TI\"]\). Horizontal size 360, padding thickness 20 and color LightGray will be used. insertImage[\!\(\* StyleBox[\"dir\", \"TI\"]\), \!\(\* StyleBox[\"file\", \"TI\"]\), \!\(\* StyleBox[\"siz\", \"TI\"]\)] same as above, but image horizontal size \!\(\* StyleBox[\"siz\", \"TI\"]\) will be used. insertImage[\!\(\* StyleBox[\"dir\", \"TI\"]\), \!\(\* StyleBox[\"file\", \"TI\"]\), \!\(\* StyleBox[\"siz\", \"TI\"]\), \!\(\* StyleBox[\"pad\", \"TI\"]\)] same as above, but image padding thickness \!\(\* StyleBox[\"pad\", \"TI\"]\) will be used. insertImage[\!\(\* StyleBox[\"dir\", \"TI\"]\), \!\(\* StyleBox[\"file\", \"TI\"]\), \!\(\* StyleBox[\"siz\", \"TI\"]\), \!\(\* StyleBox[\"pad\", \"TI\"]\), \!\(\* StyleBox[\"bkg\", \"TI\"]\)] same as above, but image padding background color \!\(\* StyleBox[\"bkg\", \"TI\"]\) will be used. insertImage[{{\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(1\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(1\)]\)}, {\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(2\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(2\)]\)}, \[Ellipsis]}] imports raster images specified by directory strings \!\(\* StyleBox[SubscriptBox[\"dir\", \"i\"], \"TI\"]\) (built with FileNameJoin, relative to notebook directory, regression to be specified by \"..\" designations) and corresponding file name strings \!\(\* StyleBox[SubscriptBox[\"file\", \"i\"], \"TI\"]\), arranging them with ImageCollage. Collage horizontal size 640, fitting \"Fit\", method \"Grid\", padding thickness 20 and color LightGray will be used. insertImage[{{\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(1\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(1\)]\)}, {\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(2\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(2\)]\)}, \[Ellipsis]}, \!\(\* StyleBox[\"siz\", \"TI\"]\)] same as above, but collage horizontal size \!\(\* StyleBox[\"siz\", \"TI\"]\) will be used. insertImage[{{\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(1\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(1\)]\)}, {\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(2\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(2\)]\)}, \[Ellipsis]}, \!\(\* StyleBox[\"siz\", \"TI\"]\), \!\(\* StyleBox[\"fit\", \"TI\"]\)] same as above, but collage fitting \!\(\* StyleBox[\"fit\", \"TI\"]\) (\"Fill\", \"Fit\", \"Stretch\") will be used. insertImage[{{\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(1\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(1\)]\)}, {\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(2\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(2\)]\)}, \[Ellipsis]}, \!\(\* StyleBox[\"siz\", \"TI\"]\), \!\(\* StyleBox[\"fit\", \"TI\"]\), \!\(\* StyleBox[\"met\", \"TI\"]\)] same as above, but collage arrangement method \!\(\* StyleBox[\"met\", \"TI\"]\) (\"Rows\", \"Columns\", \"Grid\", \"ClosestPacking\") will be used. insertImage[{{\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(1\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(1\)]\)}, {\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(2\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(2\)]\)}, \[Ellipsis]}, \!\(\* StyleBox[\"siz\", \"TI\"]\), \!\(\* StyleBox[\"fit\", \"TI\"]\), \!\(\* StyleBox[\"met\", \"TI\"]\), \!\(\* StyleBox[\"pad\", \"TI\"]\)] same as above, but collage padding thickness \!\(\* StyleBox[\"pad\", \"TI\"]\) will be used. insertImage[{{\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(1\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(1\)]\)}, {\!\(\*SubscriptBox[ StyleBox[\"dir\", \"TI\"], \(2\)]\),\!\(\*SubscriptBox[ StyleBox[\"file\", \"TI\"], \(2\)]\)}, \[Ellipsis]}, \!\(\* StyleBox[\"siz\", \"TI\"]\), \!\(\* StyleBox[\"fit\", \"TI\"]\), \!\(\* StyleBox[\"met\", \"TI\"]\), \!\(\* StyleBox[\"pad\", \"TI\"]\), \!\(\* StyleBox[\"bkg\", \"TI\"]\)] same as above, but collage padding background color \!\(\* StyleBox[\"bkg\", \"TI\"]\) will be used."; (**************** insertPDF: ****************) insertPDF::usage = "\ insertPDF[\!\(\* StyleBox[\"dir\", \"TI\"]\), \!\(\* StyleBox[\"file\", \"TI\"]\), \!\(\* StyleBox[\"options\", \"TI\"]\)] imports all pages of the PDF file specified by directory string \!\(\* StyleBox[\"dir\", \"TI\"]\) (built with FileNameJoin relative to notebook directory, path regression to be specified by \"..\" designations) and filename string \!\(\* StyleBox[\"file\", \"TI\"]\) as a single composite raster image. Default page arrangement \!\(\* StyleBox[\"arr\", \"TI\"]\) and page framing \!\(\* StyleBox[\"pag\", \"TI\"]\) will be used. insertPDF[\!\(\* StyleBox[\"dir\", \"TI\"]\), \!\(\* StyleBox[\"file\", \"TI\"]\), \!\(\* StyleBox[\"pag\", \"TI\"]\), \!\(\* StyleBox[\"options\", \"TI\"]\)] same as above, but all pages are imported if \!\(\* StyleBox[\"pag\", \"TI\"]\) is All (default), selected page(s) if \!\(\* StyleBox[\"pag\", \"TI\"]\) is a list of integers. insertPDF[\!\(\* StyleBox[\"dir\", \"TI\"]\), \!\(\* StyleBox[\"file\", \"TI\"]\), \!\(\* StyleBox[\"pag\", \"TI\"]\), \!\(\* StyleBox[\"arr\", \"TI\"]\), \!\(\* StyleBox[\"options\", \"TI\"]\)] same as above, but page arrangement will be controlled by \!\(\* StyleBox[\"arr\", \"TI\"]\) with head Symbol, Function, Composition, or RightComposition, e.g.: GraphicsRow (default), GraphicsColumn, GraphicsGrid[Partition[#1,2],##2]&, GraphicsGrid[Partition[#1,UpTo[3]],##2]&, etc. Accepted \!\(\* StyleBox[\"options\", \"TI\"]\) are passed to Import or GraphicsRow, GraphicsColumn, GraphicsGrid (indicated in parentheses):\n \[Bullet] ImageResolution\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"ires\", \"TI\"]\) (Import) image resolution in DPI for rasterization: positive integer, current default "<>ToString[First["Resolution"/.CurrentValue["ConnectedDisplays"]]]<>" is the max resolution of connected display given by $ImageResolution\n \[Bullet] RasterSize\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"rsiz\", \"TI\"]\) (Import) horizontal raster size of every PDF page in pixels for rasterization: positive integer, default Automatic\n \[Bullet] ImageSize\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"isiz\", \"TI\"]\) (Graphics*) final displayed horizontal size of composite raster image in printer's points: positive integer or Tiny, Small, Medium, \[Ellipsis], default Automatic\n \[Bullet] Background\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"bkgc\", \"TI\"]\) (Graphics*) specifies what background color to use: see documentation, None for no background, default LightGray\n \[Bullet] Spacings\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"spac\", \"TI\"]\) (Graphics*) specifies the spacings to leave between neighbor objects: see documentation, default Scaled[0.1]\n \[Bullet] Frame\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"fram\", \"TI\"]\) (Graphics*) specifies whether to include a frame: see documentation, True, All as a rule, default None\n \[Bullet] FrameStyle\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"fsty\", \"TI\"]\) (Graphics*) specifies the style in which to draw frames: see documentation, Gray, Dashed, Directive[\[Ellipsis]], \[Ellipsis] as a rule, default Automatic\n \[Bullet] Dividers\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"divs\", \"TI\"]\) (Graphics*) specifies where and how to draw divider lines: see documentation, Center as a rule, default None\n \[Bullet] AspectRatio\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"aspr\", \"TI\"]\) (Graphics*) specifies the ratio of height to width for the composite raster image: see documentation, a number, Full as a rule, default Automatic\n \[Bullet] ItemAspectRatio\[ThinSpace]\[RightArrow]\[ThinSpace]\!\(\* StyleBox[\"itar\", \"TI\"]\) (Graphics*) specifies the ratio of ht/wd for the regions in which items are placed: see documentation, a number as a rule, default Automatic\n \[Bullet] Other Graphics* options like Alignment, AlignmentPoint, BaselinePosition, BaseStyle can be given, see documentation for more information"; (**************** amendCSS: ****************) amendCSS::usage = "\ amendCSS[\!\(\* StyleBox[\"hlkcol\", \"TI\"]\), \!\(\* StyleBox[\"suffix\", \"TI\"]\), \!\(\* StyleBox[\"tabsty\", \"TI\"]\)] colorizes inline hyperlinks in HTMLFiles/*.css with color given by string \!\(\* StyleBox[\"hlkcol\", \"TI\"]\) (\"454F99\" by default; explicit \"\" mimicks default behavior of any version) and reduces excessive spaces ('padding:\[NonBreakingSpace]8px;' \[RightArrow] 'padding:\[NonBreakingSpace]0px;' in the '.HyperlinkInline' section, 'padding:\[NonBreakingSpace]8px;' \[RightArrow] 'padding:\[NonBreakingSpace]4px;' everywhere else). The original file is saved as *.\* StyleBox[\(css\!\(\* StyleBox[\"suffix\", \"TI\"]\)\)] (string \!\(\* StyleBox[\"suffix\", \"TI\"]\) is \"_orig\" by default). For the \!\(\* StyleBox[\"tabsty\", \"TI\"]\) basename (\"sh_MAIN\" by default), some table styling is added at the beginning of the HTMLFiles/*.css file."; (**************** amendHTML: ****************) amendHTML::usage = "\ amendHTML[\!\(\* StyleBox[\"idxbase\", \"TI\"]\), \!\(\* StyleBox[\"suffix\", \"TI\"]\), \!\(\* StyleBox[\"flairinsert\", \"TI\"]\), \!\(\* StyleBox[\"photoinsert\", \"TI\"]\)] adds target=\"_blank\" at the end of each and tag start to ensure that the hyperlinks open in new tabs. The original HTML file is saved as *.\* StyleBox[\(html\!\(\* StyleBox[\"suffix\", \"TI\"]\)\)] (string \!\(\* StyleBox[\"suffix\", \"TI\"]\) is \"_orig\" by default). Also renames generated *.html file to \!\(\* StyleBox[\"idxbase\", \"TI\"]\).html (\!\(\* StyleBox[\"idxbase\", \"TI\"]\) is \"index\" by default). For the \!\(\* StyleBox[\"flairinsert\", \"TI\"]\) basename (\"sh_Wolfram\" by default), the Mathematica StackExchange flair is inserted past the proper place. For the \!\(\* StyleBox[\"photoinsert\", \"TI\"]\) basename (\"sh_MAIN\" by default), linking the real photo and URLs is inserted to the proper place."; (**************** exportAsWebPage: ****************) exportAsWebPage::usage="\ exportAsWebPage[\!\(\* StyleBox[\"title\", \"TI\"]\), \!\(\* StyleBox[\"description\", \"TI\"]\), \!\(\* StyleBox[\"keywords\", \"TI\"]\), \!\(\* StyleBox[\"opts\", \"TI\"]\)] exports evaluation notebook to its NotebookDirectory[] as a HTML web page, using strings \!\(\* StyleBox[\"title\", \"TI\"]\), \!\(\* StyleBox[\"description\", \"TI\"]\), and \!\(\* StyleBox[\"keywords\", \"TI\"]\) as values of eponymous subelements of the HTML \!\(\* StyleBox[\"<\", \"InlineCode\"]\)\!\(\* StyleBox[\"head\", \"InlineCode\"]\)\!\(\* StyleBox[\">\", \"InlineCode\"]\)\!\(\* StyleBox[\" \", \"InlineCode\"]\)tag. Except the Export-specific \!\(\* StyleBox[\"opts\", \"TI\"]\) (which are passed to Export and override the default ones), the following exportAsWebPage-specific \!\(\* StyleBox[\"opts\", \"TI\"]\) are accepted (default values are shown):\n\ \[Bullet]\[NonBreakingSpace]\"Author\"\[ThinSpace]\[Rule]\[ThinSpace]\"Stanislav Hledik\"\[ThinSpace]: value of the \"author\" subelement of the HTML \!\(\* StyleBox[\"<\", \"InlineCode\"]\)\!\(\* StyleBox[\"head\", \"InlineCode\"]\)\!\(\* StyleBox[\">\", \"InlineCode\"]\)\!\(\* StyleBox[\" \", \"InlineCode\"]\)tag.\n\ \[Bullet]\[NonBreakingSpace]\"Favicon\"\[ThinSpace]\[Rule]\[ThinSpace]\"032.ico\": specifies favicon size and type in the form of string \"nnn.ext\" (nnn in padded pixels).\n\ \[Bullet]\[NonBreakingSpace]\"Viewport\"\[ThinSpace]\[Rule]\[ThinSpace]\"\"\[ThinSpace]: content of the \"viewport\" subelement of the HTML \!\(\* StyleBox[\"<\", \"InlineCode\"]\)\!\(\* StyleBox[\"head\", \"InlineCode\"]\)\!\(\* StyleBox[\">\", \"InlineCode\"]\)\!\(\* StyleBox[\" \", \"InlineCode\"]\)tag.\n\ \[Bullet]\[NonBreakingSpace]\"FreshBuild\"\[ThinSpace]\[Rule]\[ThinSpace]False\[ThinSpace]: deletes previously exported files using deleteWebFiles before export."; (**************** deleteWebFiles: ****************) deleteWebFiles::usage="\ deleteWebFiles[] deletes all web page files created by exportAsWebPage, i.e., name.html and HTMLFiles/*.*. Favicon files HTMLFiles/name-nnn.{ico\[ThinSpace]|\[ThinSpace]png} are left untouched."; Begin["`Private`"]; (**************** repeatedly used variables: ****************) $suitename="WebUtils" (* the suite base name *); (**************** lastUpdate: ****************) SyntaxInformation[insertImage]={"ArgumentsPattern"->{_,_.,_.}}; lastUpdate[ str_String, font_String:"Helvetica", img_Image:Image[CompressedData[" 1:eJztms1OwzAMxyvgwJFX4A04cixHrkM8wCbKxKVIHRLi5kfrm420aFIV5cP5 /CelVrypm+P4Z3tpt+7+8Ll7v2qa5nQrHnb776dh2P+83ImD1/70cey7t+f+ qzt2w+PhWrz4ILQVetOkl7MY5/kpz7xSZBTjwiCrbo7Ofpzd1SM6jlBFc3Ek FXsNOUjNjs5BLr4S84NmQucAzYPkJzHQPK5Kc9hxBM2C7gE0x8aP4UfHj8hD KwY63lTa/n3tUwpVuMf7KinODeiYcuvGv/G75IBjp7PR7TmyLTeey/uk2bNs fmxx+PZLKH8r7c+x4+DEw+UnRe5t/K59mYLfxO7Cb/Mdg1/nh2tDlhpx2Zfz SDp3xuz/SUfpt84Q/pBamvh168Tg1/mhRd7lY1rUmcvkwq7iV/mw8XPW0fWw yjd3fdM6xLzutdVElhB+ExvHhrsWl92nt2Pym7i4dqZ1Qvh1MYTyk6K3iLmf h9bUx5bDbxJXn6H8rvM4dgh+2Y4Yn2mfWNagnDqsNQcu7Jweqk3J4X4AOlZ0 D6Dj3Pg3fiT/GnNAAfdD0bHnqPca8pGKt4Yc5GSfhAq7RsrNPwmaGck+CRXQ AxTxfy4+wq2Nb03JkmMItKeU3s+55L9yy1IC9y+adJwm "], "Byte", ColorSpace -> "RGB", ImageResolution -> {120., 120.}, Interleaving -> True] ]:= Framed[Row[MapAt[Style[#,FontFamily->font]&,Riffle[{"Last update:", FromUnixTime[UnixTime[],DateFormat->{"DayName",", ","Year","-","Month","-","Day"," @ ","Hour24",":","Minute"," "}], img,Style[str,FontFamily->font]}, " "],{{1},{4}}]]] (**************** insertImage: ****************) insertImage::noimgf="image file `1` does not exist."; insertImage::misimg="at least one of the image files does not exist."; SyntaxInformation[insertImage]={"ArgumentsPattern"->{_,_.,_.,_.,_.,_.}}; insertImage[ dir_String, file_String, Optional[siz_/;Or[Head[siz]===Symbol,NumberQ[siz],ListQ[siz]],360], Optional[pad_/;NumberQ[pad],20], Optional[bkg_/;Or[Head[bkg]===Symbol,Head[bkg]===RGBColor,Head[bkg]===GrayLevel],LightGray] ]:= Module[{path=FileNameJoin[{NotebookDirectory[],dir,file}]}, If[Not[FileExistsQ[path]],Throw[Message[insertImage::noimgf,file]/.Null->$Failed,"noimgf",#1&]]; (*ImageResize[*)Image[ImagePad[Import[path], pad,bkg],ImageSize->siz(*,ImageResolution->300*)](*,siz,Resampling->"Lanczos"]*) ] insertImage[ files_List/;MatrixQ[files], Optional[siz_/;Or[Head[siz]===Symbol,NumberQ[siz],ListQ[siz]],640], fit_String:"Fit", met_String:"Grid", Optional[pad_/;Or[Head[pad]===Symbol,NumberQ[pad]],20], Optional[bkg_/;Or[Head[bkg]===Symbol,Head[bkg]===RGBColor,Head[bkg]===GrayLevel],LightGray] ]:= Module[{paths}, paths=Map[FileNameJoin[{NotebookDirectory[],#[[1]],#[[2]]}]&,files,Heads->False]; If[Nand@@Map[FileExistsQ,paths,Heads->False],Throw[Message[insertImage::misimg]/.Null->$Failed,"misimg",#1&]]; ImageCollage[ Map[Import[FileNameJoin[{NotebookDirectory[],#[[1]],#[[2]]}]]&,files,Heads->False],fit, ImageSize->siz,Method->met,Background->bkg,ImagePadding->pad] ] (**************** insertPDF: ****************) insertPDF::nopdff="PDF file `1` does not exist."; SyntaxInformation[insertPDF]={"ArgumentsPattern"->{_,_,_.,_.,OptionsPattern[]}}; insertPDF[ dir_String, file_String, Optional[pag_/;Or[pag===All,VectorQ[pag,IntegerQ]],All], Optional[arr:(_Symbol|_Function|_Composition|_RightComposition),GraphicsRow], opts:OptionsPattern[] ]:= Module[{path=FileNameJoin[{NotebookDirectory[],dir,file}],img,pdfimopt,arropt}, pdfimopt=FilterRules[{opts},{ImageResolution:>$ImageResolution,RasterSize->Automatic}]; If[FreeQ[pdfimopt,ImageResolution],AppendTo[pdfimopt,ImageResolution:>$ImageResolution]]; If[FreeQ[pdfimopt,RasterSize],AppendTo[pdfimopt,RasterSize->Automatic]]; arropt=FilterRules[{opts},{ImageSize->Automatic,Background->LightGray,Spacings->Scaled[0.1],Frame->None,FrameStyle->Automatic,Dividers->None,AspectRatio->Automatic,ItemAspectRatio->Automatic,Alignment->Automatic,AlignmentPoint->Center,BaselinePosition->Automatic,BaseStyle->{}}]; If[FreeQ[arropt,ImageSize],AppendTo[arropt,ImageSize->Automatic]]; If[FreeQ[arropt,Background],AppendTo[arropt,Background->LightGray]]; If[FreeQ[arropt,Spacings],AppendTo[arropt,Spacings->Scaled[0.1]]]; If[FreeQ[arropt,Frame],AppendTo[arropt,Frame->None]]; If[FreeQ[arropt,FrameStyle],AppendTo[arropt,FrameStyle->Automatic]]; If[FreeQ[arropt,Dividers],AppendTo[arropt,Dividers->None]]; If[FreeQ[arropt,AspectRatio],AppendTo[arropt,AspectRatio->Automatic]]; If[FreeQ[arropt,ItemAspectRatio],AppendTo[arropt,ItemAspectRatio->Automatic]]; If[Not[FileExistsQ[path]],Throw[Message[insertPDF::nopdff,file]/.Null->$Failed,"nopdff",#1&]]; arr[Import[path,{"PageImages",pag},Sequence@@pdfimopt],Sequence@@arropt] ] (**************** amendCSS: ****************) SyntaxInformation[amendCSS]={"ArgumentsPattern"->{_.,_.,_.}}; amendCSS[ hlkcol_String:"454F99", suffix_String:"_orig", tabsty_String:"sh_MAIN" ]:= Module[{ nbbase=FileBaseName[NotebookFileName[]],cssdirbase, cssext=".css",hypinl=".HyperlinkInline {\n color:",replaced }, cssdirbase=FileNameJoin[{NotebookDirectory[],"HTMLFiles",nbbase}]; CopyFile[cssdirbase<>cssext,cssdirbase<>cssext<>suffix,OverwriteTarget->True]; replaced=StringReplace[Import[cssdirbase<>cssext,"Text"],{ hypinl~~c__?(StringMatchQ[#,Whitespace|(Whitespace~~"#"~~(HexadecimalCharacter..))]&)~~";\n padding: 8px;\n}":>hypinl<>If[hlkcol==="",c," #"<>hlkcol]<>";\n padding: 0px;\n}", "padding: 8px;"->"padding: 4px;" }]; If[nbbase===tabsty, replaced=StringJoin["table {\n border-collapse: collapse;\n}\nth, td {\n padding: 4px;\n}\ntr:nth-child(odd) {background-color: #e8e8e8;}\n", replaced] ]; Export[cssdirbase<>cssext,replaced,"Text"]; ] (**************** amendHTML: ****************) SyntaxInformation[amendHTML]={"ArgumentsPattern"->{_.,_.,_.,_.}}; amendHTML[ idxbase_String:"index", suffix_String:"_orig", flairinsert_String:"sh_Wolfram", photoinsert_String:"sh_MAIN" ]:= Module[{ nbbase=FileBaseName[NotebookFileName[]],htmldirbase, htmlext=".html",pres="", aptbegin="

\n \n",aptend="

", flrbegin="\n\n

\n ",flrend="\n

",flair, sigbegin="\n\n ",sigend="\n
\n", imgbegin="",linkbegin,linkend,durlbegin,spanend,brend,brend2,persurl,shorturl,insturl,tmblrurl,streetaddr,streeturl,hrefbegin,titbegin, replaced}, htmldirbase=FileNameJoin[{NotebookDirectory[],nbbase}]; CopyFile[htmldirbase<>htmlext,htmldirbase<>htmlext<>suffix,OverwriteTarget->True]; replaced=StringReplace[Import[htmldirbase<>htmlext,"Text"],{ pres~~Shortest[u__]~~"\""~~Shortest[o___]~~post:>pres<>u<>"\""<>o<>tarblk<>post, pre~~Shortest[u__]~~"\""~~Shortest[o___]~~post:>pre<>u<>"\""<>o<>tarblk<>post }]; If[nbbase===flairinsert, flair="tarblk<>">\"Profile"; replaced=StringReplace[replaced,{ aptbegin~~Shortest[aptbody__]~~aptend:>aptbegin<>aptbody<>aptend<>flrbegin<>flair<>flrend }] ]; If[nbbase===photoinsert, durlbegin="";spanend="";brend="
";brend2="  (as above)
"; persurl="https://is.slu.cz/www/hle0002/"; shorturl="https://bit.ly/A9n"; insturl="https://is.slu.cz/osoba/hle0002"; tmblrurl="https://hlediks.tumblr.com/"; streetaddr="Bezručovo nám. 1150/13";streeturl="https://wolfr.am/1pELlNBSJ"; hrefbegin="persurl<>"htmllinks/RealPhoto.jpg\" title=\"Klikněte sem pro skutečnou fotku!\nClick here to see my real photo!\""<>tarblk<>">"; linkend=""; replaced=StringReplace[StringReplace[replaced,{ sigbegin~~Shortest[befstuff__]~~imgbegin~~Shortest[imgmid__]~~imgend~~Shortest[aftstuff__]~~sigend:>sigbegin<>befstuff<>linkbegin<>imgbegin<>imgmid<>imgend<>linkend<>aftstuff<>sigend }], { durlbegin~~persurl~~brend->durlbegin<>hrefbegin<>persurl<>titbegin<>"\"Můj web\nMy web\""<>tarblk<>post<>persurl<>linkend<>brend, shorturl~~brend2->hrefbegin<>shorturl<>titbegin<>"\"Zkrácený odkaz\nShortened link\""<>tarblk<>post<>shorturl<>linkend<>brend2, insturl~~spanend->hrefbegin<>insturl<>titbegin<>"\"Můj IS profil\nMy IS profile\""<>tarblk<>post<>insturl<>linkend<>spanend, durlbegin~~tmblrurl~~spanend->durlbegin~~hrefbegin<>tmblrurl<>titbegin<>"\"Microblog\""<>tarblk<>post<>tmblrurl<>linkend<>spanend, durlbegin~~streetaddr~~brend->durlbegin<>hrefbegin<>streeturl<>titbegin<>"\"Na mapě\nOn the map\""<>tarblk<>post<>streetaddr<>linkend<>brend }] ]; Export[htmldirbase<>htmlext,replaced,"Text"]; RenameFile[htmldirbase<>htmlext,FileNameJoin[{NotebookDirectory[],idxbase}]<>htmlext,OverwriteTarget->True]; ] (**************** exportAsWebPage: ****************) exportAsWebPage::invtit = "`1` entered as argument \!\(\* StyleBox[\"title\", \"TI\"]\): a string expected."; exportAsWebPage::invdsc = "`1` entered as argument \!\(\* StyleBox[\"description\", \"TI\"]\): a string expected."; exportAsWebPage::invkwd = "`1` entered as argument \!\(\* StyleBox[\"keywords\", \"TI\"]\): a string expected."; exportAsWebPage::invaut = "\"Author\"\[ThinSpace]\[Rule]\[ThinSpace]`1`: a string expected."; exportAsWebPage::invfav = "\"Favicon\"\[ThinSpace]\[Rule]\[ThinSpace]`1`: a string expected."; exportAsWebPage::invvwp = "\"Viewport\"\[ThinSpace]\[Rule]\[ThinSpace]`1`: a string expected."; exportAsWebPage::invfrb = "\"FreshBuild\"\[ThinSpace]\[Rule]\[ThinSpace]`1`: True or False expected."; Options[exportAsWebPage]={ "Author"->"Stanislav Hledik", "Favicon"->"032.ico", (*"Viewport"->"width=device-width, initial-scale=1",*) "Viewport"->"", "FreshBuild"->False }; SyntaxInformation[exportAsWebPage]={"ArgumentsPattern"->{_,_,_,OptionsPattern[]}}; exportAsWebPage[ title_/;Or[StringQ[title], Throw[Message[exportAsWebPage::invtit,title]/.Null->$Failed,"invtit",#1&]], description_/;Or[StringQ[description], Throw[Message[exportAsWebPage::invdsc,description]/.Null->$Failed,"invdsc",#1&]], keywords_/;Or[StringQ[keywords], Throw[Message[exportAsWebPage::invkwd,keywords]/.Null->$Failed,"invkwd",#1&]], opts:OptionsPattern[] ]:= Module[{ author,favic,viewport,fresh, htmlexopt,nd=NotebookDirectory[],nfbn=FileBaseName[NotebookFileName[]], hfqdn,replaced }, {author,favic,viewport,fresh}=OptionValue[exportAsWebPage,FilterRules[{opts},Options[exportAsWebPage]],Keys@Options[exportAsWebPage]]; Or[StringQ[author],Throw[Message[exportAsWebPage::invaut,author]/.Null->$Failed,"invaut",#1&]]; Or[StringQ[favic],Throw[Message[exportAsWebPage::invfav,favic]/.Null->$Failed,"invfav",#1&]]; Or[StringQ[viewport],Throw[Message[exportAsWebPage::invvwp,viewport]/.Null->$Failed,"invvwp",#1&]]; Or[BooleanQ[fresh],Throw[Message[exportAsWebPage::invfrb,fresh]/.Null->$Failed,"invfrb",#1&]]; htmlexopt=FilterRules[{opts},{"Content","ConversionRules","ConvertClosed","ConvertLinkedNotebooks","ConvertReverseClosed","CSS","FullDocument","Graphics3DOutput","GraphicsOutput","HeadAttributes","HeadElements","ManipulateOutput","MathOutput"}]; hfqdn=FileNameJoin[{nd,nfbn}]<>".html"; If[TrueQ@fresh,deleteWebFiles[]]; Export[hfqdn, EvaluationNotebook[],{"HTML","NotebookObject"}, Sequence@@htmlexopt, "Content"->False,"FullDocument"->True, "GraphicsOutput"->"GIF","Graphics3DOutput"->Automatic,"MathOutput"->"InputForm","ManipulateOutput"->"GIF", "HeadAttributes"->{"lang"->"cs"}, "HeadElements"->{ "description<>"\" />", "keywords<>"\" />", "author<>"\" />", "viewport<>"\" />", "nfbn<>"-"<>favic<>"\" />" }]; replaced=StringReplace[Import[hfqdn,"Text"],{""~~Whitespace~~nfbn~~Whitespace~~"":>""<>title<>""},1]; Export[hfqdn<>".tmp",replaced,"Text"]; RenameFile[hfqdn<>".tmp",hfqdn,OverwriteTarget->True]; ] (**************** deleteWebFiles: ****************) SyntaxInformation[deleteWebFiles]={"ArgumentsPattern"->{}}; deleteWebFiles[]:= With[{nd=NotebookDirectory[],nfbn=FileBaseName[NotebookFileName[]]}, {main=FileNameJoin[{nd,nfbn}]<>".html",htmldir="HTMLFiles"}, DeleteFile@Join[If[FileExistsQ[main],{main},{}],FileNameJoin[{nd,htmldir,#}]&/@DeleteCases[Import[FileNameJoin[{nd,htmldir}], "Directory"],s_String/;StringMatchQ[s,nfbn~~"-"~~Repeated[DigitCharacter,{3}]~~(".ico"|".png")]]] ] With[{syms = Apply[Join,Map[Names,{$suitename<>"`*"},Heads->False],Heads->False]}, SetAttributes[syms, {Protected, ReadProtected}] ]; End[(*"`Private`"*)]; EndPackage[(*"WebUtils`"*)];