<commit_before>/*
 *  cursormeStage
 *  Stage with Background Image (Screenshot)
 *  and on e second Layer have a draggable Cursor-Image
 *  be able to save the final Canvas
 *
 *  #attributes
 *  - element   @jQueryObject   element to be bound to
 *  - stage     @kineticStage   kineticStage instance
 *    - background_layer
 *    - foreground_layer
 *    - @updateStage(data)
 *
 *  #public_methods
 *  @drawBackgroundImage(imgData)
 *  @changePointer(imgData)
 *  @saveAsImage(canvas)
 *
 *  #evt_listeners
 *  @pointer.isDraggable()
 *
 *  #dependencies
 *  @require jquery.js
 *  @require kinetic.js   // canvas api  //! KineticJS v4.6.0 2013-08-12 http://www.kineticjs.com
 *            by Eric Rowell @ericdrowell - MIT License https://github.com/ericdrowell/KineticJS/wiki/License
 */

 /* globals jQuery, Kinetic */

(function ($, Kinetic) {
  "use strict";

  $.cursorMe = function (canvas, options) {
    var cMe = {
      options: $.extend({ "no_options_yet": true }, options),

      /*  initialize cursorMe with a provided canvas jQuery Object
       *
       */
      init: function (canvas) {
        var canvasParams = {
          width: canvas.width() || 1200,
          height: canvas.height() || 800,
          container: canvas.attr("id") || "container",
        };
        this.options = $.extend({}, canvasParams, options);

        this.setupCanvas();
      },

      // image is prefferably an instance of Image(), loaded or not doesnt matter
      // alternatively image can be an absolute image-url
      setBackgroundImage: function (image) {
        var imageObj;

        // no image provided - reset background anyways
        if (!image) {
          this.layer_background.removeChildren();
          this.layer_background.clear();
          this.layer_background.remove();
          this.stage.draw();
          this.updateStage({ width: this.options.width, height: this.options.height});
          return;
        }

        // allow image to be an Image() instance
        if (Image.prototype.isPrototypeOf(image) || typeof image === "object") {
          imageObj = image;
        } else {
          imageObj = new Image();

          // some more validation?
          //
          if(typeof image === "string") {
            imageObj.src = image;
          }
        }

        $(imageObj).imgLoad(function(img){
          var backgroundImage = new Kinetic.Image({
              image: img,
              width: img.width,
              height: img.height
            });

          this.layer_background.clear();
          this.layer_background.add(backgroundImage);

          this.updateStage({ width: img.width, height: img.height});
        }.bind(this, imageObj));
      },

      setPointerImage: function (imgUrl) {
        var imageObj = new Image();

        imageObj.onload = function(img) {
          var pointerImage = new Kinetic.Image({
              image: img,
              x: this.stage.getWidth() / 2,
              y: this.stage.getHeight() / 2,
              width: img.width,
              height: img.height,
              draggable: true
            });

          // cursor styling
          pointerImage.on("mouseover", function () {
            document.body.style.cursor = "pointer";
          });
          pointerImage.on("mouseout", function () {
            document.body.style.cursor = "default";
          });

          this.layer_cursor.clear();
          this.layer_cursor.removeChildren();
          this.layer_cursor.add(pointerImage);

          this.options.pointerImageUrl = imgUrl;
          this.stage.add(this.layer_cursor);
          this.stage.draw();
        }.bind(this, imageObj);

        imageObj.src = imgUrl;
      },

      saveAsImage: function () {
        // present the rendered image with cursor
        this.stage.toImage({callback:
          function(img){
            var download_action = $("<a />").attr({
                  class: "glyphicon glyphicon-save",
                  text: "Click to download as PNG Image to your computer",
                  download: "cursored_screen.png",
                  href: "#save_this_image",
                  target: "_blank",
                  data: { trackInteraction: '{"category":"action","action":"save file"}' }
                }).on("click keyup", function(){
                  // take the imgs data uri and put it in the links destination href to allow download
                  $(this).attr("href", $(this).parent().find("img").attr("src"));
                }),
                delete_action = $("<a />").attr({
                  class: "glyphicon glyphicon-trash",
                  text: "Click to Delete this Image - you got plenty left anyways right?!",
                  href: "#remove_this_image",
                  data: { trackInteraction: '{"category":"action","action":"delete file"}' }
                }).on("click touch keyup", function(event){
                  // remove the image from the savend images
                  $(this).parents("li").remove();

                  event.preventDefault();
                }),
                li = $("<li>")
                      .append($(img))
                      .append(download_action)
                      .append(delete_action);

            li.addClass("fadeInDown animated");

            $("ul#coursored_imgs").append(li);
          }
        });
      },

      /* redraw the stage and all layers
       * after changes in the layers occurred
       * @options, optional, object containing stage option changes { width : 123, height : 456}
       */
      updateStage: function (options) {
        if (options) {
          if (options.width) {this.stage.setWidth(options.width);}
          if (options.height) {this.stage.setHeight(options.height);}
        }

        this.stage.clear();
        this.stage.add(this.layer_background);

        this.setPointerImage(this.options.pointerImageUrl);

        // center content
        this.stage.content.style.marginLeft = (- Math.floor(options.width / 2)) + "px";
        this.stage.content.style.marginTop =  (- Math.floor(options.height / 2)) + "px";
        this.stage.content.style.position = "absolute";
        this.stage.content.style.left = "50%";
        this.stage.content.style.top = "50%";
      },

      setupCanvas: function () {
        this.stage = new Kinetic.Stage({
          container: this.options.container,
          width: this.options.width,
          height: this.options.height
        });

        //prepare stage layers
        this.layer_background = new Kinetic.Layer();
        this.layer_cursor     = new Kinetic.Layer();

        this.stage.draw();
      },

      setupDragnDrop: function () {
        var stageContainer = this.stage.getContainer();

        $(stageContainer).on("dragover", function (event) {
          event.preventDefault();
        });
      }
    };

    if(canvas) {
      cMe.init(canvas);
    }

    // the API
    return {
      setBackground:  cMe.setBackgroundImage.bind(cMe),
      setPointer:     cMe.setPointerImage.bind(cMe),
      save:           cMe.saveAsImage.bind(cMe)
    };
  };
})(jQuery, Kinetic);
<commit_msg>#fix Limit size of the generated images, due to changed hl structure<commit_after>/*
 *  cursormeStage
 *  Stage with Background Image (Screenshot)
 *  and on e second Layer have a draggable Cursor-Image
 *  be able to save the final Canvas
 *
 *  #attributes
 *  - element   @jQueryObject   element to be bound to
 *  - stage     @kineticStage   kineticStage instance
 *    - background_layer
 *    - foreground_layer
 *    - @updateStage(data)
 *
 *  #public_methods
 *  @drawBackgroundImage(imgData)
 *  @changePointer(imgData)
 *  @saveAsImage(canvas)
 *
 *  #evt_listeners
 *  @pointer.isDraggable()
 *
 *  #dependencies
 *  @require jquery.js
 *  @require kinetic.js   // canvas api  //! KineticJS v4.6.0 2013-08-12 http://www.kineticjs.com
 *            by Eric Rowell @ericdrowell - MIT License https://github.com/ericdrowell/KineticJS/wiki/License
 */

 /* globals jQuery, Kinetic */

(function ($, Kinetic) {
  "use strict";

  $.cursorMe = function (canvas, options) {
    var cMe = {
      options: $.extend({ "no_options_yet": true }, options),

      /*  initialize cursorMe with a provided canvas jQuery Object
       *
       */
      init: function (canvas) {
        var canvasParams = {
          width: canvas.width() || 1200,
          height: canvas.height() || 800,
          container: canvas.attr("id") || "container",
        };
        this.options = $.extend({}, canvasParams, options);

        this.setupCanvas();
      },

      // image is prefferably an instance of Image(), loaded or not doesnt matter
      // alternatively image can be an absolute image-url
      setBackgroundImage: function (image) {
        var imageObj;

        // no image provided - reset background anyways
        if (!image) {
          this.layer_background.removeChildren();
          this.layer_background.clear();
          this.layer_background.remove();
          this.stage.draw();
          this.updateStage({ width: this.options.width, height: this.options.height});
          return;
        }

        // allow image to be an Image() instance
        if (Image.prototype.isPrototypeOf(image) || typeof image === "object") {
          imageObj = image;
        } else {
          imageObj = new Image();

          // some more validation?
          //
          if(typeof image === "string") {
            imageObj.src = image;
          }
        }

        $(imageObj).imgLoad(function(img){
          var backgroundImage = new Kinetic.Image({
              image: img,
              width: img.width,
              height: img.height
            });

          this.layer_background.clear();
          this.layer_background.add(backgroundImage);

          this.updateStage({ width: img.width, height: img.height});
        }.bind(this, imageObj));
      },

      setPointerImage: function (imgUrl) {
        var imageObj = new Image();

        imageObj.onload = function(img) {
          var pointerImage = new Kinetic.Image({
              image: img,
              x: this.stage.getWidth() / 2,
              y: this.stage.getHeight() / 2,
              width: img.width,
              height: img.height,
              draggable: true
            });

          // cursor styling
          pointerImage.on("mouseover", function () {
            document.body.style.cursor = "pointer";
          });
          pointerImage.on("mouseout", function () {
            document.body.style.cursor = "default";
          });

          this.layer_cursor.clear();
          this.layer_cursor.removeChildren();
          this.layer_cursor.add(pointerImage);

          this.options.pointerImageUrl = imgUrl;
          this.stage.add(this.layer_cursor);
          this.stage.draw();
        }.bind(this, imageObj);

        imageObj.src = imgUrl;
      },

      saveAsImage: function () {
        // present the rendered image with cursor
        this.stage.toImage({callback:
          function(img){
            var download_action = $("<a />").attr({
                  class: "glyphicon glyphicon-save",
                  text: "Click to download as PNG Image to your computer",
                  download: "cursored_screen.png",
                  href: "#save_this_image",
                  target: "_blank",
                  data: { trackInteraction: '{"category":"action","action":"save file"}' }
                }).on("click keyup", function(){
                  // take the imgs data uri and put it in the links destination href to allow download
                  $(this).attr("href", $(this).parent().find("img").attr("src"));
                }),
                delete_action = $("<a />").attr({
                  class: "glyphicon glyphicon-trash",
                  text: "Click to Delete this Image - you got plenty left anyways right?!",
                  href: "#remove_this_image",
                  data: { trackInteraction: '{"category":"action","action":"delete file"}' }
                }).on("click touch keyup", function(event){
                  // remove the image from the savend images
                  $(this).parents("li").remove();

                  event.preventDefault();
                }),
                li = $("<li>")
                      .append($(img).attr({
                        width: "150"
                      }))
                      .append(download_action)
                      .append(delete_action);

            li.addClass("fadeInDown animated");

            $("ul#coursored_imgs").append(li);
          }
        });
      },

      /* redraw the stage and all layers
       * after changes in the layers occurred
       * @options, optional, object containing stage option changes { width : 123, height : 456}
       */
      updateStage: function (options) {
        if (options) {
          if (options.width) {this.stage.setWidth(options.width);}
          if (options.height) {this.stage.setHeight(options.height);}
        }

        this.stage.clear();
        this.stage.add(this.layer_background);

        this.setPointerImage(this.options.pointerImageUrl);

        // center content
        this.stage.content.style.marginLeft = (- Math.floor(options.width / 2)) + "px";
        this.stage.content.style.marginTop =  (- Math.floor(options.height / 2)) + "px";
        this.stage.content.style.position = "absolute";
        this.stage.content.style.left = "50%";
        this.stage.content.style.top = "50%";
      },

      setupCanvas: function () {
        this.stage = new Kinetic.Stage({
          container: this.options.container,
          width: this.options.width,
          height: this.options.height
        });

        //prepare stage layers
        this.layer_background = new Kinetic.Layer();
        this.layer_cursor     = new Kinetic.Layer();

        this.stage.draw();
      },

      setupDragnDrop: function () {
        var stageContainer = this.stage.getContainer();

        $(stageContainer).on("dragover", function (event) {
          event.preventDefault();
        });
      }
    };

    if(canvas) {
      cMe.init(canvas);
    }

    // the API
    return {
      setBackground:  cMe.setBackgroundImage.bind(cMe),
      setPointer:     cMe.setPointerImage.bind(cMe),
      save:           cMe.saveAsImage.bind(cMe)
    };
  };
})(jQuery, Kinetic);
<|endoftext|>


