<commit_before>/*!
 * ${copyright}
 */

sap.ui.define([
	"sap/ui/rta/plugin/Plugin",
	"sap/ui/rta/Utils",
	"sap/ui/dt/Util",
	"sap/base/Log"
], function(
	Plugin,
	Utils,
	DtUtil,
	BaseLog
) {
	"use strict";

	/**
	 * Constructor for a new Settings Plugin.
	 *
	 * @param {string} [sId] id for the new object, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new object
	 * @class The Settings allows trigger change of settings operations on the overlay
	 * @extends sap.ui.rta.plugin.Plugin
	 * @author SAP SE
	 * @version ${version}
	 * @constructor
	 * @private
	 * @since 1.44
	 * @alias sap.ui.rta.plugin.Settings
	 * @experimental Since 1.44. This class is experimental and provides only limited functionality. Also the API might be changed in future.
	 */
	var Settings = Plugin.extend("sap.ui.rta.plugin.Settings", /** @lends sap.ui.rta.plugin.Settings.prototype */ {
		metadata: {
			library: "sap.ui.rta",
			properties: {
				commandStack: {
					type: "any"
				}
			},
			associations: {},
			events: {}
		}
	});

	var sPluginId = "CTX_SETTINGS";

	/**
	 * @param {sap.ui.dt.ElementOverlay} oOverlay overlay to be checked for editable
	 * @returns {boolean} true if it's editable
	 * @private
	 */
	Settings.prototype._isEditable = function(oOverlay) {
		var vSettingsAction = this.getAction(oOverlay);
		// If no additional actions are defined in settings, a handler must be present to make it available
		if (vSettingsAction) {
			if (vSettingsAction.handler) {
				return this.hasStableId(oOverlay);
			}

			var bHandlerAndStableIdFound = Object.keys(vSettingsAction).some(function(sSettingsAction) {
				var oSettingsAction = vSettingsAction[sSettingsAction];
				return oSettingsAction.handler && this._checkRelevantContainerStableID(oSettingsAction, oOverlay);
			}.bind(this));
			if (bHandlerAndStableIdFound) {
				return this.hasStableId(oOverlay);
			}
		}

		return false;
	};

	/**
	 * Checks if settings is enabled for oOverlay
	 *
	 * @param {sap.ui.dt.ElementOverlay[]} aElementOverlays - Target overlays
	 * @returns {boolean} true if it's enabled
	 * @public
	 */
	Settings.prototype.isEnabled = function(aElementOverlays) {
		var oElementOverlay = aElementOverlays[0];
		var oAction = this.getAction(oElementOverlay);
		if (!oAction) {
			return false;
		}

		if (typeof oAction.isEnabled !== "undefined") {
			if (typeof oAction.isEnabled === "function") {
				return oAction.isEnabled(oElementOverlay.getElement());
			}
			return oAction.isEnabled;
		}
		return true;
	};

	Settings.prototype._getUnsavedChanges = function(sId, aChangeTypes) {
		var sElementId;

		var aUnsavedChanges = this.getCommandStack().getAllExecutedCommands().filter(function(oCommand) {
			sElementId = oCommand.getElementId && oCommand.getElementId() || oCommand.getElement && oCommand.getElement().getId();
			if (sElementId === sId && aChangeTypes.indexOf(oCommand.getChangeType()) >= 0) {
				return true;
			}
		}).map(function(oCommand) {
			return oCommand.getPreparedChange();
		});

		return aUnsavedChanges;
	};

	Settings.prototype._handleFlexChangeCommand = function(mChange, aSelectedOverlays, oCompositeCommand, bRuntimeOnly) {
		var mChangeSpecificData = mChange.changeSpecificData;
		var sVariantManagementReference;
		// temporarily support both
		var vSelector = mChange.selectorElement || mChange.selectorControl;
		var sControlType;
		var oControl;

		if (vSelector.controlType) {
			sControlType = vSelector.controlType;
		} else {
			oControl = vSelector;
		}

		return this.hasChangeHandler(mChangeSpecificData.changeType, oControl, sControlType)
			.then(function(bHasChangeHandler) {
				if (aSelectedOverlays[0].getVariantManagement && bHasChangeHandler) {
					sVariantManagementReference = aSelectedOverlays[0].getVariantManagement();
				}
				return this.getCommandFactory().getCommandFor(
					vSelector,
					"settings",
					mChangeSpecificData,
					undefined,
					sVariantManagementReference);
			}.bind(this))
			.then(function(oSettingsCommand) {
				if (bRuntimeOnly) {
					oSettingsCommand.setRuntimeOnly(bRuntimeOnly);
				}
				return oCompositeCommand.addCommand(oSettingsCommand);
			});
	};

	Settings.prototype._handleAppDescriptorChangeCommand = function(mChange, oElement, oCompositeCommand) {
		var mChangeSpecificData = mChange.changeSpecificData;
		var oComponent = mChange.appComponent;
		var mManifest = oComponent.getManifest();
		var sReference = mManifest["sap.app"].id;

		return this.getCommandFactory().getCommandFor(
			oElement,
			"appDescriptor",
			{
				reference: sReference,
				appComponent: oComponent,
				changeType: mChangeSpecificData.appDescriptorChangeType,
				parameters: mChangeSpecificData.content.parameters,
				texts: mChangeSpecificData.content.texts
			}
		)
		.then(function(oAppDescriptorCommand) {
			return oCompositeCommand.addCommand(oAppDescriptorCommand);
		});
	};

	Settings.prototype._handleCompositeCommand = function(aElementOverlays, oElement, aChanges, bRuntimeOnly) {
		var oCompositeCommand;

		return this.getCommandFactory().getCommandFor(oElement, "composite")

		.then(function(_oCompositeCommand) {
			oCompositeCommand = _oCompositeCommand;
		})

		.then(function() {
			return aChanges.map(function(mChange) {
				var mChangeSpecificData = mChange.changeSpecificData;
				// Flex Change
				if (mChangeSpecificData.changeType) {
					return this._handleFlexChangeCommand(mChange, aElementOverlays, oCompositeCommand, bRuntimeOnly);
				// App Descriptor Change
				} else if (mChangeSpecificData.appDescriptorChangeType) {
					return this._handleAppDescriptorChangeCommand(mChange, oElement, oCompositeCommand);
				}
			}, this);
		}.bind(this))

		.then(function(aPromises) {
			return Promise.all(aPromises);
		})

		.then(function() {
			if (oCompositeCommand.getCommands().length > 0) {
				this.fireElementModified({
					command: oCompositeCommand
				});
			}
		}.bind(this));
	};

	/**
	 * Retrieves the available actions from the DesignTime Metadata and creates
	 * the corresponding commands for them.
	 * @param {sap.ui.dt.ElementOverlay[]} aElementOverlays - Target Overlays of the action
	 * @param {object} mPropertyBag Property bag
	 * @param {function} [mPropertyBag.fnHandler] Handler function for the case of multiple settings actions
	 * @return {Promise} Returns promise resolving with the creation of the commands
	 */
	Settings.prototype.handler = function(aElementOverlays, mPropertyBag, bRuntimeOnly) {
		mPropertyBag = mPropertyBag || {};
		var oElement = aElementOverlays[0].getElement();
		var fnHandler = mPropertyBag.fnHandler;

		if (!fnHandler) {
			fnHandler = aElementOverlays[0].getDesignTimeMetadata().getAction("settings").handler;
			if (!fnHandler) {
				throw new Error("Handler not found for settings action");
			}
		}
		mPropertyBag.getUnsavedChanges = this._getUnsavedChanges.bind(this);
		mPropertyBag.styleClass = Utils.getRtaStyleClassName();

		return fnHandler(oElement, mPropertyBag)

		.then(function(aChanges) {
			if (aChanges.length > 0) {
				return this._handleCompositeCommand(aElementOverlays, oElement, aChanges, bRuntimeOnly);
			}
		}.bind(this))

		.catch(function(vError) {
			throw DtUtil.propagateError(
				vError,
				"Settings#handler",
				"Error occured during handler execution",
				"sap.ui.rta.plugin"
			);
		});
	};

	/**
	 * Retrieve the context menu item for the actions.
	 * If multiple actions are defined for Settings, it returns multiple menu items.
	 * @param {sap.ui.dt.ElementOverlay[]} aElementOverlays - Target overlays
	 * @return {object[]} array of the items with required data
	 */
	Settings.prototype.getMenuItems = function(aElementOverlays) {
		var oElementOverlay = aElementOverlays[0];
		var vSettingsActions = this.getAction(oElementOverlay);

		var aMenuItems = [];
		if (vSettingsActions) {
			var iRank = 110;

			if (vSettingsActions.handler) {
				vSettingsActions = {
					settings: vSettingsActions
				};
			}
			var aSettingsActions = Object.keys(vSettingsActions);
			aSettingsActions.forEach(function(sSettingsAction, iIndex, aActions) {
				var oSettingsAction = vSettingsActions[sSettingsAction];
				if (
					oSettingsAction.handler
					&& this._checkRelevantContainerStableID(oSettingsAction, oElementOverlay)
					&& this.isAvailable([oElementOverlay])
				) {
					var bSingleAction = aActions.length === 1;

					aMenuItems.push({
						id: bSingleAction ? sPluginId : sPluginId + iIndex,
						rank: bSingleAction ? iRank : iRank + iIndex,
						text: this.getActionText(oElementOverlay, oSettingsAction, sPluginId),
						icon: getActionIcon(oSettingsAction),
						enabled: (
							typeof oSettingsAction.isEnabled === "function"
							&& function(aElementOverlays) {
								return oSettingsAction.isEnabled(aElementOverlays[0].getElement());
							}
							|| oSettingsAction.isEnabled
							|| this.isEnabled([oElementOverlay])
						),
						handler: function(fnHandler, aElementOverlays, mPropertyBag) {
							mPropertyBag = mPropertyBag || {};
							mPropertyBag.fnHandler = fnHandler;
							return this.handler(aElementOverlays, mPropertyBag, oSettingsAction.runtimeOnly);
						}.bind(this, oSettingsAction.handler),
						submenu: formatSubMenuItems(oSettingsAction.submenu)
					});
				} else {
					BaseLog.warning("Handler not found for settings action '" + sSettingsAction + "' or relevant container has no stable id");
				}
			}, this);
		}

		return aMenuItems;
	};

	function formatSubMenuItems(aSubMenu) {
		if (aSubMenu) {
			return aSubMenu.map(function(oSubMenu, iIndex) {
				return {
					id: oSubMenu.key || sPluginId + "_SUB_" + iIndex,
					icon: oSubMenu.icon || "blank",
					text: oSubMenu.name || "",
					enabled: oSubMenu.hasOwnProperty("enabled") ? oSubMenu.enabled : true
				};
			});
		}
	}

	function getActionIcon(oSettingsAction) {
		var sDefaultSettingIcon = "sap-icon://key-user-settings";
		var sActionIcon = oSettingsAction.icon;
		if (!sActionIcon) {
			return sDefaultSettingIcon;
		}
		if (typeof sActionIcon !== "string") {
			BaseLog.error("Icon setting for settingsAction should be a string");
			return sDefaultSettingIcon;
		}
		return sActionIcon;
	}

	/**
	 * Get the name of the action related to this plugin.
	 * @return {string} Returns the action name
	 */
	Settings.prototype.getActionName = function() {
		return "settings";
	};

	return Settings;
});<commit_msg>[INTERNAL] sap.ui.rta: safeguard runtimeOnly logic in Settings plugin<commit_after>/*!
 * ${copyright}
 */

