diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 80039ef9..00000000 --- a/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ - -.gitignore -appsettings.*.json -.idea/ -.vscode/ -.vs/ -YavscWeb.userprefs -bin/ -obj/ -bower_components/ -node_modules/ -docfx_project/ -debugcmd -undefined/ -debugcode/ -kestrel*.pid -kestrel*.log -scaffold.cmds -DataProtection-Keys -RSA-Params.json -Components/ -packages/ -build/ -*.user -*.bak -*~ - diff --git a/Yavsc/ApiControllers/PdfEstimateController.cs b/Yavsc/ApiControllers/PdfEstimateController.cs new file mode 100644 index 00000000..10ba682e --- /dev/null +++ b/Yavsc/ApiControllers/PdfEstimateController.cs @@ -0,0 +1,92 @@ +using System.IO; +using Microsoft.AspNet.Authorization; +using Microsoft.AspNet.Mvc; +using System.Threading.Tasks; +using System.Web.Routing; +using Microsoft.AspNet.Mvc.ViewComponents; +using Microsoft.AspNet.Razor; + +namespace Yavsc.ApiControllers +{ + using Models; + + [Route("api/pdfestimate"), Authorize] + public class PdfEstimateController : Controller + { + ApplicationDbContext dbContext; + DefaultViewComponentHelper helper; + IViewComponentDescriptorCollectionProvider provider; + IViewComponentInvokerFactory factory; + RazorEngineHost host; + RazorTemplateEngine engine; + IViewComponentSelector selector; + + + public PdfEstimateController( + IViewComponentDescriptorCollectionProvider provider, + IViewComponentSelector selector, + IViewComponentInvokerFactory factory, + ApplicationDbContext context) + { + + this.selector = selector; + this.provider = provider; + this.factory = factory; + helper = new DefaultViewComponentHelper(provider, selector, factory); + dbContext = context; + + var language = new CSharpRazorCodeLanguage(); + host = new RazorEngineHost(language) + { + DefaultBaseClass = "RazorPage", + DefaultClassName = "Estimate", + DefaultNamespace = "Yavsc", + }; + + // Everyone needs the System namespace, right? + host.NamespaceImports.Add("System"); + engine = new RazorTemplateEngine(host); + + + /* + GeneratorResults razorResult = + engine.GenerateCode( + + ) */ + } + + + [HttpGet("get/{id}", Name = "Get"), Authorize] + public IActionResult Get(long id) + { + var filename = $"estimate-{id}.pdf"; + + var cd = new System.Net.Mime.ContentDisposition + { + // for example foo.bak + FileName = filename, + + // always prompt the user for downloading, set to true if you want + // the browser to try to show the file inline + Inline = false, + }; + + FileInfo fi = new FileInfo(Path.Combine(Startup.UserBillsDirName, filename)); + if (!fi.Exists) return Ok(new { Error = "Not generated" }); + return File(fi.OpenRead(), "application/x-pdf", filename); ; + } + + [HttpGet("estimate-{id}.tex", Name = "GetTex"), Authorize] + public IActionResult GetTex(long id) + { + Response.ContentType = "text/x-tex"; + return ViewComponent("Estimate",new object[] { id, false }); + } + + [HttpPost("gen/{id}")] + public async Task GeneratePdf(long id) + { + return ViewComponent("Estimate",new object[] { id, true } ); + } + } +} \ No newline at end of file diff --git a/Yavsc/Controllers/FrontOfficeController.cs b/Yavsc/Controllers/FrontOfficeController.cs index a7b8fb8c..e3a0959f 100644 --- a/Yavsc/Controllers/FrontOfficeController.cs +++ b/Yavsc/Controllers/FrontOfficeController.cs @@ -11,7 +11,7 @@ using System; namespace Yavsc.Controllers { - [ServiceFilter(typeof(LanguageActionFilter)), + [ServiceFilter(typeof(LanguageActionFilter)), Route("do")] public class FrontOfficeController : Controller { @@ -35,44 +35,45 @@ namespace Yavsc.Controllers return View(latestPosts); } - [Route("Book/{id?}"),HttpGet] - + [Route("Book/{id?}"), HttpGet] public ActionResult Book(string id) { - if (id == null) { + if (id == null) + { throw new NotImplementedException("No Activity code"); } - + ViewBag.Activities = _context.ActivityItems(id); - ViewBag.Activity = _context.Activities.FirstOrDefault( - a => a.Code == id ); + ViewBag.Activity = _context.Activities.FirstOrDefault( + a => a.Code == id); return View( - _context.Performers.Include(p=>p.Performer).Where + _context.Performers.Include(p => p.Performer).Where (p => p.ActivityCode == id && p.Active).OrderBy( - x=>x.MinDailyCost + x => x.MinDailyCost ) ); } - [Route("Book/{id}"),HttpPost] - + [Route("Book/{id}"), HttpPost] public ActionResult Book(BookQuery bookQuery) { - if (ModelState.IsValid) { + if (ModelState.IsValid) + { var pro = _context.Performers.Include( pr => pr.Performer ).FirstOrDefault( - x=>x.PerformerId == bookQuery.PerformerId + x => x.PerformerId == bookQuery.PerformerId ); - if (pro==null) + if (pro == null) return HttpNotFound(); // Let's create a command - if (bookQuery.Id==0) + if (bookQuery.Id == 0) { _context.BookQueries.Add(bookQuery); } - else { + else + { _context.BookQueries.Update(bookQuery); } _context.SaveChanges(); @@ -81,36 +82,39 @@ namespace Yavsc.Controllers return View("Index"); } ViewBag.Activities = _context.ActivityItems(null); - return View( _context.Performers.Include(p=>p.Performer).Where + return View(_context.Performers.Include(p => p.Performer).Where (p => p.Active).OrderBy( - x=>x.MinDailyCost + x => x.MinDailyCost )); } [Produces("text/x-tex"), Authorize, Route("estimate-{id}.tex")] public ViewResult EstimateTex(long id) { - var estimate = _context.Estimates.Include(x=>x.Query) - .Include(x=>x.Query.Client) - .Include(x=>x.Query.PerformerProfile) - .Include(x=>x.Query.PerformerProfile.OrganizationAddress) - .Include(x=>x.Query.PerformerProfile.Performer) - .Include(e=>e.Bill).FirstOrDefault(x=>x.Id==id); + var estimate = _context.Estimates.Include(x => x.Query) + .Include(x => x.Query.Client) + .Include(x => x.Query.PerformerProfile) + .Include(x => x.Query.PerformerProfile.OrganizationAddress) + .Include(x => x.Query.PerformerProfile.Performer) + .Include(e => e.Bill).FirstOrDefault(x => x.Id == id); Response.ContentType = "text/x-tex"; return View("Estimate.tex", estimate); } - - - [Produces("application/x-pdf"), Authorize, Route("estimate-{id}.pdf")] - public ViewResult EstimatePdf(long id) + + [Authorize,Route("Estimate-{id}.pdf")] + public IActionResult EstimatePdf(long id) { - var estimate = _context.Estimates.Include(x=>x.Query) - .Include(x=>x.Query.Client) - .Include(x=>x.Query.PerformerProfile) - .Include(x=>x.Query.PerformerProfile.OrganizationAddress) - .Include(x=>x.Query.PerformerProfile.Performer) - .Include(e=>e.Bill).FirstOrDefault(x=>x.Id==id); - return View("Estimate.pdf", estimate); + ViewBag.TempDir = Startup.SiteSetup.TempDir; + ViewBag.BillsDir = Startup.UserBillsDirName; + var estimate = _context.Estimates.Include(x => x.Query) + .Include(x => x.Query.Client) + .Include(x => x.Query.PerformerProfile) + .Include(x => x.Query.PerformerProfile.OrganizationAddress) + .Include(x => x.Query.PerformerProfile.Performer) + .Include(e => e.Bill).FirstOrDefault(x => x.Id == id); + if (estimate==null) + throw new Exception("No data"); + return View("Estimate.pdf",estimate); } - } -} \ No newline at end of file + } +} diff --git a/Yavsc/Helpers/TagHelpers.cs b/Yavsc/Helpers/TagHelpers.cs index fca20b37..974cbaa7 100644 --- a/Yavsc/Helpers/TagHelpers.cs +++ b/Yavsc/Helpers/TagHelpers.cs @@ -68,7 +68,6 @@ namespace Yavsc.Helpers /// /// Transforms a string of Markdown into HTML. /// - /// HtmlHelper - Not used, but required to make this an extension method. /// The Markdown that should be transformed. /// The url Base Location. /// The HTML representation of the supplied Markdown. diff --git a/Yavsc/Helpers/TeXHelpers.cs b/Yavsc/Helpers/TeXHelpers.cs index 2157520a..3f5860f9 100644 --- a/Yavsc/Helpers/TeXHelpers.cs +++ b/Yavsc/Helpers/TeXHelpers.cs @@ -1,7 +1,68 @@ +using System; +using System.IO; using System.Linq; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.ViewEngines; +using Microsoft.AspNet.Mvc.ViewFeatures; namespace Yavsc.Helpers { + public class TeXString { + + public class Replacement { + string target; + string replacement; + public Replacement(string target, string replacement){ + this.target=target; + this.replacement=replacement; + } + public string Execute(string source) + { + return source.Replace(target,replacement); + } + } + + public readonly static Replacement[] SpecialCharsToCommands = + { + new Replacement("<","\\textless"), + new Replacement(">","\\textgreater"), + new Replacement("©","\\copyright"), + new Replacement("®","\\textregistered"), + new Replacement("\\","\\textbackslash"), + new Replacement("™","\\texttrademark"), + new Replacement("¶","\\P"), + new Replacement("|","\\textbar"), + new Replacement("%","\\%"), + new Replacement("{","\\{"), + new Replacement("}","\\}"), + new Replacement("_","\\_"), + new Replacement("#","\\#"), + new Replacement("$","\\$"), + new Replacement("_","\\_"), + new Replacement("¿","\\textquestiondown"), + new Replacement("§","\\S"), + new Replacement("£","\\pounds"), + new Replacement("&","\\&"), + new Replacement("¡","\\textexclamdown"), + new Replacement("†","\\dag"), + new Replacement("–","\\textendash") + }; + string data; + public TeXString(string str) { + data = str; + foreach (var r in SpecialCharsToCommands) { + data = r.Execute(data); + } + } + + override public string ToString() + { + return data; + } + } public static class TeXHelpers { public static string NewLinesWith(this string target, string separator) @@ -11,5 +72,39 @@ namespace Yavsc.Helpers return string.Join(separator, items); } + + public static TeXString ToTeX(string target, string lineSeparator="\n\\\\") + { + if (target==null) return null; + return new TeXString(target.NewLinesWith(lineSeparator)); + } + + public static string RenderViewToString( + this Controller controller, IViewEngine engine, + IHttpContextAccessor httpContextAccessor, + string viewName, object model) +{ + using (var sw = new StringWriter()) + { + if (engine == null) + throw new InvalidOperationException("no engine"); + + // try to find the specified view + controller.TryValidateModel(model); + ViewEngineResult viewResult = engine.FindPartialView(controller.ActionContext, viewName); + // create the associated context + ViewContext viewContext = new ViewContext(); + viewContext.ActionDescriptor = controller.ActionContext.ActionDescriptor; + viewContext.HttpContext = controller.ActionContext.HttpContext; + viewContext.TempData = controller.TempData; + viewContext.View = viewResult.View; + viewContext.Writer = sw; + + // write the render view with the given context to the stringwriter + viewResult.View.RenderAsync(viewContext); + viewResult.EnsureSuccessful(); + return sw.GetStringBuilder().ToString(); + } +} } } \ No newline at end of file diff --git a/Yavsc/Settings/SiteSettings.cs b/Yavsc/Settings/SiteSettings.cs index 03cc63ee..7801060f 100644 --- a/Yavsc/Settings/SiteSettings.cs +++ b/Yavsc/Settings/SiteSettings.cs @@ -16,15 +16,32 @@ namespace Yavsc /// /// public string Authority { get; set; } + /// + /// Owner's email + /// + /// public EmailEntry Owner { get; set; } + /// + /// Administrator's email + /// + /// public EmailEntry Admin { get; set; } + /// + /// User's files directory + /// + /// public ThirdPartyFiles UserFiles { get; set; } public string BusinessName { get; set; } public string Street { get; set; } public string PostalCode { get; set; } public string CountryCode { get; set; } - + /// + /// Specifies the directory where should be + /// generated pdf files using pandoc + /// + /// The temporary directory to use + public string TempDir { get; set; } = "Temp"; } } diff --git a/Yavsc/Startup/Startup.FileServer.cs b/Yavsc/Startup/Startup.FileServer.cs index 2f66ed44..d9012fb0 100644 --- a/Yavsc/Startup/Startup.FileServer.cs +++ b/Yavsc/Startup/Startup.FileServer.cs @@ -12,6 +12,7 @@ namespace Yavsc { public static string UserFilesDirName { get; private set; } public static FileServerOptions UserFilesOptions { get; private set; } + public void ConfigureFileServerApp(IApplicationBuilder app, SiteSettings siteSettings, IHostingEnvironment env) { diff --git a/Yavsc/Startup/Startup.cs b/Yavsc/Startup/Startup.cs index f409d99c..e06782e9 100755 --- a/Yavsc/Startup/Startup.cs +++ b/Yavsc/Startup/Startup.cs @@ -1,6 +1,7 @@ using System; using System.Globalization; +using System.IO; using System.Reflection; using System.Threading.Tasks; using System.Web.Optimization; @@ -32,8 +33,11 @@ namespace Yavsc public partial class Startup { public static string ConnectionString { get; private set; } + public static string UserBillsDirName { private set; get; } public static string Authority { get; private set; } public static string Audience { get; private set; } + public static SiteSettings SiteSetup { get; private set; } + private static ILogger logger; public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) { @@ -225,7 +229,18 @@ namespace Yavsc RoleManager roleManager, ILoggerFactory loggerFactory) { + SiteSetup = siteSettings.Value; Startup.UserFilesDirName = siteSettings.Value.UserFiles.DirName; + Startup.UserBillsDirName = siteSettings.Value.UserFiles.Bills; + + // TODO implement an installation & upgrade procedure + // Create required directories + foreach (string dir in new string[] { Startup.UserFilesDirName, Startup.UserBillsDirName, SiteSetup.TempDir }) + { + DirectoryInfo di = new DirectoryInfo(dir); + if (!di.Exists) di.Create(); + } + loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); logger = loggerFactory.CreateLogger(); diff --git a/Yavsc/ViewComponents/EstimateViewComponent.cs b/Yavsc/ViewComponents/EstimateViewComponent.cs new file mode 100644 index 00000000..720bc2f1 --- /dev/null +++ b/Yavsc/ViewComponents/EstimateViewComponent.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNet.Mvc; +using Microsoft.Data.Entity; +using Yavsc.Models; +using Yavsc.Models.Billing; +using Yavsc.ViewModels.Gen; + +namespace Yavsc.ViewComponents +{ + public class EstimateViewComponent : ViewComponent + { + ApplicationDbContext dbContext; + public EstimateViewComponent(ApplicationDbContext dbContext) + { + this.dbContext = dbContext; + } + public async Task InvokeAsync(long id, bool toPdf = false) + { + Estimate estimate = + dbContext.Estimates.Include(x => x.Query) + .Include(x => x.Query.Client) + .Include(x => x.Query.PerformerProfile) + .Include(x => x.Query.PerformerProfile.OrganizationAddress) + .Include(x => x.Query.PerformerProfile.Performer) + .Include(e => e.Bill).FirstOrDefault(x => x.Id == id); + if (estimate == null) + throw new Exception("No data"); + if (toPdf) + { + string tex = null; + var oldWriter = ViewComponentContext.ViewContext.Writer; + + using (var writer = new StringWriter()) + { + this.ViewComponentContext.ViewContext.Writer = writer; + + var resultTex = View("Estimate_tex", estimate); + resultTex.Execute(this.ViewComponentContext); + tex = writer.ToString(); + + } + ViewComponentContext.ViewContext.Writer = oldWriter; + + return this.View("Estimate_pdf", + new PdfGenerationViewModel{ + TeXSource = tex, + DestDir = Startup.UserBillsDirName, + BaseFileName = $"estimate-{id}" + } ); + } + return this.View("Estimate_tex", estimate); + } + + } +} \ No newline at end of file diff --git a/Yavsc/ViewModels/Gen/PdfGenerationViewModel.cs b/Yavsc/ViewModels/Gen/PdfGenerationViewModel.cs new file mode 100644 index 00000000..6c193de4 --- /dev/null +++ b/Yavsc/ViewModels/Gen/PdfGenerationViewModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Yavsc.ViewModels.Gen +{ + public class PdfGenerationViewModel + { + [Required] + public string TeXSource { get; set; } + [Required] + public string BaseFileName { get; set; } + [Required] + public string DestDir { get; set; } + } +} \ No newline at end of file diff --git a/Yavsc/Views/Estimate/Details.cshtml b/Yavsc/Views/Estimate/Details.cshtml index ae367964..a838acf4 100644 --- a/Yavsc/Views/Estimate/Details.cshtml +++ b/Yavsc/Views/Estimate/Details.cshtml @@ -39,6 +39,12 @@ @SR["Back to List"] | @{ var filenametex = $"estimate-{Model.Id}.tex" ; var filenamepdf = $"estimate-{Model.Id}.pdf" ;} - Export au format LaTeX - Export au format LaTeX + Export au format LaTeX + + +
+ +
+ Télécharger le document +

diff --git a/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml b/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml deleted file mode 100644 index a8bb2b06..00000000 --- a/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml +++ /dev/null @@ -1,55 +0,0 @@ - -@using System.Reflection -@using System.IO -@using Microsoft.Extensions.WebEncoders -@using System.Diagnostics -@using System.Text -@using Yavsc.Formatters - -@model Estimate -@{ - Layout = null; - ViewBag.Pdf = ""; - ViewBag.TeX = ""; - var writer = new System.IO.StringWriter(); - var content = await Html.PartialAsync("Estimate.tex", Model ); - content.WriteTo(writer, new TexEncoder()); - var contentStr = writer.ToString(); - string name = $"tmpestimtex-{Model.Id}"; - string fullname = new FileInfo( - System.IO.Path.Combine(ViewBag.TempDir,name)).FullName; - - FileInfo fi = new FileInfo(fullname + ".tex"); - FileInfo fo = new FileInfo(fullname + ".pdf"); - using (StreamWriter sw = new StreamWriter (fi.FullName)) - { - sw.Write (contentStr); - } - if (!fi.Exists) - { - throw new Exception ("Source write failed"); - } - using (Process p = new Process ()) { - p.StartInfo.WorkingDirectory = ViewBag.TempDir; - p.StartInfo = new ProcessStartInfo (); - p.StartInfo.UseShellExecute = false; - p.StartInfo.FileName = "/usr/bin/texi2pdf"; - p.StartInfo.Arguments = $"--batch --build-dir=. -o {fo.FullName} {fi.FullName}"; - p.Start (); - p.WaitForExit (); - if (p.ExitCode != 0) { - throw new Exception ("Pdf generation failed with exit code:" + p.ExitCode); - } - } - if (fo.Exists) { - UTF8Encoding utf8 = new UTF8Encoding(); - - using (StreamReader sr = new StreamReader (fo.FullName)) { - byte[] buffer = File.ReadAllBytes (fo.FullName); - ViewBag.Pdf = utf8.GetString(buffer,0,buffer.Length); - } - fo.Delete(); - } - fi.Delete(); -} -@ViewBag.Pdf diff --git a/Yavsc/Views/Shared/Components/Estimate/Estimate_pdf.cshtml b/Yavsc/Views/Shared/Components/Estimate/Estimate_pdf.cshtml new file mode 100644 index 00000000..08664810 --- /dev/null +++ b/Yavsc/Views/Shared/Components/Estimate/Estimate_pdf.cshtml @@ -0,0 +1,50 @@ +@using System.Reflection +@using System.IO +@using Microsoft.Extensions.WebEncoders +@using System.Diagnostics +@using System.Text +@using Yavsc.Formatters +@model Yavsc.ViewModels.Gen.PdfGenerationViewModel +@{ + string errorMsg = null; + var billdir = Model.DestDir; + var tempdir = Startup.SiteSetup.TempDir; + string name = Model.BaseFileName; + string fullname = new FileInfo( + System.IO.Path.Combine(tempdir,name)).FullName; + string ofullname = new FileInfo( + System.IO.Path.Combine(billdir,name)).FullName; + + FileInfo fi = new FileInfo(fullname + ".tex"); + FileInfo fo = new FileInfo(ofullname + ".pdf"); + using (StreamWriter sw = new StreamWriter (fi.FullName)) + { + sw.Write (Model.TeXSource); + } + if (!fi.Exists) + { + errorMsg = "Source write failed"; + } + else { + using (Process p = new Process ()) { + p.StartInfo.WorkingDirectory = tempdir; + p.StartInfo = new ProcessStartInfo (); + p.StartInfo.UseShellExecute = false; + p.StartInfo.FileName = "/usr/bin/texi2pdf"; + p.StartInfo.Arguments = $"--batch --build-dir=. -o {fo.FullName} {fi.FullName}"; + p.Start (); + p.WaitForExit (); + if (p.ExitCode != 0) { + errorMsg = $"Pdf generation failed with exit code: {p.ExitCode}"; + } + } + fi.Delete(); + } + ViewBag.GenSuccess = fo.Exists; +} +@if (ViewBag.GenSuccess) { + @($"{name}.pdf") +} else { + @errorMsg + Something went wrong ... +} \ No newline at end of file diff --git a/Yavsc/Views/FrontOffice/Estimate.tex.cshtml b/Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml similarity index 78% rename from Yavsc/Views/FrontOffice/Estimate.tex.cshtml rename to Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml index 9633eba9..5f8c9d89 100644 --- a/Yavsc/Views/FrontOffice/Estimate.tex.cshtml +++ b/Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml @@ -1,5 +1,6 @@ -@model Estimate @using Yavsc.Helpers +@using System.Globalization +@model Estimate @{ Layout = null; var pro = Model.Query.PerformerProfile; @@ -9,8 +10,8 @@ var proaddr = Model.Query?.PerformerProfile.OrganizationAddress.Address; var proaddrn = (proaddr!=null) ? proaddr.NewLinesWith("\\\\\n") : null ; var proaddrm = (proaddr!=null) ? proaddr.NewLinesWith(" - ") : null ; -} -\documentclass[french,11pt]{article} +}\documentclass[french,11pt]{article} +\usepackage{eurosym} \usepackage{babel} \usepackage[T1]{fontenc} \usepackage[utf8]{inputenc} @@ -68,33 +69,29 @@ \def\FactureNum {@Model.Id.ToString()} % Numéro de facture \def\FactureAcquittee {non} % Facture acquittée : oui/non \def\FactureLieu {@proaddrn} % Lieu de l'édition de la facture -\def\FactureObjet {Facture : @Model.Title} % Objet du document +\def\FactureObjet {Facture : @TeXHelpers.ToTeX(Model.Title)} % Objet du document % Description de la facture \def\FactureDescr { - @Model.Description + @TeXHelpers.ToTeX(Model.Description) } % Infos Client -\def\ClientNom{@to.UserName} % Nom du client +\def\ClientNom{@TeXHelpers.ToTeX(to.UserName)} % Nom du client \def\ClientAdresse{ % Adresse du client @if (!string.IsNullOrWhiteSpace(PostalAddress)) { - @PostalAddress\\ } + @TeXHelpers.ToTeX(PostalAddress)\\ } @if (!string.IsNullOrWhiteSpace(to.PhoneNumber)) { - @to.PhoneNumber \\ + @TeXHelpers.ToTeX(to.PhoneNumber)\\ } - E-mail: @to.Email + E-mail: @TeXHelpers.ToTeX(to.Email) } % Liste des produits facturés : Désignation, prix - -@if (Model.Bill!=null) {  - foreach (CommandLine line in Model.Bill) { - -\AjouterService {@line.Description} {@line.Count} {@line.UnitaryCost} - -} } +@if (Model.Bill!=null) { foreach (CommandLine line in Model.Bill) { +\AjouterService{@TeXHelpers.ToTeX(line.Description)}{@line.Count}{@line.UnitaryCost.ToString("F2",CultureInfo.InvariantCulture)} +} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -109,24 +106,24 @@ \setlength{\parindent}{0pt} \renewcommand{\headrulewidth}{0pt} -\cfoot{ @if (!string.IsNullOrWhiteSpace(from.UserName)) { @from.UserName } - @if (!string.IsNullOrWhiteSpace(proaddrm)) { - @proaddrm } \newline - \small{ E-mail: @from.Email - @if (!string.IsNullOrWhiteSpace(from.PhoneNumber)) { - Téléphone fixe: @from.PhoneNumber } +\cfoot{ @TeXHelpers.ToTeX(from.UserName) @if (!string.IsNullOrWhiteSpace(proaddrm)) { - @TeXHelpers.ToTeX(proaddrm) } \newline + \small{ E-mail: @TeXHelpers.ToTeX(from.Email) @if (!string.IsNullOrWhiteSpace(from.PhoneNumber)) { - Téléphone fixe: @TeXHelpers.ToTeX(from.PhoneNumber) } } } \begin{document} % Logo de la société -@if (from.Avatar != null) { -\includegraphics{@from.Avatar} -} else { -%\includegraphics{logo.png} +@if (from.Avatar != null) { +\includegraphics{@from.Avatar} + +} else { +%\includegraphics{logo.png} + } % Nom et adresse de la société - @from.UserName \\ - @proaddrn + @TeXHelpers.ToTeX(from.UserName) \\ + @TeXHelpers.ToTeX(proaddrn) Facture n°\FactureNum @@ -151,7 +148,7 @@ Facture n°\FactureNum \begin{center} \begin{tabular}{lrrr} - \textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (EUR)} \\ + \textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (\euro)} \\ \hline \AfficheResultat{} \end{tabular} diff --git a/Yavsc/estimate-3.t2d/pdf/bak/estimate-3.aux b/Yavsc/estimate-3.t2d/pdf/bak/estimate-3.aux new file mode 100644 index 00000000..2398624f --- /dev/null +++ b/Yavsc/estimate-3.t2d/pdf/bak/estimate-3.aux @@ -0,0 +1,9 @@ +\relax +\catcode `:\active +\catcode `;\active +\catcode `!\active +\catcode `?\active +\select@language{french} +\@writefile{toc}{\select@language{french}} +\@writefile{lof}{\select@language{french}} +\@writefile{lot}{\select@language{french}} diff --git a/Yavsc/project.json b/Yavsc/project.json index e8fd7ef1..96bcff9c 100755 --- a/Yavsc/project.json +++ b/Yavsc/project.json @@ -140,5 +140,6 @@ "postrestore": "echo after restoring packages", "prepublish": "gulp min", "postpublish": "echo \" . ./contrib/postPublish.sh # to push in prod.\"" - } + }, + "embed": "Views/**/*.cshtml" } \ No newline at end of file diff --git a/Yavsc/tmpestimtex-3.t2d/pdf/bak/tmpestimtex-3.aux b/Yavsc/tmpestimtex-3.t2d/pdf/bak/tmpestimtex-3.aux new file mode 100644 index 00000000..2398624f --- /dev/null +++ b/Yavsc/tmpestimtex-3.t2d/pdf/bak/tmpestimtex-3.aux @@ -0,0 +1,9 @@ +\relax +\catcode `:\active +\catcode `;\active +\catcode `!\active +\catcode `?\active +\select@language{french} +\@writefile{toc}{\select@language{french}} +\@writefile{lof}{\select@language{french}} +\@writefile{lot}{\select@language{french}} diff --git a/Yavsc/wwwroot/js/to-markdown.js b/Yavsc/wwwroot/js/to-markdown.js index ca2372d1..b81025ed 100644 --- a/Yavsc/wwwroot/js/to-markdown.js +++ b/Yavsc/wwwroot/js/to-markdown.js @@ -2,204 +2,151 @@ /* * to-markdown - an HTML to Markdown converter * - * Copyright 2011-15, Dom Christie + * Copyright 2011+, Dom Christie * Licenced under the MIT licence * */ -'use strict'; - -var toMarkdown; -var converters; -var mdConverters = require('./lib/md-converters'); -var gfmConverters = require('./lib/gfm-converters'); -var collapse = require('collapse-whitespace'); +'use strict' -/* - * Set up window and document for Node.js - */ - -var _window = (typeof window !== 'undefined' ? window : this), _document; -if (typeof document === 'undefined') { - _document = require('jsdom').jsdom(); -} -else { - _document = document; -} +var toMarkdown +var converters +var mdConverters = require('./lib/md-converters') +var gfmConverters = require('./lib/gfm-converters') +var HtmlParser = require('./lib/html-parser') +var collapse = require('collapse-whitespace') /* * Utilities */ -function trim(string) { - return string.replace(/^[ \r\n\t]+|[ \r\n\t]+$/g, ''); -} - var blocks = ['address', 'article', 'aside', 'audio', 'blockquote', 'body', 'canvas', 'center', 'dd', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption', - 'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4','h5', 'h6', + 'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'html', 'isindex', 'li', 'main', 'menu', 'nav', 'noframes', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul' -]; +] -function isBlock(node) { - return blocks.indexOf(node.nodeName.toLowerCase()) !== -1; +function isBlock (node) { + return blocks.indexOf(node.nodeName.toLowerCase()) !== -1 } var voids = [ 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr' -]; - -function isVoid(node) { - return voids.indexOf(node.nodeName.toLowerCase()) !== -1; -} - -/* - * Parsing HTML strings - */ - -function canParseHtml() { - var Parser = _window.DOMParser, canParse = false; - - // Adapted from https://gist.github.com/1129031 - // Firefox/Opera/IE throw errors on unsupported types - try { - // WebKit returns null on unsupported types - if (new Parser().parseFromString('', 'text/html')) { - canParse = true; - } - } catch (e) {} - return canParse; -} - -function createHtmlParser() { - var Parser = function () {}; +] - Parser.prototype.parseFromString = function (string) { - var newDoc = _document.implementation.createHTMLDocument(''); - - if (string.toLowerCase().indexOf(' -1) { - newDoc.documentElement.innerHTML = string; - } - else { - newDoc.body.innerHTML = string; - } - return newDoc; - }; - return Parser; +function isVoid (node) { + return voids.indexOf(node.nodeName.toLowerCase()) !== -1 } -var HtmlParser = canParseHtml() ? _window.DOMParser : createHtmlParser(); - -function htmlToDom(string) { - var tree = new HtmlParser().parseFromString(string, 'text/html'); - collapse(tree, isBlock); - return tree; +function htmlToDom (string) { + var tree = new HtmlParser().parseFromString(string, 'text/html') + collapse(tree.documentElement, isBlock) + return tree } /* * Flattens DOM tree into single array */ -function bfsOrder(node) { - var inqueue = [node], - outqueue = [], - elem, children, i; +function bfsOrder (node) { + var inqueue = [node] + var outqueue = [] + var elem + var children + var i while (inqueue.length > 0) { - elem = inqueue.shift(); - outqueue.push(elem); - children = elem.childNodes; - for (i = 0 ; i < children.length; i++) { - if (children[i].nodeType === 1) { inqueue.push(children[i]); } + elem = inqueue.shift() + outqueue.push(elem) + children = elem.childNodes + for (i = 0; i < children.length; i++) { + if (children[i].nodeType === 1) inqueue.push(children[i]) } } - outqueue.shift(); - return outqueue; + outqueue.shift() + return outqueue } /* * Contructs a Markdown string of replacement text for a given node */ -function getContent(node) { - var text = ''; +function getContent (node) { + var text = '' for (var i = 0; i < node.childNodes.length; i++) { if (node.childNodes[i].nodeType === 1) { - text += node.childNodes[i]._replacement; - } - else if (node.childNodes[i].nodeType === 3) { - text += node.childNodes[i].data; - } - else { continue; } + text += node.childNodes[i]._replacement + } else if (node.childNodes[i].nodeType === 3) { + text += node.childNodes[i].data + } else continue } - return text; + return text } /* * Returns the HTML string of an element with its contents converted */ -function outer(node, content) { - return node.cloneNode(false).outerHTML.replace('><', '>'+ content +'<'); +function outer (node, content) { + return node.cloneNode(false).outerHTML.replace('><', '>' + content + '<') } -function canConvert(node, filter) { +function canConvert (node, filter) { if (typeof filter === 'string') { - return filter === node.nodeName.toLowerCase(); + return filter === node.nodeName.toLowerCase() } if (Array.isArray(filter)) { - return filter.indexOf(node.nodeName.toLowerCase()) !== -1; - } - else if (typeof filter === 'function') { - return filter.call(toMarkdown, node); - } - else { - throw new TypeError('`filter` needs to be a string, array, or function'); + return filter.indexOf(node.nodeName.toLowerCase()) !== -1 + } else if (typeof filter === 'function') { + return filter.call(toMarkdown, node) + } else { + throw new TypeError('`filter` needs to be a string, array, or function') } } -function isFlankedByWhitespace(side, node) { - var sibling, regExp, isFlanked; +function isFlankedByWhitespace (side, node) { + var sibling + var regExp + var isFlanked if (side === 'left') { - sibling = node.previousSibling; - regExp = / $/; - } - else { - sibling = node.nextSibling; - regExp = /^ /; + sibling = node.previousSibling + regExp = / $/ + } else { + sibling = node.nextSibling + regExp = /^ / } if (sibling) { if (sibling.nodeType === 3) { - isFlanked = regExp.test(sibling.nodeValue); - } - else if(sibling.nodeType === 1 && !isBlock(sibling)) { - isFlanked = regExp.test(sibling.textContent); + isFlanked = regExp.test(sibling.nodeValue) + } else if (sibling.nodeType === 1 && !isBlock(sibling)) { + isFlanked = regExp.test(sibling.textContent) } } - return isFlanked; + return isFlanked } -function flankingWhitespace(node) { - var leading = '', trailing = ''; +function flankingWhitespace (node, content) { + var leading = '' + var trailing = '' if (!isBlock(node)) { - var hasLeading = /^[ \r\n\t]/.test(node.innerHTML), - hasTrailing = /[ \r\n\t]$/.test(node.innerHTML); + var hasLeading = /^[ \r\n\t]/.test(content) + var hasTrailing = /[ \r\n\t]$/.test(content) if (hasLeading && !isFlankedByWhitespace('left', node)) { - leading = ' '; + leading = ' ' } if (hasTrailing && !isFlankedByWhitespace('right', node)) { - trailing = ' '; + trailing = ' ' } } - return { leading: leading, trailing: trailing }; + return { leading: leading, trailing: trailing } } /* @@ -207,154 +154,158 @@ function flankingWhitespace(node) { * `_replacement` */ -function process(node) { - var replacement, content = getContent(node); +function process (node) { + var replacement + var content = getContent(node) // Remove blank nodes - if (!isVoid(node) && !/A/.test(node.nodeName) && /^\s*$/i.test(content)) { - node._replacement = ''; - return; + if (!isVoid(node) && !/A|TH|TD/.test(node.nodeName) && /^\s*$/i.test(content)) { + node._replacement = '' + return } for (var i = 0; i < converters.length; i++) { - var converter = converters[i]; + var converter = converters[i] if (canConvert(node, converter.filter)) { if (typeof converter.replacement !== 'function') { throw new TypeError( '`replacement` needs to be a function that returns a string' - ); + ) } - var whitespace = flankingWhitespace(node); + var whitespace = flankingWhitespace(node, content) if (whitespace.leading || whitespace.trailing) { - content = trim(content); + content = content.trim() } replacement = whitespace.leading + - converter.replacement.call(toMarkdown, content, node) + - whitespace.trailing; - break; + converter.replacement.call(toMarkdown, content, node) + + whitespace.trailing + break } } - node._replacement = replacement; + node._replacement = replacement } toMarkdown = function (input, options) { - options = options || {}; + options = options || {} if (typeof input !== 'string') { - throw new TypeError(input + ' is not a string'); + throw new TypeError(input + ' is not a string') + } + + if (input === '') { + return '' } // Escape potential ol triggers - input = input.replace(/(\d+)\. /g, '$1\\. '); + input = input.replace(/(\d+)\. /g, '$1\\. ') - var clone = htmlToDom(input).body, - nodes = bfsOrder(clone), - output; + var clone = htmlToDom(input).body + var nodes = bfsOrder(clone) + var output - converters = mdConverters.slice(0); + converters = mdConverters.slice(0) if (options.gfm) { - converters = gfmConverters.concat(converters); + converters = gfmConverters.concat(converters) } if (options.converters) { - converters = options.converters.concat(converters); + converters = options.converters.concat(converters) } // Process through nodes in reverse (so deepest child elements are first). for (var i = nodes.length - 1; i >= 0; i--) { - process(nodes[i]); + process(nodes[i]) } - output = getContent(clone); + output = getContent(clone) return output.replace(/^[\t\r\n]+|[\t\r\n\s]+$/g, '') - .replace(/\n\s+\n/g, '\n\n') - .replace(/\n{3,}/g, '\n\n'); -}; + .replace(/\n\s+\n/g, '\n\n') + .replace(/\n{3,}/g, '\n\n') +} -toMarkdown.isBlock = isBlock; -toMarkdown.isVoid = isVoid; -toMarkdown.trim = trim; -toMarkdown.outer = outer; +toMarkdown.isBlock = isBlock +toMarkdown.isVoid = isVoid +toMarkdown.outer = outer -module.exports = toMarkdown; +module.exports = toMarkdown -},{"./lib/gfm-converters":2,"./lib/md-converters":3,"collapse-whitespace":4,"jsdom":7}],2:[function(require,module,exports){ -'use strict'; +},{"./lib/gfm-converters":2,"./lib/html-parser":3,"./lib/md-converters":4,"collapse-whitespace":7}],2:[function(require,module,exports){ +'use strict' -function cell(content, node) { - var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node); - var prefix = ' '; - if (index === 0) { prefix = '| '; } - return prefix + content + ' |'; +function cell (content, node) { + var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node) + var prefix = ' ' + if (index === 0) prefix = '| ' + return prefix + content + ' |' } -var highlightRegEx = /highlight highlight-(\S+)/; +var highlightRegEx = /highlight highlight-(\S+)/ module.exports = [ { filter: 'br', replacement: function () { - return '\n'; + return '\n' } }, { filter: ['del', 's', 'strike'], replacement: function (content) { - return '~~' + content + '~~'; + return '~~' + content + '~~' } }, { filter: function (node) { - return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'; + return node.type === 'checkbox' && node.parentNode.nodeName === 'LI' }, replacement: function (content, node) { - return (node.checked ? '[x]' : '[ ]') + ' '; + return (node.checked ? '[x]' : '[ ]') + ' ' } }, { filter: ['th', 'td'], replacement: function (content, node) { - return cell(content, node); + return cell(content, node) } }, { filter: 'tr', replacement: function (content, node) { - var borderCells = ''; - var alignMap = { left: ':--', right: '--:', center: ':-:' }; + var borderCells = '' + var alignMap = { left: ':--', right: '--:', center: ':-:' } if (node.parentNode.nodeName === 'THEAD') { for (var i = 0; i < node.childNodes.length; i++) { - var align = node.childNodes[i].attributes.align; - var border = '---'; + var align = node.childNodes[i].attributes.align + var border = '---' - if (align) { border = alignMap[align.value] || border; } + if (align) border = alignMap[align.value] || border - borderCells += cell(border, node.childNodes[i]); + borderCells += cell(border, node.childNodes[i]) } } - return '\n' + content + (borderCells ? '\n' + borderCells : ''); + return '\n' + content + (borderCells ? '\n' + borderCells : '') } }, { filter: 'table', replacement: function (content) { - return '\n\n' + content + '\n\n'; + return '\n\n' + content + '\n\n' } }, { filter: ['thead', 'tbody', 'tfoot'], replacement: function (content) { - return content; + return content } }, @@ -362,11 +313,11 @@ module.exports = [ { filter: function (node) { return node.nodeName === 'PRE' && - node.firstChild && - node.firstChild.nodeName === 'CODE'; + node.firstChild && + node.firstChild.nodeName === 'CODE' }, - replacement: function(content, node) { - return '\n\n```\n' + node.firstChild.textContent + '\n```\n\n'; + replacement: function (content, node) { + return '\n\n```\n' + node.firstChild.textContent + '\n```\n\n' } }, @@ -374,233 +325,357 @@ module.exports = [ { filter: function (node) { return node.nodeName === 'PRE' && - node.parentNode.nodeName === 'DIV' && - highlightRegEx.test(node.parentNode.className); + node.parentNode.nodeName === 'DIV' && + highlightRegEx.test(node.parentNode.className) }, replacement: function (content, node) { - var language = node.parentNode.className.match(highlightRegEx)[1]; - return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n'; + var language = node.parentNode.className.match(highlightRegEx)[1] + return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n' } }, { filter: function (node) { return node.nodeName === 'DIV' && - highlightRegEx.test(node.className); + highlightRegEx.test(node.className) }, replacement: function (content) { - return '\n\n' + content + '\n\n'; + return '\n\n' + content + '\n\n' } } -]; +] },{}],3:[function(require,module,exports){ -'use strict'; +/* + * Set up window for Node.js + */ + +var _window = (typeof window !== 'undefined' ? window : this) + +/* + * Parsing HTML strings + */ + +function canParseHtmlNatively () { + var Parser = _window.DOMParser + var canParse = false + + // Adapted from https://gist.github.com/1129031 + // Firefox/Opera/IE throw errors on unsupported types + try { + // WebKit returns null on unsupported types + if (new Parser().parseFromString('', 'text/html')) { + canParse = true + } + } catch (e) {} + + return canParse +} + +function createHtmlParser () { + var Parser = function () {} + + // For Node.js environments + if (typeof document === 'undefined') { + var jsdom = require('jsdom') + Parser.prototype.parseFromString = function (string) { + return jsdom.jsdom(string, { + features: { + FetchExternalResources: [], + ProcessExternalResources: false + } + }) + } + } else { + if (!shouldUseActiveX()) { + Parser.prototype.parseFromString = function (string) { + var doc = document.implementation.createHTMLDocument('') + doc.open() + doc.write(string) + doc.close() + return doc + } + } else { + Parser.prototype.parseFromString = function (string) { + var doc = new window.ActiveXObject('htmlfile') + doc.designMode = 'on' // disable on-page scripts + doc.open() + doc.write(string) + doc.close() + return doc + } + } + } + return Parser +} + +function shouldUseActiveX () { + var useActiveX = false + + try { + document.implementation.createHTMLDocument('').open() + } catch (e) { + if (window.ActiveXObject) useActiveX = true + } + + return useActiveX +} + +module.exports = canParseHtmlNatively() ? _window.DOMParser : createHtmlParser() + +},{"jsdom":6}],4:[function(require,module,exports){ +'use strict' module.exports = [ { filter: 'p', replacement: function (content) { - return '\n\n' + content + '\n\n'; - } - }, - { - filter: 'div', - replacement: function (content) { - return content + '\n'; + return '\n\n' + content + '\n\n' } }, + { filter: 'br', replacement: function () { - return ' \n'; + return ' \n' } }, { - filter: ['h1', 'h2', 'h3', 'h4','h5', 'h6'], - replacement: function(content, node) { - var hLevel = node.nodeName.charAt(1); - var hPrefix = ''; - for(var i = 0; i < hLevel; i++) { - hPrefix += '#'; + filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + replacement: function (content, node) { + var hLevel = node.nodeName.charAt(1) + var hPrefix = '' + for (var i = 0; i < hLevel; i++) { + hPrefix += '#' } - return '\n\n' + hPrefix + ' ' + content + '\n\n'; + return '\n\n' + hPrefix + ' ' + content + '\n\n' } }, { filter: 'hr', replacement: function () { - return '\n\n* * *\n\n'; + return '\n\n* * *\n\n' } }, { filter: ['em', 'i'], replacement: function (content) { - return '*' + content + '*'; + return '_' + content + '_' + } + }, + + { + filter: ['strong', 'b'], + replacement: function (content) { + return '**' + content + '**' } }, { filter: ['u'], replacement: function (content) { - return '_' + content + '_'; + return '_' + content + '_' } }, { - filter: ['strong', 'b'], + filter: ['del', 's', 'strike'], replacement: function (content) { - return '**' + content + '**'; + return '~~' + content + '~~' } }, { - filter: ['strike','s'], + filter: 'div', replacement: function (content) { - return '~~' + content + '~~'; + return content + '\n\n' } }, + // Inline code { filter: function (node) { - var hasSiblings = node.previousSibling || node.nextSibling; - var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings; + var hasSiblings = node.previousSibling || node.nextSibling + var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings - return node.nodeName === 'CODE' && !isCodeBlock; + return node.nodeName === 'CODE' && !isCodeBlock }, - replacement: function(content) { - return '`' + content + '`'; + replacement: function (content) { + return '`' + content + '`' } }, + { filter: function (node) { - return node.nodeName === 'A' && node.getAttribute('href'); + return node.nodeName === 'A' && node.getAttribute('href') }, - replacement: function(content, node) { - var titlePart = node.title ? ' "'+ node.title +'"' : ''; - return '[' + content + '](' + node.getAttribute('href') + titlePart + ')'; + replacement: function (content, node) { + var titlePart = node.title ? ' "' + node.title + '"' : '' + return '[' + content + '](' + node.getAttribute('href') + titlePart + ')' } }, - { filter: 'video', - replacement: function(content, node) { - var alt = node.getAttribute("alt") || ''; - var src ; - for (var i = 0; i < node.childNodes.length; i++) - { - if (node.childNodes[i].localName == 'source') { - src = node.childNodes[i].getAttribute('src') ; - break; - } - } - var title = node.title || ''; - var titlePart = title ? ' "'+ title +'"' : ''; - return src ? '![video:' + alt + ']' + '(' + src + titlePart + ')' : ''; + replacement: function (content, node) { + var alt = node.getAttribute('alt') || '' + var src + for (var i = 0; i < node.childNodes.length; i++) { + if (node.childNodes[i].localName === 'source') { + src = node.childNodes[i].getAttribute('src') + break + } } + var title = node.title || '' + var titlePart = title ? ' "' + title + '"' : '' + return src ? '![video:' + alt + ']' + '(' + src + titlePart + ')' : '' } }, { filter: 'audio', - replacement: function(content, node) { - var alt = node.getAttribute("alt") || ''; - var src = node.getAttribute('src') || ''; - if (!src) - for (var i = 0; i < node.childNodes.length; i++) - { - if (node.childNodes[i].localName == 'source') { - src = node.childNodes[i].getAttribute('src') ; - break; - } - } - var title = node.title || ''; - var titlePart = title ? ' "'+ title +'"' : ''; - return src ? '![audio:' + alt + ']' + '(' + src + titlePart + ')' : ''; + replacement: function (content, node) { + var alt = node.getAttribute('alt') || '' + var src = node.getAttribute('src') || '' + if (!src) { + for (var i = 0; i < node.childNodes.length; i++) { + if (node.childNodes[i].localName === 'source') { + src = node.childNodes[i].getAttribute('src') + break + } } } + var title = node.title || '' + var titlePart = title ? ' "' + title + '"' : '' + return src ? '![audio:' + alt + ']' + '(' + src + titlePart + ')' : '' } }, + { filter: 'img', - replacement: function(content, node) { - var alt = node.getAttribute("alt") || ''; - var src = node.getAttribute('src') || ''; - var title = node.getAttribute('title') || ''; - var titlePart = title ? ' "'+ title +'"' : ''; - return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''; + replacement: function (content, node) { + var alt = node.alt || '' + var src = node.getAttribute('src') || '' + var title = node.title || '' + var titlePart = title ? ' "' + title + '"' : '' + return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '' } }, // Code blocks { filter: function (node) { - return node.nodeName === 'PRE' && node.firstChild.nodeName === 'CODE'; + return node.nodeName === 'PRE' && node.firstChild.nodeName === 'CODE' }, - replacement: function(content, node) { - return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n'; + replacement: function (content, node) { + return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n' } }, { filter: 'blockquote', replacement: function (content) { - content = this.trim(content); - content = content.replace(/\n{3,}/g, '\n\n'); - content = content.replace(/^/gm, '> '); - return '\n\n' + content + '\n\n'; + content = content.trim() + content = content.replace(/\n{3,}/g, '\n\n') + content = content.replace(/^/gm, '> ') + return '\n\n' + content + '\n\n' } }, { filter: 'li', replacement: function (content, node) { - content = content.replace(/^\s+/, '').replace(/\n/gm, '\n '); - var prefix = '* '; - var parent = node.parentNode; - var index = Array.prototype.indexOf.call(parent.children, node) + 1; + content = content.replace(/^\s+/, '').replace(/\n/gm, '\n ') + var prefix = '* ' + var parent = node.parentNode + var index = Array.prototype.indexOf.call(parent.children, node) + 1 - prefix = /ol/i.test(parent.nodeName) ? index + '. ' : '* '; - return prefix + content; + prefix = /ol/i.test(parent.nodeName) ? index + '. ' : '* ' + return prefix + content } }, { filter: ['ul', 'ol'], replacement: function (content, node) { - var strings = []; + var strings = [] for (var i = 0; i < node.childNodes.length; i++) { - strings.push(node.childNodes[i]._replacement); + strings.push(node.childNodes[i]._replacement) } if (/li/i.test(node.parentNode.nodeName)) { - return '\n' + strings.join('\n'); + return '\n' + strings.join('\n') } - return '\n\n' + strings.join('\n') + '\n\n'; + return '\n\n' + strings.join('\n') + '\n\n' } }, { filter: function (node) { - return this.isBlock(node); + return this.isBlock(node) }, replacement: function (content, node) { - return '\n\n' + this.outer(node, content) + '\n\n'; + return '\n\n' + this.outer(node, content) + '\n\n' } }, // Anything else! { filter: function () { - return true; + return true }, replacement: function (content, node) { - return this.outer(node, content); + return this.outer(node, content) } } +] + +},{}],5:[function(require,module,exports){ +/** + * This file automatically generated from `build.js`. + * Do not manually edit. + */ + +module.exports = [ + "address", + "article", + "aside", + "audio", + "blockquote", + "canvas", + "dd", + "div", + "dl", + "fieldset", + "figcaption", + "figure", + "footer", + "form", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "header", + "hgroup", + "hr", + "main", + "nav", + "noscript", + "ol", + "output", + "p", + "pre", + "section", + "table", + "tfoot", + "ul", + "video" ]; -},{}],4:[function(require,module,exports){ +},{}],6:[function(require,module,exports){ + +},{}],7:[function(require,module,exports){ 'use strict'; var voidElements = require('void-elements'); @@ -738,51 +813,7 @@ function next(prev, current) { module.exports = collapseWhitespace; -},{"block-elements":5,"void-elements":6}],5:[function(require,module,exports){ -/** - * This file automatically generated from `build.js`. - * Do not manually edit. - */ - -module.exports = [ - "address", - "article", - "aside", - "audio", - "blockquote", - "canvas", - "dd", - "div", - "dl", - "fieldset", - "figcaption", - "figure", - "footer", - "form", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "header", - "hgroup", - "hr", - "main", - "nav", - "noscript", - "ol", - "output", - "p", - "pre", - "section", - "table", - "tfoot", - "ul", - "video" -]; - -},{}],6:[function(require,module,exports){ +},{"block-elements":5,"void-elements":8}],8:[function(require,module,exports){ /** * This file automatically generated from `pre-publish.js`. * Do not manually edit. @@ -807,7 +838,5 @@ module.exports = { "wbr": true }; -},{}],7:[function(require,module,exports){ - },{}]},{},[1])(1) }); \ No newline at end of file