From 3f8b5a865ad7f8d58f92c68bef45d8e63dbc480d Mon Sep 17 00:00:00 2001 From: benweet Date: Thu, 14 Aug 2014 00:44:33 +0100 Subject: [PATCH] Implemented PDF options --- app/pdf.js | 7 +- public/res/core.js | 23 +- public/res/extensions/dialogAbout.js | 6 + public/res/html/bodyIndex.html | 36 +- .../res/html/tooltipSettingsPdfOptions.html | 19 + public/res/providers/dropboxProvider.js | 2 +- public/res/providers/gdriveProviderBuilder.js | 2 +- public/res/publisher.js | 703 +++++++++--------- public/res/settings.js | 4 +- public/res/utils.js | 19 +- 10 files changed, 449 insertions(+), 372 deletions(-) create mode 100644 public/res/html/tooltipSettingsPdfOptions.html diff --git a/app/pdf.js b/app/pdf.js index cc72c864..f125cfad 100644 --- a/app/pdf.js +++ b/app/pdf.js @@ -18,10 +18,10 @@ module.exports = function(req, res, next) { } // Margins - var marginRight = parseInt(options.marginRight); - params.push('-R', isNaN(marginRight) ? 25 : marginRight); var marginTop = parseInt(options.marginTop); params.push('-T', isNaN(marginTop) ? 25 : marginTop); + var marginRight = parseInt(options.marginRight); + params.push('-R', isNaN(marginRight) ? 25 : marginRight); var marginBottom = parseInt(options.marginBottom); params.push('-B', isNaN(marginBottom) ? 25 : marginBottom); var marginLeft = parseInt(options.marginLeft); @@ -42,8 +42,7 @@ module.exports = function(req, res, next) { options.footerFontSize && params.push('--footer-font-size ', options.footerFontSize); // Page size - var pageSize = options.pageSize; - params.push('--page-size', authorizedPageSizes.indexOf(pageSize) === -1 ? 'A4' : pageSize); + params.push('--page-size', authorizedPageSizes.indexOf(options.pageSize) === -1 ? 'A4' : options.pageSize); // wkhtmltopdf can't access /dev/stdout on Amazon EC2 for some reason var filePath = '/tmp/' + Date.now() + '.pdf'; diff --git a/public/res/core.js b/public/res/core.js index a26c531e..d1c23c75 100644 --- a/public/res/core.js +++ b/public/res/core.js @@ -14,9 +14,10 @@ define([ "text!html/bodyIndex.html", "text!html/bodyViewer.html", "text!html/tooltipSettingsTemplate.html", + "text!html/tooltipSettingsPdfOptions.html", "storage", 'pagedown' -], function($, _, crel, editor, layout, constants, utils, storage, settings, eventMgr, MonetizeJS, bodyIndexHTML, bodyViewerHTML, settingsTemplateTooltipHTML) { +], function($, _, crel, editor, layout, constants, utils, storage, settings, eventMgr, MonetizeJS, bodyIndexHTML, bodyViewerHTML, settingsTemplateTooltipHTML, settingsPdfOptionsTooltipHTML) { var core = {}; @@ -142,8 +143,8 @@ define([ utils.setInputValue("#textarea-settings-publish-template", settings.template); // PDF template utils.setInputValue("#textarea-settings-pdf-template", settings.pdfTemplate); - // PDF page size - utils.setInputValue("#input-settings-pdf-page-size", settings.pdfPageSize); + // PDF options + utils.setInputValue("#textarea-settings-pdf-options", settings.pdfOptions); // SSH proxy utils.setInputValue("#input-settings-ssh-proxy", settings.sshProxy); @@ -189,8 +190,8 @@ define([ newSettings.template = utils.getInputTextValue("#textarea-settings-publish-template", event); // PDF template newSettings.pdfTemplate = utils.getInputTextValue("#textarea-settings-pdf-template", event); - // PDF page size - newSettings.pdfPageSize = utils.getInputValue("#input-settings-pdf-page-size"); + // PDF options + newSettings.pdfOptions = utils.getInputJSONValue("#textarea-settings-pdf-options", event); // SSH proxy newSettings.sshProxy = utils.checkUrl(utils.getInputTextValue("#input-settings-ssh-proxy", event), true); @@ -331,10 +332,12 @@ define([ }); var $alerts = $(); - function hasPaid(payments) { - return payments && ( + function isSponsor(payments) { + var result = payments && ( (payments.chargeOption && payments.chargeOption.alias == 'once') || (payments.subscriptionOption && payments.subscriptionOption.alias == 'yearly')); + eventMgr.isSponsor = result; + return result; } function removeAlerts() { @@ -346,11 +349,10 @@ define([ monetize.getPayments({ pricingOptions: [ 'once', - 'monthly', 'yearly' ] }, function(err, payments) { - if(hasPaid(payments)) { + if(isSponsor(payments)) { eventMgr.onMessage('Thank you for sponsoring StackEdit!'); removeAlerts(); } @@ -363,7 +365,7 @@ define([ } monetize.getPaymentsImmediate(function(err, payments) { removeAlerts(); - if(!hasPaid(payments)) { + if(!isSponsor(payments)) { _.each(document.querySelectorAll('.modal-body'), function(modalBodyElt) { var $elt = $('
Please consider sponsoring StackEdit for $5/year (or sign in if you\'re already a sponsor).
'); $elt.find('a').click(performPayment); @@ -542,6 +544,7 @@ define([ 'NOTE: Backlinks in Stack Exchange Q/A are not welcome.' ].join('')); utils.createTooltip(".tooltip-template", settingsTemplateTooltipHTML); + utils.createTooltip(".tooltip-pdf-options", settingsPdfOptionsTooltipHTML); // Avoid dropdown panels to close on click $("div.dropdown-menu").click(function(e) { diff --git a/public/res/extensions/dialogAbout.js b/public/res/extensions/dialogAbout.js index 1adae893..6268e2d6 100644 --- a/public/res/extensions/dialogAbout.js +++ b/public/res/extensions/dialogAbout.js @@ -10,6 +10,11 @@ define([ var dialogAbout = new Extension("dialogAbout", 'Dialog "About"'); + var eventMgr; + dialogAbout.onEventMgrCreated = function(eventMgrParameter) { + eventMgr = eventMgrParameter; + }; + var monetize = new MonetizeJS({ applicationID: 'iklMbzDI7dvMEScb' }); @@ -22,6 +27,7 @@ define([ monetize.getPayments({ summary: true }, function() { + eventMgr.onMessage('Please refresh the page for your sponsorship to take effect.'); }); }); }; diff --git a/public/res/html/bodyIndex.html b/public/res/html/bodyIndex.html index 77fffb3b..5bad0226 100644 --- a/public/res/html/bodyIndex.html +++ b/public/res/html/bodyIndex.html @@ -89,7 +89,7 @@
Synchronize
- Backup, collaborate in the cloud + Backup, collaborate...
@@ -1072,14 +1072,12 @@
- +
- +
@@ -1303,4 +1301,24 @@
+ + +
diff --git a/public/res/html/tooltipSettingsPdfOptions.html b/public/res/html/tooltipSettingsPdfOptions.html new file mode 100644 index 00000000..48268b50 --- /dev/null +++ b/public/res/html/tooltipSettingsPdfOptions.html @@ -0,0 +1,19 @@ +Option object in JSON format. Possible attributes: +

+marginTop, +marginRight, +marginBottom, +marginLeft,
+headerCenter, +headerLeft, +headerRight, +headerFontName, +headerFontSize,
+footerCenter, +footerLeft, +footerRight, +footerFontName, +footerFontSize
+pageSize

+Please check out the +wkhtmltopdf documentation for more info. diff --git a/public/res/providers/dropboxProvider.js b/public/res/providers/dropboxProvider.js index 1e4b1c13..c2e01b40 100644 --- a/public/res/providers/dropboxProvider.js +++ b/public/res/providers/dropboxProvider.js @@ -86,7 +86,7 @@ define([ var syncIndex = createSyncIndex(path); var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex); if(fileDesc !== undefined) { - return eventMgr.onError('"' + fileDesc.title + '" was already imported.'); + return eventMgr.onError('"' + fileDesc.title + '" is already in your local documents.'); } importPaths.push(path); }); diff --git a/public/res/providers/gdriveProviderBuilder.js b/public/res/providers/gdriveProviderBuilder.js index b0f5e575..136d7091 100644 --- a/public/res/providers/gdriveProviderBuilder.js +++ b/public/res/providers/gdriveProviderBuilder.js @@ -91,7 +91,7 @@ define([ var syncIndex = createSyncIndex(doc.id); var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex); if(fileDesc !== undefined) { - return eventMgr.onError('"' + fileDesc.title + '" was already imported.'); + return eventMgr.onError('"' + fileDesc.title + '" is already in your local documents.'); } importIds.push(doc.id); }); diff --git a/public/res/publisher.js b/public/res/publisher.js index f2b0b53a..ede3c881 100644 --- a/public/res/publisher.js +++ b/public/res/publisher.js @@ -1,376 +1,391 @@ define([ - "jquery", - "underscore", - "constants", - "utils", - "storage", - "settings", - "eventMgr", - "fileSystem", - "fileMgr", - "sharing", - "classes/Provider", - "classes/AsyncTask", - "providers/bloggerProvider", - "providers/bloggerPageProvider", - "providers/dropboxProvider", - "providers/gistProvider", - "providers/githubProvider", - "providers/gdriveProvider", - "providers/gdrivesecProvider", - "providers/gdriveterProvider", - "providers/sshProvider", - "providers/tumblrProvider", - "providers/wordpressProvider" -], function($, _, constants, utils, storage, settings, eventMgr, fileSystem, fileMgr, sharing, Provider, AsyncTask) { + "jquery", + "underscore", + "constants", + "utils", + "storage", + "settings", + "eventMgr", + "fileSystem", + "fileMgr", + "sharing", + "monetizejs", + "classes/Provider", + "classes/AsyncTask", + "providers/bloggerProvider", + "providers/bloggerPageProvider", + "providers/dropboxProvider", + "providers/gistProvider", + "providers/githubProvider", + "providers/gdriveProvider", + "providers/gdrivesecProvider", + "providers/gdriveterProvider", + "providers/sshProvider", + "providers/tumblrProvider", + "providers/wordpressProvider" +], function($, _, constants, utils, storage, settings, eventMgr, fileSystem, fileMgr, sharing, MonetizeJS, Provider, AsyncTask) { - var publisher = {}; + var publisher = {}; - // Create a map with providerId: providerModule - var providerMap = _.chain(arguments).map(function(argument) { - return argument instanceof Provider && argument.isPublishEnabled === true && [ - argument.providerId, - argument - ]; - }).compact().object().value(); + // Create a map with providerId: providerModule + var providerMap = _.chain(arguments).map(function(argument) { + return argument instanceof Provider && argument.isPublishEnabled === true && [ + argument.providerId, + argument + ]; + }).compact().object().value(); - // Retrieve publish locations from storage - (function() { - var publishIndexMap = {}; - _.each(fileSystem, function(fileDesc) { - utils.retrieveIndexArray(fileDesc.fileIndex + ".publish").forEach(function(publishIndex) { - try { - var publishAttributes = JSON.parse(storage[publishIndex]); - // Store publishIndex - publishAttributes.publishIndex = publishIndex; - // Replace provider ID by provider module in attributes - var provider = providerMap[publishAttributes.provider]; - if(!provider) { - throw new Error("Invalid provider ID: " + publishAttributes.provider); - } - publishAttributes.provider = provider; - fileDesc.publishLocations[publishIndex] = publishAttributes; - publishIndexMap[publishIndex] = publishAttributes; - } - catch(e) { - // storage can be corrupted - eventMgr.onError(e); - // Remove publish location - utils.removeIndexFromArray(fileDesc.fileIndex + ".publish", publishIndex); - } - }); - }); + // Retrieve publish locations from storage + (function() { + var publishIndexMap = {}; + _.each(fileSystem, function(fileDesc) { + utils.retrieveIndexArray(fileDesc.fileIndex + ".publish").forEach(function(publishIndex) { + try { + var publishAttributes = JSON.parse(storage[publishIndex]); + // Store publishIndex + publishAttributes.publishIndex = publishIndex; + // Replace provider ID by provider module in attributes + var provider = providerMap[publishAttributes.provider]; + if(!provider) { + throw new Error("Invalid provider ID: " + publishAttributes.provider); + } + publishAttributes.provider = provider; + fileDesc.publishLocations[publishIndex] = publishAttributes; + publishIndexMap[publishIndex] = publishAttributes; + } + catch(e) { + // storage can be corrupted + eventMgr.onError(e); + // Remove publish location + utils.removeIndexFromArray(fileDesc.fileIndex + ".publish", publishIndex); + } + }); + }); - // Clean fields from deleted files in local storage - Object.keys(storage).forEach(function(key) { - var match = key.match(/publish\.\S+/); - if(match && !publishIndexMap.hasOwnProperty(match[0])) { - storage.removeItem(key); - } - }); - })(); + // Clean fields from deleted files in local storage + Object.keys(storage).forEach(function(key) { + var match = key.match(/publish\.\S+/); + if(match && !publishIndexMap.hasOwnProperty(match[0])) { + storage.removeItem(key); + } + }); + })(); - // Apply template to the current document - publisher.applyTemplate = function(fileDesc, publishAttributes, html) { - try { - var template = (publishAttributes && publishAttributes.customTmpl) || settings.template; - return _.template(template, { - documentTitle: fileDesc.title, - documentMarkdown: fileDesc.content, - strippedDocumentMarkdown: fileDesc.content.substring(fileDesc.frontMatter ? fileDesc.frontMatter._frontMatter.length : 0), - documentHTML: html.withoutComments, + // Apply template to the current document + publisher.applyTemplate = function(fileDesc, publishAttributes, html) { + try { + var template = (publishAttributes && publishAttributes.customTmpl) || settings.template; + return _.template(template, { + documentTitle: fileDesc.title, + documentMarkdown: fileDesc.content, + strippedDocumentMarkdown: fileDesc.content.substring(fileDesc.frontMatter ? fileDesc.frontMatter._frontMatter.length : 0), + documentHTML: html.withoutComments, documentHTMLWithFrontMatter: (fileDesc.frontMatter ? fileDesc.frontMatter._frontMatter : '') + html.withoutComments, - documentHTMLWithComments: html.withComments, - frontMatter: fileDesc.frontMatter, - publishAttributes: publishAttributes - }); - } - catch(e) { - eventMgr.onError(e); - return e.message; - } - }; + documentHTMLWithComments: html.withComments, + frontMatter: fileDesc.frontMatter, + publishAttributes: publishAttributes + }); + } + catch(e) { + eventMgr.onError(e); + return e.message; + } + }; - // Used to get content to publish - function getPublishContent(fileDesc, publishAttributes, html) { - if(publishAttributes.format === undefined) { - publishAttributes.format = utils.getInputRadio("radio-publish-format"); - if(publishAttributes.format == 'template' && utils.getInputChecked("#checkbox-publish-custom-template")) { - publishAttributes.customTmpl = utils.getInputValue('#textarea-publish-custom-template'); - } - } - if(publishAttributes.format == "markdown") { - return fileDesc.content; - } - else if(publishAttributes.format == "html") { - return html.withoutComments; - } - else { - return publisher.applyTemplate(fileDesc, publishAttributes, html); - } - } + // Used to get content to publish + function getPublishContent(fileDesc, publishAttributes, html) { + if(publishAttributes.format === undefined) { + publishAttributes.format = utils.getInputRadio("radio-publish-format"); + if(publishAttributes.format == 'template' && utils.getInputChecked("#checkbox-publish-custom-template")) { + publishAttributes.customTmpl = utils.getInputValue('#textarea-publish-custom-template'); + } + } + if(publishAttributes.format == "markdown") { + return fileDesc.content; + } + else if(publishAttributes.format == "html") { + return html.withoutComments; + } + else { + return publisher.applyTemplate(fileDesc, publishAttributes, html); + } + } - // Recursive function to publish a file on multiple locations - var publishAttributesList = []; - var publishFileDesc; - var publishHTML; - function publishLocation(callback, errorFlag) { + // Recursive function to publish a file on multiple locations + var publishAttributesList = []; + var publishFileDesc; + var publishHTML; - // No more publish location for this document - if(publishAttributesList.length === 0) { - callback(errorFlag); - return; - } + function publishLocation(callback, errorFlag) { - // Dequeue a synchronized location - var publishAttributes = publishAttributesList.pop(); + // No more publish location for this document + if(publishAttributesList.length === 0) { + callback(errorFlag); + return; + } - // Format the content - var content = getPublishContent(publishFileDesc, publishAttributes, publishHTML); - var title = (publishFileDesc.frontMatter || {}).title || publishFileDesc.title; + // Dequeue a synchronized location + var publishAttributes = publishAttributesList.pop(); - // Call the provider - publishAttributes.provider.publish(publishAttributes, publishFileDesc.frontMatter, title, content, function(error) { - if(error !== undefined) { - var errorMsg = error.toString(); - if(errorMsg.indexOf("|removePublish") !== -1) { - publishFileDesc.removePublishLocation(publishAttributes); - eventMgr.onPublishRemoved(publishFileDesc, publishAttributes); - } - if(errorMsg.indexOf("|stopPublish") !== -1) { - callback(error); - return; - } - } - publishLocation(callback, errorFlag || error); - }); - } + // Format the content + var content = getPublishContent(publishFileDesc, publishAttributes, publishHTML); + var title = (publishFileDesc.frontMatter || {}).title || publishFileDesc.title; - // Get the html from the onPreviewFinished callback - var currentHTML; - eventMgr.addListener("onPreviewFinished", function(htmlWithComments, htmlWithoutComments) { - currentHTML = { - withComments: htmlWithComments, - withoutComments: htmlWithoutComments - }; - }); + // Call the provider + publishAttributes.provider.publish(publishAttributes, publishFileDesc.frontMatter, title, content, function(error) { + if(error !== undefined) { + var errorMsg = error.toString(); + if(errorMsg.indexOf("|removePublish") !== -1) { + publishFileDesc.removePublishLocation(publishAttributes); + eventMgr.onPublishRemoved(publishFileDesc, publishAttributes); + } + if(errorMsg.indexOf("|stopPublish") !== -1) { + callback(error); + return; + } + } + publishLocation(callback, errorFlag || error); + }); + } - // Listen to offline status changes - var isOffline = false; - eventMgr.addListener("onOfflineChanged", function(isOfflineParam) { - isOffline = isOfflineParam; - }); + // Get the html from the onPreviewFinished callback + var currentHTML; + eventMgr.addListener("onPreviewFinished", function(htmlWithComments, htmlWithoutComments) { + currentHTML = { + withComments: htmlWithComments, + withoutComments: htmlWithoutComments + }; + }); - var publishRunning = false; - publisher.publish = function() { - // If publish is running or offline - if(publishRunning === true || isOffline === true) { - return; - } + // Listen to offline status changes + var isOffline = false; + eventMgr.addListener("onOfflineChanged", function(isOfflineParam) { + isOffline = isOfflineParam; + }); - publishRunning = true; - eventMgr.onPublishRunning(true); - publishFileDesc = fileMgr.currentFile; - publishHTML = currentHTML; - publishAttributesList = _.values(publishFileDesc.publishLocations); - publishLocation(function(errorFlag) { - publishRunning = false; - eventMgr.onPublishRunning(false); - if(errorFlag === undefined) { - eventMgr.onPublishSuccess(publishFileDesc); - } - }); - }; + var publishRunning = false; + publisher.publish = function() { + // If publish is running or offline + if(publishRunning === true || isOffline === true) { + return; + } - // Generate a publishIndex associated to a file and store publishAttributes - function createPublishIndex(fileDesc, publishAttributes) { - var publishIndex; - do { - publishIndex = "publish." + utils.randomString(); - } while (_.has(storage, publishIndex)); - publishAttributes.publishIndex = publishIndex; - fileDesc.addPublishLocation(publishAttributes); - eventMgr.onNewPublishSuccess(fileDesc, publishAttributes); - } + publishRunning = true; + eventMgr.onPublishRunning(true); + publishFileDesc = fileMgr.currentFile; + publishHTML = currentHTML; + publishAttributesList = _.values(publishFileDesc.publishLocations); + publishLocation(function(errorFlag) { + publishRunning = false; + eventMgr.onPublishRunning(false); + if(errorFlag === undefined) { + eventMgr.onPublishSuccess(publishFileDesc); + } + }); + }; - // Initialize the "New publication" dialog - var newLocationProvider; - function initNewLocation(provider) { - var defaultPublishFormat = provider.defaultPublishFormat || "markdown"; - newLocationProvider = provider; - $(".publish-provider-name").text(provider.providerName); + // Generate a publishIndex associated to a file and store publishAttributes + function createPublishIndex(fileDesc, publishAttributes) { + var publishIndex; + do { + publishIndex = "publish." + utils.randomString(); + } while(_.has(storage, publishIndex)); + publishAttributes.publishIndex = publishIndex; + fileDesc.addPublishLocation(publishAttributes); + eventMgr.onNewPublishSuccess(fileDesc, publishAttributes); + } - // Show/hide controls depending on provider - $('.modal-publish [class*=" modal-publish-"]').hide().filter(".modal-publish-" + provider.providerId).show(); + // Initialize the "New publication" dialog + var newLocationProvider; - // Reset fields - utils.resetModalInputs(); - utils.setInputRadio("radio-publish-format", defaultPublishFormat); - utils.setInputChecked("#checkbox-publish-custom-template", false); - utils.setInputValue('#textarea-publish-custom-template', settings.template); + function initNewLocation(provider) { + var defaultPublishFormat = provider.defaultPublishFormat || "markdown"; + newLocationProvider = provider; + $(".publish-provider-name").text(provider.providerName); - // Load preferences - var publishPreferences = utils.retrieveIgnoreError(provider.providerId + ".publishPreferences"); - if(publishPreferences) { - _.each(provider.publishPreferencesInputIds, function(inputId) { - var publishPreferenceValue = publishPreferences[inputId]; - if(_.isBoolean(publishPreferenceValue)) { - utils.setInputChecked("#input-publish-" + inputId, publishPreferenceValue); - } - else { - utils.setInputValue("#input-publish-" + inputId, publishPreferenceValue); - } - }); - utils.setInputRadio("radio-publish-format", publishPreferences.format); - utils.setInputChecked("#checkbox-publish-custom-template", publishPreferences.customTmpl !== undefined); - utils.setInputValue('#textarea-publish-custom-template', publishPreferences.customTmpl || settings.template); - } + // Show/hide controls depending on provider + $('.modal-publish [class*=" modal-publish-"]').hide().filter(".modal-publish-" + provider.providerId).show(); - // Open dialog box - $(".modal-publish").modal(); - } + // Reset fields + utils.resetModalInputs(); + utils.setInputRadio("radio-publish-format", defaultPublishFormat); + utils.setInputChecked("#checkbox-publish-custom-template", false); + utils.setInputValue('#textarea-publish-custom-template', settings.template); - // Add a new publish location to a local document - function performNewLocation(event) { - var provider = newLocationProvider; - var publishAttributes = provider.newPublishAttributes(event); - if(publishAttributes === undefined) { - return; - } + // Load preferences + var publishPreferences = utils.retrieveIgnoreError(provider.providerId + ".publishPreferences"); + if(publishPreferences) { + _.each(provider.publishPreferencesInputIds, function(inputId) { + var publishPreferenceValue = publishPreferences[inputId]; + if(_.isBoolean(publishPreferenceValue)) { + utils.setInputChecked("#input-publish-" + inputId, publishPreferenceValue); + } + else { + utils.setInputValue("#input-publish-" + inputId, publishPreferenceValue); + } + }); + utils.setInputRadio("radio-publish-format", publishPreferences.format); + utils.setInputChecked("#checkbox-publish-custom-template", publishPreferences.customTmpl !== undefined); + utils.setInputValue('#textarea-publish-custom-template', publishPreferences.customTmpl || settings.template); + } - // Perform provider's publishing - var fileDesc = fileMgr.currentFile; - var content = getPublishContent(fileDesc, publishAttributes, currentHTML); - var title = (fileDesc.frontMatter && fileDesc.frontMatter.title) || fileDesc.title; - provider.publish(publishAttributes, fileDesc.frontMatter, title, content, function(error) { - if(error === undefined) { - publishAttributes.provider = provider; - sharing.createLink(publishAttributes, function() { - createPublishIndex(fileDesc, publishAttributes); - }); - } - }); + // Open dialog box + $(".modal-publish").modal(); + } - // Store input values as preferences for next time we open the publish - // dialog - var publishPreferences = {}; - _.each(provider.publishPreferencesInputIds, function(inputId) { - var inputElt = document.getElementById("input-publish-" + inputId); - if(inputElt.type == 'checkbox') { - publishPreferences[inputId] = inputElt.checked; - } - else { - publishPreferences[inputId] = inputElt.value; - } - }); - publishPreferences.format = publishAttributes.format; - publishPreferences.customTmpl = publishAttributes.customTmpl; - storage[provider.providerId + ".publishPreferences"] = JSON.stringify(publishPreferences); - } + // Add a new publish location to a local document + function performNewLocation(event) { + var provider = newLocationProvider; + var publishAttributes = provider.newPublishAttributes(event); + if(publishAttributes === undefined) { + return; + } - var initPublishButtonTmpl = [ - '
  • ', - ' ', - ' <%= provider.providerName %>', - ' ', - '
  • ' - ].join(''); - eventMgr.addListener("onReady", function() { - if(window.viewerMode === false) { - // Add every provider in the panel menu - var publishMenuElt = document.querySelector('.menu-panel .publish-on-provider-list'); - var publishMenuHtml = _.reduce(providerMap, function(result, provider) { - return result + _.template(initPublishButtonTmpl, { - provider: provider - }); - }, ''); - publishMenuElt.innerHTML = publishMenuHtml; - _.each(providerMap, function(provider) { - // Click on open publish dialog - $(publishMenuElt.querySelector('.action-init-publish-' + provider.providerId)).click(function() { - initNewLocation(provider); - }); - // Click on perform new publication - $(".action-publish-" + provider.providerId).click(function() { - initNewLocation(provider); - }); - }); - } + // Perform provider's publishing + var fileDesc = fileMgr.currentFile; + var content = getPublishContent(fileDesc, publishAttributes, currentHTML); + var title = (fileDesc.frontMatter && fileDesc.frontMatter.title) || fileDesc.title; + provider.publish(publishAttributes, fileDesc.frontMatter, title, content, function(error) { + if(error === undefined) { + publishAttributes.provider = provider; + sharing.createLink(publishAttributes, function() { + createPublishIndex(fileDesc, publishAttributes); + }); + } + }); - $(".action-process-publish").click(performNewLocation); + // Store input values as preferences for next time we open the publish + // dialog + var publishPreferences = {}; + _.each(provider.publishPreferencesInputIds, function(inputId) { + var inputElt = document.getElementById("input-publish-" + inputId); + if(inputElt.type == 'checkbox') { + publishPreferences[inputId] = inputElt.checked; + } + else { + publishPreferences[inputId] = inputElt.value; + } + }); + publishPreferences.format = publishAttributes.format; + publishPreferences.customTmpl = publishAttributes.customTmpl; + storage[provider.providerId + ".publishPreferences"] = JSON.stringify(publishPreferences); + } - var $customTmplCollapseElt = $('.publish-custom-template-collapse').collapse({ - toggle: false - }); - var $customTmplTextareaElt = $('#textarea-publish-custom-template'); - var doCustomTmplCollapse = _.debounce(function() { - $customTmplCollapseElt.collapse(utils.getInputRadio("radio-publish-format") == 'template' ? 'show' : 'hide'); - }, 100); - $("#checkbox-publish-custom-template").change(function() { - $customTmplTextareaElt.prop('disabled', !this.checked); - }); - $("input:radio[name=radio-publish-format]").change(function() { - doCustomTmplCollapse(); - }); - $('.modal-publish').on('hidden.bs.modal', function() { - $customTmplCollapseElt.collapse('hide'); - }); + var initPublishButtonTmpl = [ + '
  • ', + ' ', + ' <%= provider.providerName %>', + ' ', + '
  • ' + ].join(''); + eventMgr.addListener("onReady", function() { + if(window.viewerMode === false) { + // Add every provider in the panel menu + var publishMenuElt = document.querySelector('.menu-panel .publish-on-provider-list'); + var publishMenuHtml = _.reduce(providerMap, function(result, provider) { + return result + _.template(initPublishButtonTmpl, { + provider: provider + }); + }, ''); + publishMenuElt.innerHTML = publishMenuHtml; + _.each(providerMap, function(provider) { + // Click on open publish dialog + $(publishMenuElt.querySelector('.action-init-publish-' + provider.providerId)).click(function() { + initNewLocation(provider); + }); + // Click on perform new publication + $(".action-publish-" + provider.providerId).click(function() { + initNewLocation(provider); + }); + }); + } - // Save As menu items - $(".action-download-md").click(function() { - var content = fileMgr.currentFile.content; - var title = fileMgr.currentFile.title; - utils.saveAs(content, title + ".md"); - }); - $(".action-download-html").click(function() { - var title = fileMgr.currentFile.title; - utils.saveAs(currentHTML.withoutComments, title + ".html"); - }); - $(".action-download-template").click(function() { - var fileDesc = fileMgr.currentFile; - var content = publisher.applyTemplate(fileDesc, undefined, currentHTML); - utils.saveAs(content, fileDesc.title + (settings.template.indexOf("documentHTML") === -1 ? ".md" : ".html")); - }); - $(".action-download-pdf").click(function() { - var fileDesc = fileMgr.currentFile; - var content = publisher.applyTemplate(fileDesc, { - customTmpl: settings.pdfTemplate - }, currentHTML); - var task = new AsyncTask(); - var pdf; - task.onRun(function() { - if(isOffline === true) { - eventMgr.onError("Operation not available in offline mode."); - task.chain(); - return; - } - var xhr = new XMLHttpRequest(); - xhr.open('POST', constants.HTMLTOPDF_URL, true); - xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - xhr.responseType = 'blob'; - xhr.onreadystatechange = function() { - if(this.readyState == 4) { - if(this.status == 200) { - pdf = this.response; - } - else { - eventMgr.onError("Error when trying to generate PDF: " + this.status); - } - task.chain(); - } - }; - xhr.send(content); - }); - task.onSuccess(function() { - if(pdf !== undefined) { - utils.saveAs(pdf, fileMgr.currentFile.title + ".pdf"); - } - }); - task.enqueue(); - }); - }); + $(".action-process-publish").click(performNewLocation); - eventMgr.onPublisherCreated(publisher); - return publisher; + var $customTmplCollapseElt = $('.publish-custom-template-collapse').collapse({ + toggle: false + }); + var $customTmplTextareaElt = $('#textarea-publish-custom-template'); + var doCustomTmplCollapse = _.debounce(function() { + $customTmplCollapseElt.collapse(utils.getInputRadio("radio-publish-format") == 'template' ? 'show' : 'hide'); + }, 100); + $("#checkbox-publish-custom-template").change(function() { + $customTmplTextareaElt.prop('disabled', !this.checked); + }); + $("input:radio[name=radio-publish-format]").change(function() { + doCustomTmplCollapse(); + }); + $('.modal-publish').on('hidden.bs.modal', function() { + $customTmplCollapseElt.collapse('hide'); + }); + + // Save As menu items + $(".action-download-md").click(function() { + var content = fileMgr.currentFile.content; + var title = fileMgr.currentFile.title; + utils.saveAs(content, title + ".md"); + }); + $(".action-download-html").click(function() { + var title = fileMgr.currentFile.title; + utils.saveAs(currentHTML.withoutComments, title + ".html"); + }); + $(".action-download-template").click(function() { + var fileDesc = fileMgr.currentFile; + var content = publisher.applyTemplate(fileDesc, undefined, currentHTML); + utils.saveAs(content, fileDesc.title + (settings.template.indexOf("documentHTML") === -1 ? ".md" : ".html")); + }); + var monetize = new MonetizeJS({ + applicationID: 'iklMbzDI7dvMEScb' + }); + $(".action-download-pdf").click(function() { + var fileDesc = fileMgr.currentFile; + var content = publisher.applyTemplate(fileDesc, { + customTmpl: settings.pdfTemplate + }, currentHTML); + var task = new AsyncTask(); + var pdf, token; + task.onRun(function() { + if(isOffline === true) { + eventMgr.onError("Operation not available in offline mode."); + return task.chain(); + } + if(!eventMgr.isSponsor) { + $('.modal-sponsorship-required').modal('show'); + return task.chain(); + } + monetize.getTokenImmediate(function(err, result) { + token = result || ''; + task.chain(); + }); + }); + task.onRun(function() { + var xhr = new XMLHttpRequest(); + xhr.open('POST', constants.HTMLTOPDF_URL + '?token=' + encodeURIComponent(token) + '&options=' + encodeURIComponent(settings.pdfOptions), true); + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + xhr.responseType = 'blob'; + xhr.onreadystatechange = function() { + if(this.readyState == 4) { + if(this.status == 200) { + pdf = this.response; + } + else { + eventMgr.onError("Error when trying to generate PDF: " + this.status); + } + task.chain(); + } + }; + xhr.send(content); + }); + task.onSuccess(function() { + if(pdf !== undefined) { + utils.saveAs(pdf, fileMgr.currentFile.title + ".pdf"); + } + }); + task.enqueue(); + }); + }); + + eventMgr.onPublisherCreated(publisher); + return publisher; }); diff --git a/public/res/settings.js b/public/res/settings.js index c3409cd7..79ecb47c 100644 --- a/public/res/settings.js +++ b/public/res/settings.js @@ -52,10 +52,10 @@ define([ constants.MAIN_URL, 'libs/MathJax/MathJax.js?config=TeX-AMS_HTML">\n', '\n', - '<%= documentHTML %>\n', + '<%= documentHTML %>\n', '' ].join(""), - pdfPageSize: 'A4', + pdfOptions: '{}', sshProxy: constants.SSH_PROXY_URL, extensionSettings: {} }; diff --git a/public/res/utils.js b/public/res/utils.js index 710453f0..3d623a1d 100644 --- a/public/res/utils.js +++ b/public/res/utils.js @@ -129,7 +129,7 @@ define([ // For input control function inputError(element, event) { if(event !== undefined) { - element.stop(true, true).addClass("error").delay(1000).queue(function() { + element.stop(true, true).addClass("error").delay(3000).queue(function() { $(this).removeClass("error"); $(this).dequeue(); }); @@ -223,6 +223,23 @@ define([ return value; }; + // Return input value and check that it's a valid JSON + utils.getInputJSONValue = function(element, event) { + element = jqElt(element); + var value = utils.getInputTextValue(element, event); + if(value === undefined) { + return undefined; + } + try { + JSON.parse(value); + } + catch(e) { + inputError(element, event); + return undefined; + } + return value; + }; + // Return checkbox boolean value utils.getInputChecked = function(element) { element = jqElt(element);