sap.ui.define([
	"sap/ui/rta/plugin/Plugin",
	"sap/ui/rta/Utils",
	"sap/ui/dt/Util",
	"sap/base/Log"
], function(
	Plugin,
	Utils,
	DtUtil,
	BaseLog
) {
	"use strict";

	/**
	 * Constructor for a new Settings Plugin.
	 *
	 * @param {string} [sId] id for the new object, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new object
	 * @class The Settings allows trigger change of settings operations on the overlay
	 * @extends sap.ui.rta.plugin.Plugin
	 * @author SAP SE
	 * @version ${version}
	 * @constructor
	 * @private
	 * @since 1.44
	 * @alias sap.ui.rta.plugin.Settings
	 * @experimental Since 1.44. This class is experimental and provides only limited functionality. Also the API might be changed in future.
	 */
	var Settings = Plugin.extend("sap.ui.rta.plugin.Settings", /** @lends sap.ui.rta.plugin.Settings.prototype */ {
		metadata: {
			library: "sap.ui.rta",
			properties: {
				commandStack: {
					type: "any"
				}
			},
			associations: {},
			events: {}
		}
	});

	var sPluginId = "CTX_SETTINGS";

	/**
	 * @param {sap.ui.dt.ElementOverlay} oOverlay overlay to be checked for editable
	 * @returns {boolean} true if it's editable
	 * @private
	 */
	Settings.prototype._isEditable = function(oOverlay) {
		var vSettingsAction = this.getAction(oOverlay);
		// If no additional actions are defined in settings, a handler must be present to make it available
		if (vSettingsAction) {
			if (vSettingsAction.handler) {
				return this.hasStableId(oOverlay);
			}

			var bHandlerAndStableIdFound = Object.keys(vSettingsAction).some(function(sSettingsAction) {
				var oSettingsAction = vSettingsAction[sSettingsAction];
				return oSettingsAction.handler && this._checkRelevantContainerStableID(oSettingsAction, oOverlay);
			}.bind(this));
			if (bHandlerAndStableIdFound) {
				return this.hasStableId(oOverlay);
			}
		}

		return false;
	};

	/**
	 * Checks if settings is enabled for oOverlay
	 *
	 * @param {sap.ui.dt.ElementOverlay[]} aElementOverlays - Target overlays
	 * @returns {boolean} true if it's enabled
	 * @public
	 */
	Settings.prototype.isEnabled = function(aElementOverlays) {
		var oElementOverlay = aElementOverlays[0];
		var oAction = this.getAction(oElementOverlay);
		if (!oAction) {
			return false;
		}

		if (typeof oAction.isEnabled !== "undefined") {
			if (typeof oAction.isEnabled === "function") {
				return oAction.isEnabled(oElementOverlay.getElement());
			}
			return oAction.isEnabled;
		}
		return true;
	};

	Settings.prototype._getUnsavedChanges = function(sId, aChangeTypes) {
		var sElementId;

		var aUnsavedChanges = this.getCommandStack().getAllExecutedCommands().filter(function(oCommand) {
			sElementId = oCommand.getElementId && oCommand.getElementId() || oCommand.getElement && oCommand.getElement().getId();
			if (sElementId === sId && aChangeTypes.indexOf(oCommand.getChangeType()) >= 0) {
				return true;
			}
		}).map(function(oCommand) {
			return oCommand.getPreparedChange();
		});

		return aUnsavedChanges;
	};

	Settings.prototype._handleFlexChangeCommand = function(mChange, aSelectedOverlays, oCompositeCommand, bRuntimeOnly) {
		var mChangeSpecificData = mChange.changeSpecificData;
		var sVariantManagementReference;
		// temporarily support both
		var vSelector = mChange.selectorElement || mChange.selectorControl;
		var sControlType;
		var oControl;

		if (vSelector.controlType) {
			sControlType = vSelector.controlType;
		} else {
			oControl = vSelector;
		}

		return this.hasChangeHandler(mChangeSpecificData.changeType, oControl, sControlType)
			.then(function(bHasChangeHandler) {
				if (aSelectedOverlays[0].getVariantManagement && bHasChangeHandler) {
					sVariantManagementReference = aSelectedOverlays[0].getVariantManagement();
				}
				return this.getCommandFactory().getCommandFor(
					vSelector,
					"settings",
					mChangeSpecificData,
					undefined,
					sVariantManagementReference);
			}.bind(this))
			.then(function(oSettingsCommand) {
				if (oSettingsCommand && bRuntimeOnly) {
					oSettingsCommand.setRuntimeOnly(bRuntimeOnly);
				}
				return oCompositeCommand.addCommand(oSettingsCommand);
			});
	};

	Settings.prototype._handleAppDescriptorChangeCommand = function(mChange, oElement, oCompositeCommand) {
		var mChangeSpecificData = mChange.changeSpecificData;
		var oComponent = mChange.appComponent;
		var mManifest = oComponent.getManifest();
		var sReference = mManifest["sap.app"].id;

		return this.getCommandFactory().getCommandFor(
			oElement,
			"appDescriptor",
			{
				reference: sReference,
				appComponent: oComponent,
				changeType: mChangeSpecificData.appDescriptorChangeType,
				parameters: mChangeSpecificData.content.parameters,
				texts: mChangeSpecificData.content.texts
			}
		)
		.then(function(oAppDescriptorCommand) {
			return oCompositeCommand.addCommand(oAppDescriptorCommand);
		});
	};

	Settings.prototype._handleCompositeCommand = function(aElementOverlays, oElement, aChanges, bRuntimeOnly) {
		var oCompositeCommand;

		return this.getCommandFactory().getCommandFor(oElement, "composite")

		.then(function(_oCompositeCommand) {
			oCompositeCommand = _oCompositeCommand;
		})

		.then(function() {
			return aChanges.map(function(mChange) {
				var mChangeSpecificData = mChange.changeSpecificData;
				// Flex Change
				if (mChangeSpecificData.changeType) {
					return this._handleFlexChangeCommand(mChange, aElementOverlays, oCompositeCommand, bRuntimeOnly);
				// App Descriptor Change
				} else if (mChangeSpecificData.appDescriptorChangeType) {
					return this._handleAppDescriptorChangeCommand(mChange, oElement, oCompositeCommand);
				}
			}, this);
		}.bind(this))

		.then(function(aPromises) {
			return Promise.all(aPromises);
		})

		.then(function() {
			if (oCompositeCommand.getCommands().length > 0) {
				this.fireElementModified({
					command: oCompositeCommand
				});
			}
		}.bind(this));
	};

	/**
	 * Retrieves the available actions from the DesignTime Metadata and creates
	 * the corresponding commands for them.
	 * @param {sap.ui.dt.ElementOverlay[]} aElementOverlays - Target Overlays of the action
	 * @param {object} mPropertyBag Property bag
	 * @param {function} [mPropertyBag.fnHandler] Handler function for the case of multiple settings actions
	 * @return {Promise} Returns promise resolving with the creation of the commands
	 */
	Settings.prototype.handler = function(aElementOverlays, mPropertyBag, bRuntimeOnly) {
		mPropertyBag = mPropertyBag || {};
		var oElement = aElementOverlays[0].getElement();
		var fnHandler = mPropertyBag.fnHandler;

		if (!fnHandler) {
			fnHandler = aElementOverlays[0].getDesignTimeMetadata().getAction("settings").handler;
			if (!fnHandler) {
				throw new Error("Handler not found for settings action");
			}
		}
		mPropertyBag.getUnsavedChanges = this._getUnsavedChanges.bind(this);
		mPropertyBag.styleClass = Utils.getRtaStyleClassName();

		return fnHandler(oElement, mPropertyBag)

		.then(function(aChanges) {
			if (aChanges.length > 0) {
				return this._handleCompositeCommand(aElementOverlays, oElement, aChanges, bRuntimeOnly);
			}
		}.bind(this))

		.catch(function(vError) {
			throw DtUtil.propagateError(
				vError,
				"Settings#handler",
				"Error occured during handler execution",
				"sap.ui.rta.plugin"
			);
		});
	};

	/**
	 * Retrieve the context menu item for the actions.
	 * If multiple actions are defined for Settings, it returns multiple menu items.
	 * @param {sap.ui.dt.ElementOverlay[]} aElementOverlays - Target overlays
	 * @return {object[]} array of the items with required data
	 */
	Settings.prototype.getMenuItems = function(aElementOverlays) {
		var oElementOverlay = aElementOverlays[0];
		var vSettingsActions = this.getAction(oElementOverlay);

		var aMenuItems = [];
		if (vSettingsActions) {
			var iRank = 110;

			if (vSettingsActions.handler) {
				vSettingsActions = {
					settings: vSettingsActions
				};
			}
			var aSettingsActions = Object.keys(vSettingsActions);
			aSettingsActions.forEach(function(sSettingsAction, iIndex, aActions) {
				var oSettingsAction = vSettingsActions[sSettingsAction];
				if (
					oSettingsAction.handler
					&& this._checkRelevantContainerStableID(oSettingsAction, oElementOverlay)
					&& this.isAvailable([oElementOverlay])
				) {
					var bSingleAction = aActions.length === 1;

					aMenuItems.push({
						id: bSingleAction ? sPluginId : sPluginId + iIndex,
						rank: bSingleAction ? iRank : iRank + iIndex,
						text: this.getActionText(oElementOverlay, oSettingsAction, sPluginId),
						icon: getActionIcon(oSettingsAction),
						enabled: (
							typeof oSettingsAction.isEnabled === "function"
							&& function(aElementOverlays) {
								return oSettingsAction.isEnabled(aElementOverlays[0].getElement());
							}
							|| oSettingsAction.isEnabled
							|| this.isEnabled([oElementOverlay])
						),
						handler: function(fnHandler, aElementOverlays, mPropertyBag) {
							mPropertyBag = mPropertyBag || {};
							mPropertyBag.fnHandler = fnHandler;
							return this.handler(aElementOverlays, mPropertyBag, oSettingsAction.runtimeOnly);
						}.bind(this, oSettingsAction.handler),
						submenu: formatSubMenuItems(oSettingsAction.submenu)
					});
				} else {
					BaseLog.warning("Handler not found for settings action '" + sSettingsAction + "' or relevant container has no stable id");
				}
			}, this);
		}

		return aMenuItems;
	};

	function formatSubMenuItems(aSubMenu) {
		if (aSubMenu) {
			return aSubMenu.map(function(oSubMenu, iIndex) {
				return {
					id: oSubMenu.key || sPluginId + "_SUB_" + iIndex,
					icon: oSubMenu.icon || "blank",
					text: oSubMenu.name || "",
					enabled: oSubMenu.hasOwnProperty("enabled") ? oSubMenu.enabled : true
				};
			});
		}
	}

	function getActionIcon(oSettingsAction) {
		var sDefaultSettingIcon = "sap-icon://key-user-settings";
		var sActionIcon = oSettingsAction.icon;
		if (!sActionIcon) {
			return sDefaultSettingIcon;
		}
		if (typeof sActionIcon !== "string") {
			BaseLog.error("Icon setting for settingsAction should be a string");
			return sDefaultSettingIcon;
		}
		return sActionIcon;
	}

	/**
	 * Get the name of the action related to this plugin.
	 * @return {string} Returns the action name
	 */
	Settings.prototype.getActionName = function() {
		return "settings";
	};

	return Settings;
});<|endoftext|>


<commit_before>/*
 * @copyright Adam Benda, 2016
 *
 */

/* global Blob, File, SVGSVGElement, EventTarget */

/**
 * @classdesc SVG Rendering library
 * @class
 */
var SVGRender = function () {

};

/**
 * Loads one SVG image from various source.
 * Will wipe out previously loaded image
 * @param {SVGSVGElement |  Blob | File | String} svg - svg element or its source
 * @returns {undefined}
 *
 * @public
 **/
