api.js

(function (w) {

  var DEBUG = false;

  /**
   * Assert function used by API calls
   * @param  {boolean} condition    A true or false condition
   * @param  {String}  errorMessage The error message to display on assert failure
   * @return {boolean}              The same true or false condition
   * @author Bruno Sabot
   * @private
   */
  function _assert(condition, errorMessage) {

    if (condition === false && DEBUG === true) {
      console.log(errorMessage);
    }

    return condition;

  }

  /**
   * Assert function used by API calls to check integer numbers
   * @param  {mixed}   value        The value to test as an integer
   * @param  {String}  errorMessage The error message to display on assert failure
   * @return {boolean}              A true or false condition
   * @author Bruno Sabot
   * @private
   */
  function _assertInteger(value, errorMessage) {

    return _assert(value % 1 === 0, errorMessage);

  }

  /**
   * Assert function used by API calls to check string values
   * @param  {mixed}   value        The value to test as a string
   * @param  {String}  errorMessage The error message to display on assert failure
   * @return {boolean}              A true or false condition
   * @author Bruno Sabot
   * @private
   */
  function _assertString(value, errorMessage) {

    return _assert(typeof (value) === 'string', errorMessage);

  }

  /**
   * Assert function used by API calls to check if string values are valid json
   * @param  {mixed}   value        The value to test as a string
   * @param  {String}  errorMessage The error message to display on assert failure
   * @return {boolean}              A true or false condition
   * @author Bruno Sabot
   * @private
   */
  function _assertJson(value, errorMessage) {

    if (_assert(typeof (value) === 'string', errorMessage)) {

      var result = true;
      try {
        var json = JSON.parse(value);
      } catch (e) {
        result = false;
      }
      return _assert(result, errorMessage);

    } else {
      return false;
    }

  }

  /**
   * Assert function used by API calls to check if string values are valid json
   * @param  {mixed}   value        The value to find into allowed values
   * @param  {Array}   dataSet      Array of allowed values
   * @param  {String}  errorMessage The error message to display on assert failure
   * @return {boolean}              A true or false condition
   * @author Alessandro Cipolletti
   * @private
   */
  function _assertOneOf(value, dataSet, errorMessage) {

    return _assert(dataSet.indexOf(value) >= 0, errorMessage);

  }

  /**
   * Transform the rest query string to an argument list
   * @param {String} data The rest query string
   * @author Bruno Sabot
   * @private
   */
  function _getArguments(data) {

    data = data.split('/');

    var dataOut = [];
    for (var i = 1; i < data.length; i += 2) {
      dataOut[data[i]] = data[i + 1];
    }

    return dataOut;

  }

  /**
   * Get the method name from the rest query string
   * @param {String} data The rest query string
   * @author Bruno Sabot
   * @private
   */
  function _getMethod(data) {

    return data.split('/')[0];

  }

  /**
   * Reader V3 web API
   * @namespace
   */
  w.API = {
    /**
     * Disable the debug mode to hide error logs
     * @return {boolean} Always true
     * @author Bruno Sabot
     * @example
     * // Disable the debug mode
     * elementWindow.postMessage("debugDisable", "*");
     */
    debugDisable: function () {

      DEBUG = false;
      return true;

    },
    /**
     * Enable the debug mode to see error logs
     * @return {boolean} Always true
     * @author Bruno Sabot
     * @example
     * // Enable the debug mode
     * elementWindow.postMessage("debugEnable", "*");
     */
    debugEnable: function () {

      DEBUG = true;
      return true;

    },
    /**
     * Get the current debug state
     * @return {boolean} The current debug state
     * @author Bruno Sabot
     * @example
     * // Get the current debug state
     * window.addEventListener("message", function (event) {
     *   if (event.data.method === "debugGetState") {
     *     console.log("debug state is : " + event.data.result);
     *   }
     * }, false);
     * elementWindow.postMessage("debugGetState", "*");
     */
    debugGetState: function () {

      return DEBUG;

    },
    /**
     * Toggle the debug mode state
     * @return {boolean} Always true
     * @author Bruno Sabot
     * @example
     * // Toggle the debug mode
     * elementWindow.postMessage("debugToggle", "*");
     */
    debugToggle: function () {

      DEBUG = !DEBUG;
      return true;

    },
    /**
     * Display the device type
     * @return {string} Device type
     * @author Ronny Tite
     * @since 3.18
     * @example
     * // Display the device type (desktop, tablet, phablet, phone, unknown)
     * window.addEventListener("message", function (event) {
     *   if (event.data.method === "deviceType") {
     *     console.log("This device is a " + event.data.result);
     *   }
     * }, false);
     * elementWindow.postMessage("deviceType", "*");
     */
    deviceType: function () {

      return w.Param.userAgent.device.type;

    },
    /**
     * Close the lightbox
     * @author Ronny Tite
     * @since 3.18
     * @example
     * // Close the menu
     * elementWindow.postMessage("lightboxClose", "*");
     */
    lightboxClose: function () {

      w.Class.LightboxManager.closeAll();

    },
    /**
     * Load a lightbox with an url in an iFrame
     * Available arguments:
     * * title:
     *     - the title of the lightbox, if title is not defined , it will be a blank title.
     * * url: (Mandatory)
     *     - The url of the iFrame we want to load , this url need to be encoded;
     * * header:
     *     - Define if the header is visible or not
     *     - By default, set to "true"
     *     - Set header to false to hide the header
     * @param  {Object}  args The object list
     * @return {boolean}      return true on success and false on failure
     * @since 3.18
     * @author Ronny Tite
     * @example
     * // Define the arguments
     * var lightboxTitle = "test";
     * var lightboxUrl = encodeURIComponent('http://www.webpublication.fr');
     * var header = false;
     * // Open the lightbox without title
     * elementWindow.postMessage("lightboxOpen/url/" + lightboxUrl,"*")
     * // Open the lightbox with a title with header
     * elementWindow.postMessage("lightboxOpen/title/" + lightboxTitle + "/url/" + lightboxUrl,"*")
     * // Open the lightbox without header
     * elementWindow.postMessage("lightboxOpen/header/false/url/" + lightboxUrl,"*")
     */
    lightboxOpen: function (args) {

      var popup = new w.Class.LightboxManager.getLightbox({
        "id": "iframe",
        "title": args.title,
        "header": (args.header === "false" ? false : true),
        "url": w.Main.xmlManager.resolve(decodeURIComponent(args.url)),
        "onLoaded": function (popup) {

          var content = popup.template.querySelector('.lightbox__content');
          var iframe = document.createElement('iframe');

          iframe.src = popup.url;
          iframe.allowFullscreen = true;
          iframe.frameBorder = "0";
          iframe.style.width = "100%";
          iframe.style.height = "100%";
          content.appendChild(iframe);

        }
      });

    },
    /**
     * Close the menu
     * @return {boolean} Always true
     * @author Alessandro Cipolletti
     * @example
     * // Close the menu
     * elementWindow.postMessage("menuClose", "*");
     */
    menuClose: function () {
      return w.Main.menuManager.hideMenu();
    },
    /**
     * Open the menu
     * @return {boolean} Always true
     * @author Alessandro Cipolletti
     * @example
     * // Open the menu
     * elementWindow.postMessage("menuOpen", "*");
     */
    menuOpen: function () {
      return w.Main.menuManager.showMenu();
    },
    /**
     * Toggle the menu state
     * @return {boolean} Always true
     * @author Alessandro Cipolletti
     * @example
     * // Toggle the menu state
     * elementWindow.postMessage("menuToggle", "*");
     */
    menuToggle: function () {
      return w.Main.menuManager.toggleMenu();
    },
    /**
     * Get the amount of pages in the publication
     * @return {integer} The amount of pages in the publication
     * @author Bruno Sabot
     * @example
     * // Get the current debug state
     * window.addEventListener("message", function (event) {
     *   if (event.data.method === "pageCount") {
     *     console.log("There is " + event.data.result + " pages in the publication");
     *   }
     * }, false);
     * elementWindow.postMessage("pageCount", "*");
     */
    pageCount: function () {

      return w.Utils.prodTools.getPageLength();

    },
    /**
     * Load a specific page on the publication
     *
     * The number argument is always used before the name argument
     *
     * Available arguments:
     * * number:
     *     - load a page number, starting from 1 to the latest page.
     *     - If the number is higher than the page size, it goes to the latest
     *     - If the number is lower than one, it does nothing
     * * name:
     *     - The name can be one of next, previous, first or last and goes to the associated page
     * @param  {Object}  args The object list
     * @return {boolean}      return true on success and false on failure
     * @author Bruno Sabot
     * @example
     * // Go to page 10
     * elementWindow.postMessage("pageLoad/number/10", "*");
     * // Go to the next page
     * elementWindow.postMessage("pageLoad/name/next", "*");
     * // Go to the previous page
     * elementWindow.postMessage("pageLoad/name/previous", "*");
     * // Go to the first page
     * elementWindow.postMessage("pageLoad/name/first", "*");
     * // Go to the last page
     * elementWindow.postMessage("pageLoad/name/last", "*");
     */
    pageLoad: function (args) {

      // Handle the number argument
      if (args.number) {

        if (_assertInteger(args.number, "[pageLoad] The number argument must be an integer")) {
          if (w.Param.newViewerVersion) {
            w.Main.viewerManager.goToPage(args.number);
          } else {
            w.Main.controlManager.goToPage(args.number);
          }
          return true;
        }

        return false;

      }

      // Handle the name argument
      if (args.name) {

        if (args.name === 'next') {
          if (w.Param.newViewerVersion) {
            w.Main.viewerManager.scrollFrame("next");
          } else {
            w.Main.controlManager.nextPage();
          }
        } else if (args.name === 'previous' || args.name === 'prev') {
          if (w.Param.newViewerVersion) {
            w.Main.viewerManager.scrollFrame("prev");
          } else {
            w.Main.controlManager.prevPage();
          }
        } else if (args.name === 'first') {
          if (w.Param.newViewerVersion) {
            w.Main.viewerManager.goToPage(1);
          } else {
            w.Main.controlManager.goToPage(1);
          }
        } else if (args.name === 'last') {
          if (w.Param.newViewerVersion) {
            w.Main.viewerManager.goToPage(w.Utils.prodTools.getPageLength());
          } else {
            w.Main.controlManager.goToPage(w.Utils.prodTools.getPageLength());
          }
        } else {
          return false;
        }

        return true;

      }

      _assert(false, "[pageLoad] The argument is missing or incorrect");
      return false;

    },
    /**
     * Send a json string to all iframes link with a postMessage
     * Available arguments:
     * * mode:
     *      - "all"     send message to all iframe, also the sender
     *      - "others"  send message to all iframe except the sender
     * * data:
     *      - a valid json string
     * @param  {Object}  args The object list
     * @return {boolean}      return true on success and false on failure
     * @author Alessandro Cipolletti
     * @since 3.18
     * @example
     * // (into an iframe link) send a json to all others iframe's links
     * window.parent.postMessage('broadcast/mode/others/data/{"hello": "world"}', "*");
     * // to see received json message into the target iframe
     * window.addEventListener("message", function (e) {
     *   console.log(e.data);
     * });
     */
    broadcast: function (args) {

      if (
        _assertOneOf(args.mode, ["all", "others"], "Mode must be 'all' or 'others'") &&
        _assertJson(args.data, "Data must be a valid json string")
      ) {

        var exceptWindow = (args.mode === "others" ? this : false);

        var data = JSON.parse(args.data);
        data.type = "broadcast";

        if (w.Param.newViewerVersion) {
          w.Main.linksManagerNew.linksBroadcast(args.mode, data, exceptWindow);
        } else {
          w.Main.linksManager.linksBroadcast(args.mode, data, exceptWindow);
        }
        return true;

      } else {
        return false;
      }

    },
    /**
     * Simulates a click on a specific link
     * For any page, also not currently displayed
     * @author Alessandro Cipolletti
     * @example
     * // Click on first link of page 10
     * elementWindow.postMessage("linkClick/page/10/index/0", "*");
     */
    linkClick: function () {

      var maxPage = w.Main.xmlManager.get("contents").config.pages_nr;

      return function (args) {

        if (
          _assertInteger(args.page, "Page number must be an integer") &&
          _assertInteger(args.index, "Link index must be an integer")
        ) {

          if (args.page > 0 && args.page <= maxPage && args.index >= 0) {
            w.Main.linksManagerNew.linkClick(args.page, {
              index: args.index
            });
          }

        } else {
          return false;
        }

      };

    }(),
    /**
     * Open the startup panel
     * @return {boolean} return true on success and false on failure
     * @author Bruno Sabot
     * @since 3.18
     * @example
     * // Open the startup panel
     * elementWindow.postMessage("welcomepageOpen", "*");
     */
    welcomepageOpen: function () {

      var panelUrl = w.Main.startupManager.get('startup.welcomepage.url');
      if (panelUrl) {

        w.Class.LightboxManager.getLightbox({
          "id": "startupPanel",
          "url": w.Main.xmlManager.resolve(panelUrl),
          "header": false
        });

        return true;

      }

      return false;

    },
    /**
     * Download the PDF
     * @return {boolean} return true on success and false on failure
     * @author Bruno Sabot
     * @example
     * // Download the PDF
     * elementWindow.postMessage("pdfDownload", "*");
     */
    pdfDownload: function () {

      window.location.href = './publication/contents/pdfweb.pdf';

    },
    /**
     * Get the pdf url
     * @return {String} return the global url to publication's pdf
     * @author Alessandro Cipolletti
     * @example
     * // if you want to open the pdf of the publication contained inside an iframe
     * window.addEventListener("message", function (e) {
     *   if (e.data.method === "pdfGetUrl") {
     *     location.href = e.data.result;
     *   }
     * }, false);
     * iframeElement.contentWindow.postMessage("pdfGetUrl", "*");
     */
    pdfGetUrl: function (args) {

      return location.pathname + "publication/contents/pdfweb.pdf";

    },
    /**
     * Share on social page
     * @return {boolean} return true on success and false on failure
     * @author Ronny Tite
     * @example
     * // Share on tacebook page
     * elementWindow.postMessage("share/network/facebook", "*")
     * // Share on Twitter page
     * elementWindow.postMessage("share/network/twitter", "*")
     * // Share on Pinterest page
     * elementWindow.postMessage("share/network/pinterest", "*")
     * // Share on Tumblr page
     * elementWindow.postMessage("share/network/tumblr", "*")
     * // Share on Google + page
     * elementWindow.postMessage("share/network/googleplus", "*")
     * // Share on Linkedin page
     * elementWindow.postMessage("share/network/linkedin", "*")
     *
     */
    share: (function () {

      var _socials = ["linkedin", "googleplus", "tumblr", "pinterest", "twitter", "facebook", "mail"];
      var el;

      return function (args) {

        if (typeof (args.network) === "undefined" && _socials.indexOf(args.network) < 0) {
          return false;
        }

        if (args.network === "mail") {
          el = w.Main.menuService.get("email_btn");
        } else {
          el = w.Main.menuService.get(args.network + "_btn");
        }

        if (el) {

          el.onload();
          el.onclick();

        }

      };

    })(),
    /**
     * Open the search panel
     * @return {boolean} return true on success and false on failure
     * @author Bruno Sabot
     * @example
     * // Open the search panel
     * elementWindow.postMessage("searchOpen", "*");
     */
    searchOpen: function () {

      var searchButton = w.Main.menuService.get("search_btn");
      searchButton.onload();
      searchButton.onclick();

      return true;

    },
    /**
     * Open the thumbnails page
     * @return {boolean} return true on success and false on failure
     * @author Ronny Tite
     * @example
     * // Open the thumbnails page
     * elementWindow.postMessage("thumbnailOpen", "*");
     */
    thumbnailOpen: function () {

      var thumbButton = w.Main.menuService.get("thumbnails_btn");
      thumbButton.onload();
      thumbButton.onclick();

      return true;

    },
    /**
     * Get the viewport scale value used in the publication that allows the use of retina images
     * @return {float} The publication viewport scale
     * @author Bruno Sabot
     * @example
     * // Get the viewport scale
     * window.addEventListener("message", function (event) {
     *   if (event.data.method === "viewportGetScale") {
     *     console.log("The viewport scale value of the publication is " + event.data.result);
     *   }
     * }, false);
     * elementWindow.postMessage("viewportGetScale", "*");
     */
    viewportGetScale: function () {

      return w.Starter.defaultViewportScale;

    }
  };

  // Listen message events
  window.addEventListener("message", function (event) {

    if (_assertString(event.data)) {

      var method = _getMethod(event.data);
      var args = _getArguments(event.data);

      if (w.API.hasOwnProperty(method)) {

        var result = w.API[method].call(event.source, args);

        // On same window : no call
        if (event.source) {
          event.source.postMessage({
            "method": method,
            "arguments": args,
            "result": result,
            "queryId": args.queryId
          }, event.origin);
        }

      }

    }

  }, false);

})(webpublicationNamespace);