<commit_before>/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { InnerBlocks } from '@wordpress/block-editor';

/**
 * Internal dependencies
 */
import { addBackgroundColorToOverlay } from '../../helpers';
import { IMAGE_BACKGROUND_TYPE, VIDEO_BACKGROUND_TYPE } from '../../constants';
import EditPage from './edit';
import blockIcon from '../../../images/amp-story-page-icon.svg';

export const name = 'amp/amp-story-page';

const schema = {
	anchor: {
		source: 'attribute',
		selector: 'amp-story-page',
		attribute: 'id',
	},
	mediaId: {
		type: 'number',
	},
	mediaUrl: {
		type: 'string',
		source: 'attribute',
		selector: 'amp-story-grid-layer[template="fill"] > amp-img, amp-story-grid-layer[template="fill"] > amp-video',
		attribute: 'src',
	},
	mediaType: {
		type: 'string',
	},
	poster: {
		type: 'string',
	},
	focalPoint: {
		type: 'object',
	},
	autoAdvanceAfter: {
		type: 'string',
	},
	autoAdvanceAfterDuration: {
		type: 'number',
	},
	autoAdvanceAfterMedia: {
		type: 'string',
	},
	backgroundColors: {
		default: '[]',
	},
	overlayOpacity: {
		default: 50,
	},
};

export const settings = {
	title: __( 'Page', 'amp' ),
	category: 'layout',
	icon: blockIcon( { width: 24, height: 24 } ),
	attributes: schema,

	supports: {
		reusable: true,
	},

	/*
     * <amp-story-page>:
     *   mandatory_parent: "AMP-STORY"
     *   mandatory_min_num_child_tags: 1
     *   child_tag_name_oneof: "AMP-ANALYTICS"
     *   child_tag_name_oneof: "AMP-PIXEL"
     *   child_tag_name_oneof: "AMP-STORY-CTA-LAYER"
     *   child_tag_name_oneof: "AMP-STORY-GRID-LAYER"
     *
     * https://github.com/ampproject/amphtml/blob/87fe1d02f902be97b596b36ec3421592c83d241e/extensions/amp-story/validator-amp-story.protoascii#L146-L171
     * */

	edit: EditPage,

	save( { attributes } ) {
		const {
			anchor,
			overlayOpacity,
			mediaUrl,
			mediaType,
			poster,
			autoAdvanceAfter,
			autoAdvanceAfterDuration,
			autoAdvanceAfterMedia,
		} = attributes;

		const backgroundColors = JSON.parse( attributes.backgroundColors );

		let advanceAfter;

		if ( [ 'auto', 'time' ].includes( autoAdvanceAfter ) && autoAdvanceAfterDuration ) {
			advanceAfter = parseInt( autoAdvanceAfterDuration ) + 's';
		} else if ( 'media' === autoAdvanceAfter ) {
			advanceAfter = autoAdvanceAfterMedia;
		}

		let overlayStyle = {};
		if ( 0 < backgroundColors.length ) {
			overlayStyle = addBackgroundColorToOverlay( overlayStyle, backgroundColors );
			overlayStyle.opacity = overlayOpacity / 100;
		}

		return (
			<amp-story-page style={ { backgroundColor: '#ffffff' } } id={ anchor } auto-advance-after={ advanceAfter }>
				{
					mediaUrl && (
						<amp-story-grid-layer template="fill">
							{ IMAGE_BACKGROUND_TYPE === mediaType && (
								<amp-img layout="fill" src={ mediaUrl } />
							) }
							{ VIDEO_BACKGROUND_TYPE === mediaType && (
								<amp-video layout="fill" src={ mediaUrl } poster={ poster } muted autoplay loop />
							) }
						</amp-story-grid-layer>
					)
				}
				<amp-story-grid-layer template="fill" style={ overlayStyle }>
				<InnerBlocks.Content />
			</amp-story-page>
		);
	},
};
<commit_msg>Add closing tag<commit_after>/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { InnerBlocks } from '@wordpress/block-editor';

/**
 * Internal dependencies
 */
import { addBackgroundColorToOverlay } from '../../helpers';
import { IMAGE_BACKGROUND_TYPE, VIDEO_BACKGROUND_TYPE } from '../../constants';
import EditPage from './edit';
import blockIcon from '../../../images/amp-story-page-icon.svg';

export const name = 'amp/amp-story-page';

const schema = {
	anchor: {
		source: 'attribute',
		selector: 'amp-story-page',
		attribute: 'id',
	},
	mediaId: {
		type: 'number',
	},
	mediaUrl: {
		type: 'string',
		source: 'attribute',
		selector: 'amp-story-grid-layer[template="fill"] > amp-img, amp-story-grid-layer[template="fill"] > amp-video',
		attribute: 'src',
	},
	mediaType: {
		type: 'string',
	},
	poster: {
		type: 'string',
	},
	focalPoint: {
		type: 'object',
	},
	autoAdvanceAfter: {
		type: 'string',
	},
	autoAdvanceAfterDuration: {
		type: 'number',
	},
	autoAdvanceAfterMedia: {
		type: 'string',
	},
	backgroundColors: {
		default: '[]',
	},
	overlayOpacity: {
		default: 50,
	},
};

export const settings = {
	title: __( 'Page', 'amp' ),
	category: 'layout',
	icon: blockIcon( { width: 24, height: 24 } ),
	attributes: schema,

	supports: {
		reusable: true,
	},

	/*
     * <amp-story-page>:
     *   mandatory_parent: "AMP-STORY"
     *   mandatory_min_num_child_tags: 1
     *   child_tag_name_oneof: "AMP-ANALYTICS"
     *   child_tag_name_oneof: "AMP-PIXEL"
     *   child_tag_name_oneof: "AMP-STORY-CTA-LAYER"
     *   child_tag_name_oneof: "AMP-STORY-GRID-LAYER"
     *
     * https://github.com/ampproject/amphtml/blob/87fe1d02f902be97b596b36ec3421592c83d241e/extensions/amp-story/validator-amp-story.protoascii#L146-L171
     * */

	edit: EditPage,

	save( { attributes } ) {
		const {
			anchor,
			overlayOpacity,
			mediaUrl,
			mediaType,
			poster,
			autoAdvanceAfter,
			autoAdvanceAfterDuration,
			autoAdvanceAfterMedia,
		} = attributes;

		const backgroundColors = JSON.parse( attributes.backgroundColors );

		let advanceAfter;

		if ( [ 'auto', 'time' ].includes( autoAdvanceAfter ) && autoAdvanceAfterDuration ) {
			advanceAfter = parseInt( autoAdvanceAfterDuration ) + 's';
		} else if ( 'media' === autoAdvanceAfter ) {
			advanceAfter = autoAdvanceAfterMedia;
		}

		let overlayStyle = {};
		if ( 0 < backgroundColors.length ) {
			overlayStyle = addBackgroundColorToOverlay( overlayStyle, backgroundColors );
			overlayStyle.opacity = overlayOpacity / 100;
		}

		return (
			<amp-story-page style={ { backgroundColor: '#ffffff' } } id={ anchor } auto-advance-after={ advanceAfter }>
				{
					mediaUrl && (
						<amp-story-grid-layer template="fill">
							{ IMAGE_BACKGROUND_TYPE === mediaType && (
								<amp-img layout="fill" src={ mediaUrl } />
							) }
							{ VIDEO_BACKGROUND_TYPE === mediaType && (
								<amp-video layout="fill" src={ mediaUrl } poster={ poster } muted autoplay loop />
							) }
						</amp-story-grid-layer>
					)
				}
				<amp-story-grid-layer template="fill" style={ overlayStyle }></amp-story-grid-layer>
				<InnerBlocks.Content />
			</amp-story-page>
		);
	},
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org)  Apache License, Version 2.0  http://www.apache.org/licenses/LICENSE-2.0
 */