SVGRender.prototype.load = function (svg) {
    /**
     * Loading from a file is asynchronous = do not call render() untill file is loaded.
     * @type {Boolean}
     * @private
     */
    this.loaded = false;

    /**
     * Signalizes that computation was interrupted/paused
     * @type Boolean
     */
    this.interrupted = false;

    /**
     * Signalizes that computation finished sucessfully
     * @type Boolean
     */
    this.finished = false;

    if (Blob.prototype.isPrototypeOf(svg) || File.prototype.isPrototypeOf(svg)) {
//to be read with FileReader
        if (!svg.type || svg.type !== "image/svg+xml") {
            throw "Wrong file/blob type, should be image/svg+xml, is " + svg.type;
        }

        /**
         * File reader of input File / Blob
         * @type {FileReader}
         * @private
         */
        this.reader = new FileReader();
        this.reader.readAsDataURL(svg);
        this.reader.onload = function () {
            //File was loaded from input to dataURI

            //http://stackoverflow.com/questions/11335460/how-do-i-parse-a-data-url-in-node
            var svgCodeB64 = this.reader.result;
            var regex = /^data:.+\/(.+);base64,(.*)$/;
            var matches = svgCodeB64.match(regex);
            var data = matches[2];
            var svgCode = atob(data);
            this.load.bind(this)(svgCode);
            //Call load function again - but with svg source loaded from file
            return;
        }.bind(this);
        return;

    } else if (typeof svg === "string") {
        //svg xml code
        var svgCode = svg;
        //var svgCode = this.result.replace(/<?xml[^>]*/,"").replace(/<!DOCTYPE[^>]*/,"");

        //We are using document from global namespace
        //todo: cleanup afterwards
        this.svgDivElement = document.createElement('div');
        this.svgDivElement.innerHTML = svgCode;
        var svgElement = this.svgDivElement.children[0];
        document.body.appendChild(this.svgDivElement);
        this.svgDivElement.style.visibility = 'hidden';
        this.load(svgElement);
        return;
    } else if (SVGSVGElement.prototype.isPrototypeOf(svg)) {

        /**
         * SVG element present in document.
         * @type {SVGSVGElement}
         * @private
         */
        this.svgElement = svg;
        this.loaded = true;
        return;
    } else {
        throw "Unknown svg type in svg-render!";
    }
};

/**
 * Start rendering
 * @param {Object} options - contains numbers FPS, time, imagesCount and function progressSignal
 * @param {function} callback
 * @returns {undefined}
 *
 * @public
 */
SVGRender.prototype.render = function (options, callback) {
    if (!options) {
        options = {};
    }

    /**
     * Will be called after rendering is finished
     * @type {function}
     */
    this.callback = callback;
    if (!this.callback) {
        this.callback = function () {};
    }

    if (!this.loaded) {
        //todo: more elegant solution
        setTimeout(this.render.bind(this, options, callback), 100);
        return;
    }

    /**
     * Function to be called repeatedly when frame is rendered.
     * has two parameters; count(total #frames) and doneCount(#frames rendered)
     * @type {function}
     * @private
     */
    this.progressSignal = (options.progressSignal || function () {});

    /**
     * begin time (seconds)
     * @type {number}
     * @private
     */
    this.beginMS = (options.begin * 1000 || 0); //default begin time

    /**
     * Frames per Second
     * @type {number}
     * @private
     */
    this.FPS = (options.FPS || 60); //default FPS

    /**
     * total time in miliseconds
     * @type {number}
     * @private
     */
    this.timeMS = (options.time * 1000 || 1000);

    /**
     * Number of frames to render
     * @type {number}
     * @private
     */
    this.imagesCount = Math.round(this.FPS * this.timeMS / 1000);

    if (options.imagesCount && options.imagesCount !== this.imagesCount) {
        //imagesCount was given
        if (options.time && options.FPS) {
            //FPS+time were also given and the tree given parameters are contradicting
            throw "Conflicting parameters FPS,time,imagesCount";
        } else if (options.time) {
            this.FPS = this.imagesCount * 1000 / this.timeMS;
        } else if (options.FPS) {
            this.timeMS = this.imagesCount * 1000 / this.FPS;
        }
    }

    /**
     * Time in miliseconds from the animation start time.
     * @type {int}
     * @private
     */
    this.SVGtime = 0; //in miliseconds

    /**
     * Number of already rendered images
     * @type {int}
     * @public
     */
    this.imagesDoneCount = 0;

    /**
     * Array of all rendered images in png format
     * @type {base64}
     * @public
     */
    this.images = [];

    /**
     * Array of all rendered images in png format
     * @type {number}
     * @private
     */
    this.nextFrame = setTimeout(this.renderNextFrame.bind(this), 0);

    /**
     * Canvas to draw on (optional - drawing is invisible if not provided)
     * @type {HTMLCanvasElement}
     * @private
     */
    this.canvas = (options.canvas || document.createElement('canvas')); //default begin time

};

/**
 * Goes through DOM tree of given HTMLElement and removes specific tags
 * @param {HTMLElement} htmlElement
 * @param {String[]} tags
 * @return {integer} - number of elements removed
 *
 * @private
 */
SVGRender.prototype.filterOut = function (htmlElement, tags) {
    var ret = 0;
    if (tags.indexOf(htmlElement.tagName) >= 0) {
        htmlElement.parentNode.removeChild(htmlElement);
        return 1;
    } else {
        //call filterOut recursively
        for (var i = 0; i < htmlElement.children.length; i++) {
            ret += this.filterOut(htmlElement.children[i], tags);
        }
    }
    return ret;
};

/**
 * Render next frame and schedule next run of render next frame
 * @returns {undefined}
 * @private
 */
SVGRender.prototype.renderNextFrame = function () {
    if (!this.svgElement) {
        throw "Cannot render - no svgElement loaded!";
    }

    if (this.interrupted) {
        //rendering was stopped
        //(this.nextFrame timeout should have been removed already!)
        throw "this.nextFrame timeout should have been removed already!";
        return;
    }

    this.SVGtime = this.beginMS + Math.round(1000 * this.imagesDoneCount) / (this.FPS);

    this.svgElement.pauseAnimations();
    this.svgElement.setCurrentTime(this.SVGtime / 1000);
    this.svgElement.forceRedraw();

    function exportStyle(el) {
        var ret = {};
        ret.children = [];
        for (var i = 0; i < el.children.length; i++) {
            ret.children[i] = exportStyle(el.children[i]);
        }

        ret.value = {};
        var styles = window.getComputedStyle(el);
        /*
         * //TODO: identify which styles have to be copied this way.
         for (var styleType in styles) {
         ret.value[styleType] = styles[styleType];
         }
         */
        ret.value["opacity"] = styles["opacity"];
        return ret;
    }

    function importStyle(el, data) {
        for (var i = 0; i < el.children.length; i++) {
            //recursive
            importStyle(el.children[i], data.children[i]);
        }
        for (var styleType in data.value) {
            el.style[styleType] = data.value[styleType];
        }
    }

    //Do deep copy of svgElement!
    var svgElementNew = this.svgElement.cloneNode(true);
    //Copy styles
    var styles = exportStyle(this.svgElement);
    importStyle(svgElementNew, styles);

    //maybe unnescessary
    svgElementNew.pauseAnimations();
    svgElementNew.setCurrentTime(this.SVGtime / 1000);
    svgElementNew.forceRedraw();
    document.body.appendChild(svgElementNew);

    this.filterOut(svgElementNew, "animate");
    this.filterOut(svgElementNew, "animateTransform");
    this.filterOut(svgElementNew, "animateMotion");
    this.filterOut(svgElementNew, "animateColor");

    var svgString = new XMLSerializer().serializeToString(svgElementNew);
    this.svgImage = new Image();
    this.svgImage.onload = function () {

        tmpCanvasx = this.canvas.getContext('2d');
        this.canvas.width = this.svgImage.width;
        this.canvas.height = this.svgImage.height;
        tmpCanvasx.clearRect(0, 0, this.svgImage.width, this.svgImage.height);
        tmpCanvasx.drawImage(this.svgImage, 0, 0);
        //image now in tmpCanvas

        //signalize progress
        if (this.progressSignal && typeof this.progressSignal === "function") {
            this.progressSignal(this.imagesDoneCount, this.imagesCount);
        }

        this.images[this.imagesDoneCount++] = this.canvas.toDataURL("image/png").replace(/^data:.+\/(.+);base64,/, "");
        if (this.imagesDoneCount < this.imagesCount) {
            this.nextFrame = setTimeout(this.renderNextFrame.bind(this), 0);
        } else {
            this.finished = true;
            this.callback();
        }
    }.bind(this);

    this.svgImage.src = "data:image/svg+xml;base64," + btoa("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n\
        <!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" + svgString);
};

/**
 * Pause rendering
 * @returns {undefined}
 */
SVGRender.prototype.pause = function () {
    this.interrupted = true;
    clearTimeout(this.nextFrame);
    this.nextFrame = null;
};

/**
 * Resumes rendering
 * @returns {undefined}
 */
SVGRender.prototype.resume = function () {
    if (this.finished || !this.interrupted) {
        //not needed
        return;
    }

    this.interrupted = false;
    if (!this.nextFrame) {
        //next frame is not scheduled
        this.nextFrame = setTimeout(this.renderNextFrame.bind(this), 0);
    }
};

<commit_msg>fill,fillOpacity,stroke,strokeOpacity added to export<commit_after>/*
 * @copyright Adam Benda, 2016
 *
 */

/* global Blob, File, SVGSVGElement, EventTarget */

/**
 * @classdesc SVG Rendering library
 * @class
 */
var SVGRender = function () {

};

/**
 * Loads one SVG image from various source.
 * Will wipe out previously loaded image
 * @param {SVGSVGElement |  Blob | File | String} svg - svg element or its source
 * @returns {undefined}
 *
 * @public
 **/
SVGRender.prototype.load = function (svg) {
    /**
     * Loading from a file is asynchronous = do not call render() untill file is loaded.
     * @type {Boolean}
     * @private
     */
    this.loaded = false;

    /**
     * Signalizes that computation was interrupted/paused
     * @type Boolean
     */
    this.interrupted = false;

    /**
     * Signalizes that computation finished sucessfully
     * @type Boolean
     */
    this.finished = false;

    if (Blob.prototype.isPrototypeOf(svg) || File.prototype.isPrototypeOf(svg)) {
//to be read with FileReader
        if (!svg.type || svg.type !== "image/svg+xml") {
            throw "Wrong file/blob type, should be image/svg+xml, is " + svg.type;
        }

        /**
         * File reader of input File / Blob
         * @type {FileReader}
         * @private
         */
        this.reader = new FileReader();
        this.reader.readAsDataURL(svg);
        this.reader.onload = function () {
            //File was loaded from input to dataURI

            //http://stackoverflow.com/questions/11335460/how-do-i-parse-a-data-url-in-node
            var svgCodeB64 = this.reader.result;
            var regex = /^data:.+\/(.+);base64,(.*)$/;
            var matches = svgCodeB64.match(regex);
            var data = matches[2];
            var svgCode = atob(data);
            this.load.bind(this)(svgCode);
            //Call load function again - but with svg source loaded from file
            return;
        }.bind(this);
        return;

    } else if (typeof svg === "string") {
        //svg xml code
        var svgCode = svg;
        //var svgCode = this.result.replace(/<?xml[^>]*/,"").replace(/<!DOCTYPE[^>]*/,"");

        //We are using document from global namespace
        //todo: cleanup afterwards
        this.svgDivElement = document.createElement('div');
        this.svgDivElement.innerHTML = svgCode;
        var svgElement = this.svgDivElement.children[0];
        document.body.appendChild(this.svgDivElement);
        this.svgDivElement.style.visibility = 'hidden';
        this.load(svgElement);
        return;
    } else if (SVGSVGElement.prototype.isPrototypeOf(svg)) {

        /**
         * SVG element present in document.
         * @type {SVGSVGElement}
         * @private
         */
        this.svgElement = svg;
        this.loaded = true;
        return;
    } else {
        throw "Unknown svg type in svg-render!";
    }
};

