cortav  Diff

Differences From Artifact [78b49cf252]:

To Artifact [8ab06e9795]:


   401    401   			h1 {
   402    402   				page-break-before: always;
   403    403   			}
   404    404   			h1,h2,h3,h4,h5,h6 {
   405    405   				page-break-after: avoid;
   406    406   			}
   407    407   		]];
          408  +		linkBlock = [[
          409  +			a[href].link {
          410  +				position: relative;
          411  +				display: block;
          412  +				padding: .5em;
          413  +				padding-right: 1.5em;
          414  +				border: 1px solid @tone(0.2 30);
          415  +				background: @tone(0.05 30);
          416  +				font-size: 1.1em;
          417  +				margin: 0 1em;
          418  +				text-decoration: none;
          419  +				color: @tone(0.8 30);
          420  +			}
          421  +			a[href].link + a[href].link {
          422  +				margin-top: -1px;
          423  +			}
          424  +			a[href].link:hover {
          425  +				border-color: @tone(0.3 30);
          426  +				background: @tone(0.2 30);
          427  +				color: @tone(0.95 30);
          428  +			}
          429  +			a[href].link:hover + a[href].link {
          430  +				margin-top: 0;
          431  +				border-top: none;
          432  +			}
          433  +			a[href].link::after {
          434  +				display: block;
          435  +				position: absolute;
          436  +				right: .5em;
          437  +				content: "→";
          438  +				top: 50%;
          439  +				margin-left: 1em;
          440  +				font-size: 1.8em;
          441  +				transform: translateY(-50%);
          442  +				color: @tone(0.3 30);
          443  +			}
          444  +			a[href].link:hover::after {
          445  +				color: @tone(0.7 30);
          446  +			}
          447  +		]];
   408    448   	}
   409    449   
   410    450   	local stylesNeeded = {
   411    451   		flags = {};
   412    452   		order = {};
   413    453   	}
   414    454   	local function addStyle(sty)