define(['require', 'lodash', 'log', 'jquery', 'backbone', 'command', 'sample_preview', 'workspace/file', 'enjoyhint', 'guide', 'version'],
    function (require, _, log, $, Backbone, CommandManager, SamplePreviewView, File, EnjoyHint, Guide, Version) {

        var FirstLaunchWelcomePage = Backbone.View.extend({
            initialize: function (options) {
                var errMsg;
                if (!_.has(options, 'tab')) {
                    errMsg = 'unable to find a reference for editor tab';
                    log.error(errMsg);
                    throw errMsg;
                }
                this._tab = _.get(options, 'tab');
                var container = $(this._tab.getContentContainer());
                // make sure default tab content are cleared
                container.empty();
                // check whether container element exists in dom
                if (!container.length > 0) {
                    errMsg = 'unable to find container for welcome screen with selector: ' +
                        _.get(options, 'container');
                    log.error(errMsg);
                    throw errMsg;
                }
                this.app = options.application;
                this._$parent_el = container;
                this._options = options;
            },

            hide: function () {
                //Hiding menu bar
                this._options.application.menuBar.show();
                this.$el.hide();
            },

            show: function () {
                //Hiding menu bar
                this._options.application.menuBar.hide();
                this.$el.show();
            },

            render: function () {
                var self = this;
                var backgroundDiv = $('

');
                var mainWelcomeDiv = $('

');
                var leftPane = $('

');
                var buttonWrap = $('

');
                var productNameWrap = $('

');
                var newButton = $('<button id="newButton"></button>');
                var createNewETLFlowButton = $('<button id="createETLFlowBtnId"></button>');
                var openButton = $('<button></button>');

                var contentPane = $('

');
                var scrollInner = $('

');
                var scrollWrapper = $('

');
                var recentFilesPane = $('

');
                var samplesPane = $('

');
                var quickLinksPane = $('

');

                backgroundDiv.addClass(_.get(this._options, 'cssClass.parent'));
                mainWelcomeDiv.addClass(_.get(this._options, 'cssClass.outer'));
                leftPane.addClass(_.get(this._options, 'cssClass.leftPane'));
                buttonWrap.addClass(_.get(this._options, 'cssClass.buttonWrap'));
                productNameWrap.addClass(_.get(this._options, 'cssClass.productNameWrap'));
                newButton.addClass(_.get(this._options, 'cssClass.buttonNew'));
                createNewETLFlowButton.addClass(_.get(this._options, 'cssClass.buttonCreateNewETLFlow'));
                openButton.addClass(_.get(this._options, 'cssClass.buttonOpen'));
                contentPane.addClass(_.get(this._options, 'cssClass.contentPane'));
                recentFilesPane.addClass(_.get(this._options, 'cssClass.recentFilesPane'));
                samplesPane.addClass(_.get(this._options, 'cssClass.samplesPane'));
                quickLinksPane.addClass(_.get(this._options, 'cssClass.quickLinksPane'));

                newButton.text("New");
                createNewETLFlowButton.text("New ETL Flow");
                openButton.text("Open");
                buttonWrap.append(newButton);
                buttonWrap.append(createNewETLFlowButton);
                buttonWrap.append(openButton);

                $('#query-guide-link-container').append(' Siddhi Query Guide');
                $('#step-2 > div.step-description-text').append('Use ${...} format to template siddhi apps');
                $('#step-3 > div.step-description-text').append('Use ${...} format to template the configurations');

                var productNameWrapHeader = $('
' +
                    '' +
                    '
Streaming Integrator Tooling

');
                productNameWrap.append(productNameWrapHeader);

                leftPane.append(buttonWrap);
                leftPane.append(productNameWrap);

                mainWelcomeDiv.append(leftPane);

                var recentFilesHeader = $('
Recently opened
');
                recentFilesPane.append(recentFilesHeader);

                var samplesHeader = $('
Try out samples
');
                samplesPane.append(samplesHeader)
                var bodyUlSampleContent = $('

');
                var moreSampleLink = $('' +
                    'More Samples');
                bodyUlSampleContent.attr('id', "sampleContent");
                samplesPane.append(bodyUlSampleContent);
                samplesPane.append(moreSampleLink);

                // Show the import file dialog when "More Samples" is clicked.
                $(moreSampleLink).click(function () {
                    command.dispatch("open-sample-file-open-dialog");
                });

                var quickLinkHeader = $('
Quick links
');
                quickLinksPane.append(quickLinkHeader);

                var bodyUlQuickLinkContent = $('
' +
                    '
Quick Start Guide
' +
                    '
Siddhi Grammar
' +
                    '
Q&A
' +
                    '
Tutorials
' +
                    '
Documentation
' +
                    '
Support

');

                quickLinksPane.append(bodyUlQuickLinkContent);
                scrollInner.append(samplesPane);
                scrollInner.append(quickLinksPane);
                scrollWrapper.append(scrollInner);
                contentPane.append(scrollWrapper);

                mainWelcomeDiv.append(contentPane);
                backgroundDiv.append(mainWelcomeDiv);

                this._$parent_el.append(backgroundDiv);
                this.$el = backgroundDiv;

                var command = this._options.application.commandManager;
                var browserStorage = this._options.application.browserStorage;

                var samples = _.get(this._options, "samples", []);

                var config;
                var samplePreview;

                var self = this;
                var workspaceServiceURL = self.app.config.services.workspace.endpoint;
                var sampleServiceURL = workspaceServiceURL + "/read/sample";

                for (var i = 0; i < samples.length; i++) {

                    var payload = samples[i];

                    $.ajax({
                        type: "POST",
                        contentType: "text/plain; charset=utf-8",
                        url: sampleServiceURL,
                        indexValue: i,
                        data: payload,
                        async: true,
                        success: function (data, textStatus, xhr) {
                            var config =
                                {
                                    "sampleName": this.data.replace(/^.*[\\\/]/, '').match(/[^.]*/i)[0],
                                    "content": data.content,
                                    "parentContainer": "#sampleContent",
                                    "firstItem": this.indexValue === 0,
                                    "clickEventCallback": function (event) {
                                        event.preventDefault();
                                        var file = new File({
                                            content: data.content
                                        }, {
                                            storage: browserStorage
                                        });
                                        self.app.commandManager.dispatch("create-new-tab", {tabOptions: {file: file}});
                                        browserStorage.put("pref:passedFirstLaunch", true);
                                    }
                                };
                            samplePreview = new SamplePreviewView(config);
                            samplePreview.render();
                        },
                        error: function () {
                            alertError("Unable to read a sample file.");
                            throw "Unable to read a sample file.";
                        }
                    });
                }

                var workExPath = 'workspace';
                command.dispatch("open-folder", workExPath);

                var command = this._options.application.commandManager;
                var browserStorage = this._options.application.browserStorage;

                // When "new" is clicked, open up an empty workspace.
                $(newButton).on('click', function () {
                    command.dispatch("create-new-tab");
                    browserStorage.put("pref:passedFirstLaunch", true);
                });

                // When "Create New ETL Flow" is clicked, open up an new ETL flow.
                $(createNewETLFlowButton).on('click', function () {
                    command.dispatch("create-new-etl-flow");
                    browserStorage.put("pref:passedFirstLaunch", true);
                });

                // Show the open file dialog when "open" is clicked.
                $(openButton).click(function () {
                    command.dispatch("open-file-open-dialog");
                    browserStorage.put("pref:passedFirstLaunch", true);
                });

                // upon welcome tab remove, set flag to indicate first launch pass
                this._tab.on('removed', function () {
                    browserStorage.put("pref:passedFirstLaunch", true);
                });

                function alertError(errorMessage) {
                    var errorNotification = getErrorNotification(errorMessage);
                    $("#notification-container").append(errorNotification);
                    errorNotification.fadeTo(2000, 200).slideUp(1000, function () {
                        errorNotification.slideUp(1000);
                    });
                }

                function getErrorNotification(errorMessage) {
                    return $(
                        "
" +
                        "" +
                        errorMessage +
                        "" +
                        "
");
                };
            }
        });

        return FirstLaunchWelcomePage;

    });

<commit_msg>Fix broken link in editor<commit_after>/**
 * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org)  Apache License, Version 2.0  http://www.apache.org/licenses/LICENSE-2.0
 */
define(['require', 'lodash', 'log', 'jquery', 'backbone', 'command', 'sample_preview', 'workspace/file', 'enjoyhint', 'guide', 'version'],
    function (require, _, log, $, Backbone, CommandManager, SamplePreviewView, File, EnjoyHint, Guide, Version) {

        var FirstLaunchWelcomePage = Backbone.View.extend({
            initialize: function (options) {
                var errMsg;
                if (!_.has(options, 'tab')) {
                    errMsg = 'unable to find a reference for editor tab';
                    log.error(errMsg);
                    throw errMsg;
                }
                this._tab = _.get(options, 'tab');
                var container = $(this._tab.getContentContainer());
                // make sure default tab content are cleared
                container.empty();
                // check whether container element exists in dom
                if (!container.length > 0) {
                    errMsg = 'unable to find container for welcome screen with selector: ' +
                        _.get(options, 'container');
                    log.error(errMsg);
                    throw errMsg;
                }
                this.app = options.application;
                this._$parent_el = container;
                this._options = options;
            },

            hide: function () {
                //Hiding menu bar
                this._options.application.menuBar.show();
                this.$el.hide();
            },

            show: function () {
                //Hiding menu bar
                this._options.application.menuBar.hide();
                this.$el.show();
            },

            render: function () {
                var self = this;
                var backgroundDiv = $('

');
                var mainWelcomeDiv = $('

');
                var leftPane = $('

');
                var buttonWrap = $('

');
                var productNameWrap = $('

');
                var newButton = $('<button id="newButton"></button>');
                var createNewETLFlowButton = $('<button id="createETLFlowBtnId"></button>');
                var openButton = $('<button></button>');

                var contentPane = $('

');
                var scrollInner = $('

');
                var scrollWrapper = $('

');
                var recentFilesPane = $('

');
                var samplesPane = $('

');
                var quickLinksPane = $('

');

                backgroundDiv.addClass(_.get(this._options, 'cssClass.parent'));
                mainWelcomeDiv.addClass(_.get(this._options, 'cssClass.outer'));
                leftPane.addClass(_.get(this._options, 'cssClass.leftPane'));
                buttonWrap.addClass(_.get(this._options, 'cssClass.buttonWrap'));
                productNameWrap.addClass(_.get(this._options, 'cssClass.productNameWrap'));
                newButton.addClass(_.get(this._options, 'cssClass.buttonNew'));
                createNewETLFlowButton.addClass(_.get(this._options, 'cssClass.buttonCreateNewETLFlow'));
                openButton.addClass(_.get(this._options, 'cssClass.buttonOpen'));
                contentPane.addClass(_.get(this._options, 'cssClass.contentPane'));
                recentFilesPane.addClass(_.get(this._options, 'cssClass.recentFilesPane'));
                samplesPane.addClass(_.get(this._options, 'cssClass.samplesPane'));
                quickLinksPane.addClass(_.get(this._options, 'cssClass.quickLinksPane'));

                newButton.text("New");
                createNewETLFlowButton.text("New ETL Flow");
                openButton.text("Open");
                buttonWrap.append(newButton);
                buttonWrap.append(createNewETLFlowButton);
                buttonWrap.append(openButton);

                $('#query-guide-link-container').append(' Siddhi Query Guide');
                $('#step-2 > div.step-description-text').append('Use ${...} format to template siddhi apps');
                $('#step-3 > div.step-description-text').append('Use ${...} format to template the configurations');

                var productNameWrapHeader = $('
' +
                    '' +
                    '
Streaming Integrator Tooling

');
                productNameWrap.append(productNameWrapHeader);

                leftPane.append(buttonWrap);
                leftPane.append(productNameWrap);

                mainWelcomeDiv.append(leftPane);

                var recentFilesHeader = $('
Recently opened
');
                recentFilesPane.append(recentFilesHeader);

                var samplesHeader = $('
Try out samples
');
                samplesPane.append(samplesHeader)
                var bodyUlSampleContent = $('

');
                var moreSampleLink = $('' +
                    'More Samples');
                bodyUlSampleContent.attr('id', "sampleContent");
                samplesPane.append(bodyUlSampleContent);
                samplesPane.append(moreSampleLink);

                // Show the import file dialog when "More Samples" is clicked.
                $(moreSampleLink).click(function () {
                    command.dispatch("open-sample-file-open-dialog");
                });

                var quickLinkHeader = $('
Quick links
');
                quickLinksPane.append(quickLinkHeader);

                var bodyUlQuickLinkContent = $('
' +
                    '
Quick Start Guide
' +
                    '
Siddhi Grammar
' +
                    '
Q&A
' +
                    '
Tutorials
' +
                    '
Documentation
' +
                    '
Support

');

                quickLinksPane.append(bodyUlQuickLinkContent);
                scrollInner.append(samplesPane);
                scrollInner.append(quickLinksPane);
                scrollWrapper.append(scrollInner);
                contentPane.append(scrollWrapper);

                mainWelcomeDiv.append(contentPane);
                backgroundDiv.append(mainWelcomeDiv);

                this._$parent_el.append(backgroundDiv);
                this.$el = backgroundDiv;

                var command = this._options.application.commandManager;
                var browserStorage = this._options.application.browserStorage;

                var samples = _.get(this._options, "samples", []);

                var config;
                var samplePreview;

                var self = this;
                var workspaceServiceURL = self.app.config.services.workspace.endpoint;
                var sampleServiceURL = workspaceServiceURL + "/read/sample";

                for (var i = 0; i < samples.length; i++) {

                    var payload = samples[i];

                    $.ajax({
                        type: "POST",
                        contentType: "text/plain; charset=utf-8",
                        url: sampleServiceURL,
                        indexValue: i,
                        data: payload,
                        async: true,
                        success: function (data, textStatus, xhr) {
                            var config =
                                {
                                    "sampleName": this.data.replace(/^.*[\\\/]/, '').match(/[^.]*/i)[0],
                                    "content": data.content,
                                    "parentContainer": "#sampleContent",
                                    "firstItem": this.indexValue === 0,
                                    "clickEventCallback": function (event) {
                                        event.preventDefault();
                                        var file = new File({
                                            content: data.content
                                        }, {
                                            storage: browserStorage
                                        });
                                        self.app.commandManager.dispatch("create-new-tab", {tabOptions: {file: file}});
                                        browserStorage.put("pref:passedFirstLaunch", true);
                                    }
                                };
                            samplePreview = new SamplePreviewView(config);
                            samplePreview.render();
                        },
                        error: function () {
                            alertError("Unable to read a sample file.");
                            throw "Unable to read a sample file.";
                        }
                    });
                }

                var workExPath = 'workspace';
                command.dispatch("open-folder", workExPath);

                var command = this._options.application.commandManager;
                var browserStorage = this._options.application.browserStorage;

                // When "new" is clicked, open up an empty workspace.
                $(newButton).on('click', function () {
                    command.dispatch("create-new-tab");
                    browserStorage.put("pref:passedFirstLaunch", true);
                });

                // When "Create New ETL Flow" is clicked, open up an new ETL flow.
                $(createNewETLFlowButton).on('click', function () {
                    command.dispatch("create-new-etl-flow");
                    browserStorage.put("pref:passedFirstLaunch", true);
                });

                // Show the open file dialog when "open" is clicked.
                $(openButton).click(function () {
                    command.dispatch("open-file-open-dialog");
                    browserStorage.put("pref:passedFirstLaunch", true);
                });

                // upon welcome tab remove, set flag to indicate first launch pass
                this._tab.on('removed', function () {
                    browserStorage.put("pref:passedFirstLaunch", true);
                });

                function alertError(errorMessage) {
                    var errorNotification = getErrorNotification(errorMessage);
                    $("#notification-container").append(errorNotification);
                    errorNotification.fadeTo(2000, 200).slideUp(1000, function () {
                        errorNotification.slideUp(1000);
                    });
                }

                function getErrorNotification(errorMessage) {
                    return $(
                        "
" +
                        "" +
                        errorMessage +
                        "" +
                        "
");
                };
            }
        });

        return FirstLaunchWelcomePage;

    });

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016, WSO2 Inc. (http://wso2.com) All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
"use strict";
/**
 * Manage API access keys with corresponding keys,Not related to the keymanager used in backend
 */
class KeyManager {
    /**
     *
     * @param {string} access_key - Default access key if only one access key is using
     */
    constructor(access_key = '') {
        this._keys = {};
        this.addKey(access_key);
    }

    /**
     *
     * @param {string} access_key - Access key to be saved
     * @param {string} scope - Scope of the access key provided above
     * @returns {string} - Return newly added key in success
     */
    addKey(access_key, scope = 'default') {
        if (!(scope in this._keys)) {
            this._keys[scope] = access_key;
            return this._keys[scope];
        } else {
            throw 'Key already exist `' + this._keys[scope] + '` for scope `' + scope + '`';
        }

    }

    /**
     * Replace existing key with new valid key
     * @param {string} access_key
     * @param {string} scope
     * @returns {string} - Return updated key
     */
    updateKey(access_key, scope = 'default') {
        this._keys[scope] = access_key;
        return this._keys;
    }

    /**
     * Get key by giving the scope of the key
     * @param {string} scope
     * @returns {string|null} - If key found return it else null
     */
    getKey(scope) {
        if (scope === undefined) {
            scope = 'default';
            if (this.size() > 1) {
                throw 'Should provide scope parameter when there are more than single key'
            }
        }
        if (scope in this._keys) {
            return this._keys[scope]
        } else {
            return null;
        }
    }

    /**
     * Retrun the number of keys in the hash
     * @returns {number} Count of the access keys
     */
    size() {
        var keys_count = 0;
        for (var index in this._keys) {
            if (this._keys.hasOwnProperty(index) && this._keys[index]) {
                keys_count++;
            }
        }
        return keys_count;
    }
}

class AuthClient {

    /**
     * Static method to handle unauthorized user action error catch, It will look for response status code and skip !401 errors
     * @param {object} error_response
     */
    static unauthorizedErrorHandler(error_response) {
        if (error_response.status !== 401) { /* Skip unrelated response code to handle in unauthorizedErrorHandler*/
            throw error_response;
            /* re throwing the error since we don't handle it here and propagate to downstream error handlers in catch chain*/
        }
        var error_data = JSON.parse(error_response.data);
        var message = "Error[" + error_data.code + "]: " + error_data.description + " | " + error_data.message + ".
 You will be redirect to the login page ...";
        noty({
            text: message,
            type: 'error',
            dismissQueue: true,
            modal: true,
            progressBar: true,
            timeout: 5000,
            layout: 'top',
            theme: 'relax',
            maxVisible: 10,
            callback: {
                afterClose: function () {
                    window.location = contextPath + "/auth/login";
                },
            }
        });
    }

}
/**
 * An abstract representation of an API
 */
class API {
    /**
     * @constructor
     * @param {string} access_key - Access key for invoking the backend REST API call.
     */
    constructor(access_key) {
        this.client = new SwaggerClient({
            url: this._getSwaggerURL(),
            usePromise: true
        });
        this.auth_client = new AuthClient();
        this.client.then(
            (swagger) => {
                swagger.setSchemes(["http"]);
                swagger.setHost("localhost:9090");
                this.keyMan = new KeyManager(access_key);
                let scopes = swagger.swaggerObject["x-wso2-security"].apim["x-wso2-scopes"];
                for (var index in scopes) {
                    if (scopes.hasOwnProperty(index)) {
                        let scope_key = scopes[index].key;
                        this.keyMan.addKey(null, scope_key);
                        /* Fill with available scopes */
                    }
                }
            }
        );
        this.client.catch(
            error => {
                var n = noty({
                    text: error,
                    type: 'warning',
                    dismissQueue: true,
                    layout: 'top',
                    theme: 'relax',
                    progressBar: true,
                    timeout: 5000,
                    closeWith: ['click']
                });
            }
        );
    }

    _getSwaggerURL() {
        return swaggerURL;
    }

    _getCookie(name) {
        var value = "; " + document.cookie;
        var parts = value.split("; " + name + "=");
        if (parts.length == 2) return parts.pop().split(";").shift();
    }

    /**
     *
     * @param data
     * @returns {{clientAuthorizations: {api_key: SwaggerClient.ApiKeyAuthorization}, requestContentType: (*|string)}}
     * @private
     */
    _requestMetaData(data = {}) {
        let access_key_header = "Bearer " + this._getCookie("WSO2_AM_TOKEN_1");
        let request_meta = {
            clientAuthorizations: {
                api_key: new SwaggerClient.ApiKeyAuthorization("Authorization", access_key_header, "header")
            },
            requestContentType: data['Content-Type'] || "application/json"
        };
        return request_meta;
    }

    /**
     * Intend to be a private static method in API class,Update the API template with given parameter values.
     * @param {Object} api_data - API data which need to fill the placeholder values in the @get_template
     */
    _updateTemplate(api_data) {
        let payload;
        let template = {
            "name": null,
            "context": null,
            "version": null
        };
        var user_keys = Object.keys(api_data);
        for (var index in user_keys) {
            if (!(user_keys[index] in template)) {
                throw 'Invalid key provided, Valid keys are `' + Object.keys(template) + '`';
            }
        }
        payload = Object.assign(template, api_data);
        return payload;
    }

    /**
     * Create an API with the given parameters in template and call the callback method given optional.
     * @param {Object} api_data - API data which need to fill the placeholder values in the @get_template
     * @param {function} callback - An optional callback method
     * @returns {Promise} Promise after creating and optionally calling the callback method.
     */
    create(api_data, callback = null) {
        let payload;
        let promise_create;
        if (api_data.constructor.name == "Blob") {
            payload = {file: api_data, 'Content-Type': "multipart/form-data"};
            promise_create = this.client.then(
                (client) => {
                    return client["API (Collection)"].post_apis_import_definition(
                        payload, this._requestMetaData({'Content-Type': "multipart/form-data"})).catch(AuthClient.unauthorizedErrorHandler);
                }
            );
        } else {
            payload = {body: this._updateTemplate(api_data), "Content-Type": "application/json"};
            promise_create = this.client.then(
                (client) => {
                    return client["API (Collection)"].post_apis(
                        payload, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
                }
            );
        }
        if (callback) {
            return promise_create.then(callback);
        } else {
            return promise_create;
        }
    }

    /**
     * Get list of all the available APIs, If the call back is given (TODO: need to ask for fallback sequence as well tmkb)
     * It will be invoked upon receiving the response from REST service.Else will return a promise.
     * @param callback {function} A callback function to invoke after receiving successful response.
     * @returns {promise} With given callback attached to the success chain else API invoke promise.
     */
    getAll(callback) {
        var promise_get_all = this.client.then(
            (client) => {
                return client["API (Collection)"].get_apis({}, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
            }
        );
        if (callback) {
            return promise_get_all.then(callback);
        } else {
            return promise_get_all;
        }
    }

    get(id, callback = null) {
        var promise_get = this.client.then(
            (client) => {
                return client["API (Individual)"].get_apis_apiId(
                    {apiId: id}, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
            }
        );
        if (callback) {
            return promise_get.then(callback);
        } else {
            return promise_get;
        }
    }

    /**
     * Get the available policies information by tier level.
     * @param {String} tier_level List API or Application or Resource type policies.parameter should be one of api, application and resource
     * @returns {Promise.<TResult>}
     */
    policies(tier_level) {
        var promise_policies = this.client.then(
            (client) => {
                client["Throttling Tier (Collection)"].operations.get_policies_tierLevel.path = "/policies/tierLevel/{tierLevel}";
                return client["Throttling Tier (Collection)"].get_policies_tierLevel(
                    {tierLevel: 'api'}, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
            }
        );
        return promise_policies;
    }

    /**
     * Delete an API given an api identifier
     * @param id {String} UUID of the API which want to delete
     * @param callback {function} Function which needs to be called upon success of the API deletion
     * @returns {promise} With given callback attached to the success chain else API invoke promise.
     */
    deleteAPI(id) {
        var promised_delete = this.client.then(
            (client) => {
                return client["API (Individual)"].delete_apis_apiId(
                    {apiId: id}, this._requestMetaData());
            }
        ).catch(AuthClient.unauthorizedErrorHandler);
        return promised_delete;
    }

    /**
     * Update the life cycle state of an API given its id (UUID)
     * @param id {string} UUID of the api
     * @param state {string} Target state which need to be transferred
     * @param callback {function} Callback function which needs to be executed in the success call
     */
    updateLcState(id, state, callback = null) {
        var payload = {action: state, apiId: id, "Content-Type": "application/json"};
        var promise_lc_update = this.client.then(
            (client) => {
                return client["API (Individual)"].post_apis_change_lifecycle(
                    payload, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
            }
        );
        if (callback) {
            return promise_lc_update.then(callback);
        } else {
            return promise_lc_update;
        }
    }

}<commit_msg>Remove temp fix used to incompatibility between swagger and java code<commit_after>/**
 * Copyright (c) 2016, WSO2 Inc. (http://wso2.com) All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
"use strict";
/**
 * Manage API access keys with corresponding keys,Not related to the keymanager used in backend
 */
class KeyManager {
    /**
     *
     * @param {string} access_key - Default access key if only one access key is using
     */
    constructor(access_key = '') {
        this._keys = {};
        this.addKey(access_key);
    }

    /**
     *
     * @param {string} access_key - Access key to be saved
     * @param {string} scope - Scope of the access key provided above
     * @returns {string} - Return newly added key in success
     */
    addKey(access_key, scope = 'default') {
        if (!(scope in this._keys)) {
            this._keys[scope] = access_key;
            return this._keys[scope];
        } else {
            throw 'Key already exist `' + this._keys[scope] + '` for scope `' + scope + '`';
        }

    }

    /**
     * Replace existing key with new valid key
     * @param {string} access_key
     * @param {string} scope
     * @returns {string} - Return updated key
     */
    updateKey(access_key, scope = 'default') {
        this._keys[scope] = access_key;
        return this._keys;
    }

    /**
     * Get key by giving the scope of the key
     * @param {string} scope
     * @returns {string|null} - If key found return it else null
     */
    getKey(scope) {
        if (scope === undefined) {
            scope = 'default';
            if (this.size() > 1) {
                throw 'Should provide scope parameter when there are more than single key'
            }
        }
        if (scope in this._keys) {
            return this._keys[scope]
        } else {
            return null;
        }
    }

    /**
     * Retrun the number of keys in the hash
     * @returns {number} Count of the access keys
     */
    size() {
        var keys_count = 0;
        for (var index in this._keys) {
            if (this._keys.hasOwnProperty(index) && this._keys[index]) {
                keys_count++;
            }
        }
        return keys_count;
    }
}

class AuthClient {

    /**
     * Static method to handle unauthorized user action error catch, It will look for response status code and skip !401 errors
     * @param {object} error_response
     */
    static unauthorizedErrorHandler(error_response) {
        if (error_response.status !== 401) { /* Skip unrelated response code to handle in unauthorizedErrorHandler*/
            throw error_response;
            /* re throwing the error since we don't handle it here and propagate to downstream error handlers in catch chain*/
        }
        var error_data = JSON.parse(error_response.data);
        var message = "Error[" + error_data.code + "]: " + error_data.description + " | " + error_data.message + ".
 You will be redirect to the login page ...";
        noty({
            text: message,
            type: 'error',
            dismissQueue: true,
            modal: true,
            progressBar: true,
            timeout: 5000,
            layout: 'top',
            theme: 'relax',
            maxVisible: 10,
            callback: {
                afterClose: function () {
                    window.location = contextPath + "/auth/login";
                },
            }
        });
    }

}
/**
 * An abstract representation of an API
 */
class API {
    /**
     * @constructor
     * @param {string} access_key - Access key for invoking the backend REST API call.
     */
    constructor(access_key) {
        this.client = new SwaggerClient({
            url: this._getSwaggerURL(),
            usePromise: true
        });
        this.auth_client = new AuthClient();
        this.client.then(
            (swagger) => {
                swagger.setSchemes(["http"]);
                swagger.setHost("localhost:9090");
                this.keyMan = new KeyManager(access_key);
                let scopes = swagger.swaggerObject["x-wso2-security"].apim["x-wso2-scopes"];
                for (var index in scopes) {
                    if (scopes.hasOwnProperty(index)) {
                        let scope_key = scopes[index].key;
                        this.keyMan.addKey(null, scope_key);
                        /* Fill with available scopes */
                    }
                }
            }
        );
        this.client.catch(
            error => {
                var n = noty({
                    text: error,
                    type: 'warning',
                    dismissQueue: true,
                    layout: 'top',
                    theme: 'relax',
                    progressBar: true,
                    timeout: 5000,
                    closeWith: ['click']
                });
            }
        );
    }

    _getSwaggerURL() {
        return swaggerURL;
    }

    _getCookie(name) {
        var value = "; " + document.cookie;
        var parts = value.split("; " + name + "=");
        if (parts.length == 2) return parts.pop().split(";").shift();
    }

    /**
     *
     * @param data
     * @returns {{clientAuthorizations: {api_key: SwaggerClient.ApiKeyAuthorization}, requestContentType: (*|string)}}
     * @private
     */
    _requestMetaData(data = {}) {
        let access_key_header = "Bearer " + this._getCookie("WSO2_AM_TOKEN_1");
        let request_meta = {
            clientAuthorizations: {
                api_key: new SwaggerClient.ApiKeyAuthorization("Authorization", access_key_header, "header")
            },
            requestContentType: data['Content-Type'] || "application/json"
        };
        return request_meta;
    }

    /**
     * Intend to be a private static method in API class,Update the API template with given parameter values.
     * @param {Object} api_data - API data which need to fill the placeholder values in the @get_template
     */
    _updateTemplate(api_data) {
        let payload;
        let template = {
            "name": null,
            "context": null,
            "version": null
        };
        var user_keys = Object.keys(api_data);
        for (var index in user_keys) {
            if (!(user_keys[index] in template)) {
                throw 'Invalid key provided, Valid keys are `' + Object.keys(template) + '`';
            }
        }
        payload = Object.assign(template, api_data);
        return payload;
    }

    /**
     * Create an API with the given parameters in template and call the callback method given optional.
     * @param {Object} api_data - API data which need to fill the placeholder values in the @get_template
     * @param {function} callback - An optional callback method
     * @returns {Promise} Promise after creating and optionally calling the callback method.
     */
    create(api_data, callback = null) {
        let payload;
        let promise_create;
        if (api_data.constructor.name == "Blob") {
            payload = {file: api_data, 'Content-Type': "multipart/form-data"};
            promise_create = this.client.then(
                (client) => {
                    return client["API (Collection)"].post_apis_import_definition(
                        payload, this._requestMetaData({'Content-Type': "multipart/form-data"})).catch(AuthClient.unauthorizedErrorHandler);
                }
            );
        } else {
            payload = {body: this._updateTemplate(api_data), "Content-Type": "application/json"};
            promise_create = this.client.then(
                (client) => {
                    return client["API (Collection)"].post_apis(
                        payload, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
                }
            );
        }
        if (callback) {
            return promise_create.then(callback);
        } else {
            return promise_create;
        }
    }

    /**
     * Get list of all the available APIs, If the call back is given (TODO: need to ask for fallback sequence as well tmkb)
     * It will be invoked upon receiving the response from REST service.Else will return a promise.
     * @param callback {function} A callback function to invoke after receiving successful response.
     * @returns {promise} With given callback attached to the success chain else API invoke promise.
     */
    getAll(callback) {
        var promise_get_all = this.client.then(
            (client) => {
                return client["API (Collection)"].get_apis({}, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
            }
        );
        if (callback) {
            return promise_get_all.then(callback);
        } else {
            return promise_get_all;
        }
    }

    get(id, callback = null) {
        var promise_get = this.client.then(
            (client) => {
                return client["API (Individual)"].get_apis_apiId(
                    {apiId: id}, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
            }
        );
        if (callback) {
            return promise_get.then(callback);
        } else {
            return promise_get;
        }
    }

    /**
     * Get the available policies information by tier level.
     * @param {String} tier_level List API or Application or Resource type policies.parameter should be one of api, application and resource
     * @returns {Promise.<TResult>}
     */
    policies(tier_level) {
        var promise_policies = this.client.then(
            (client) => {
                return client["Throttling Tier (Collection)"].get_policies_tierLevel(
                    {tierLevel: 'api'}, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
            }
        );
        return promise_policies;
    }

    /**
     * Delete an API given an api identifier
     * @param id {String} UUID of the API which want to delete
     * @param callback {function} Function which needs to be called upon success of the API deletion
     * @returns {promise} With given callback attached to the success chain else API invoke promise.
     */
    deleteAPI(id) {
        var promised_delete = this.client.then(
            (client) => {
                return client["API (Individual)"].delete_apis_apiId(
                    {apiId: id}, this._requestMetaData());
            }
        ).catch(AuthClient.unauthorizedErrorHandler);
        return promised_delete;
    }

    /**
     * Update the life cycle state of an API given its id (UUID)
     * @param id {string} UUID of the api
     * @param state {string} Target state which need to be transferred
     * @param callback {function} Callback function which needs to be executed in the success call
     */
    updateLcState(id, state, callback = null) {
        var payload = {action: state, apiId: id, "Content-Type": "application/json"};
        var promise_lc_update = this.client.then(
            (client) => {
                return client["API (Individual)"].post_apis_change_lifecycle(
                    payload, this._requestMetaData()).catch(AuthClient.unauthorizedErrorHandler);
            }
        );
        if (callback) {
            return promise_lc_update.then(callback);
        } else {
            return promise_lc_update;
        }
    }

}<|endoftext|>


<commit_before>;(function($, modernizr, window, document, undefined) {
    "use strict";

    /**
     * Product Slider Plugin
     *
     * The plugin provides the functionality to create dynamic product sliders
     * in every part of the shop. Via the config settings you have many options for
     * adjusting the slider to fit your needs. The products for example can be set by
     * the local template or loaded via ajax. Different view options and optional touch
     * gestures make the slider full responsive on any device. See the defaults for all
     * available config options. All config settings can also be set via data attributes.
     *
     * @Example DOM structure:
     * ```
     * <div class="product-slider" data-touchControl="true">
     *     <div class="product-slider--container">
     *         <div class="product-slider--item"></div>
     *         <div class="product-slider--item"></div>
     *         <div class="product-slider--item"></div>
     *     </div>
     * </div>
     * ```
     *
     * ToDo: Add additional functionality like dot navigation or infinite sliding.
     */
    var pluginName = 'productSlider',
        defaults = {
            /**
             * The mode how the products are loaded.
             * @string local | ajax
             */
            mode: 'local',

            /**
             * The category id of the products to load.
             * @integer
             */
            categoryID: 1,

            /**
             * The number of products shown per page.
             * @integer
             */
            perPage: 5,

            /**
             * The number of products moved per slide.
             * @integer
             */
            perSlide: 1,

            /**
             * The maximum of products available to laod via ajax.
             * @integer
             */
            ajaxMaxAvailable: 20,

            /**
             * The maximum of products should be shown via ajax.
             * @integer
             */
            ajaxMaxShow: 20,

            /**
             * Show or hide the arrow buttons.
             * @bool
             */
            showArrows: true,

            /**
             * Active touch gesture controls.
             * @bool
             */
            touchControl: false,

            /**
             * Active automatic sliding.
             * @bool
             */
            autoSlide: false,

            /**
             * Set the interval of the automatic sliding.
             * @integer
             */
            autoSlideInterval: 4000,

            /**
             * Set the speed of a single slide animation.
             * @integer
             */
            animationSpeed: 300,

            /**
             * Set the controller url which returns the products loaded via ajax.
             * @string
             */
            controllerUrl: '/widgets/emotion/emotionTopSeller',

            /**
             * An additional css class for the wrapper element.
             * @string
             */
            wrapperClass: 'product-slider',

            /**
             * The css class of the slider element.
             * @string
             */
            containerClass: 'product-slider--container',

            /**
             * The css class of a single slider item.
             * @string
             */
            itemClass: 'product-slider--item',

            /**
             * The css class of the left arrow button.
             * @string
             */
            arrowClassLeft: 'product-slider--arrow is--left',

            /**
             * The css class of the right arrow button.
             * @string
             */
            arrowClassRight: 'product-slider--arrow is--right'
        };

    /**
     * Plugin constructor which merges the default settings with the user settings.
     *
     * @param {HTMLElement} element - Element which should be used in the plugin
     * @param {Object} userOpts - User settings for the plugin
     * @constructor
     */
    function Plugin(element, userOpts) {
        var me = this;

        me.$el = $(element);

        me.opts = $.extend({}, defaults, userOpts);

        me.getDataConfig();

        me._defaults = defaults;
        me._name = pluginName;

        me.slideIndex = 0;
        me.slideInterval = false;
        me.touchEvent = {};

        me.$items = false;

        me.itemsMaxShow = (me.opts.ajaxMaxShow > me.opts.ajaxMaxAvailable) ? me.opts.ajaxMaxAvailable : me.opts.ajaxMaxShow;

        me.$el.addClass(me.opts.wrapperClass);

        me.$container = me.createSlideContainer();
        me.createItems();
    }

    /**
     * Loads config settings which are set via data attributes and
     * overrides the old setting with the data attribute of the
     * same name if defined.
     */
    Plugin.prototype.getDataConfig = function() {
        var me = this,
            attr;

        $.each(me.opts, function(key, value) {
            attr = me.$el.attr('data-' + key);
            if ( attr !== undefined ) {
                me.opts[key] = attr;
            }
        });
    };

    /**
     * Initializes the plugin and calls all necessary functions.
     */
    Plugin.prototype.init = function() {
        var me = this;

        me.active = (me.itemsCount > me.opts.perPage);

        me.setSizes();
        me.setPosition();
        me.createArrows();
        me.registerEvents();

        if (me.opts.autoSlide && me.active) {
            me.startAutoSlide();
        }
    };

    /**
     * Gets the container element of the sliding items.
     * Creates a new container if no element is found.
     */
    Plugin.prototype.createSlideContainer = function() {
        var me = this,
            container = me.$el.find('.' + me.opts.containerClass);

        if (!container.length) {
            container = $('<div>', {
                'class': me.opts.containerClass
            }).appendTo(me.$el);
        }

        return container;
    };

    /**
     * Creates the slider items.
     * Calls the init function if after the products are loaded.
     */
    Plugin.prototype.createItems = function() {
        var me = this,
            loadCount = me.opts.perPage * 2;

        if (loadCount < 4) loadCount = 4;
        if (loadCount > me.itemsMaxShow) loadCount = me.itemsMaxShow;

        if (me.opts.mode == 'ajax') {
            me.loadItems(0, loadCount, function(response) {
                me.$container.html(response);
                me.trackItems();
                me.init();
            });
        } else {
            me.trackItems();
            me.init();
        }
    };

    /**
     * Tracks all slider items and sets some necessary variables.
     * Is called on initialization and on every slide to update the information.
     */
    Plugin.prototype.trackItems = function() {
        var me = this;

        me.$items = me.$container.find('.' + me.opts.itemClass);

        me.itemsCount = me.$items.length;

        me.itemsMaxCount = (me.opts.mode == 'ajax') ? me.opts.ajaxMaxAvailable : me.itemsCount;

        me.twoPages = me.opts.perPage * 2;
        me.minIndex = 0;
        me.maxIndex = (me.opts.mode == 'ajax') ? me.itemsMaxShow - me.opts.perPage : me.itemsCount - me.opts.perPage;

        me.itemsToLoad = me.itemsMaxShow - me.itemsCount;
    };

    /**
     * Loads products via ajax.
     *
     * @integer start
     * @integer limit
     * @function callback
     */
    Plugin.prototype.loadItems = function(start, limit, callback) {
        var me = this,
            cb = callback || function() {};

        $.ajax({
            url: me.opts.controllerUrl,
            method: 'POST',
            data: {
                'category': me.opts.categoryID,
                'start': start,
                'limit': limit
            },
            success: function(response) {
                cb.call(me, response);
            }
        });
    };

    /**
     * Sets the sizes of the container and the slider items.
     * Triggers also the picturefill method to adjust the product images.
     */
    Plugin.prototype.setSizes = function() {
        var me = this;

        me.wrapperWidth = me.$el.outerWidth();
        me.itemsWidth = me.wrapperWidth / me.opts.perPage;

        me.$items.css({ width: me.itemsWidth });
        me.$container.stop(true, true).css({ width: me.itemsCount * me.itemsWidth + 20 });

        me.setPosition(me.slideIndex);

        // Also handle new loaded images bye the picturefill
        window.picturefill();
    };

    /**
     * Set the position of the slider directly to a given item index.
     *
     * @integer index
     */
    Plugin.prototype.setPosition = function(index) {
        var me = this,
            i = index || me.slideIndex;

        me.$container.css({ left: - ( i * me.itemsWidth ) });
    };

    /**
     * Registers all necessary event handlers.
     */
    Plugin.prototype.registerEvents = function() {
        var me = this;

        $(window).on('resize.' + pluginName,  me.setSizes.bind(me));

        me.$arrowLeft.on('click.' + pluginName, function(e) {
            e.preventDefault();
            me.slidePrev();
        });
        me.$arrowRight.on('click.' + pluginName, function(e) {
            e.preventDefault();
            me.slideNext();
        });

        if (me.opts.touchControl && me.active) {
            me.$el.on('swipeleft.' + pluginName, me.slideNext.bind(me));
            me.$el.on('swiperight.' + pluginName, me.slidePrev.bind(me));

            // Touch scrolling fix
            me.$el.on('movestart.' + pluginName, function(e) {
                if ((e.distX > e.distY && e.distX < -e.distY) ||
                    (e.distX < e.distY && e.distX > -e.distY)) {
                    e.preventDefault();
                }
            });
        }

        if (me.opts.autoSlide && me.active) {
            me.$el.on('mouseenter.' + pluginName, me.stopAutoSlide.bind(me));
            me.$el.on('mouseleave.' + pluginName, me.startAutoSlide.bind(me));
        }

        $.subscribe('plugin/tabContent/onChangeTab', function() {
            me.setSizes();
            me.setPosition(me.slideIndex);
        });
    };

    /**
     * Creates the arrow buttons.
     */
    Plugin.prototype.createArrows = function() {
        var me = this;

        me.$arrowLeft = $('<a>', {
            'class': me.opts.arrowClassLeft
        });

        me.$arrowRight = $('<a>', {
            'class': me.opts.arrowClassRight
        });

        if (me.opts.showArrows && me.active) {
            me.$arrowLeft.prependTo(me.$el);
            me.$arrowRight.prependTo(me.$el);
        }

        me.trackArrows();
    };

    /**
     * Tracks the view of the arrow buttons.
     * Hides the specific arrow button when the slider comes to last item.
     */
    Plugin.prototype.trackArrows = function() {
        var me = this;

        me.$arrowRight[( me.slideIndex == me.maxIndex ) ? 'hide' : 'show']();
        me.$arrowLeft[( me.slideIndex == me.minIndex ) ? 'hide' : 'show']();
    };

    /**
     * Starts the automatic sliding.
     * Calls slideNext() in the configured interval.
     */
    Plugin.prototype.startAutoSlide = function() {
        var me = this;

        me.slideInterval = window.setInterval(function(){
            me.slideNext();
        }, me.opts.autoSlideInterval);
    };

    /**
     * Stops the automatic sliding.
     */
    Plugin.prototype.stopAutoSlide = function() {
        var me = this;

        window.clearInterval(me.slideInterval);
    };

    /**
     * Handles the sliding forward to next items.
     * Loads new products via ajax if necessary.
     */
    Plugin.prototype.slideNext = function() {
        var me = this,
            newIndex = me.slideIndex + me.opts.perSlide,
            itemsLeftToSlideNext = me.itemsCount - (me.slideIndex + me.opts.perPage),
            offset = me.opts.perPage;

        if ( me.opts.perSlide > itemsLeftToSlideNext ) {
            newIndex = me.slideIndex + itemsLeftToSlideNext;
        }

        if ( newIndex <= me.maxIndex ) {
            me.slide(newIndex);
        }

        if ( me.opts.mode == 'ajax'
            && me.itemsToLoad > 0
            && me.itemsMaxShow > me.itemsCount) {

            if (offset < 4) offset = 4;
            if ( me.opts.perPage < me.itemsToLoad ) offset = me.itemsToLoad;

            me.loadItems(me.itemsCount, offset, function(response) {
                me.$container.append(response);
                me.trackItems();
                me.setSizes();
            });
        }
    };

    /**
     * Handles the sliding backwards to previous items.
     */
    Plugin.prototype.slidePrev = function() {
        var me = this,
            newIndex = me.slideIndex - me.opts.perSlide;

        if ( me.opts.perSlide > me.slideIndex ) {
            newIndex = 0;
        }

        if ( newIndex >= me.minIndex ) {
            me.slide(newIndex);
        }
    };

    /**
     * Basic slide function which handles the animation based on the new index.
     * Is called by slideNext() and slidePrev().
     *
     * @integer index
     * @function callback
     */
    Plugin.prototype.slide = function(index, callback) {
        var me = this,
            newPosition = -(index * me.itemsWidth) + 'px',
            afterSlide = callback || function() {};

        me.slideIndex = index;

        me.trackArrows();

        if (modernizr.csstransitions) {
            me.$container.transition({ left: newPosition }, me.opts.animationSpeed, afterSlide);
        } else {
            me.$container.animate({ left: newPosition }, me.opts.animationSpeed, afterSlide);
        }
    };

    /**
     * Destroyes the initialized plugin completely, so all event listeners will
     * be removed and the plugin data, which is stored in-memory referenced to
     * the DOM node.
     */
    Plugin.prototype.destroy = function() {
        var me = this;

        me.stopAutoSlide();

        me.$arrowLeft.off('click.' + pluginName).remove();
        me.$arrowRight.off('click.' + pluginName).remove();

        me.$el.off('mouseenter.' + pluginName);
        me.$el.off('mouseleave.' + pluginName);
        me.$el.off('swipeleft.' + pluginName);
        me.$el.off('swiperight.' + pluginName);
        me.$el.off('movestart.' + pluginName);

        $(window).off('resize.' + pluginName);

        me.$el.removeData('plugin_' + pluginName);
    };

    $.fn[pluginName] = function ( options ) {
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                $.data(this, 'plugin_' + pluginName,
                    new Plugin( this, options ));
            }
        });
    };

})(jQuery, Modernizr, window, document);<commit_msg>SW-8569 Optimized product slider plugin for better use with other plugins<commit_after>;(function($, modernizr, window, document, undefined) {
    "use strict";

    /**
     * Product Slider Plugin
     *
     * The plugin provides the functionality to create dynamic product sliders
     * in every part of the shop. Via the config settings you have many options for
     * adjusting the slider to fit your needs. The products for example can be set by
     * the local template or loaded via ajax. Different view options and optional touch
     * gestures make the slider full responsive on any device. See the defaults for all
     * available config options. All config settings can also be set via data attributes.
     *
     * @Example DOM structure:
     * ```
     * <div class="product-slider" data-touchControl="true">
     *     <div class="product-slider--container">
     *         <div class="product-slider--item"></div>
     *         <div class="product-slider--item"></div>
     *         <div class="product-slider--item"></div>
     *     </div>
     * </div>
     * ```
     *
     * ToDo: Add additional functionality like dot navigation or infinite sliding.
     */
    var pluginName = 'productSlider',
        defaults = {
            /**
             * The mode how the products are loaded.
             * @string local | ajax
             */
            mode: 'local',

            /**
             * The category id of the products to load.
             * @integer
             */
            categoryID: 1,

            /**
             * The number of products shown per page.
             * @integer
             */
            perPage: 5,

            /**
             * The number of products moved per slide.
             * @integer
             */
            perSlide: 1,

            /**
             * The maximum of products available to laod via ajax.
             * @integer
             */
            ajaxMaxAvailable: 20,

            /**
             * The maximum of products should be shown via ajax.
             * @integer
             */
            ajaxMaxShow: 20,

            /**
             * Show or hide the arrow buttons.
             * @bool
             */
            showArrows: true,

            /**
             * Active touch gesture controls.
             * @bool
             */
            touchControl: false,

            /**
             * Active automatic sliding.
             * @bool
             */
            autoSlide: false,

            /**
             * Set the interval of the automatic sliding.
             * @integer
             */
            autoSlideInterval: 4000,

            /**
             * Set the speed of a single slide animation.
             * @integer
             */
            animationSpeed: 300,

            /**
             * Set the controller url which returns the products loaded via ajax.
             * @string
             */
            controllerUrl: '/widgets/emotion/emotionTopSeller',

            /**
             * An additional css class for the wrapper element.
             * @string
             */
            wrapperClass: 'product-slider',

            /**
             * The css class of the slider element.
             * @string
             */
            containerClass: 'product-slider--container',

            /**
             * The css class of a single slider item.
             * @string
             */
            itemClass: 'product-slider--item',

            /**
             * The css class of the left arrow button.
             * @string
             */
            arrowClassLeft: 'product-slider--arrow is--left',

            /**
             * The css class of the right arrow button.
             * @string
             */
            arrowClassRight: 'product-slider--arrow is--right'
        };

    /**
     * Plugin constructor which merges the default settings with the user settings.
     *
     * @param {HTMLElement} element - Element which should be used in the plugin
     * @param {Object} userOpts - User settings for the plugin
     * @constructor
     */
    function Plugin(element, userOpts) {
        var me = this;

        me.$el = $(element);

        me.opts = $.extend({}, defaults, userOpts);

        me.getDataConfig();

        me._defaults = defaults;
        me._name = pluginName;

        me.itemsCount = 0;
        me.slideIndex = 0;
        me.slideInterval = false;
        me.touchEvent = {};

        me.$items = false;

        me.itemsMaxShow = (me.opts.ajaxMaxShow > me.opts.ajaxMaxAvailable) ? me.opts.ajaxMaxAvailable : me.opts.ajaxMaxShow;

        me.$el.addClass(me.opts.wrapperClass);

        me.$container = me.createSlideContainer();
        me.createItems();
    }

    /**
     * Loads config settings which are set via data attributes and
     * overrides the old setting with the data attribute of the
     * same name if defined.
     */
    Plugin.prototype.getDataConfig = function() {
        var me = this,
            attr;

        $.each(me.opts, function(key, value) {
            attr = me.$el.attr('data-' + key);
            if ( attr !== undefined ) {
                me.opts[key] = attr;
            }
        });
    };

    /**
     * Initializes the plugin and calls all necessary functions.
     */
    Plugin.prototype.init = function() {
        var me = this;

        me.checkActiveState();

        me.setSizes();
        me.setPosition();
        me.createArrows();
        me.registerEvents();

        if (me.opts.autoSlide && me.active) {
            me.startAutoSlide();
        }
    };

    /**
     * Checks if there are enough items
     * and actives the slider if necessary.
     */
    Plugin.prototype.checkActiveState = function() {
        var me = this;

        me.active = (me.itemsCount > me.opts.perPage);
    };

    /**
     * Gets the container element of the sliding items.
     * Creates a new container if no element is found.
     */
    Plugin.prototype.createSlideContainer = function() {
        var me = this,
            container = me.$el.find('.' + me.opts.containerClass);

        if (!container.length) {
            container = $('<div>', {
                'class': me.opts.containerClass
            }).appendTo(me.$el);
        }

        return container;
    };

    /**
     * Creates the slider items.
     * Calls the init function if after the products are loaded.
     */
    Plugin.prototype.createItems = function() {
        var me = this,
            loadCount = me.opts.perPage * 2;

        if (loadCount < 4) loadCount = 4;
        if (loadCount > me.itemsMaxShow) loadCount = me.itemsMaxShow;

        if (me.opts.mode == 'ajax') {
            me.loadItems(0, loadCount, function(response) {
                me.$container.html(response);
                me.trackItems();
                me.init();
            });
        } else {
            me.trackItems();
            me.init();
        }
    };

    /**
     * Tracks all slider items and sets some necessary variables.
     * Is called on initialization and on every slide to update the information.
     */
    Plugin.prototype.trackItems = function() {
        var me = this;

        me.$items = me.$container.find('.' + me.opts.itemClass);

        me.itemsCount = me.$items.length;

        me.itemsMaxCount = (me.opts.mode == 'ajax') ? me.opts.ajaxMaxAvailable : me.itemsCount;

        me.twoPages = me.opts.perPage * 2;
        me.minIndex = 0;
        me.maxIndex = (me.opts.mode == 'ajax') ? me.itemsMaxShow - me.opts.perPage : me.itemsCount - me.opts.perPage;

        me.itemsToLoad = me.itemsMaxShow - me.itemsCount;
    };

    /**
     * Loads products via ajax.
     *
     * @integer start
     * @integer limit
     * @function callback
     */
    Plugin.prototype.loadItems = function(start, limit, callback) {
        var me = this,
            cb = callback || function() {};

        $.ajax({
            url: me.opts.controllerUrl,
            method: 'POST',
            data: {
                'category': me.opts.categoryID,
                'start': start,
                'limit': limit
            },
            success: function(response) {
                cb.call(me, response);
            }
        });
    };

    /**
     * Sets the sizes of the container and the slider items.
     * Triggers also the picturefill method to adjust the product images.
     */
    Plugin.prototype.setSizes = function() {
        var me = this;

        me.wrapperWidth = me.$el.outerWidth();
        me.itemsWidth = me.wrapperWidth / me.opts.perPage;

        me.$items.css({ width: me.itemsWidth });
        me.$container.stop(true, true).css({ width: me.itemsCount * me.itemsWidth + 20 });

        me.setPosition(me.slideIndex);

        // Also handle new loaded images bye the picturefill
        window.picturefill();
    };

    /**
     * Set the position of the slider directly to a given item index.
     *
     * @integer index
     */
    Plugin.prototype.setPosition = function(index) {
        var me = this,
            i = index || me.slideIndex;

        me.$container.css({ left: - ( i * me.itemsWidth ) });
    };

    /**
     * Registers all necessary event handlers.
     */
    Plugin.prototype.registerEvents = function() {
        var me = this;

        $(window).on('resize.' + pluginName, $.proxy(me.setSizes, me));

        me.$arrowLeft.on('click.' + pluginName, function(e) {
            e.preventDefault();
            me.slidePrev();
        });
        me.$arrowRight.on('click.' + pluginName, function(e) {
            e.preventDefault();
            me.slideNext();
        });

        if (me.opts.touchControl) {
            me.$el.on('swipeleft.' + pluginName, $.proxy(me.slideNext, me));
            me.$el.on('swiperight.' + pluginName, $.proxy(me.slidePrev, me));

            // Touch scrolling fix
            me.$el.on('movestart.' + pluginName, function(e) {
                if ((e.distX > e.distY && e.distX < -e.distY) ||
                    (e.distX < e.distY && e.distX > -e.distY)) {
                    e.preventDefault();
                }
            });
        }

        if (me.opts.autoSlide) {
            me.$el.on('mouseenter.' + pluginName, $.proxy(me.stopAutoSlide, me));
            me.$el.on('mouseleave.' + pluginName, $.proxy(me.startAutoSlide, me));
        }

        $.subscribe('plugin/tabContent/onChangeTab', function() {
            me.setSizes();
            me.setPosition(me.slideIndex);
        });
    };

    /**
     * Creates the arrow buttons.
     */
    Plugin.prototype.createArrows = function() {
        var me = this;

        if (!me.opts.showArrows) {
            return;
        }

        if (!me.$arrowLeft) {
            me.$arrowLeft = $('<a>', {
                'class': me.opts.arrowClassLeft
            }).prependTo(me.$el);
        }

        if (!me.$arrowRight) {
            me.$arrowRight = $('<a>', {
                'class': me.opts.arrowClassRight
            }).prependTo(me.$el);
        }

        me.trackArrows();
    };

    /**
     * Tracks the view of the arrow buttons.
     * Hides the specific arrow button when the slider comes to last item.
     */
    Plugin.prototype.trackArrows = function() {
        var me = this;

        if (!me.active) {
            me.$arrowRight.hide();
            me.$arrowLeft.hide();
            return;
        }

        me.$arrowRight[( me.slideIndex == me.maxIndex ) ? 'hide' : 'show']();
        me.$arrowLeft[( me.slideIndex == me.minIndex ) ? 'hide' : 'show']();
    };

    /**
     * Starts the automatic sliding.
     * Calls slideNext() in the configured interval.
     */
    Plugin.prototype.startAutoSlide = function() {
        var me = this;

        if (!me.active) {
            return;
        }

        me.slideInterval = window.setInterval(function(){
            me.slideNext();
        }, me.opts.autoSlideInterval);
    };

    /**
     * Stops the automatic sliding.
     */
    Plugin.prototype.stopAutoSlide = function() {
        var me = this;

        window.clearInterval(me.slideInterval);
    };

    /**
     * Handles the sliding forward to next items.
     * Loads new products via ajax if necessary.
     */
    Plugin.prototype.slideNext = function() {
        var me = this,
            newIndex = me.slideIndex + me.opts.perSlide,
            itemsLeftToSlideNext = me.itemsCount - (me.slideIndex + me.opts.perPage),
            offset = me.opts.perPage;

        if (!me.active) {
            return;
        }

        if ( me.opts.perSlide > itemsLeftToSlideNext ) {
            newIndex = me.slideIndex + itemsLeftToSlideNext;
        }

        if ( newIndex <= me.maxIndex ) {
            me.slide(newIndex);
        }

        if ( me.opts.mode == 'ajax'
            && me.itemsToLoad > 0
            && me.itemsMaxShow > me.itemsCount) {

            if (offset < 4) offset = 4;
            if ( me.opts.perPage < me.itemsToLoad ) offset = me.itemsToLoad;

            me.loadItems(me.itemsCount, offset, function(response) {
                me.$container.append(response);
                me.trackItems();
                me.setSizes();
            });
        }
    };

    /**
     * Handles the sliding backwards to previous items.
     */
    Plugin.prototype.slidePrev = function() {
        var me = this,
            newIndex = me.slideIndex - me.opts.perSlide;

        if (!me.active) {
            return;
        }

        if ( me.opts.perSlide > me.slideIndex ) {
            newIndex = 0;
        }

        if ( newIndex >= me.minIndex ) {
            me.slide(newIndex);
        }
    };

    /**
     * Basic slide function which handles the animation based on the new index.
     * Is called by slideNext() and slidePrev().
     *
     * @integer index
     * @function callback
     */
    Plugin.prototype.slide = function(index, callback) {
        var me = this,
            newPosition = -(index * me.itemsWidth) + 'px',
            afterSlide = callback || function() {};

        if (!me.active) {
            return;
        }

        me.slideIndex = index;

        me.trackArrows();

        if (modernizr.csstransitions) {
            me.$container.transition({ left: newPosition }, me.opts.animationSpeed, afterSlide);
        } else {
            me.$container.animate({ left: newPosition }, me.opts.animationSpeed, afterSlide);
        }
    };

    /**
     * Destroyes the initialized plugin completely, so all event listeners will
     * be removed and the plugin data, which is stored in-memory referenced to
     * the DOM node.
     */
    Plugin.prototype.destroy = function() {
        var me = this;

        me.stopAutoSlide();

        me.$arrowLeft.off('click.' + pluginName).remove();
        me.$arrowRight.off('click.' + pluginName).remove();

        me.$el.off('mouseenter.' + pluginName);
        me.$el.off('mouseleave.' + pluginName);
        me.$el.off('swipeleft.' + pluginName);
        me.$el.off('swiperight.' + pluginName);
        me.$el.off('movestart.' + pluginName);

        $(window).off('resize.' + pluginName);

        me.$el.removeData('plugin_' + pluginName);
    };

    $.fn[pluginName] = function ( options ) {
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                $.data(this, 'plugin_' + pluginName,
                    new Plugin( this, options ));
            }
        });
    };

})(jQuery, Modernizr, window, document);<|endoftext|>