/**
 * Start rendering
 * @param {Object} options - contains numbers FPS, time, imagesCount and function progressSignal
 * @param {function} callback
 * @returns {undefined}
 *
 * @public
 */
SVGRender.prototype.render = function (options, callback) {
    if (!options) {
        options = {};
    }

    /**
     * Will be called after rendering is finished
     * @type {function}
     */
    this.callback = callback;
    if (!this.callback) {
        this.callback = function () {};
    }

    if (!this.loaded) {
        //todo: more elegant solution
        setTimeout(this.render.bind(this, options, callback), 100);
        return;
    }

    /**
     * Function to be called repeatedly when frame is rendered.
     * has two parameters; count(total #frames) and doneCount(#frames rendered)
     * @type {function}
     * @private
     */
    this.progressSignal = (options.progressSignal || function () {});

    /**
     * begin time (seconds)
     * @type {number}
     * @private
     */
    this.beginMS = (options.begin * 1000 || 0); //default begin time

    /**
     * Frames per Second
     * @type {number}
     * @private
     */
    this.FPS = (options.FPS || 60); //default FPS

    /**
     * total time in miliseconds
     * @type {number}
     * @private
     */
    this.timeMS = (options.time * 1000 || 1000);

    /**
     * Number of frames to render
     * @type {number}
     * @private
     */
    this.imagesCount = Math.round(this.FPS * this.timeMS / 1000);

    if (options.imagesCount && options.imagesCount !== this.imagesCount) {
        //imagesCount was given
        if (options.time && options.FPS) {
            //FPS+time were also given and the tree given parameters are contradicting
            throw "Conflicting parameters FPS,time,imagesCount";
        } else if (options.time) {
            this.FPS = this.imagesCount * 1000 / this.timeMS;
        } else if (options.FPS) {
            this.timeMS = this.imagesCount * 1000 / this.FPS;
        }
    }

    /**
     * Time in miliseconds from the animation start time.
     * @type {int}
     * @private
     */
    this.SVGtime = 0; //in miliseconds

    /**
     * Number of already rendered images
     * @type {int}
     * @public
     */
    this.imagesDoneCount = 0;

    /**
     * Array of all rendered images in png format
     * @type {base64}
     * @public
     */
    this.images = [];

    /**
     * Array of all rendered images in png format
     * @type {number}
     * @private
     */
    this.nextFrame = setTimeout(this.renderNextFrame.bind(this), 0);

    /**
     * Canvas to draw on (optional - drawing is invisible if not provided)
     * @type {HTMLCanvasElement}
     * @private
     */
    this.canvas = (options.canvas || document.createElement('canvas')); //default begin time

};

/**
 * Goes through DOM tree of given HTMLElement and removes specific tags
 * @param {HTMLElement} htmlElement
 * @param {String[]} tags
 * @return {integer} - number of elements removed
 *
 * @private
 */
SVGRender.prototype.filterOut = function (htmlElement, tags) {
    var ret = 0;
    if (tags.indexOf(htmlElement.tagName) >= 0) {
        htmlElement.parentNode.removeChild(htmlElement);
        return 1;
    } else {
        //call filterOut recursively
        for (var i = 0; i < htmlElement.children.length; i++) {
            ret += this.filterOut(htmlElement.children[i], tags);
        }
    }
    return ret;
};

/**
 * Render next frame and schedule next run of render next frame
 * @returns {undefined}
 * @private
 */
SVGRender.prototype.renderNextFrame = function () {
    if (!this.svgElement) {
        throw "Cannot render - no svgElement loaded!";
    }

    if (this.interrupted) {
        //rendering was stopped
        //(this.nextFrame timeout should have been removed already!)
        throw "this.nextFrame timeout should have been removed already!";
        return;
    }

    this.SVGtime = this.beginMS + Math.round(1000 * this.imagesDoneCount) / (this.FPS);

    this.svgElement.pauseAnimations();
    this.svgElement.setCurrentTime(this.SVGtime / 1000);
    this.svgElement.forceRedraw();

    function exportStyle(el) {
        var ret = {};
        ret.children = [];
        for (var i = 0; i < el.children.length; i++) {
            ret.children[i] = exportStyle(el.children[i]);
        }

        ret.value = {};
        var styles = window.getComputedStyle(el);
        /*
         * //TODO: identify which styles have to be copied this way.
         for (var styleType in styles) {
         ret.value[styleType] = styles[styleType];
         }
         */
        ret.value["opacity"] = styles["opacity"];
        ret.value["fill"] = styles["fill"];
        ret.value["fillOpacity"] = styles["fillOpacity"];
        ret.value["stroke"] = styles["stroke"];
        ret.value["strokeOpacity"] = styles["strokeOpacity"];
        return ret;
    }

    function importStyle(el, data) {
        for (var i = 0; i < el.children.length; i++) {
            //recursive
            importStyle(el.children[i], data.children[i]);
        }
        for (var styleType in data.value) {
            el.style[styleType] = data.value[styleType];
        }
    }

    //Do deep copy of svgElement!
    var svgElementNew = this.svgElement.cloneNode(true);
    //Copy styles
    var styles = exportStyle(this.svgElement);
    importStyle(svgElementNew, styles);

    //maybe unnescessary
    svgElementNew.pauseAnimations();
    svgElementNew.setCurrentTime(this.SVGtime / 1000);
    svgElementNew.forceRedraw();

    this.filterOut(svgElementNew, "animate");
    this.filterOut(svgElementNew, "animateTransform");
    this.filterOut(svgElementNew, "animateMotion");
    this.filterOut(svgElementNew, "animateColor");

    var svgString = new XMLSerializer().serializeToString(svgElementNew);
    this.svgImage = new Image();
    this.svgImage.onload = function () {

        tmpCanvasx = this.canvas.getContext('2d');
        this.canvas.width = this.svgImage.width;
        this.canvas.height = this.svgImage.height;
        tmpCanvasx.clearRect(0, 0, this.svgImage.width, this.svgImage.height);
        tmpCanvasx.drawImage(this.svgImage, 0, 0);
        //image now in tmpCanvas

        //signalize progress
        if (this.progressSignal && typeof this.progressSignal === "function") {
            this.progressSignal(this.imagesDoneCount, this.imagesCount);
        }

        this.images[this.imagesDoneCount++] = this.canvas.toDataURL("image/png").replace(/^data:.+\/(.+);base64,/, "");
        if (this.imagesDoneCount < this.imagesCount) {
            this.nextFrame = setTimeout(this.renderNextFrame.bind(this), 0);
        } else {
            this.finished = true;
            this.callback();
        }
    }.bind(this);

    this.svgImage.src = "data:image/svg+xml;base64," + btoa("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n\
        <!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" + svgString);
};

/**
 * Pause rendering
 * @returns {undefined}
 */
SVGRender.prototype.pause = function () {
    this.interrupted = true;
    clearTimeout(this.nextFrame);
    this.nextFrame = null;
};

/**
 * Resumes rendering
 * @returns {undefined}
 */
SVGRender.prototype.resume = function () {
    if (this.finished || !this.interrupted) {
        //not needed
        return;
    }

    this.interrupted = false;
    if (!this.nextFrame) {
        //next frame is not scheduled
        this.nextFrame = setTimeout(this.renderNextFrame.bind(this), 0);
    }
};

<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