................................................................................
   447    487   
   448    488   	local renderJob = doc:job('render_html', nil, render_state_handle)
   449    489   	doc.stage.job = renderJob;
   450    490   
   451    491   	local runhook = function(h, ...)
   452    492   		return renderJob:hook(h, render_state_handle, ...)
   453    493   	end
          494  +
          495  +	local function htmlURI(uri)
          496  +		local family = uri:canfetch()
          497  +		if family == 'file' then
          498  +			if uri.namespace == 'localhost' then
          499  +				-- emit an actual file url
          500  +				return 'file://' .. uri:construct('path','frag')
          501  +			elseif uri.namespace == nil then
          502  +				-- this is gonna be tricky. first we establish the location
          503  +				-- of the CWD/asset base relative to the output file (if any;
          504  +				-- assume equivalent otherwise) then express the difference
          505  +				-- as a directory prefix.
          506  +				-- jk tho for now we just emit the path+frag sadlol TODO
          507  +				if uri.path == nil and uri.frag then
          508  +					-- file:#sec links to #sec within the current document
          509  +					return uri:part 'frag'
          510  +				else
          511  +					return uri:construct('path','frag')
          512  +				end
          513  +			else
          514  +				b.origin:fail('file: URI namespace must be empty or “localhost” for HTML links; others are not meaningful (offending URI: “%s”)', uri.raw)
          515  +			end
          516  +		elseif family == 'http' then
          517  +			local sc = 'http'
          518  +			if uri.class[1] == 'https' or uri.class[2] == 'tls' then
          519  +				sc = 'https'
          520  +			end
          521  +			if uri.namespace == nil and uri.auth == nil and uri.svc == nil then
          522  +				-- omit the scheme so we can use a relative path
          523  +				return uri:construct('path','query','frag')
          524  +			else
          525  +				uri.class = {sc}
          526  +				return tostring(uri)
          527  +			end
          528  +		else return tostring(uri) end
          529  +	end
          530  +
          531  +	local function idLink(id,b)
          532  +		local dest_o, _, dest_s = b.origin:ref(id)
          533  +		if dest_o == nil then
          534  +			-- link is to the section itself
          535  +			return '#' .. getSafeID(dest_s)
          536  +		else
          537  +			if type(dest_o) == 'table' then
          538  +				return '#' .. getSafeID(dest_o)
          539  +			else -- URI in reference
          540  +				return htmlURI(ss.uri(dest_o))
          541  +			end
          542  +		end
          543  +	end
   454    544   
   455    545   	local tagproc do
   456    546   		local html_open = function(t,attrs)
   457    547   			if attrs then
   458    548   				return t .. ss.reduce(function(a,b) return a..b end, '',
   459    549   					ss.map(function(v,k)
   460    550   						if v == true
................................................................................
   611    701   		end
   612    702   
   613    703   		function span_renderers.raw(v,b,s)
   614    704   			return htmlSpan(v.spans, b, s)
   615    705   		end
   616    706   
   617    707   		function span_renderers.link(sp,b,s)
   618         -			local dest_o, _, dest_s = b.origin:ref(sp.ref)
   619         -			local href
   620         -			if dest_o == nil then
   621         -				-- link is to the section itself
   622         -				href = '#' .. getSafeID(dest_s)
   623         -			else
   624         --- 				if sp.addr then href = sp.addr else
   625         -				if type(dest_o) == 'table' then
   626         -					href = '#' .. getSafeID(dest_o)
   627         -				else -- URI in reference
   628         -					local uri = ss.uri(dest_o)
   629         -					if uri.class[1] == 'file'
   630         -					or uri.class[1] == 'asset' then
   631         -						if uri.namespace == 'localhost' then
   632         -							-- emit an actual file url
   633         -							href = 'file://' .. uri:construct('path','frag')
   634         -						elseif uri.namespace == nil then
   635         -							-- this is gonna be tricky. first we establish the location
   636         -							-- of the CWD/asset base relative to the output file (if any;
   637         -							-- assume equivalent otherwise) then express the difference
   638         -							-- as a directory prefix.
   639         -							-- jk tho for now we just emit the path+frag sadlol TODO
   640         -							href = uri:construct('path','frag')
   641         -						else
   642         -							b.origin:fail('file: URI namespace must be empty or “localhost” for HTML links; others are not meaningful (offending URI: “%s”)', dest_o)
   643         -						end
   644         -					elseif uri:canfetch() == 'http' then
   645         -						local sc = 'http'
   646         -						if uri.class[1] == 'https' or uri.class[2] == 'tls' then
   647         -							sc = 'https'
   648         -						end
   649         -						if uri.namespace == nil and uri.auth == nil and uri.svc == nil then
   650         -							-- omit the scheme so we can use a relative path
   651         -							href = uri:construct('path','query','frag')
   652         -						else
   653         -							uri.class = {sc}
   654         -							href = tostring(uri)
   655         -						end
   656         -					else href = tostring(uri) end
   657         -				end
   658         -			end
   659         -			return tag('a',{href=href},next(sp.spans) and htmlSpan(sp.spans,b,s) or href)
          708  +			local href = idLink(sp.ref,b)
          709  +			return tag('a',{href=href}, next(sp.spans) and htmlSpan(sp.spans,b,s) or href)
   660    710   		end
   661    711   
   662    712   		span_renderers['line-break'] = function(sp,b,s)
   663    713   			return elt('br')
   664    714   		end
   665    715   
   666    716   		function span_renderers.macro(m,b,s)
................................................................................
   773    823   				else
   774    824   					-- handle other uses of labels here
   775    825   				end
   776    826   			end;
   777    827   			['list-item'] = function(b,s)
   778    828   				return tag('li', nil, sr.htmlSpan(b.spans, b, s), b)
   779    829   			end;
          830  +			link = function(b,s)
          831  +				addStyle 'linkBlock'
          832  +				local href
          833  +				if b.uri then
          834  +					href = htmlURI(b.uri)
          835  +				elseif b.ref then
          836  +					href = idLink(b.ref, b)
          837  +				end
          838  +				local sp = sr.htmlSpan(b.spans, b, s)
          839  +				return tag('div', {},
          840  +					catenate{tag('a',{class='link', href=href},sp)})
          841  +			end;
   780    842   			table = function(b,s)
   781    843   				local tb = {}
   782    844   				for i, r in ipairs(b.rows) do
   783    845   					local row = {}
   784    846   					for i, c in ipairs(r) do
   785    847   						table.insert(row, tag(c.header and 'th' or 'td',
   786    848   						{align=c.align}, sr.htmlSpan(c.spans, b)))
................................................................................
   863    925   
   864    926   		function block_renderers.embed(b,s)
   865    927   			local obj
   866    928   			if b.rsrc
   867    929   				then obj = b.rsrc
   868    930   				else obj = b.origin:ref(b.ref)
   869    931   			end
   870         -			local function htmlURI(u)
   871         -				local family = u:canfetch()
   872         -				if  family == 'file' or
   873         -					(family == 'http' and u.namespace == nil) then
   874         -					-- TODO asset:
   875         -					return u.path
   876         -				else
   877         -					return tostring(u)
   878         -				end
   879         -			end
   880    932   			local function uriForSource(s)
   881    933   				if s.mode == 'link' or s.mode == 'auto' then
   882    934   					return htmlURI(s.uri)
   883    935   				elseif s.mode == 'embed' then
   884    936   					local mime = s.mime:clone()
   885    937   					mime.opts = {}
   886    938   					return string.format('data:%s;base64,%s', mime, ss.str.b64e(s.raw))