// Provides control sap.ui.table.CreationRow.
sap.ui.define([
	"./CreationRowRenderer",
	"./Column",
	"./TableUtils",
	"sap/ui/core/Control",
	"sap/m/library",
	"sap/m/OverflowToolbar",
	"sap/m/ToolbarSpacer",
	"sap/m/Button"
], function(Renderer, Column, TableUtils, Control, MLibrary, OverflowToolbar, ToolbarSpacer, Button) {
	"use strict";

	/**
	 * Constructor for a new CreationRow.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Allows to enter data in a row shaped form, if placed inside a {@link sap.ui.table.Table}.
	 * The form elements (cells aggregation) are aligned with the columns of the table, and are created automatically based on the
	 * {@link sap.ui.table.Column#getCreationTemplate creationTemplate} aggregation of the {@link sap.ui.table.Column}.
	 *
	 * Note: This control is compatible only with the sap.m library. Do not use it together with the
	 * sap.ui.commons library.
	 * @extends sap.ui.core.Control
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @private
	 * @ui5-restricted sap.ui.mdc
	 * @alias sap.ui.table.CreationRow
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var CreationRow = Control.extend("sap.ui.table.CreationRow", /** @lends sap.ui.table.CreationRow.prototype */ {
		metadata: {
			library: "sap.ui.table",
			properties: {
				/**
				 * If set to false, the {@link #event:apply apply} event is not fired. The corresponding keyboard shortcut and the
				 * apply button of the default toolbar are disabled.
				 */
				applyEnabled: {type: "boolean", group: "Behavior", defaultValue: true}
			},
			aggregations: {
				/**
				 * The actual cells are a table-internal construct. The controls in this aggregation are the content of the cells.
				 * This aggregation is managed by the table and must not be manipulated. Only read access is allowed.
				 */
				cells: {type: "sap.ui.core.Control", multiple: true, singularName: "cell"},

				/**
				 * The toolbar that is placed below the form.
				 * If no toolbar is set, a default toolbar is created. Basic buttons and functionality are provided only in the default toolbar.
				 */
				toolbar: {type: "sap.ui.core.Toolbar", multiple: false}
			},
			events: {
				/**
				 * Fired when the corresponding keyboard shortcut or the apply button of the default toolbar are pressed.
				 */
				apply: {
					allowPreventDefault: true
				}
			}
		}
	});

	/*
	 * @see JSDoc generated by SAPUI5 control API generator
	 */
	CreationRow.prototype.setApplyEnabled = function(bEnabled) {
		this.setProperty("applyEnabled", bEnabled, true);
		this._updateDefaultToolbar();
		return this;
	};

	/**
	 * @override
	 * @inheritDoc
	 */
	CreationRow.prototype.setParent = function(oParent) {
		Control.prototype.setParent.apply(this, arguments);
		this._update();
		return this;
	};

	/**
	 * Sets the focus to the first editable form element.
	 *
	 * @return {boolean} Whether the focus was set
	 * @public
	 */
	CreationRow.prototype.resetFocus = function() {
		var oInteractiveElement = this._getFirstInteractiveElement();

		if (oInteractiveElement) {
			oInteractiveElement.focus();
			TableUtils.selectElementText(oInteractiveElement);
			return true;
		}

		return false;
	};

	/**
	 * @override
	 * @inheritDoc
	 */
	CreationRow.prototype.getFocusDomRef = function() {
		var oInteractiveElement = this._getFirstInteractiveElement();

		if (oInteractiveElement) {
			return oInteractiveElement;
		}

		return Control.prototype.getFocusDomRef.apply(this, arguments);
	};

	/**
	 * Fires the apply event and resets the focus, if the default action was not prevented.
	 *
	 * @returns {boolean} Whether the focus was set or not.
	 * @private
	 */
	CreationRow.prototype._fireApply = function() {
		var bFocusSet = false;

		if (this.fireApply()) {
			bFocusSet = this.resetFocus();
		}

		return bFocusSet;
	};

	CreationRow.prototype.onkeydown = function(oEvent) {
		// TODO: don't hardcode keycodes. maybe move #isKeyCombination of keyboard delegate to utils and use that.
		if (this.getApplyEnabled() && oEvent.ctrlKey && oEvent.keyCode === 13 /* Enter */) {
			// The FocusHandler triggers the "sapfocusleave" event in a timeout of 0ms after a blur event. To give the control in the cell
			// enough time to react to the "sapfocusleave" event (e.g. sap.m.Input - changes its value), the "apply" event is fired asynchronously.
			var oFocusedElement = document.activeElement;

			oFocusedElement.blur();

			window.setTimeout(function() {
				if (!this._fireApply()) {
					oFocusedElement.focus();
				}
			}.bind(this), 0);
		}
	};

	/**
	 * Creates a default toolbar providing basic buttons and functionality.
	 *
	 * @param {sap.ui.table.CreationRow} oCreationRow The creation row to get the settings for the toolbar creation from.
	 * @returns {sap.m.OverflowToolbar} The default toolbar.
	 */
	function createDefaultToolbar(oCreationRow) {
		return new OverflowToolbar({
			content: [
				new ToolbarSpacer(),
				new Button({
					text: TableUtils.getResourceText("TBL_CREATIONROW_APPLY"),
					type: MLibrary.ButtonType.Emphasized,
					enabled: oCreationRow.getApplyEnabled(),
					press: function() {
						oCreationRow._fireApply();
					}
				})
			],
			style: MLibrary.ToolbarStyle.Clear,
			ariaLabelledBy: [oCreationRow.getId() + "-label"]
		});
	}

	/**
	 * Gets either the toolbar or the default toolbar if none is set.
	 *
	 * @returns {sap.ui.core.Toolbar} The toolbar that should be used in the CreationRow.
	 * @private
	 */
	CreationRow.prototype._getToolbar = function() {
		var oToolbar = this.getToolbar();

		if (!oToolbar) {
			if (!this._oDefaultToolbar) {
				this._oDefaultToolbar = createDefaultToolbar(this);
				this.addDependent(this._oDefaultToolbar);
			}

			oToolbar = this._oDefaultToolbar;

			if (oToolbar.data("sap-ui-invalid")) {
				this._updateDefaultToolbar();
			}
		}

		return oToolbar;
	};

	/**
	 * Updates the default toolbar. For example, the enabled state of the apply button is updated according to the applyEnabled
	 * property value.
	 * If a toolbar is set, the default toolbar is not updated, but just marked as "invalid". It will then be updated the next time
	 * the default toolbar is returned by {@link #_getToolbar}.
	 *
	 * @private
	 */
	CreationRow.prototype._updateDefaultToolbar = function() {
		if (this.getToolbar()) {
			// No need to update the default toolbar if a custom toolbar is used.
			if (this._oDefaultToolbar) {
				this._oDefaultToolbar.data("sap-ui-invalid", true);
			}
			return;
		}

		if (!this._oDefaultToolbar) {
			return;
		}

		var oApplyButton = this._oDefaultToolbar.getContent()[1];

		oApplyButton.setEnabled(this.getApplyEnabled());
		this._oDefaultToolbar.data("sap-ui-invalid", null);
	};

	/**
	 * Gets the first interactive (editable) form element.
	 *
	 * @return {HTMLElement|null} The first interactive DOM element.
	 * @private
	 */
	CreationRow.prototype._getFirstInteractiveElement = function() {
		var aCells = this.getCells();

		for (var i = 0; i < aCells.length; i++) {
			var oCellContent = aCells[i].getDomRef();
			var $Cell = TableUtils.getCell(this._getTable(), oCellContent, true);
			var $InteractiveElements = TableUtils.getInteractiveElements($Cell);

			if ($InteractiveElements) {
				return $InteractiveElements[0];
			}
		}

		return null;
	};

	/**
	 * Gets the cell control of the corresponding column.
	 *
	 * @param {int} iColumnIndex The index of the column in the table's columns aggregation.
	 * @return {sap.ui.core.Control|null} The cell control.
	 * @private
	 */
	CreationRow.prototype._getCell = function(iColumnIndex) {
		var aCells = this.getCells();
		var oCell = aCells.filter(function(oCell) {
			return Column.ofCell(oCell).getIndex() === iColumnIndex;
		})[0];

		if (!oCell) {
			return null;
		}

		return oCell;
	};

	/**
	 * Gets the cell DOM element of the corresponding column.
	 *
	 * @param {int} iColumnIndex The index of the column in the table's columns aggregation.
	 * @return {HTMLElement|null} The cell DOM element.
	 * @private
	 */
	CreationRow.prototype._getCellDomRef = function(iColumnIndex) {
		var oCell = this._getCell(iColumnIndex);
		var oCellContent = oCell ? oCell.getDomRef() : null;
		var $Cell = TableUtils.getCell(this._getTable(), oCellContent, true);

		if (!$Cell) {
			return null;
		}

		return $Cell;
	};

	/**
	 * Focuses the first interactive element in a cell of the corresponding column.
	 * If the cell has no interactive elements, the focus will not be set.
	 *
	 * @param {int} iColumnIndex The index of the column in the table's columns aggregation.
	 * @return {boolean} Whether the focus was set.
	 * @private
	 */
	CreationRow.prototype._focusCell = function(iColumnIndex) {
		var oCellDomRef = this._getCellDomRef(iColumnIndex);
		var $InteractiveElements = TableUtils.getInteractiveElements(oCellDomRef);

		if ($InteractiveElements) {
			$InteractiveElements[0].focus();
			TableUtils.selectElementText($InteractiveElements[0]);
			return true;
		}

		return false;
	};

	/**
	 * The row takes over keyboard handling within the table.
	 *
	 * @param {jQuery.Event} [oEvent] The event object, if the keyboard handling takeover is triggered by an event.
	 * @return {boolean} Whether the keyboard handling was taken over.
	 * @private
	 */
	CreationRow.prototype._takeOverKeyboardHandling = function(oEvent) {
		var oTable = this._getTable();
		var oTableDomRef = oTable ? oTable.getDomRef() : null;

		if (!oTableDomRef || !oTableDomRef.contains(document.activeElement)) {
			// Keyboard handling will not be taken over if the table is not rendered or the focus is not inside the table.
			return false;
		}

		var oCell = TableUtils.getCell(this._getTable(), document.activeElement);
		var oCellInfo = TableUtils.getCellInfo(oCell);
		var bFocusSet = false;

		if (oCellInfo.columnIndex != null && oCellInfo.columnIndex >= 0) {
			// If the currently focused element is a table cell with a column index information, the keyboard handling will only be taken over if the
			// cell of the corresponding column in this row contains an interactive element.
			bFocusSet = this._focusCell(oCellInfo.columnIndex);
		} else {
			bFocusSet = this.resetFocus();
		}

		if (bFocusSet && oEvent) {
			oEvent.preventDefault(); // Prevent positioning the cursor. The text should be selected instead.
		}

		return bFocusSet; // The keyboard handling is only taken over if the focus was set into the CreationRow.
	};

	/**
	 * Updates the row (e.g. the cells) based on the configuration of the table this row is inside.
	 *
	 * @private
	 */
	CreationRow.prototype._update = function() {
		var oTable = this._getTable();

		if (!oTable) {
			this.removeAllCells();
			return;
		}

		var aColumns = oTable.getColumns();

		this.removeAllCells();

		for (var i = 0, l = aColumns.length; i < l; i++) {
			if (aColumns[i].getVisible()) {
				this.addCell(aColumns[i].getTemplateClone(i, "Creation"));
			}
		}
	};

	/**
	 * Gets the table this row is inside.
	 *
	 * @return {sap.ui.table.Table|null} The instance of the table or null, if this row is not inside a table.
	 * @private
	 */
	CreationRow.prototype._getTable = function() {
		var oParent = this.getParent();
		return TableUtils.isA(oParent, "sap.ui.table.Table") ? oParent : null;
	};

	return CreationRow;
});<commit_msg>[INTERNAL] GridTable.CreationRow: Button is no longer emphasized<commit_after>/*!
 * ${copyright}
 */

// Provides control sap.ui.table.CreationRow.
sap.ui.define([
	"./CreationRowRenderer",
	"./Column",
	"./TableUtils",
	"sap/ui/core/Control",
	"sap/m/library",
	"sap/m/OverflowToolbar",
	"sap/m/ToolbarSpacer",
	"sap/m/Button"
], function(Renderer, Column, TableUtils, Control, MLibrary, OverflowToolbar, ToolbarSpacer, Button) {
	"use strict";

	/**
	 * Constructor for a new CreationRow.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Allows to enter data in a row shaped form, if placed inside a {@link sap.ui.table.Table}.
	 * The form elements (cells aggregation) are aligned with the columns of the table, and are created automatically based on the
	 * {@link sap.ui.table.Column#getCreationTemplate creationTemplate} aggregation of the {@link sap.ui.table.Column}.
	 *
	 * Note: This control is compatible only with the sap.m library. Do not use it together with the
	 * sap.ui.commons library.
	 * @extends sap.ui.core.Control
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @private
	 * @ui5-restricted sap.ui.mdc
	 * @alias sap.ui.table.CreationRow
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var CreationRow = Control.extend("sap.ui.table.CreationRow", /** @lends sap.ui.table.CreationRow.prototype */ {
		metadata: {
			library: "sap.ui.table",
			properties: {
				/**
				 * If set to false, the {@link #event:apply apply} event is not fired. The corresponding keyboard shortcut and the
				 * apply button of the default toolbar are disabled.
				 */
				applyEnabled: {type: "boolean", group: "Behavior", defaultValue: true}
			},
			aggregations: {
				/**
				 * The actual cells are a table-internal construct. The controls in this aggregation are the content of the cells.
				 * This aggregation is managed by the table and must not be manipulated. Only read access is allowed.
				 */
				cells: {type: "sap.ui.core.Control", multiple: true, singularName: "cell"},

				/**
				 * The toolbar that is placed below the form.
				 * If no toolbar is set, a default toolbar is created. Basic buttons and functionality are provided only in the default toolbar.
				 */
				toolbar: {type: "sap.ui.core.Toolbar", multiple: false}
			},
			events: {
				/**
				 * Fired when the corresponding keyboard shortcut or the apply button of the default toolbar are pressed.
				 */
				apply: {
					allowPreventDefault: true
				}
			}
		}
	});

	/*
	 * @see JSDoc generated by SAPUI5 control API generator
	 */
	CreationRow.prototype.setApplyEnabled = function(bEnabled) {
		this.setProperty("applyEnabled", bEnabled, true);
		this._updateDefaultToolbar();
		return this;
	};

	/**
	 * @override
	 * @inheritDoc
	 */
	CreationRow.prototype.setParent = function(oParent) {
		Control.prototype.setParent.apply(this, arguments);
		this._update();
		return this;
	};

	/**
	 * Sets the focus to the first editable form element.
	 *
	 * @return {boolean} Whether the focus was set
	 * @public
	 */
	CreationRow.prototype.resetFocus = function() {
		var oInteractiveElement = this._getFirstInteractiveElement();

		if (oInteractiveElement) {
			oInteractiveElement.focus();
			TableUtils.selectElementText(oInteractiveElement);
			return true;
		}

		return false;
	};

	/**
	 * @override
	 * @inheritDoc
	 */
	CreationRow.prototype.getFocusDomRef = function() {
		var oInteractiveElement = this._getFirstInteractiveElement();

		if (oInteractiveElement) {
			return oInteractiveElement;
		}

		return Control.prototype.getFocusDomRef.apply(this, arguments);
	};

	/**
	 * Fires the apply event and resets the focus, if the default action was not prevented.
	 *
	 * @returns {boolean} Whether the focus was set or not.
	 * @private
	 */
	CreationRow.prototype._fireApply = function() {
		var bFocusSet = false;

		if (this.fireApply()) {
			bFocusSet = this.resetFocus();
		}

		return bFocusSet;
	};

	CreationRow.prototype.onkeydown = function(oEvent) {
		// TODO: don't hardcode keycodes. maybe move #isKeyCombination of keyboard delegate to utils and use that.
		if (this.getApplyEnabled() &&  (oEvent.metaKey || oEvent.ctrlKey) && oEvent.keyCode === 13 /* Enter */) {
			// The FocusHandler triggers the "sapfocusleave" event in a timeout of 0ms after a blur event. To give the control in the cell
			// enough time to react to the "sapfocusleave" event (e.g. sap.m.Input - changes its value), the "apply" event is fired asynchronously.
			var oFocusedElement = document.activeElement;

			oFocusedElement.blur();

			window.setTimeout(function() {
				if (!this._fireApply()) {
					oFocusedElement.focus();
				}
			}.bind(this), 0);
		}
	};

	/**
	 * Creates a default toolbar providing basic buttons and functionality.
	 *
	 * @param {sap.ui.table.CreationRow} oCreationRow The creation row to get the settings for the toolbar creation from.
	 * @returns {sap.m.OverflowToolbar} The default toolbar.
	 */
	function createDefaultToolbar(oCreationRow) {
		return new OverflowToolbar({
			content: [
				new ToolbarSpacer(),
				new Button({
					text: TableUtils.getResourceText("TBL_CREATIONROW_APPLY"),
					enabled: oCreationRow.getApplyEnabled(),
					press: function() {
						oCreationRow._fireApply();
					}
				})
			],
			style: MLibrary.ToolbarStyle.Clear,
			ariaLabelledBy: [oCreationRow.getId() + "-label"]
		});
	}

	/**
	 * Gets either the toolbar or the default toolbar if none is set.
	 *
	 * @returns {sap.ui.core.Toolbar} The toolbar that should be used in the CreationRow.
	 * @private
	 */
	CreationRow.prototype._getToolbar = function() {
		var oToolbar = this.getToolbar();

		if (!oToolbar) {
			if (!this._oDefaultToolbar) {
				this._oDefaultToolbar = createDefaultToolbar(this);
				this.addDependent(this._oDefaultToolbar);
			}

			oToolbar = this._oDefaultToolbar;

			if (oToolbar.data("sap-ui-invalid")) {
				this._updateDefaultToolbar();
			}
		}

		return oToolbar;
	};

	/**
	 * Updates the default toolbar. For example, the enabled state of the apply button is updated according to the applyEnabled
	 * property value.
	 * If a toolbar is set, the default toolbar is not updated, but just marked as "invalid". It will then be updated the next time
	 * the default toolbar is returned by {@link #_getToolbar}.
	 *
	 * @private
	 */
	CreationRow.prototype._updateDefaultToolbar = function() {
		if (this.getToolbar()) {
			// No need to update the default toolbar if a custom toolbar is used.
			if (this._oDefaultToolbar) {
				this._oDefaultToolbar.data("sap-ui-invalid", true);
			}
			return;
		}

		if (!this._oDefaultToolbar) {
			return;
		}

		var oApplyButton = this._oDefaultToolbar.getContent()[1];

		oApplyButton.setEnabled(this.getApplyEnabled());
		this._oDefaultToolbar.data("sap-ui-invalid", null);
	};

	/**
	 * Gets the first interactive (editable) form element.
	 *
	 * @return {HTMLElement|null} The first interactive DOM element.
	 * @private
	 */
	CreationRow.prototype._getFirstInteractiveElement = function() {
		var aCells = this.getCells();

		for (var i = 0; i < aCells.length; i++) {
			var oCellContent = aCells[i].getDomRef();
			var $Cell = TableUtils.getCell(this._getTable(), oCellContent, true);
			var $InteractiveElements = TableUtils.getInteractiveElements($Cell);

			if ($InteractiveElements) {
				return $InteractiveElements[0];
			}
		}

		return null;
	};

	/**
	 * Gets the cell control of the corresponding column.
	 *
	 * @param {int} iColumnIndex The index of the column in the table's columns aggregation.
	 * @return {sap.ui.core.Control|null} The cell control.
	 * @private
	 */
	CreationRow.prototype._getCell = function(iColumnIndex) {
		var aCells = this.getCells();
		var oCell = aCells.filter(function(oCell) {
			return Column.ofCell(oCell).getIndex() === iColumnIndex;
		})[0];

		if (!oCell) {
			return null;
		}

		return oCell;
	};

	/**
	 * Gets the cell DOM element of the corresponding column.
	 *
	 * @param {int} iColumnIndex The index of the column in the table's columns aggregation.
	 * @return {HTMLElement|null} The cell DOM element.
	 * @private
	 */
	CreationRow.prototype._getCellDomRef = function(iColumnIndex) {
		var oCell = this._getCell(iColumnIndex);
		var oCellContent = oCell ? oCell.getDomRef() : null;
		var $Cell = TableUtils.getCell(this._getTable(), oCellContent, true);

		if (!$Cell) {
			return null;
		}

		return $Cell;
	};

	/**
	 * Focuses the first interactive element in a cell of the corresponding column.
	 * If the cell has no interactive elements, the focus will not be set.
	 *
	 * @param {int} iColumnIndex The index of the column in the table's columns aggregation.
	 * @return {boolean} Whether the focus was set.
	 * @private
	 */
	CreationRow.prototype._focusCell = function(iColumnIndex) {
		var oCellDomRef = this._getCellDomRef(iColumnIndex);
		var $InteractiveElements = TableUtils.getInteractiveElements(oCellDomRef);

		if ($InteractiveElements) {
			$InteractiveElements[0].focus();
			TableUtils.selectElementText($InteractiveElements[0]);
			return true;
		}

		return false;
	};

	/**
	 * The row takes over keyboard handling within the table.
	 *
	 * @param {jQuery.Event} [oEvent] The event object, if the keyboard handling takeover is triggered by an event.
	 * @return {boolean} Whether the keyboard handling was taken over.
	 * @private
	 */
	CreationRow.prototype._takeOverKeyboardHandling = function(oEvent) {
		var oTable = this._getTable();
		var oTableDomRef = oTable ? oTable.getDomRef() : null;

		if (!oTableDomRef || !oTableDomRef.contains(document.activeElement)) {
			// Keyboard handling will not be taken over if the table is not rendered or the focus is not inside the table.
			return false;
		}

		var oCell = TableUtils.getCell(this._getTable(), document.activeElement);
		var oCellInfo = TableUtils.getCellInfo(oCell);
		var bFocusSet = false;

		if (oCellInfo.columnIndex != null && oCellInfo.columnIndex >= 0) {
			// If the currently focused element is a table cell with a column index information, the keyboard handling will only be taken over if the
			// cell of the corresponding column in this row contains an interactive element.
			bFocusSet = this._focusCell(oCellInfo.columnIndex);
		} else {
			bFocusSet = this.resetFocus();
		}

		if (bFocusSet && oEvent) {
			oEvent.preventDefault(); // Prevent positioning the cursor. The text should be selected instead.
		}

		return bFocusSet; // The keyboard handling is only taken over if the focus was set into the CreationRow.
	};

	/**
	 * Updates the row (e.g. the cells) based on the configuration of the table this row is inside.
	 *
	 * @private
	 */
	CreationRow.prototype._update = function() {
		var oTable = this._getTable();

		if (!oTable) {
			this.removeAllCells();
			return;
		}

		var aColumns = oTable.getColumns();

		this.removeAllCells();

		for (var i = 0, l = aColumns.length; i < l; i++) {
			if (aColumns[i].getVisible()) {
				this.addCell(aColumns[i].getTemplateClone(i, "Creation"));
			}
		}
	};

	/**
	 * Gets the table this row is inside.
	 *
	 * @return {sap.ui.table.Table|null} The instance of the table or null, if this row is not inside a table.
	 * @private
	 */
	CreationRow.prototype._getTable = function() {
		var oParent = this.getParent();
		return TableUtils.isA(oParent, "sap.ui.table.Table") ? oParent : null;
	};

	return CreationRow;
});<|endoftext|>


<commit_before>// mobile javascript
var data;

$(document).ready(function() {

    var course_data = null;
    var book_data = null;
    // This is to prevent multiple events on load from making
    // multiple web service calls.  This is required due to the
    // fix for MUWM-368
    var loaded_url = null;

    History.Adapter.bind(window,'statechange',function(){
        var history_state = History.getState();
        var data = history_state.data;
        var state = data.state;

        var state_url = history_state.url;
        // This is the check of the same url, to prevent
        // duplicate web service requests on page load.
        if (state_url === loaded_url) {
            return;
        }

        $("#landing").removeClass("active");
        $("#nav_course_list").removeClass("active");
        $("#nav_visual_schedule").removeClass("active");
        $("#nav_finabala").removeClass("active");

        // Page titles are defined in templates/index.html
        if (state === undefined) {
            show_page_from_url();
            return;
        }
        else if (state === "landing") {
            Landing.render(data.term, data.course_index);
            $("#landing").addClass("active")
            document.title = window.page_titles["landing"];
        }
        else if (state === "course_list") {
            // Figure out what to do from the url
            CourseList.show_list(data.term, data.course_index);
            $("#nav_course_list").addClass("active");
            document.title = window.page_titles["course_list"];
        }
        else if (state === "instructor") {
            Instructor.show_instructor(data.term, data.instructor);
            document.title = window.page_titles["instructor"];
        }
        else if (state === "future_quarters") {
            FutureQuarter.render(data.term);
            document.title = window.page_titles["future_quarters"];
        }
        else if (state === "textbooks") {
            TextBooks.show_books(data.term, data.textbook);
            document.title = window.page_titles["textbooks"];
        }
        else if (state === "finabala") {
            HfsAccounts.show_balances();
            $("#nav_finabala").addClass("active");
            document.title = window.page_titles["finabala"];
        }
        else if (state === "visual") {
            VisualSchedule.show_visual_schedule(data.term, data.course_index);
            $("#nav_visual_schedule").addClass("active");
            document.title = window.page_titles["visual"];
        }
        else if (state === "final_exams") {
            FinalExams.show_finals(data.term, data.course_index);
            document.title = window.page_titles["finals"];
        }
        else if (state === "grades") {
            Grades.show_grades(data.term);
            document.title = window.page_titles["grades"];
        }
        else if (state === "weekly") {
            Weekly.show_current_week(data);
            document.title = window.page_titles["weekly"];
        }
        else if (state === "libraries") {
            Libraries.show_card();
            document.title = window.page_titles["libraries"];
        }
        else if (state === "notices") {
            Notices.show_notices();
            document.title = window.page_titles["notices"];
        }
        else if (state === "category_page") {
            Category.show_category_page(data.category, data.topic);
            document.title = window.page_titles["category_page"];
        }

        loaded_url = state_url;
    });

    function show_page_from_url() {
        var path = window.location.pathname;

        var hist = window.History;

        if (path === "/mobile/") {
            hist.replaceState({
                state: "landing",
            },  "", "/mobile/landing/");
            return;
        }
        else if (path.match(/^\/mobile\/[0-9]{4},[a-z]+[,-abterm]*$/)) {
            var matches = path.match(/^\/mobile\/([0-9]{4},[a-z]+[,-abterm]*)$/);
            var state = "course_list";
            var term = matches[1];
            hist.replaceState({
                state: "course_list",
                term: matches[1]
            }, "", "/mobile/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/visual\/[^\/]+\/[0-9]+$/)) {
            var matches = path.match(/^\/mobile\/visual\/([^\/]+)\/([0-9]+)/);
            hist.replaceState({
                state: "visual",
                term: matches[1],
                course_index: matches[2]
            },  "", "/mobile/visual/"+matches[1]+"/"+matches[2]);
        }
        else if (path.match(/^\/mobile\/visual\/[0-9]{4},[a-z]+[,-abterm]*$/)) {
            var matches = path.match(/^\/mobile\/visual\/([0-9]{4},[a-z]+[,-abterm]*)$/);
            hist.replaceState({
                state: "visual",
                term: matches[1]
            },  "", "/mobile/visual/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/visual\/[0-9]+$/)) {
            var matches = path.match(/^\/mobile\/visual\/([0-9]+)/);
            hist.replaceState({
                state: "visual",
                course_index: matches[1]
            },  "", "/mobile/visual/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/visual\/?/)) {
            hist.replaceState({
                state: "visual"
            },  "", "/mobile/visual");
        }
        else if (path.match(/^\/mobile\/landing/)) {
            hist.replaceState({
                state: "landing",
            },  "", "/mobile/landing/");
        }
        else if (path.match(/^\/mobile\/textbooks\/[0-9]{4}[-,a-z]+\/[%A-Z0-9]+$/)) {
            var matches = path.match(/^\/mobile\/textbooks\/([0-9]{4}[-,a-z]+)\/([%A-Z0-9]+)$/);
            hist.replaceState({
                state: "textbooks",
                term: matches[1],
                textbook: matches[2]
            },  "", path);
        }
        else if (path.match(/^\/mobile\/textbooks\/[0-9]{4}[-,a-z]+\/?$/i)) {
             var matches = path.match(/^\/mobile\/textbooks\/([0-9]{4}[-,a-z]+)\/?$/i);
             hist.replaceState({
                 state: "textbooks",
                 term: matches[1]
             },  "", path);
        }
        else if (path.match(/^\/mobile\/textbooks\/?/)) {
            hist.replaceState({
                state: "textbooks",
                term: "current"
            },  "", path);
        }
        else if (path === "/mobile/finabala") {
            hist.replaceState({
                state: "finabala"
            },  "", "/mobile/finabala");
        }
        else if (path.match(/^\/mobile\/future_quarters\/[0-9]{4},[-,a-z]+/)) {
            var matches = path.match(/^\/mobile\/future_quarters\/([0-9]{4},[-,a-z]+)/);
            hist.replaceState({
                state: "future_quarters",
                term: matches[1],
            },  "", path);
        }
        else if (path === "/mobile/final_exams") {
            hist.replaceState({
                state: "final_exams"
            },  "", "/mobile/final_exams");
        }
        else if (path.match("/mobile/final_exams/[0-9]+$")) {
            var matches = path.match(/^\/mobile\/final_exams\/([0-9]+)/);
            hist.replaceState({
                state: "final_exams",
                course_index: matches[1]
            },  "", "/mobile/final_exams/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/final_exams\/[^\/]+\/[0-9]+/)) {
            var matches = path.match(/^\/mobile\/final_exams\/([^\/]+)\/([0-9]+)/);
            hist.replaceState({
                state: "final_exams",
                term: matches[1],
                course_index: matches[2]
            },  "", "/mobile/final_exams/"+matches[1]+"/"+matches[2]);
        }
        else if (path.match(/^\/mobile\/final_exams\/[^\/]+/)) {
            var matches = path.match(/^\/mobile\/final_exams\/([^\/]+)/);
            hist.replaceState({
                state: "final_exams",
                term: matches[1],
            },  "", "/mobile/final_exams/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/instructor\/[A-Z0-9]+/)) {
            var matches = path.match(/^\/mobile\/instructor\/([A-Z0-9]+)/);
            hist.pushState({
                state: "instructor",
                instructor: matches[1]
            },  "", "/mobile/instructor/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/grades/)) {
            var matches = path.match(/^\/mobile\/grades\/([0-9,a-z]+)/);
            hist.replaceState({
                state: "grades",
                term: (matches ? matches[1] : "")
            },  "", "/mobile/grades/" + (matches
                                                 ? matches[1]
                                                 : ""));
        }
        else if (path.match(/^\/mobile\/weekly/)) {
            hist.replaceState({
                state: "weekly",
            },  "", "/mobile/weekly/");
        }
        else if (path.match(/^\/mobile\/libraries/)) {
            hist.replaceState({
                state: "libraries",
            },  "", "/mobile/libraries/");
        }
        else if (path.match(/^\/mobile\/notices/)) {
            hist.replaceState({
                state: "notices",
            },  "", "/mobile/notices/");
        }
        else if (path.match(/^\/mobile\/resource\/([a-z]+)/)) {
            var matches = path.match(/^\/mobile\/resource\/([a-z]+)\/?([a-z]+)?/),
                category = (matches ? matches[1] : ""),
                topic = (matches ? matches[2] : undefined);
            var slug = category;
            if (topic !== undefined) {
                slug += "/" + topic;
            }

            hist.replaceState({
                state: "category_page",
                category: category,
                topic: topic
            },  "", "/mobile/resource/" + slug );
        }
        else {
            // Just fall back to the course list?
            hist.replaceState({
                state: "course_list",
                }, "", "/mobile"
            );
            //CourseList.show_list();
        }

        History.Adapter.trigger(window, 'statechange');
    }

    var test_status = window.location.hash.indexOf('alert') === -1 ? 'false' : 'true';
    var test_alert_color;
    if (test_status) {
        test_alert_color = window.location.hash;
    }

    show_page_from_url();

    if (test_alert_color) {
        window.location.hash = test_alert_color;
    }

    $(".finabala").bind("click", function(ev) {
        $("#myuw_nav").collapse('hide');
        var hist = window.History;
        hist.pushState({
            state: "finabala",
        },  "", "/mobile/finabala");

        return false;
    });

    $(".logout_link").bind("click", function(ev) {
        $("#logout_form").submit();
        return false;
    });

    $("#nav_course_list").bind("click", function(ev) {
        WSData.log_interaction("nav_menu_course_list");
    });

    $("#nav_visual_schedule").bind("click", function(ev) {
        WSData.log_interaction("nav_menu_visual_schedule");
    });

    // handle clicking on resources
    $("#categories_link").bind("click", function(ev) {
        ev.preventDefault();
        $('html, body').animate({
            scrollTop: $("#categories").offset().top
        }, "fast");
        return false;
    });

});

var showLoading = function() {
    var source = $("#loading_header").html();
    var template = Handlebars.compile(source);
    $("#page-header").html(template());

    source = $("#loading_body").html();
    template = Handlebars.compile(source);
    $("#main-content").html(template());
};

var showError = function() {
    var source = $("#error_header").html();
    var template = Handlebars.compile(source);
    $("#page-header").html(template());

    source = $("#error_body").html();
    template = Handlebars.compile(source);
    $("#main-content").html(template());
};

// The strings from our web service only work w/ the native Date parsing on chrome :(
var date_from_string = function(date_string) {
    if (!date_string) {
        return;
    }
    var matches = date_string.match(/([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2})/);
    if (!matches) {
        return;
    }
    var date_object = new Date(matches[1], (parseInt(matches[2], 10) - 1), parseInt(matches[3], 10), parseInt(matches[4], 10), parseInt(matches[5], 10));

    return date_object;
};

var titilizeTerm = function(term) {
    //Takes a term string (Eg 2032,summer,b-term) and
    //returns a title (Eg Summer 2032 B-term)
    var pieces = term.split(",");
    var string = capitalizeString(pieces[1]) + " " + pieces[0];
    if (pieces.length > 2) {
        string += " " + capitalizeString(pieces[2]);
    }
    return string

}

var capitalizeString = function(string) {
    if (string.match(/^[ab]-term$/gi)) {
        value = string.split("-");
        return value[0].toUpperCase() + "-" + value[1].charAt(0).toUpperCase() + value[1].slice(1);
    }
    return string.charAt(0).toUpperCase() + string.slice(1);
}

var isScrolledIntoView = function(elem) {
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
<commit_msg>Broader redirect for /mobile<commit_after>// mobile javascript
var data;

$(document).ready(function() {

    var course_data = null;
    var book_data = null;
    // This is to prevent multiple events on load from making
    // multiple web service calls.  This is required due to the
    // fix for MUWM-368
    var loaded_url = null;

    History.Adapter.bind(window,'statechange',function(){
        var history_state = History.getState();
        var data = history_state.data;
        var state = data.state;

        var state_url = history_state.url;
        // This is the check of the same url, to prevent
        // duplicate web service requests on page load.
        if (state_url === loaded_url) {
            return;
        }

        $("#landing").removeClass("active");
        $("#nav_course_list").removeClass("active");
        $("#nav_visual_schedule").removeClass("active");
        $("#nav_finabala").removeClass("active");

        // Page titles are defined in templates/index.html
        if (state === undefined) {
            show_page_from_url();
            return;
        }
        else if (state === "landing") {
            Landing.render(data.term, data.course_index);
            $("#landing").addClass("active")
            document.title = window.page_titles["landing"];
        }
        else if (state === "course_list") {
            // Figure out what to do from the url
            CourseList.show_list(data.term, data.course_index);
            $("#nav_course_list").addClass("active");
            document.title = window.page_titles["course_list"];
        }
        else if (state === "instructor") {
            Instructor.show_instructor(data.term, data.instructor);
            document.title = window.page_titles["instructor"];
        }
        else if (state === "future_quarters") {
            FutureQuarter.render(data.term);
            document.title = window.page_titles["future_quarters"];
        }
        else if (state === "textbooks") {
            TextBooks.show_books(data.term, data.textbook);
            document.title = window.page_titles["textbooks"];
        }
        else if (state === "finabala") {
            HfsAccounts.show_balances();
            $("#nav_finabala").addClass("active");
            document.title = window.page_titles["finabala"];
        }
        else if (state === "visual") {
            VisualSchedule.show_visual_schedule(data.term, data.course_index);
            $("#nav_visual_schedule").addClass("active");
            document.title = window.page_titles["visual"];
        }
        else if (state === "final_exams") {
            FinalExams.show_finals(data.term, data.course_index);
            document.title = window.page_titles["finals"];
        }
        else if (state === "grades") {
            Grades.show_grades(data.term);
            document.title = window.page_titles["grades"];
        }
        else if (state === "weekly") {
            Weekly.show_current_week(data);
            document.title = window.page_titles["weekly"];
        }
        else if (state === "libraries") {
            Libraries.show_card();
            document.title = window.page_titles["libraries"];
        }
        else if (state === "notices") {
            Notices.show_notices();
            document.title = window.page_titles["notices"];
        }
        else if (state === "category_page") {
            Category.show_category_page(data.category, data.topic);
            document.title = window.page_titles["category_page"];
        }

        loaded_url = state_url;
    });

    function show_page_from_url() {
        var path = window.location.pathname;

        var hist = window.History;

        if (path === "/mobile/" || path === "/mobile") {
            hist.replaceState({
                state: "landing",
            },  "", "/mobile/landing/");
            return;
        }
        else if (path.match(/^\/mobile\/[0-9]{4},[a-z]+[,-abterm]*$/)) {
            var matches = path.match(/^\/mobile\/([0-9]{4},[a-z]+[,-abterm]*)$/);
            var state = "course_list";
            var term = matches[1];
            hist.replaceState({
                state: "course_list",
                term: matches[1]
            }, "", "/mobile/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/visual\/[^\/]+\/[0-9]+$/)) {
            var matches = path.match(/^\/mobile\/visual\/([^\/]+)\/([0-9]+)/);
            hist.replaceState({
                state: "visual",
                term: matches[1],
                course_index: matches[2]
            },  "", "/mobile/visual/"+matches[1]+"/"+matches[2]);
        }
        else if (path.match(/^\/mobile\/visual\/[0-9]{4},[a-z]+[,-abterm]*$/)) {
            var matches = path.match(/^\/mobile\/visual\/([0-9]{4},[a-z]+[,-abterm]*)$/);
            hist.replaceState({
                state: "visual",
                term: matches[1]
            },  "", "/mobile/visual/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/visual\/[0-9]+$/)) {
            var matches = path.match(/^\/mobile\/visual\/([0-9]+)/);
            hist.replaceState({
                state: "visual",
                course_index: matches[1]
            },  "", "/mobile/visual/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/visual\/?/)) {
            hist.replaceState({
                state: "visual"
            },  "", "/mobile/visual");
        }
        else if (path.match(/^\/mobile\/landing/)) {
            hist.replaceState({
                state: "landing",
            },  "", "/mobile/landing/");
        }
        else if (path.match(/^\/mobile\/textbooks\/[0-9]{4}[-,a-z]+\/[%A-Z0-9]+$/)) {
            var matches = path.match(/^\/mobile\/textbooks\/([0-9]{4}[-,a-z]+)\/([%A-Z0-9]+)$/);
            hist.replaceState({
                state: "textbooks",
                term: matches[1],
                textbook: matches[2]
            },  "", path);
        }
        else if (path.match(/^\/mobile\/textbooks\/[0-9]{4}[-,a-z]+\/?$/i)) {
             var matches = path.match(/^\/mobile\/textbooks\/([0-9]{4}[-,a-z]+)\/?$/i);
             hist.replaceState({
                 state: "textbooks",
                 term: matches[1]
             },  "", path);
        }
        else if (path.match(/^\/mobile\/textbooks\/?/)) {
            hist.replaceState({
                state: "textbooks",
                term: "current"
            },  "", path);
        }
        else if (path === "/mobile/finabala") {
            hist.replaceState({
                state: "finabala"
            },  "", "/mobile/finabala");
        }
        else if (path.match(/^\/mobile\/future_quarters\/[0-9]{4},[-,a-z]+/)) {
            var matches = path.match(/^\/mobile\/future_quarters\/([0-9]{4},[-,a-z]+)/);
            hist.replaceState({
                state: "future_quarters",
                term: matches[1],
            },  "", path);
        }
        else if (path === "/mobile/final_exams") {
            hist.replaceState({
                state: "final_exams"
            },  "", "/mobile/final_exams");
        }
        else if (path.match("/mobile/final_exams/[0-9]+$")) {
            var matches = path.match(/^\/mobile\/final_exams\/([0-9]+)/);
            hist.replaceState({
                state: "final_exams",
                course_index: matches[1]
            },  "", "/mobile/final_exams/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/final_exams\/[^\/]+\/[0-9]+/)) {
            var matches = path.match(/^\/mobile\/final_exams\/([^\/]+)\/([0-9]+)/);
            hist.replaceState({
                state: "final_exams",
                term: matches[1],
                course_index: matches[2]
            },  "", "/mobile/final_exams/"+matches[1]+"/"+matches[2]);
        }
        else if (path.match(/^\/mobile\/final_exams\/[^\/]+/)) {
            var matches = path.match(/^\/mobile\/final_exams\/([^\/]+)/);
            hist.replaceState({
                state: "final_exams",
                term: matches[1],
            },  "", "/mobile/final_exams/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/instructor\/[A-Z0-9]+/)) {
            var matches = path.match(/^\/mobile\/instructor\/([A-Z0-9]+)/);
            hist.pushState({
                state: "instructor",
                instructor: matches[1]
            },  "", "/mobile/instructor/"+matches[1]);
        }
        else if (path.match(/^\/mobile\/grades/)) {
            var matches = path.match(/^\/mobile\/grades\/([0-9,a-z]+)/);
            hist.replaceState({
                state: "grades",
                term: (matches ? matches[1] : "")
            },  "", "/mobile/grades/" + (matches
                                                 ? matches[1]
                                                 : ""));
        }
        else if (path.match(/^\/mobile\/weekly/)) {
            hist.replaceState({
                state: "weekly",
            },  "", "/mobile/weekly/");
        }
        else if (path.match(/^\/mobile\/libraries/)) {
            hist.replaceState({
                state: "libraries",
            },  "", "/mobile/libraries/");
        }
        else if (path.match(/^\/mobile\/notices/)) {
            hist.replaceState({
                state: "notices",
            },  "", "/mobile/notices/");
        }
        else if (path.match(/^\/mobile\/resource\/([a-z]+)/)) {
            var matches = path.match(/^\/mobile\/resource\/([a-z]+)\/?([a-z]+)?/),
                category = (matches ? matches[1] : ""),
                topic = (matches ? matches[2] : undefined);
            var slug = category;
            if (topic !== undefined) {
                slug += "/" + topic;
            }

            hist.replaceState({
                state: "category_page",
                category: category,
                topic: topic
            },  "", "/mobile/resource/" + slug );
        }
        else {
            // Just fall back to the course list?
            hist.replaceState({
                state: "course_list",
                }, "", "/mobile"
            );
            //CourseList.show_list();
        }

        History.Adapter.trigger(window, 'statechange');
    }

    var test_status = window.location.hash.indexOf('alert') === -1 ? 'false' : 'true';
    var test_alert_color;
    if (test_status) {
        test_alert_color = window.location.hash;
    }

    show_page_from_url();

    if (test_alert_color) {
        window.location.hash = test_alert_color;
    }

    $(".finabala").bind("click", function(ev) {
        $("#myuw_nav").collapse('hide');
        var hist = window.History;
        hist.pushState({
            state: "finabala",
        },  "", "/mobile/finabala");

        return false;
    });

    $(".logout_link").bind("click", function(ev) {
        $("#logout_form").submit();
        return false;
    });

    $("#nav_course_list").bind("click", function(ev) {
        WSData.log_interaction("nav_menu_course_list");
    });

    $("#nav_visual_schedule").bind("click", function(ev) {
        WSData.log_interaction("nav_menu_visual_schedule");
    });

    // handle clicking on resources
    $("#categories_link").bind("click", function(ev) {
        ev.preventDefault();
        $('html, body').animate({
            scrollTop: $("#categories").offset().top
        }, "fast");
        return false;
    });

});

var showLoading = function() {
    var source = $("#loading_header").html();
    var template = Handlebars.compile(source);
    $("#page-header").html(template());

    source = $("#loading_body").html();
    template = Handlebars.compile(source);
    $("#main-content").html(template());
};

var showError = function() {
    var source = $("#error_header").html();
    var template = Handlebars.compile(source);
    $("#page-header").html(template());

    source = $("#error_body").html();
    template = Handlebars.compile(source);
    $("#main-content").html(template());
};

// The strings from our web service only work w/ the native Date parsing on chrome :(
var date_from_string = function(date_string) {
    if (!date_string) {
        return;
    }
    var matches = date_string.match(/([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2})/);
    if (!matches) {
        return;
    }
    var date_object = new Date(matches[1], (parseInt(matches[2], 10) - 1), parseInt(matches[3], 10), parseInt(matches[4], 10), parseInt(matches[5], 10));

    return date_object;
};

var titilizeTerm = function(term) {
    //Takes a term string (Eg 2032,summer,b-term) and
    //returns a title (Eg Summer 2032 B-term)
    var pieces = term.split(",");
    var string = capitalizeString(pieces[1]) + " " + pieces[0];
    if (pieces.length > 2) {
        string += " " + capitalizeString(pieces[2]);
    }
    return string

}

var capitalizeString = function(string) {
    if (string.match(/^[ab]-term$/gi)) {
        value = string.split("-");
        return value[0].toUpperCase() + "-" + value[1].charAt(0).toUpperCase() + value[1].slice(1);
    }
    return string.charAt(0).toUpperCase() + string.slice(1);
}

var isScrolledIntoView = function(elem) {
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
<|endoftext|>


<commit_before>var stripe = require('stripe')(process.env.StripeTestSecretKey);

stripe.charges.create({
  amount: 400,
  currency: "gbp",
  description: "Charge for test@example.com"
}, function(err, charge) {
  console.log(charge)
});<commit_msg>console log charge and erros<commit_after>var stripe = require('stripe')(process.env.StripeTestSecretKey);

stripe.charges.create({
  amount: 400,
  currency: "gbp",
  source: "tok_17IKIZA9VROQGHUtuB7vZQY3",
  customer: "cus_7XPJJLaVUDUJAB"
}, function(err, charge) {
  console.log('Error', err)
  console.log('Charge:', charge)
});<|endoftext|>


<commit_before>import User from './User'
import Question from './Question'

// Remember to change if scores have been added

export default async function setupModels() {
  await User.sync({ force: true })
  await User.bulkCreate([
    { email: 'user1@gmail.com', name: 'User 1', score:40, maxUnlock: 2},
    { email: 'user2@gmail.com', name: 'User 2', score:40, maxUnlock: 2},
    { email: 'user3@gmail.com', name: 'User 3', score:40, maxUnlock: 2},
    { email: 'user4@gmail.com', name: 'User 4', score:30, maxUnlock: 1},
    { email: 'user5@gmail.com', name: 'User 5', score:50, maxUnlock: 3},
  ]);
  await Question.sync({ force: true })
  await Question.bulkCreate([
    { qno: 1, title: 'QTitle 1', body: 'QBody 1', answer: JSON.stringify(['1','2','3'])},
    { qno: 2, title: 'QTitle 2', body: 'QBody 2', answer: '2'},
    { qno: 3, title: 'QTitle 3', body: 'QBody 3', answer: JSON.stringify(['1','4'])},
    { qno: 4, title: 'QTitle 4', body: 'QBody 4', answer: '4'},
    { qno: 5, title: 'QTitle 5', body: 'QBody 5', answer: '5'},
  ]);
}
<commit_msg>Fixed #23: Error in muliple answers (#24)<commit_after>import User from './User'
import Question from './Question'

// Remember to change if scores have been added

export default async function setupModels() {
  await User.sync({ force: true })
  await User.bulkCreate([
    { email: 'user1@gmail.com', name: 'User 1', score:40, maxUnlock: 2},
    { email: 'user2@gmail.com', name: 'User 2', score:40, maxUnlock: 2},
    { email: 'user3@gmail.com', name: 'User 3', score:40, maxUnlock: 2},
    { email: 'user4@gmail.com', name: 'User 4', score:30, maxUnlock: 1},
    { email: 'user5@gmail.com', name: 'User 5', score:50, maxUnlock: 3},
  ]);
  await Question.sync({ force: true })
  await Question.bulkCreate([
    { qno: 1, title: 'QTitle 1', body: 'QBody 1', answer: JSON.stringify(['1','2','3'])},
    { qno: 2, title: 'QTitle 2', body: 'QBody 2', answer: JSON.stringify(['2'])},
    { qno: 3, title: 'QTitle 3', body: 'QBody 3', answer: JSON.stringify(['1','4'])},
    { qno: 4, title: 'QTitle 4', body: 'QBody 4', answer: JSON.stringify(['3'])},
    { qno: 5, title: 'QTitle 5', body: 'QBody 5', answer: JSON.stringify(['4'])},
  ]);
}
<|endoftext|>


<commit_before>/*!
 * Chai - addMethod utility
 * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>
 * MIT Licensed
 */

var config = require('../config');

/**
 * ### .addMethod (ctx, name, method)
 *
 * Adds a method to the prototype of an object.
 *
 *     utils.addMethod(chai.Assertion.prototype, 'foo', function (str) {
 *       var obj = utils.flag(this, 'object');
 *       new chai.Assertion(obj).to.be.equal(str);
 *     });
 *
 * Can also be accessed directly from `chai.Assertion`.
 *
 *     chai.Assertion.addMethod('foo', fn);
 *
 * Then can be used as any other assertion.
 *
 *     expect(fooStr).to.be.foo('bar');
 *
 * @param {Object} ctx object to which the method is added
 * @param {String} name of method to add
 * @param {Function} method function to be used for name
 * @name addMethod
 * @api public
 */
var flag = require('./flag');

module.exports = function (ctx, name, method) {
  ctx[name] = function () {
    var old_ssfi = flag(this, 'ssfi');
    if (old_ssfi && config.includeStack === false)
      flag(this, 'ssfi', ctx[name]);
    var result = method.apply(this, arguments);
    return result === undefined ? this : result;
  };
};
<commit_msg>Delete addMethod.js<commit_after><|endoftext|>