<commit_before>/*
 Copyright 2017 Paul Zuehlcke - paul.zuehlcke.de

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

/**
 * Small iterator to traverse through a history
 */
class HistoryIterator {
  /**
   * Initialize this iterator on the given history.
   *
   * Be aware that you need to initialize a new iterator when the history changes,
   * as the index is not reset automatically.
   * @param {CommandHistory} history - history, this iterator is based on.
   */
  constructor(history) {
    this._history = history;
    this._i = history.size();
  }

  /**
   * Evaluates if there is an element after the current one
   * @returns {boolean} - true, if there is a next element to get via next(), false otherwise.
   */
  hasNext() {
    return this._i < (this._history);
  }

  /**
   * Returns the next entry in the history (i.e. forward in time).
   *
   * @returns {string | undefined} requested entry, undefined if no next entry exists
   */
  next() {
    const next = this._history.get(this._i);
    this._i += 1;
    if (next === undefined) { this._i -= 1; }
    return next;
  }

  /**
   * Returns the previous entry in the history (i.e. back in time).
   *
   * @returns {string | undefined} requested entry, undefined if no previous entry exists
   */
  prev() {
    const prev = this._history.get(this._i);
    this._i -= 1;
    if (prev === undefined) { this._i -= 1; }
    return prev;
  }
}

/**
 * This class is a simple array wrapper, designed to store the history of the commandline.
 */
export default class CommandHistory {
  /**
     * Initialize a new CommandHistory instance (optionally based on an existing history array).
     * @param {Array} history - array this history is based on. Leave undefined for empty array.
     */
  constructor(history = []) {
    this._history = history;
  }

  /**
     * Get history for given index.
     * @param {int} [index] - target index in history array.
     * @returns {string} command - command at given index.
     */
  get(index) {
    if (index === undefined) { return this._history; }
    return this._history[index];
  }

  /**
     * Returns the size of the history.
     * @returns {Number} - Length of history array
     */
  size() {
    return this._history.length;
  }

  /**
     * Adds entry to history.
     * @param {String} entry - entry to be stored in history
     * @returns {Number} - New length of history array
     */
  add(entry) {
    return this._history.push(entry);
  }

  /**
     * Returns an iterator for this history for easy traversal.
     * @returns {HistoryIterator} iterator
     */
  iterator() {
    return new HistoryIterator(this);
  }
}
<commit_msg>Fixed bug in CommandHistory navigation<commit_after>/*
 Copyright 2017 Paul Zuehlcke - paul.zuehlcke.de

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

/**
 * Small iterator to traverse through a history
 */
class HistoryIterator {
  /**
   * Initialize this iterator on the given history.
   *
   * Be aware that you need to initialize a new iterator when the history changes,
   * as the index is not reset automatically.
   * @param {CommandHistory} history - history, this iterator is based on.
   */
  constructor(history) {
    this._history = history;
    this._i = history.size();
  }

  /**
   * Evaluates if there is an element after the current one
   * @returns {boolean} - true, if there is a next element to get via next(), false otherwise.
   */
  hasNext() {
    return this._i < (this._history);
  }

  /**
   * Returns the next entry in the history (i.e. forward in time).
   *
   * @returns {string | undefined} requested entry, undefined if no next entry exists
   */
  next() {
    this._i += 1;
    const next = this._history.get(this._i);
    if (next === undefined) { this._i -= 1; }
    return next;
  }

  /**
   * Returns the previous entry in the history (i.e. back in time).
   *
   * @returns {string | undefined} requested entry, undefined if no previous entry exists
   */
  prev() {
    this._i -= 1;
    const prev = this._history.get(this._i);
    if (prev === undefined) { this._i += 1; }
    return prev;
  }
}

/**
 * This class is a simple array wrapper, designed to store the history of the commandline.
 */
export default class CommandHistory {
  /**
     * Initialize a new CommandHistory instance (optionally based on an existing history array).
     * @param {Array} history - array this history is based on. Leave undefined for empty array.
     */
  constructor(history = []) {
    this._history = history;
  }

  /**
     * Get history for given index.
     * @param {int} [index] - target index in history array.
     * @returns {string} command - command at given index.
     */
  get(index) {
    if (index === undefined) { return this._history; }
    return this._history[index];
  }

  /**
     * Returns the size of the history.
     * @returns {Number} - Length of history array
     */
  size() {
    return this._history.length;
  }

  /**
     * Adds entry to history.
     * @param {String} entry - entry to be stored in history
     * @returns {Number} - New length of history array
     */
  add(entry) {
    return this._history.push(entry);
  }

  /**
     * Returns an iterator for this history for easy traversal.
     * @returns {HistoryIterator} iterator
     */
  iterator() {
    return new HistoryIterator(this);
  }
}
<|endoftext|>


<commit_before>			makeProperty = (function () {
				var makeProperty,
					getVal,
					stack = makeList(),
					// Flag to indicate that properties can only add themselves as
					// dependencies iff the property at the top of the stack has
					// the same owner. By default this is set to false, meaning that
					// if a property were to call another property of a different
					// owner then the property called would be marked as a dependency.
					// This value is never changed at runtime.
					strictDependencies = false;

				stack.pushProperty = function (property) {
					if (this.length) {
						if (!strictDependencies || this["peek"]()["owner"] === property["owner"]) {
							this.push(property);
						}
					} else {
						this.push(property);
					}
				};
				stack.addDependency = function (property) {
					if (this.length) {
						if (!strictDependencies || this["peek"]()["owner"] === property["owner"]) {
							this["peek"]().dependencies()["add"](property);
						}
					}
				};

				makeProperty = function (options, set, owner) {
					var writing = false,
						dependencies = makeList(),
						subscriptions = [],
						setter,
						getter,
						memo,
						property,
						observer = function () {
							memo = undefined;
							property["notify"]();
						};

					dependencies["add"] = function (prop) {
						if (!this["contains"](prop)) {
							this.push(prop);
							subscriptions.push(prop["subscribe"](observer));
						}
					};

					property = function (value) {
						var ret, origOwner = property["owner"];

						// Temporarily set the owner to the 'this' object.
						if (this !== undefined) {
							property["owner"] = this;
						}

						if (arguments.length) {
							property["set"](value);
							ret = this;
						} else {
							ret = property["get"]();
						}

						property["owner"] = origOwner;

						return ret;
					};
					property["equals"] = function (b) {
						var a = this["get"]();
						b = getVal(b);

						a = a ? a.valueOf() : a;
						b = b ? b.valueOf() : b;

						return a === b;
					};
					property["changed"] = function (b) {
						var a = this["get"]();
						b = getVal(b);

						a = a ? a.valueOf() : a;
						b = b ? b.valueOf() : b;

						return a !== b;
					};
					property["clearMemo"] = function () {
						memo = undefined;
					};
					property["get"] = function () {
						if (!writing) {
							stack.addDependency(this);
							stack.pushProperty(this);
						}

						var result = memo === undefined ? getter.call(this["owner"]) : memo;
						memo = result;

						if (stack[stack.length - 1] === this) {
							stack.pop();
						}

						return result;
					};
					property["set"] = function (value) {
						// Check if the property is writable.
						if (typeof setter === 'function') {
							writing = true;

							if (!this["equals"](value) || this["changed"](value)) {
								// We block just in case our value is an ObservableList
								// or something that is observable that will also trigger
								// a notification when it is changed. This will occur
								// if the property's value is an ObservableList.
								this["block"]();
								setter.call(this["owner"], value);
								memo = undefined;
								this["unblock"]();
								this["notify"]();
							}

							writing = false;
						}
					};
					property["dependencies"] = function () {
						return dependencies;
					};
					property["isDependent"] = function () {
						return dependencies.length !== 0;
					};
					property["toString"] = function () {
						return util.str(this["get"]());
					};
					property["valueOf"] = function () {
						var value = this["get"]();
						return util.isNil(value) ? value : value.valueOf();
					};

					util.mixin(property, makeObservable());

					// Initialization.
					(function () {
						var value,
							self = property,
							lazy = false,
							isObject = util.isObject,
							isArray = util.isArray,
							adheresTo = util.adheresTo;

						self["owner"] = undefined;

						// Just a getter function, with optional setter and or owner.
						// (getter)
						// (getter, owner)
						// (getter, setter)
						// (getter, setter, owner)
						if (typeof options === 'function') {
							getter = options;
							setter = typeof set === 'function' ? set : null;
							self["owner"] = typeof set === 'function' ? owner : set;
						// {get, [set, lazy, changed, equals, owner]}
						} else if (isObject(options) && typeof options["get"] === 'function') {
							lazy = options["lazy"];
							getter = options["get"];
							setter = typeof options["set"] === 'function' ? options["set"] : null;
							self["equals"] = typeof options["equals"] === 'function' ? options["equals"] : self["equals"];
							self["changed"] = typeof options["changed"] === 'function' ? options["changed"] : self["changed"];
							self["owner"] = options["owner"];
						} else {
							// {value, [changed, equals]}
							if (isObject(options)) {
								self["equals"] = typeof options["equals"] === 'function' ? options["equals"] : self["equals"];
								self["changed"] = typeof options["changed"] === 'function' ? options["changed"] : self["changed"];
								value = options["value"];
							// Just the value.
							} else {
								value = options;
							}

							// Make all Arrays into ObservableLists.
							if (isArray(value) && !adheresTo(value, makeObservable["interfce"])) {
								value = makeObservableList(value);

								// For array values the equals and changed operators
								// specified in the options are opertors for testing items in the list
								// not for operating on individual lists themselves.

								// Override the item operators for the newly created ObservableList
								// so that the item operators are taken from the options.
								value["getItemOperators"] = (function (equals, changed, operators) {
									equals = typeof equals === 'function' ? equals : operators["equals"];
									changed = typeof changed === 'function' ? changed : operators["changed"];

									return function () {
										return {
											"equals": equals,
											"changed": changed
										};
									};
								}(options["equals"], options["changed"], value["getItemOperators"]()));

								self["equals"] = function (b) {
									b = getVal(b);
									return value["equals"](b);
								};
								self["changed"] = function (b) {
									b = getVal(b);
									return value["changed"](b);
								};
							}

							// If the value is observable then we observe it for notifications.
							if (value && typeof value["subscribe"] === 'function' && typeof value["dispose"] === 'function') {
								subscriptions.push(value["subscribe"](observer));
							}

							getter = function () {
								return value;
							};
							setter = function (v) {
								if (adheresTo(value, makeList["interfce"])) {
									value["clear"]();

									if (isArray(v)) {
										value.push.apply(value, v);
									} else {
										value.push(v);
									}
								} else if (isArray(value)) {
									while (value.length) {
										value.pop();
									}

									if (isArray(v)) {
										value.push.apply(value, v);
									} else {
										value.push(v);
									}
								} else if (value !== v) {
									value = v;
								}
							};
						}

						self["dispose"] = (function (base) {
							return function () {
								while (subscriptions.length) {
									subscriptions.pop()["dispose"]();
								}
								while (dependencies.length) {
									dependencies.pop();
								}
								base.call(this);
							};
						}(self["dispose"]));

						// Watch dependent properties automatically
						// if they are not 'lazy'. If we are lazy then
						// dependent properties will not be tracked until
						// we have been read at least once.
						if (!lazy) {
							property["get"]();
						}
					}());

					return property;
				};

				// Convenience method to retrieve the value of the specified property.
				// If the specified property is not a property then returns property.
				getVal = function (property) {
					if (property && typeof property["get"] === 'function') {
						return property["get"]();
					}
					return property;
				};
				makeProperty["get"] = getVal;

				makeProperty["interfce"] = util.mixin({
					"dependencies": 'function',
					"isDependent": 'function',
					"clearMemo": 'function',
					"get": 'function',
					"set": 'function',
					"equals": 'function',
					"changed": 'function'
				}, makeObservable["interfce"]);

				return makeProperty;
			}()),<commit_msg>Resolve conflicts<commit_after>			makeProperty = (function () {
				var makeProperty,
					getVal,
					stack = makeList(),
					// Flag to indicate that properties can only add themselves as
					// dependencies iff the property at the top of the stack has
					// the same owner. By default this is set to false, meaning that
					// if a property were to call another property of a different
					// owner then the property called would be marked as a dependency.
					// This value is never changed at runtime.
					strictDependencies = false;

				stack.pushProperty = function (property) {
					if (this.length) {
						if (!strictDependencies || this["peek"]()["owner"] === property["owner"]) {
							this.push(property);
						}
					} else {
						this.push(property);
					}
				};
				stack.addDependency = function (property) {
					if (this.length) {
						if (!strictDependencies || this["peek"]()["owner"] === property["owner"]) {
							this["peek"]()["dependencies"]()["add"](property);
						}
					}
				};

				makeProperty = function (options, set, owner) {
					var writing = false,
						dependencies = makeList(),
						subscriptions = [],
						setter,
						getter,
						memo,
						property,
						observer = function () {
							memo = undefined;
							property["notify"]();
						};

					dependencies["add"] = function (prop) {
						if (!this["contains"](prop)) {
							this.push(prop);
							subscriptions.push(prop["subscribe"](observer));
						}
					};

					property = function (value) {
						var ret, origOwner = property["owner"];

						// Temporarily set the owner to the 'this' object.
						if (this !== undefined) {
							property["owner"] = this;
						}

						if (arguments.length) {
							property["set"](value);
							ret = this;
						} else {
							ret = property["get"]();
						}

						property["owner"] = origOwner;

						return ret;
					};
					property["equals"] = function (b) {
						var a = this["get"]();
						b = getVal(b);

						a = a ? a.valueOf() : a;
						b = b ? b.valueOf() : b;

						return a === b;
					};
					property["changed"] = function (b) {
						var a = this["get"]();
						b = getVal(b);

						a = a ? a.valueOf() : a;
						b = b ? b.valueOf() : b;

						return a !== b;
					};
					property["clearMemo"] = function () {
						memo = undefined;
					};
					property["get"] = function () {
						if (!writing) {
							stack.addDependency(this);
							stack.pushProperty(this);
						}

						var result = memo === undefined ? getter.call(this["owner"]) : memo;
						memo = result;

						if (stack[stack.length - 1] === this) {
							stack.pop();
						}

						return result;
					};
					property["set"] = function (value) {
						// Check if the property is writable.
						if (typeof setter === 'function') {
							writing = true;

							if (!this["equals"](value) || this["changed"](value)) {
								// We block just in case our value is an ObservableList
								// or something that is observable that will also trigger
								// a notification when it is changed. This will occur
								// if the property's value is an ObservableList.
								this["block"]();
								setter.call(this["owner"], value);
								memo = undefined;
								this["unblock"]();
								this["notify"]();
							}

							writing = false;
						}
					};
					property["dependencies"] = function () {
						return dependencies;
					};
					property["isDependent"] = function () {
						return dependencies.length !== 0;
					};
					property["toString"] = function () {
						return util.str(this["get"]());
					};
					property["valueOf"] = function () {
						var value = this["get"]();
						return util.isNil(value) ? value : value.valueOf();
					};

					util.mixin(property, makeObservable());

					// Initialization.
					(function () {
						var value,
							self = property,
							lazy = false,
							isObject = util.isObject,
							isArray = util.isArray,
							adheresTo = util.adheresTo;

						self["owner"] = undefined;

						// Just a getter function, with optional setter and or owner.
						// (getter)
						// (getter, owner)
						// (getter, setter)
						// (getter, setter, owner)
						if (typeof options === 'function') {
							getter = options;
							setter = typeof set === 'function' ? set : null;
							self["owner"] = typeof set === 'function' ? owner : set;
						// {get, [set, lazy, changed, equals, owner]}
						} else if (isObject(options) && typeof options["get"] === 'function') {
							lazy = options["lazy"];
							getter = options["get"];
							setter = typeof options["set"] === 'function' ? options["set"] : null;
							self["equals"] = typeof options["equals"] === 'function' ? options["equals"] : self["equals"];
							self["changed"] = typeof options["changed"] === 'function' ? options["changed"] : self["changed"];
							self["owner"] = options["owner"];
						} else {
							// {value, [changed, equals]}
							if (isObject(options)) {
								self["equals"] = typeof options["equals"] === 'function' ? options["equals"] : self["equals"];
								self["changed"] = typeof options["changed"] === 'function' ? options["changed"] : self["changed"];
								value = options["value"];
							// Just the value.
							} else {
								value = options;
							}

							// Make all Arrays into ObservableLists.
							if (isArray(value) && !adheresTo(value, makeObservable["interfce"])) {
								value = makeObservableList(value);

								// For array values the equals and changed operators
								// specified in the options are opertors for testing items in the list
								// not for operating on individual lists themselves.

								// Override the item operators for the newly created ObservableList
								// so that the item operators are taken from the options.
								value["getItemOperators"] = (function (equals, changed, operators) {
									equals = typeof equals === 'function' ? equals : operators["equals"];
									changed = typeof changed === 'function' ? changed : operators["changed"];

									return function () {
										return {
											"equals": equals,
											"changed": changed
										};
									};
								}(options["equals"], options["changed"], value["getItemOperators"]()));

								self["equals"] = function (b) {
									b = getVal(b);
									return value["equals"](b);
								};
								self["changed"] = function (b) {
									b = getVal(b);
									return value["changed"](b);
								};
							}

							// If the value is observable then we observe it for notifications.
							if (value && typeof value["subscribe"] === 'function' && typeof value["dispose"] === 'function') {
								subscriptions.push(value["subscribe"](observer));
							}

							getter = function () {
								return value;
							};
							setter = function (v) {
								if (adheresTo(value, makeList["interfce"])) {
									value["clear"]();

									if (isArray(v)) {
										value.push.apply(value, v);
									} else {
										value.push(v);
									}
								} else if (isArray(value)) {
									while (value.length) {
										value.pop();
									}

									if (isArray(v)) {
										value.push.apply(value, v);
									} else {
										value.push(v);
									}
								} else if (value !== v) {
									value = v;
								}
							};
						}

						self["dispose"] = (function (base) {
							return function () {
								while (subscriptions.length) {
									subscriptions.pop()["dispose"]();
								}
								while (dependencies.length) {
									dependencies.pop();
								}
								base.call(this);
							};
						}(self["dispose"]));

						// Watch dependent properties automatically
						// if they are not 'lazy'. If we are lazy then
						// dependent properties will not be tracked until
						// we have been read at least once.
						if (!lazy) {
							property["get"]();
						}
					}());

					return property;
				};

				// Convenience method to retrieve the value of the specified property.
				// If the specified property is not a property then returns property.
				getVal = function (property) {
					if (property && typeof property["get"] === 'function') {
						return property["get"]();
					}
					return property;
				};
				makeProperty["get"] = getVal;

				makeProperty["interfce"] = util.mixin({
					"dependencies": 'function',
					"isDependent": 'function',
					"clearMemo": 'function',
					"get": 'function',
					"set": 'function',
					"equals": 'function',
					"changed": 'function'
				}, makeObservable["interfce"]);

				return makeProperty;
			}()),<|endoftext|>


<commit_before>//
// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

var fs = require('fs');
var path = require('path');
var azure;

try {
  fs.statSync('./../../lib/azure.js');
  azure = require('./../../lib/azure');
} catch(error) {
  azure = require('azure');
}

var express = require('express');
var expressEjsLayouts = require('express-ejs-layouts');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var errorHandler = require('errorhandler');
var formidable = require('formidable');
var helpers = require('./helpers.js');

var app = module.exports = express();
// Global request options, set the retryPolicy
// var blobClient = azure.createBlobService('UseDevelopmentStorage=true')
var blobClient = null;
var containerName = 'webpi';

//Configuration
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(expressEjsLayouts);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true}));
app.use(methodOverride());
app.use(express.static(path.join(__dirname, 'public')));

if(app.get('env') === 'development') {
  app.use(errorHandler());
};

if(app.get('env') === 'production') {
  app.use(errorHandler());
};

app.param('id', function (req, res, next, id) {
  console.log('param :id %s', id);
  next();
});

//Routes
app.get('/', function (req, res) {
  res.render('index.ejs', {
      title: 'Welcome'
    });
});

app.get('/Upload', function (req, res) {
  res.render('upload.ejs', { locals: {
    title: 'Upload File'
  }
  });
});

app.get('/Display', function (req, res) {
  blobClient.listBlobs(containerName, function (error, blobs) {
    res.render('display.ejs', { locals: {
      title: 'List of Blobs',
      serverBlobs: blobs
    }
    });
  });
});

app.get('/Download/:id', function (req, res) {
  blobClient.getBlobProperties(containerName, req.params.id, function (err, blobInfo) {
    if (err === null) {
      res.header('content-type', blobInfo.contentType);
      res.header('content-disposition', 'attachment; filename=' + blobInfo.metadata.filename);
      blobClient.getBlobToStream(containerName, req.params.id, res, function () { });
    } else {
      helpers.renderError(res);
    }
  });
});

app.post('/uploadhandler', function (req, res) {
  var form = new formidable.IncomingForm();

  form.parse(req, function (err, fields, files) {
    var formValid = true;
    if (fields.itemName === '') {
      helpers.renderError(res);
      formValid = false;
    }

    if (formValid) {
      var extension = files.uploadedFile.name.split('.').pop();
      var newName = fields.itemName + '.' + extension;

      var options = {
        contentType: files.uploadedFile.type,
        metadata: { fileName: newName }
      };

      blobClient.createBlockBlobFromFile(containerName, fields.itemName, files.uploadedFile.path, options, function (error) {
        if (error != null) {
          helpers.renderError(res);
        } else {
          setSAS(containerName, fields.itemName);
          res.redirect('/Display');
        }
      });
    } else {
      helpers.renderError(res);
    }
  });
});

app.post('/Delete/:id', function (req, res) {
  blobClient.deleteBlob(containerName, req.params.id, function (error) {
    if (error != null) {
      helpers.renderError(res);
    } else {
      res.redirect('/Display');
    }
  });
});

app.listen(app.get('port'), function() {
  console.log("Express server listening on port %d in %s mode", app.get('port'), app.get('env'));
  blobClient = azure.createBlobService(process.env.CONNECTION_STRING)
    .withFilter(new azure.ExponentialRetryPolicyFilter());
  blobClient.createContainerIfNotExists(containerName, {publicAccessType: 'blob'},
    function (error, result, response) {
      if(error) {
        console.log(error);
      }
  });
});

function setSAS(containerName, blobName) {
    var sharedAccessPolicy = {
        AccessPolicy: {
            Expiry: azure.date.minutesFromNow(3)
        }
    };

    var blobUrl = blobClient.getBlobUrl(containerName, blobName, sharedAccessPolicy);
    console.log("access the blob at ", blobUrl);
}<commit_msg>Fix List rendering with new api<commit_after>//
// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

var fs = require('fs');
var path = require('path');
var azure;

try {
  fs.statSync('./../../lib/azure.js');
  azure = require('./../../lib/azure');
} catch(error) {
  azure = require('azure');
}

var express = require('express');
var expressEjsLayouts = require('express-ejs-layouts');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var errorHandler = require('errorhandler');
var formidable = require('formidable');
var helpers = require('./helpers.js');

var app = module.exports = express();
// Global request options, set the retryPolicy
// var blobClient = azure.createBlobService('UseDevelopmentStorage=true')
var blobClient = null;
var containerName = 'webpi';

//Configuration
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(expressEjsLayouts);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true}));
app.use(methodOverride());
app.use(express.static(path.join(__dirname, 'public')));

if(app.get('env') === 'development') {
  app.use(errorHandler());
};

if(app.get('env') === 'production') {
  app.use(errorHandler());
};

app.param('id', function (req, res, next, id) {
  console.log('param :id %s', id);
  next();
});

//Routes
app.get('/', function (req, res) {
  res.render('index.ejs', {
      title: 'Welcome'
    });
});

app.get('/Upload', function (req, res) {
  res.render('upload.ejs', { locals: {
    title: 'Upload File'
  }
  });
});

app.get('/Display', function (req, res) {
  blobClient.listBlobsSegmented(containerName, null, {}, function (error, result, response) {
    // result {continuationToken, entries}
    res.render('display.ejs', {
      title: 'List of Blobs',
      serverBlobs: result.entries
    });
  });
});

app.get('/Download/:id', function (req, res) {
  blobClient.getBlobProperties(containerName, req.params.id, function (err, blobInfo) {
    if (err === null) {
      res.header('content-type', blobInfo.contentType);
      res.header('content-disposition', 'attachment; filename=' + blobInfo.metadata.filename);
      blobClient.getBlobToStream(containerName, req.params.id, res, function () { });
    } else {
      helpers.renderError(res);
    }
  });
});

app.post('/uploadhandler', function (req, res) {
  var form = new formidable.IncomingForm();

  form.parse(req, function (err, fields, files) {
    var formValid = true;
    if (fields.itemName === '') {
      helpers.renderError(res);
      formValid = false;
    }

    if (formValid) {
      var extension = files.uploadedFile.name.split('.').pop();
      var newName = fields.itemName + '.' + extension;

      var options = {
        contentType: files.uploadedFile.type,
        metadata: { fileName: newName }
      };

      blobClient.createBlockBlobFromFile(containerName, fields.itemName, files.uploadedFile.path, options, function (error) {
        if (error != null) {
          helpers.renderError(res);
        } else {
          setSAS(containerName, fields.itemName);
          res.redirect('/Display');
        }
      });
    } else {
      helpers.renderError(res);
    }
  });
});

app.post('/Delete/:id', function (req, res) {
  blobClient.deleteBlob(containerName, req.params.id, function (error) {
    if (error != null) {
      helpers.renderError(res);
    } else {
      res.redirect('/Display');
    }
  });
});

app.listen(app.get('port'), function() {
  console.log("Express server listening on port %d in %s mode", app.get('port'), app.get('env'));
  blobClient = azure.createBlobService(process.env.CONNECTION_STRING)
    .withFilter(new azure.ExponentialRetryPolicyFilter());
  blobClient.createContainerIfNotExists(containerName, {publicAccessType: 'blob'},
    function (error, result, response) {
      if(error) {
        console.log(error);
      }
  });
});

function setSAS(containerName, blobName) {
    var sharedAccessPolicy = {
        AccessPolicy: {
            Expiry: azure.date.minutesFromNow(3)
        }
    };

    var blobUrl = blobClient.getBlobUrl(containerName, blobName, sharedAccessPolicy);
    console.log("access the blob at ", blobUrl);
}<|endoftext|>


<commit_before>import React, { Component } from 'react'
import {
	View,
	Text,
	FlatList,
	ActivityIndicator
} from 'react-native'
import { connect } from 'react-redux'
import moment from 'moment'
import Icon from 'react-native-vector-icons/MaterialIcons'
import logger from '../../util/logger'
import css from '../../styles/css'

const checkData = (data) => {
	if (!Array.isArray(data)) return null
	const cleanData = data.filter((item) => {
		const day = moment.unix(item.timestamp)
		if (day.isValid()) {
			return true
		}
		return false
	})

	return cleanData
}

export class Messaging extends Component {
	static navigationOptions = { title: 'Notifications' }

	componentDidMount() {
		logger.ga('View Loaded: Messaging')
		this.props.updateMessages(new Date().getTime())
	}

	renderSeparator = ({ leadingItem }) => (
		<View
			style={{ height: 1, width: '100%', backgroundColor: '#D2D2D2' }}
		/>
	)

	renderItem = ({ item }) => {
		const { message, timestamp } = item
		const { message: messageText, title } = message
		const day = moment(timestamp)

		let timeString
		if (day.isSame(moment(), 'day')) {
			timeString = day.format('h:mm a')
		} else {
			timeString = day.fromNow()
		}

		return (
			<View style={{ height: 110, width: '100%', flexDirection: 'row', justifyContent: 'flex-start' }}>
				<View style={{ justifyContent: 'center', alignItems: 'center', marginLeft: 10, marginRight: 20 }}>
					<Icon
						name="check-circle"
						size={30}
						style={{ color: '#21D383' }}
					/>
				</View>
				<View  style={{ flexDirection: 'column', justifyContent: 'center', flex: 1 }}>
					<Text style={{ color: '#a1a1a1', fontWeight: 'bold', fontSize: 10 }}>{timeString}</Text>
					<Text style={{ color: '#818181', fontWeight: 'bold', fontSize: 24 }}>{title}</Text>
					<Text style={{ color: '#818181', fontWeight: 'bold', fontSize: 14 }}>{messageText}</Text>
				</View>
			</View>
		)
	}

	render() {
		if (this.props.hasUnreadMsgs) {
			this.props.setMessagesRead()
		}
		const { messages, nextTimestamp } = this.props.messages
		const { updateMessages } = this.props
		const filteredData = checkData(messages)

		let isLoading = false
		if (this.props.myMessagesStatus) isLoading = true

		return (
			<View style={css.scroll_default}>
				<FlatList
					data={filteredData}
					onRefresh={() => updateMessages(new Date().getTime())}
					refreshing={isLoading}
					renderItem={this.renderItem}
					keyExtractor={(item, index) => item.id}
					ItemSeparatorComponent={this.renderSeparator}
					onEndReachedThreshold={0.5}
					ListFooterComponent={isLoading ? <ActivityIndicator size="large" animating /> : null}
					onEndReached={(info) => {
						// this if check makes sure that we dont fetch extra data in the intialization of the list
						if (info.distanceFromEnd > 0
							&& nextTimestamp
							&& !isLoading) {
							updateMessages(nextTimestamp)
						}
					}}
				/>
			</View>
		)
	}
}

const mapStateToProps = (state, props) => (
	{
		messages: state.messages,
		myMessagesStatus: state.requestStatuses.GET_MESSAGES,
		myMessagesError: state.requestErrors.GET_MESSAGES,
		hasUnreadMsgs: state.messages.hasUnreadMsgs
	}
)

const mapDispatchToProps = (dispatch, ownProps) => (
	{
		updateMessages: (timestamp) => {
			dispatch({ type: 'UPDATE_MESSAGES', timestamp })
		},
		setMessagesRead: () => {
			dispatch({ type: 'SET_MESSAGES_READ' })
		}
	}
)

export default connect(mapStateToProps, mapDispatchToProps)(Messaging)
<commit_msg>Small UI tweaks for notifications tab<commit_after>import React, { Component } from 'react'
import {
	View,
	Text,
	FlatList,
	ActivityIndicator
} from 'react-native'
import { connect } from 'react-redux'
import moment from 'moment'
import Icon from 'react-native-vector-icons/MaterialIcons'
import logger from '../../util/logger'
import css from '../../styles/css'

const checkData = (data) => {
	if (!Array.isArray(data)) return null
	const cleanData = data.filter((item) => {
		const day = moment.unix(item.timestamp)
		if (day.isValid()) {
			return true
		}
		return false
	})

	return cleanData
}

export class Messaging extends Component {
	static navigationOptions = { title: 'Notifications' }

	componentDidMount() {
		logger.ga('View Loaded: Messaging')
		this.props.updateMessages(new Date().getTime())
	}

	renderSeparator = ({ leadingItem }) => (
		<View
			style={{ height: 1, width: '100%', backgroundColor: '#D2D2D2' }}
		/>
	)

	renderItem = ({ item }) => {
		const { message, timestamp } = item
		const { message: messageText, title } = message
		const day = moment(timestamp)

		let timeString
		if (day.isSame(moment(), 'day')) {
			timeString = day.format('h:mm a')
		} else {
			timeString = day.fromNow()
		}

		return (
			<View style={{ height: 110, width: '100%', flexDirection: 'row', justifyContent: 'flex-start' }}>
				<View style={{ justifyContent: 'center', alignItems: 'center', marginLeft: 10, marginRight: 20 }}>
					<Icon
						name="check-circle"
						size={30}
						style={{ color: '#21D383' }}
					/>
				</View>
				<View  style={{ flexDirection: 'column', justifyContent: 'center', flex: 1 }}>
					<Text style={{ color: '#a1a1a1', fontWeight: 'bold', fontSize: 10 }}>{timeString}</Text>
					<Text style={{ color: '#818181', fontWeight: 'bold', fontSize: 24 }}>{title}</Text>
					<Text style={{ color: '#818181', fontWeight: 'bold', fontSize: 14 }}>{messageText}</Text>
				</View>
			</View>
		)
	}

	render() {
		if (this.props.hasUnreadMsgs) {
			this.props.setMessagesRead()
		}
		const { messages, nextTimestamp } = this.props.messages
		const { updateMessages } = this.props
		const filteredData = checkData(messages)

		let isLoading = false
		if (this.props.myMessagesStatus) isLoading = true

		return (
			<FlatList
				data={filteredData}
				style={css.scroll_default}
				contentContainerStyle={css.main_full}
				onRefresh={() => updateMessages(new Date().getTime())}
				refreshing={isLoading}
				renderItem={this.renderItem}
				keyExtractor={(item, index) => item.id}
				ItemSeparatorComponent={this.renderSeparator}
				onEndReachedThreshold={0.5}
				ListFooterComponent={(isLoading && nextTimestamp) ? <ActivityIndicator size="large" animating /> : null}
				onEndReached={(info) => {
					// this if check makes sure that we dont fetch extra data in the intialization of the list
					if (info.distanceFromEnd > 0
						&& nextTimestamp
						&& !isLoading) {
						updateMessages(nextTimestamp)
					}
				}}
			/>
		)
	}
}

const mapStateToProps = (state, props) => (
	{
		messages: state.messages,
		myMessagesStatus: state.requestStatuses.GET_MESSAGES,
		myMessagesError: state.requestErrors.GET_MESSAGES,
		hasUnreadMsgs: state.messages.hasUnreadMsgs
	}
)

const mapDispatchToProps = (dispatch, ownProps) => (
	{
		updateMessages: (timestamp) => {
			dispatch({ type: 'UPDATE_MESSAGES', timestamp })
		},
		setMessagesRead: () => {
			dispatch({ type: 'SET_MESSAGES_READ' })
		}
	}
)

export default connect(mapStateToProps, mapDispatchToProps)(Messaging)
<|endoftext|>


<commit_before>import { observer as globalObserver } from 'binary-common-utils/lib/observer';
import { getToken } from 'binary-common-utils/lib/storageManager';
import { translate } from '../../common/i18n';
import updateLogTable from './updateLogTable';

const log = (type, ...args) => {
    if (type === 'warn') {
        console.warn(...args); // eslint-disable-line no-console
    } else {
        console.log(...args); // eslint-disable-line no-console
    }
    const date = new Date();
    const timestamp = `${date.toISOString().split('T')[0]} ${date.toTimeString().slice(0, 8)}`;
    updateLogTable({ type, timestamp, message: args.join(':') });
};

const isNewMessage = (shown = []) => msg => {
    const timestamp = parseInt(new Date().getTime() / 1000);

    const shownMsg = shown.find(e => e.msg === msg);
    if (shownMsg) {
        const oldTimestamp = shownMsg.timestamp;

        shownMsg.timestamp = timestamp;
        return timestamp - oldTimestamp >= 1;
    }

    shown.push({ msg, timestamp });
    return true;
};

const isNewNotification = isNewMessage();

const isNewError = isNewMessage();

const notify = ({ className, message, position = 'left', sound = 'silent' }) => {
    if (message && isNewNotification(message)) {
        log(className, message);
        $.notify(message, { position: `bottom ${position}`, className });
        if (sound !== 'silent') {
            $(`#${sound}`).get(0).play();
        }
    }
};

const notifyError = error => {
    if (!error) {
        return;
    }

    let message = error.message;
    let errorCode = error.name;

    if (error.error) {
        message = error.error.message;
        errorCode = error.error.errorCode;
        if (error.error.error) {
            message = error.error.error.message;
            message = error.error.error.message;
            errorCode = error.error.error.errorCode;
        }
    }

    if (errorCode === 'DisconnectError') {
        message = translate('Connection lost before receiving the response from the server');
    }

    const errorWithCode = new Error(error);
    errorWithCode.message = errorCode ? `${errorCode}: ${message}` : message;

    if (trackJs && isNewError(message)) {
        trackJs.track(errorWithCode);
    }

    notify({ className: 'error', message, position: 'right' });
};

const waitForNotifications = () => {
    const notifList = ['success', 'info', 'warn', 'error'];

    const logList = [
        'log.bot.start',
        'log.bot.login',
        'log.bot.proposal',
        'log.purchase.start',
        'log.trade.purchase',
        'log.trade.update',
        'log.trade.finish',
    ];

    const amplitudeList = ['log.bot.login', 'log.trade.finish'];

    logList.forEach(event => globalObserver.register(event, d => log('info', event, d)));

    globalObserver.register('Notify', notify);

    globalObserver.register('Error', notifyError);

    notifList.forEach(className =>
        globalObserver.register(`ui.log.${className}`, message => notify({ className, message, position: 'right' }))
    );

    amplitudeList.forEach(event => globalObserver.register(event, d => amplitude.getInstance().logEvent(event, d)));

    globalObserver.register('log.revenue', data => {
        const { user, profit, contract } = data;

        if (typeof amplitude !== 'undefined' && !user.isVirtual) {
            const revenue = new amplitude.Revenue()
                .setProductId(`${contract.underlying}.${contract.contract_type}`)
                .setPrice(-profit)
                .setRevenueType(profit < 0 ? 'loss' : 'win');

            amplitude.getInstance().logRevenueV2(revenue, { contract });
        }
    });
};

const logHandler = () => {
    const token = $('.account-id').first().attr('value');
    const userId = getToken(token).account_name;

    if (amplitude) {
        amplitude.getInstance().setUserId(userId);
    }

    if (trackJs) {
        trackJs.configure({ userId });
    }

    waitForNotifications();
};

export default logHandler;
<commit_msg>Log user notifications with duplications<commit_after>import { observer as globalObserver } from 'binary-common-utils/lib/observer';
import { getToken } from 'binary-common-utils/lib/storageManager';
import { translate } from '../../common/i18n';
import updateLogTable from './updateLogTable';

const log = (type, ...args) => {
    if (type === 'warn') {
        console.warn(...args); // eslint-disable-line no-console
    } else {
        console.log(...args); // eslint-disable-line no-console
    }
    const date = new Date();
    const timestamp = `${date.toISOString().split('T')[0]} ${date.toTimeString().slice(0, 8)}`;
    updateLogTable({ type, timestamp, message: args.join(':') });
};

const isNewMessage = (shown = []) => msg => {
    const timestamp = parseInt(new Date().getTime() / 1000);

    const shownMsg = shown.find(e => e.msg === msg);
    if (shownMsg) {
        const oldTimestamp = shownMsg.timestamp;

        shownMsg.timestamp = timestamp;
        return timestamp - oldTimestamp >= 1;
    }

    shown.push({ msg, timestamp });
    return true;
};

const isNewNotification = isNewMessage();

const isNewError = isNewMessage();

const notify = ({ className, message, position = 'left', sound = 'silent' }) => {
    if (message && (position === 'left' || isNewNotification(message))) {
        log(className, message);
        $.notify(message, { position: `bottom ${position}`, className });
        if (sound !== 'silent') {
            $(`#${sound}`).get(0).play();
        }
    }
};

const notifyError = error => {
    if (!error) {
        return;
    }

    let message = error.message;
    let errorCode = error.name;

    if (error.error) {
        message = error.error.message;
        errorCode = error.error.errorCode;
        if (error.error.error) {
            message = error.error.error.message;
            message = error.error.error.message;
            errorCode = error.error.error.errorCode;
        }
    }

    if (errorCode === 'DisconnectError') {
        message = translate('Connection lost before receiving the response from the server');
    }

    const errorWithCode = new Error(error);
    errorWithCode.message = errorCode ? `${errorCode}: ${message}` : message;

    if (trackJs && isNewError(message)) {
        trackJs.track(errorWithCode);
    }

    notify({ className: 'error', message, position: 'right' });
};

const waitForNotifications = () => {
    const notifList = ['success', 'info', 'warn', 'error'];

    const logList = [
        'log.bot.start',
        'log.bot.login',
        'log.bot.proposal',
        'log.purchase.start',
        'log.trade.purchase',
        'log.trade.update',
        'log.trade.finish',
    ];

    const amplitudeList = ['log.bot.login', 'log.trade.finish'];

    logList.forEach(event => globalObserver.register(event, d => log('info', event, d)));

    globalObserver.register('Notify', notify);

    globalObserver.register('Error', notifyError);

    notifList.forEach(className =>
        globalObserver.register(`ui.log.${className}`, message => notify({ className, message, position: 'right' }))
    );

    amplitudeList.forEach(event => globalObserver.register(event, d => amplitude.getInstance().logEvent(event, d)));

    globalObserver.register('log.revenue', data => {
        const { user, profit, contract } = data;

        if (typeof amplitude !== 'undefined' && !user.isVirtual) {
            const revenue = new amplitude.Revenue()
                .setProductId(`${contract.underlying}.${contract.contract_type}`)
                .setPrice(-profit)
                .setRevenueType(profit < 0 ? 'loss' : 'win');

            amplitude.getInstance().logRevenueV2(revenue, { contract });
        }
    });
};

const logHandler = () => {
    const token = $('.account-id').first().attr('value');
    const userId = getToken(token).account_name;

    if (amplitude) {
        amplitude.getInstance().setUserId(userId);
    }

    if (trackJs) {
        trackJs.configure({ userId });
    }

    waitForNotifications();
};

export default logHandler;
<|endoftext|>


<commit_before>/**
 * URLSearchWidget component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { useState, useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { CORE_SITE } from '../../datastore/site/constants';
import { CORE_LOCATION } from '../../datastore/location/constants';
import Button from '../../../components/Button';
import PostSearcherAutoSuggest from '../../../components/PostSearcherAutoSuggest';
import WidgetNull from './WidgetNull';
const { useSelect, useDispatch } = Data;

function URLSearchWidget( { Widget = WidgetNull } = {} ) {
	const [ canSubmit, setCanSubmit ] = useState( false );
	const [ match, setMatch ] = useState( {} );

	const detailsURL = useSelect( ( select ) => select( CORE_SITE ).getAdminURL( 'googlesitekit-dashboard', { permaLink: match?.permalink } ) );

	const { navigateTo } = useDispatch( CORE_LOCATION );
	const onClick = useCallback( () => {
		if ( match?.permalink ) {
			navigateTo( detailsURL );
		}
	}, [ detailsURL, match ] );

	return (

			<Widget
				Header={ () => (

						{ __( 'Search for individual page or post information', 'google-site-kit' ) }

				) }
				noPadding
			>

									{ __( 'Title or URL', 'google-site-kit' ) }

								<PostSearcherAutoSuggest
									setCanSubmit={ setCanSubmit }
									setMatch={ setMatch }
								/>

									<Button
										onClick={ onClick }
										className="googlesitekit-post-searcher__button"
										disabled={ ! canSubmit }
									>
										{ __( 'View Data', 'google-site-kit' ) }
									</Button>

			</Widget>

	);
}

export default URLSearchWidget;
<commit_msg>Remove WidgetNull reference.<commit_after>/**
 * URLSearchWidget component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { useState, useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { CORE_SITE } from '../../datastore/site/constants';
import { CORE_LOCATION } from '../../datastore/location/constants';
import Button from '../../../components/Button';
import PostSearcherAutoSuggest from '../../../components/PostSearcherAutoSuggest';
const { useSelect, useDispatch } = Data;

function URLSearchWidget( { Widget } ) {
	const [ canSubmit, setCanSubmit ] = useState( false );
	const [ match, setMatch ] = useState( {} );

	const detailsURL = useSelect( ( select ) => select( CORE_SITE ).getAdminURL( 'googlesitekit-dashboard', { permaLink: match?.permalink } ) );

	const { navigateTo } = useDispatch( CORE_LOCATION );
	const onClick = useCallback( () => {
		if ( match?.permalink ) {
			navigateTo( detailsURL );
		}
	}, [ detailsURL, match ] );

	return (

			<Widget
				Header={ () => (

						{ __( 'Search for individual page or post information', 'google-site-kit' ) }

				) }
				noPadding
			>

									{ __( 'Title or URL', 'google-site-kit' ) }

								<PostSearcherAutoSuggest
									setCanSubmit={ setCanSubmit }
									setMatch={ setMatch }
								/>

									<Button
										onClick={ onClick }
										className="googlesitekit-post-searcher__button"
										disabled={ ! canSubmit }
									>
										{ __( 'View Data', 'google-site-kit' ) }
									</Button>

			</Widget>

	);
}

export default URLSearchWidget;
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

({
    afterRender: function (cmp, helper) {
        this.superAfterRender();
        var dom = cmp.getElement();
        var scrollables = dom.querySelectorAll('.scrollable');
        for (var i = 0; i < scrollables.length; i++) {
            helper.lib.panelLibCore.scopeScroll(scrollables[i]);
        }
    }
})<commit_msg>keep classes on compoment after re-render @bug W-2659319@ @rev apalke@<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

({
    afterRender: function (cmp, helper) {
        this.superAfterRender();
        var dom = cmp.getElement();
        var scrollables = dom.querySelectorAll('.scrollable');
        for (var i = 0; i < scrollables.length; i++) {
            helper.lib.panelLibCore.scopeScroll(scrollables[i]);
        }
    },
    rerender: function (cmp, helper) {
    	var currentEl =cmp.getElement();
    	var classes = [];

    	// The things that set these classes
    	// are async so there is a race condition
    	// at re-render time causing these to be erased.
    	// There is probably a better way, but this works for now
    	if(currentEl.className.match(/(\s|^)open(\s|$)/)) {
    		classes.push('open');
    	}
    	if(currentEl.className.match(/(\s|^)active(\s|$)/)) {
    		classes.push('active');
    	}

    	vClass = cmp.get('v.class');
    	if(vClass) {
    		classes.push(vClass);
    	}
    	cmp.set('v.class', classes.join(' '));
    	this.superRerender();

    }
})<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*jslint sub: true */
var p = Action.prototype;
exp(p,
    "auraType", p.auraType,
    "getDef", p.getDef,
    "setParams", p.setParams,
    "setParam", p.setParam,
    "getParam", p.getParam,
    "getParams", p.getParams,
    "setCallback", p.setCallback,
    "run", p.run,
    "runDeprecated", p.runDeprecated,
    "getState", p.getState,
    "getReturnValue", p.getReturnValue,
    "getStorage", p.getStorage,
    "runAfter", p.runAfter,
    "getError", p.getError,
    "setAbortable", p.setAbortable,
    "isAbortable", p.isAbortable,
    "isBackground", p.isBackground,
    "setBackground", p.setBackground,
    "setExclusive", p.setExclusive,
    "isExclusive", p.isExclusive,
    "setChained", p.setChained,
    "setStorable", p.setStorable,
    "getAbortableKey", p.getAbortableKey,
    "isStorable", p.isStorable,
    "setCaboose", p.setCaboose,
    "isCaboose", p.isCaboose,
    "setAllAboardCallback", p.setAllAboardCallback,
    "isFromStorage", p.isFromStorage,
    "toJSON", p.toJSON,
    "getStorageKey", p.getStorageKey
    //#if {"excludeModes" : ["PRODUCTION", "PRODUCTIONDEBUG"]}
     ,"getId", p.getId
	//#end
);
<commit_msg>Revert exposing getStorageKey.<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*jslint sub: true */
var p = Action.prototype;
exp(p,
    "auraType", p.auraType,
    "getDef", p.getDef,
    "setParams", p.setParams,
    "setParam", p.setParam,
    "getParam", p.getParam,
    "getParams", p.getParams,
    "setCallback", p.setCallback,
    "run", p.run,
    "runDeprecated", p.runDeprecated,
    "getState", p.getState,
    "getReturnValue", p.getReturnValue,
    "getStorage", p.getStorage,
    "runAfter", p.runAfter,
    "getError", p.getError,
    "setAbortable", p.setAbortable,
    "isAbortable", p.isAbortable,
    "isBackground", p.isBackground,
    "setBackground", p.setBackground,
    "setExclusive", p.setExclusive,
    "isExclusive", p.isExclusive,
    "setChained", p.setChained,
    "setStorable", p.setStorable,
    "getAbortableKey", p.getAbortableKey,
    "isStorable", p.isStorable,
    "setCaboose", p.setCaboose,
    "isCaboose", p.isCaboose,
    "setAllAboardCallback", p.setAllAboardCallback,
    "isFromStorage", p.isFromStorage,
    "toJSON", p.toJSON
    //#if {"excludeModes" : ["PRODUCTION", "PRODUCTIONDEBUG"]}
     ,"getId", p.getId
     ,"getStorageKey", p.getStorageKey
	//#end
);
<|endoftext|>


<commit_before>import React, {
  Component,
  View,
  TextInput,
  StyleSheet,
  ScrollView,
  DeviceEventEmitter,
  Dimensions,
  LayoutAnimation,
  PropTypes,
} from 'react-native';

const {
  height: screenHeight,
  width: screenWidth
} = Dimensions.get('window');

const animations = {
    layout: {
        spring: {
            duration: 250,
            create: {
                duration: 250,
                type: LayoutAnimation.Types.easeInEaseOut,
                property: LayoutAnimation.Properties.opacity
            },
            update: {
                type: LayoutAnimation.Types.spring,
                springDamping: 200
            }
        },
        easeInEaseOut: {
            duration: 50,
            create: {
                type: LayoutAnimation.Types.easeInEaseOut,
                property: LayoutAnimation.Properties.scaleXY
            },
            update: {
                delay: 500,
                type: LayoutAnimation.Types.easeInEaseOut
            }
        }
    }
};

export default class SuperScroll extends Component {

  constructor(){
    super();
    this.state = {
      scrollPosition : 0
    }
    this._refCreator           = this._refCreator.bind(this);
    this._focusNode            = this._focusNode.bind(this);
    this._keyboardWillHide     = this._keyboardWillHide.bind(this);
    this._keyboardWillShow     = this._keyboardWillShow.bind(this);
    this._updateScrollPosition = this._updateScrollPosition.bind(this);
  }

  componentDidMount() {
    this._listeners = [
      DeviceEventEmitter.addListener('keyboardWillShow', this._keyboardWillShow),
      DeviceEventEmitter.addListener('keyboardWillHide', this._keyboardWillHide)
    ];
  }

  componentWillUpdate(props, state) {
    if (state.keyboardUp !== this.state.keyboardUp) {
      LayoutAnimation.configureNext(animations.layout.spring)
    }
  }

  componentWillReceiveProps(props) {
    if (props.forceFocusFieldIndex !== undefined){
      this._focusField('input_' + props.forceFocusFieldIndex)
    }
  }

  componentWillUnmount() {
    this._listeners.forEach((listener) => listener.remove());
  }

  _keyboardWillShow(e) {
    const scrollWindowHeight = this._findScrollWindowHeight(e.endCoordinates.height)

    this.setState({
      scrollWindowHeight,
      keyBoardUp: true
    })
  }

  _keyboardWillHide() {
    this.setState({
      keyBoardUp: false
    });
    this._superScroll && this._superScroll.scrollTo(0);
  }

  _refCreator (ref) {
    return component => this[ref] = component
  }

  _focusField (ref) {
    this[ref].focus()
  }

  _focusNode (focusedNode) {
    setTimeout(() => {
      const {
        scrollPosition,
        scrollWindowHeight,
      }         = this.state;
      const num = React.findNodeHandle(this._superScroll);

        this[focusedNode].measureLayout(num, (X,Y,W,H) => {
          const py = Y - scrollPosition;

          if ( py + H > scrollWindowHeight ){
            const nextScrollPosition = (Y + H) - scrollWindowHeight;

            this._superScroll.scrollTo(nextScrollPosition);
            this.setState({scrollPosition:nextScrollPosition })
          } else if ( py < 0 ) {
            this._superScroll.scrollTo(Y)
            this.setState({ scrollPosition: Y })
          }
        });
      }, 0);
  }

  _updateScrollPosition(event){
    this.setState({ scrollPosition: event.nativeEvent.contentOffset.y });
  }

  render () {
    let inputIndex   = 0;
    const superClone = (element, i) => {
      const { superScrollOptions } = element.props;
      let superProps               = { key: i };

      if (superScrollOptions.type === 'text') {
        const ref          = 'input_' + inputIndex;

        superProps.onFocus = () => this._focusNode(ref,'text');
        superProps.ref     = this._refCreator(ref);

        if (superScrollOptions.moveToNext === true) {
          const nextRef              = 'input_' + (inputIndex+1);
          superProps.blurOnSubmit    = false;
          superProps.onSubmitEditing = () => this._focusField(nextRef);
        }
        inputIndex += 1
      }

      return React.cloneElement(element, superProps)
    }

    function recursivelyCheckAndAdd(children, i) {
      return React.Children.map(children, (child, j) => {

        if (child.props.superScrollOptions !== undefined) {
          return superClone(child, ''+i+j);
        } else if (child.props.children !== undefined) {
          return React.cloneElement(child, {key: i}, recursivelyCheckAndAdd(child.props.children, ''+i+j));
        } else {
          return React.cloneElement(child, {key: i});
        }
      })
    }

    const content = recursivelyCheckAndAdd(this.props.children,'0');

    return (
      <View
        style = {{ flex: 1}}
        onLayout = {x => {
          const {y, height}  = x.nativeEvent.layout;
          const spaceBelow   = screenHeight - y - height;

          this._findScrollWindowHeight = (keyboardHeight) => {
            return height - Math.max(keyboardHeight - spaceBelow, 0);
          }
        }}
      >
        <View
          style = {this.state.keyBoardUp ? { height: this.state.scrollWindowHeight } : { flex: 1}}
        >
          <ScrollView
            ref                              = { component => this._superScroll=component}
            automaticallyAdjustContentInsets = {false}
            scrollsToTop                     = {false}
            scrollEnabled                    = {this.state.keyBoardUp}
            style                            = {{ flex: 1}}
            onScroll                         = {this._updateScrollPosition}
            scrollEventThrottle              = {16}
            contentContainerStyle            = {this.props.contentContainerStyle}
            centerContent                    = {true}
            keyboardShouldPersistTaps        = {true}
          >
            {content}
          </ScrollView>
        </View>
      </View>
    );
  }
}

SuperScroll.propTypes = {
  children: PropTypes.arrayOf(PropTypes.element),
  contentContainerStyle: PropTypes.number,
  forceFocusFieldIndex: PropTypes.number
}
<commit_msg>first go at PropTypes for superscroll and customisable container styles, fixes #1 and fixes #2<commit_after>import React, {
  Component,
  View,
  TextInput,
  StyleSheet,
  ScrollView,
  DeviceEventEmitter,
  Dimensions,
  LayoutAnimation,
  PropTypes,
} from 'react-native';

const {
  height: screenHeight,
  width: screenWidth
} = Dimensions.get('window');

const animations = {
    layout: {
        spring: {
            duration: 250,
            create: {
                duration: 250,
                type: LayoutAnimation.Types.easeInEaseOut,
                property: LayoutAnimation.Properties.opacity
            },
            update: {
                type: LayoutAnimation.Types.spring,
                springDamping: 200
            }
        },
        easeInEaseOut: {
            duration: 50,
            create: {
                type: LayoutAnimation.Types.easeInEaseOut,
                property: LayoutAnimation.Properties.scaleXY
            },
            update: {
                delay: 500,
                type: LayoutAnimation.Types.easeInEaseOut
            }
        }
    }
};

export default class SuperScroll extends Component {

  constructor(){
    super();
    this.state = {
      scrollPosition : 0
    }
    this._refCreator           = this._refCreator.bind(this);
    this._focusNode            = this._focusNode.bind(this);
    this._keyboardWillHide     = this._keyboardWillHide.bind(this);
    this._keyboardWillShow     = this._keyboardWillShow.bind(this);
    this._updateScrollPosition = this._updateScrollPosition.bind(this);
  }

  componentDidMount() {
    this._listeners = [
      DeviceEventEmitter.addListener('keyboardWillShow', this._keyboardWillShow),
      DeviceEventEmitter.addListener('keyboardWillHide', this._keyboardWillHide)
    ];
  }

  componentWillUpdate(props, state) {
    if (state.keyboardUp !== this.state.keyboardUp) {
      LayoutAnimation.configureNext(animations.layout.spring)
    }
  }

  componentWillReceiveProps(props) {
    if (props.forceFocusFieldIndex !== undefined){
      this._focusField('input_' + props.forceFocusFieldIndex)
    }
  }

  componentWillUnmount() {
    this._listeners.forEach((listener) => listener.remove());
  }

  _keyboardWillShow(e) {
    const scrollWindowHeight = this._findScrollWindowHeight(e.endCoordinates.height)

    this.setState({
      scrollWindowHeight,
      keyBoardUp: true
    })
  }

  _keyboardWillHide() {
    this.setState({
      keyBoardUp: false
    });
    this._superScroll && this._superScroll.scrollTo(0);
  }

  _refCreator (ref) {
    return component => this[ref] = component
  }

  _focusField (ref) {
    this[ref].focus()
  }

  _focusNode (focusedNode) {
    setTimeout(() => {
      const {
        scrollPosition,
        scrollWindowHeight,
      }         = this.state;
      const num = React.findNodeHandle(this._superScroll);

        this[focusedNode].measureLayout(num, (X,Y,W,H) => {
          const py = Y - scrollPosition;

          if ( py + H > scrollWindowHeight ){
            const nextScrollPosition = (Y + H) - scrollWindowHeight;

            this._superScroll.scrollTo(nextScrollPosition);
            this.setState({scrollPosition:nextScrollPosition })
          } else if ( py < 0 ) {
            this._superScroll.scrollTo(Y)
            this.setState({ scrollPosition: Y })
          }
        });
      }, 0);
  }

  _updateScrollPosition(event){
    this.setState({ scrollPosition: event.nativeEvent.contentOffset.y });
  }

  render () {
    const {
      children: scrollChildren,
      contentContainerStyle,
      scrollContainerStyle
    }                = this.props;
    let inputIndex   = 0;
    const superClone = (element, i) => {
      const { superScrollOptions } = element.props;
      let superProps               = { key: i };

      if (superScrollOptions.type === 'text') {
        const ref          = 'input_' + inputIndex;

        superProps.onFocus = () => this._focusNode(ref,'text');
        superProps.ref     = this._refCreator(ref);

        if (superScrollOptions.moveToNext === true) {
          const nextRef              = 'input_' + (inputIndex+1);
          superProps.blurOnSubmit    = false;
          superProps.onSubmitEditing = () => this._focusField(nextRef);
        }
        inputIndex += 1
      }

      return React.cloneElement(element, superProps)
    }

    function recursivelyCheckAndAdd(children, i) {
      return React.Children.map(children, (child, j) => {

        if (child.props.superScrollOptions !== undefined) {
          return superClone(child, ''+i+j);
        } else if (child.props.children !== undefined) {
          return React.cloneElement(child, {key: i}, recursivelyCheckAndAdd(child.props.children, ''+i+j));
        } else {
          return React.cloneElement(child, {key: i});
        }
      })
    }

    const content = recursivelyCheckAndAdd(scrollChildren, '0');

    return (
      <View
        style = {scrollContainerStyle}
        onLayout = {x => {
          const { y, height } = x.nativeEvent.layout;
          const spaceBelow    = screenHeight - y - height;

          this._findScrollWindowHeight = (keyboardHeight) => {
            return height - Math.max(keyboardHeight - spaceBelow, 0);
          }
        }}
      >
        <ScrollView
          ref                              = { component => this._superScroll=component}
          automaticallyAdjustContentInsets = {false}
          scrollsToTop                     = {false}
          scrollEnabled                    = {this.state.keyBoardUp}
          style                            = {this.state.keyBoardUp ? { height: this.state.scrollWindowHeight } : styles.flex1}
          onScroll                         = {this._updateScrollPosition}
          scrollEventThrottle              = {16}
          contentContainerStyle            = {contentContainerStyle}
          centerContent                    = {true}
          keyboardShouldPersistTaps        = {true}
        >
          {content}
        </ScrollView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  flex1: {
    flex: 1
  }
})

SuperScroll.propTypes = {
  children:              PropTypes.arrayOf(PropTypes.element),
  forceFocusFieldIndex:  PropTypes.number,
  scrollContainerStyle:  PropTypes.number,
  contentContainerStyle: PropTypes.number
}

SuperScroll.defaultProps = {
  scrollContainerStyle: styles.flex1
}
<|endoftext|>


<commit_before>/**
 * Tatoeba Project, free collaborative creation of multilingual corpuses project
 * Copyright (C) 2014 Gilles Bedel
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

$(document).ready(function(){
    $(".annexeLogEntry").each(function(){
        var historyRecord = $(this);

        historyRecord.find('a').each(function(){
            var historyRecordSentenceLink = $(this).attr('href');
            var sentence = $(".sentenceContent > a[href='" + historyRecordSentenceLink + "']").parent();
            historyRecord.hover(
                function() {
                    sentence.addClass("highlighted");
                    historyRecord.addClass("historyHighlighted");
                },
                function() {
                    sentence.removeClass("highlighted");
                    historyRecord.removeClass("historyHighlighted");
                }
            );
        });
    });
});
<commit_msg>Make log highlight touchscreen-friendly.<commit_after>/**
 * Tatoeba Project, free collaborative creation of multilingual corpuses project
 * Copyright (C) 2014 Gilles Bedel
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

$(document).ready(function(){
    $(".annexeLogEntry").each(function(){
        var historyRecord = $(this);

        historyRecord.find('a').each(function(){
            var historyRecordSentenceLink = $(this).attr('href');
            var sentence = $(".sentenceContent > a[href='" + historyRecordSentenceLink + "']").parent();
            var updateHighlight = function() {
                $(".sentenceContent.highlighted").removeClass("highlighted");
                $(".annexeLogEntry.historyHighlighted").removeClass("historyHighlighted");
                sentence.addClass("highlighted");
                historyRecord.addClass("historyHighlighted");
            };

            historyRecord.hover(updateHighlight, null);
            // Touchscreens cannot (or simulate) hovering, so let them use simple click instead
            historyRecord.click(function() { updateHighlight() });
        });
    });
});
<|endoftext|>


<commit_before>// Initialise popup pointer
/*var popupWin = null;

function openPopup(jid) {
	var url = BASE_URI + PAGE_KEY_URI + "visio&f="+jid
	if( !popupWin || popupWin.closed ) {
		popupWin = window.open( url, "popupWin",  "height=480,width=640,directories=0,titlebar=0,toolbar=0,location=0,status=0, personalbar=0,menubar=0,resizable=0" );
	} else popupWin.focus();
}

function closePopup() {
    popupWin.close();
}

function focusPopup() {
    popupWin.focus();
}

function popUpEvent(args) {
	if( popupWin && !popupWin.closed ) {
		// The popup is open so call it
        var func = args[0];
        args.shift();
		var params = args;

        window['popupWin'][func](params);
	} else {
		// The popup is closed so open it
		openPopup();
	}
}*/

var Popup = {
    win : null,
    jid : null,

    setJid: function(jid) {
        this.jid = jid;
    },

    open: function(jid) {
        console.log('Opening the Popup');
        var url = BASE_URI + PAGE_KEY_URI + "visio&f="+jid

        this.setJid(jid);

        if( !this.win || this.win.closed ) {
            this.win = window.open( url, "win",  "height=480,width=640,directories=0,titlebar=0,toolbar=0,location=0,status=0, personalbar=0,menubar=0,resizable=0" );
        } else this.win.focus();
    },

    close: function() {
        this.win.close();
    },

    focus: function() {
        this.win.focus();
    },

    send: function(args) {
        var func = args[0];
        args.shift();
        var params = args;

        console.log('Calling the Popup');
        this.win[func](params);
    },

    call: function(args) {
        if( this.win && !this.win.closed ) {
            // The popup is open so call it
            this.win[func](params);
        } else if(this.jid) {
            // The popup is closed so open it
            console.log('We open the Popup');
            this.open(this.jid);

            console.log('We wait a little');
            setTimeout(function() {Popup.send(args); }, 1000);
        }
    }
}
<commit_msg>- Fix a dumb issue<commit_after>// Initialise popup pointer
/*var popupWin = null;

function openPopup(jid) {
	var url = BASE_URI + PAGE_KEY_URI + "visio&f="+jid
	if( !popupWin || popupWin.closed ) {
		popupWin = window.open( url, "popupWin",  "height=480,width=640,directories=0,titlebar=0,toolbar=0,location=0,status=0, personalbar=0,menubar=0,resizable=0" );
	} else popupWin.focus();
}

function closePopup() {
    popupWin.close();
}

function focusPopup() {
    popupWin.focus();
}

function popUpEvent(args) {
	if( popupWin && !popupWin.closed ) {
		// The popup is open so call it
        var func = args[0];
        args.shift();
		var params = args;

        window['popupWin'][func](params);
	} else {
		// The popup is closed so open it
		openPopup();
	}
}*/

var Popup = {
    win : null,
    jid : null,

    setJid: function(jid) {
        this.jid = jid;
    },

    open: function(jid) {
        console.log('Opening the Popup');
        var url = BASE_URI + PAGE_KEY_URI + "visio&f="+jid

        this.setJid(jid);

        if( !this.win || this.win.closed ) {
            this.win = window.open( url, "win",  "height=480,width=640,directories=0,titlebar=0,toolbar=0,location=0,status=0, personalbar=0,menubar=0,resizable=0" );
        } else this.win.focus();
    },

    close: function() {
        this.win.close();
    },

    focus: function() {
        this.win.focus();
    },

    send: function(args) {
        var func = args[0];
        args.shift();
        var params = args;

        console.log('Calling the Popup');
        this.win[func](params);
    },

    call: function(args) {
        if( this.win && !this.win.closed ) {
            // The popup is open so call it
            Popup.send(args);
        } else if(this.jid) {
            // The popup is closed so open it
            console.log('We open the Popup');
            this.open(this.jid);

            console.log('We wait a little');
            setTimeout(function() {Popup.send(args); }, 1000);
        }
    }
}
<|endoftext|>


<commit_before>import extend from 'extend'

export default class Form {

  constructor() {
    this._form = {

    }
    this._key = []
  }

  /**
   * Get all input from a template
   * @return {Array} array of input form
   */
  get form(){
    return this._form
  }

  /**
   * Check if key is not is the form array
   * @param  {[type]} key [description]
   * @return {[type]}     [description]
   */
  dontHaveKey(key){
    return this._key[key] == null
  }

  /**
   * Add entry to abe engine form
   * @param {String} type        textarea | text | meta | link | image | ...
   * @param {String} key         unique ID, no space allowed
   * @param {String} desc        input description
   * @param {Int}    max-length   maximum characteres allowed inside input
   * @param {String} tab         tab name
   * @param {String} jsonValue
   * @return {Void}
   */
  add(obj) {
    var defaultValues = {
      autocomplete: null,
      block:'',
      desc: '',
      display: null,
      editable: true,
      key: '',
      'max-length': null,
      order: 0,
      placeholder: '',
      prefill: false,
      'prefill-quantity': null,
      reload: false,
      required: false,
      source: null,
      tab: 'default',
      type: 'text',
      value: null,
      visible: true,
      precontribTemplate: ''
    }

    obj = extend(true, defaultValues, obj)
    obj.key = obj.key//.replace(/\./, '-')

    if(obj.key.indexOf('[') < 0 && obj.key.indexOf('.') > -1) {
      obj.block = obj.key.split('.')[0]
    }

    if(this._form[obj.tab] == null) this._form[obj.tab] = {item:[]}

    this._key[obj.key] = true // save key for dontHaveKey()
    this._form[obj.tab].item.push(obj)
  }
}<commit_msg>ic: cleaning code<commit_after>import extend from 'extend'

export default class Form {

  constructor() {
    this._form = {}
    this._key = []
  }

  /**
   * Get all input from a template
   * @return {Array} array of input form
   */
  get form(){
    return this._form
  }

  /**
   * Check if key is not in the form array
   * @param  {[type]} key [description]
   * @return {[type]}     [description]
   */
  dontHaveKey(key){
    return this._key[key] == null
  }

  /**
   * Add entry to abe engine form
   * @param {String} type        textarea | text | meta | link | image | ...
   * @param {String} key         unique ID, no space allowed
   * @param {String} desc        input description
   * @param {Int}    max-length   maximum characteres allowed inside input
   * @param {String} tab         tab name
   * @param {String} jsonValue
   * @return {Void}
   */
  add(obj) {
    var defaultValues = {
      autocomplete: null,
      block:'',
      desc: '',
      display: null,
      editable: true,
      key: '',
      'max-length': null,
      order: 0,
      placeholder: '',
      prefill: false,
      'prefill-quantity': null,
      reload: false,
      required: false,
      source: null,
      tab: 'default',
      type: 'text',
      value: null,
      visible: true,
      precontribTemplate: ''
    }

    obj = extend(true, defaultValues, obj)

    if(obj.key.indexOf('[') < 0 && obj.key.indexOf('.') > -1) {
      obj.block = obj.key.split('.')[0]
    }

    if(this._form[obj.tab] == null) this._form[obj.tab] = {item:[]}

    this._key[obj.key] = true // save key for dontHaveKey()
    this._form[obj.tab].item.push(obj)
  }
}<|endoftext|>


<commit_before><commit_msg>Remove extraneous titles from block definitions<commit_after><|endoftext|>


<commit_before>(function(config, models, views, routers, utils, templates) {

views.Post = Backbone.View.extend({

  id: 'post',

  events: {
    'click .save': '_save',
    'click a.toggle.view': '_toggleView',
    'click a.toggle.meta': '_toggleMeta',
    'change input': '_makeDirty',
    'change #post_published': 'updateMetaData',
    'click .delete': '_delete',
    'click .toggle-options': '_toggleOptions'
  },

  _toggleOptions: function() {
    $('.options').toggle();
    return false;
  },

  _delete: function() {
    if (confirm("Are you sure you want to delete that document?")) {
      deletePost(app.state.user, app.state.repo, app.state.branch, this.model.path, this.model.file, _.bind(function(err) {
        if (err) return alert('Error during deletion. Please wait 30 seconds and try again.');
        router.navigate([app.state.user, app.state.repo, app.state.branch, this.model.path].join('/'), true);
      }, this));
    }
    return false;
  },

  updateURL: function() {
    var url = _.compact([app.state.user, app.state.repo, app.state.branch, this.model.path, this.model.file]);

    if (!this.model.preview) url.push('edit');
    router.navigate(url.join('/'), false);
  },

  updateFilename: function(file, cb) {
    var that = this;

    if (!_.validFilename(file)) return cb('error');
    app.state.path = this.model.path;
    app.state.file = file;
    // rerender header to reflect the filename change
    app.instance.header.render();
    this.model.file = file;

    function finish() {
      that.updateURL();
      app.state.path = that.model.path + "/" + file;
    }

    if (this.model.persisted) {
      movePost(app.state.user, app.state.repo, app.state.branch, this.model.path + "/" + this.model.file, this.model.path + "/" + file, _.bind(function(err) {
        if (!err) finish()
        err ? cb('error') : cb(null)
      }, this));
    } else {
      finish();
      cb(null);
    }
  },

  _makeDirty: function(e) {
    this.dirty = true;
    if (this.editor) this.model.content = this.editor.getValue();
    if (this.metadataEditor) this.model.raw_metadata = this.metadataEditor.getValue();
    // $('.document')[0].scrollLeft = '-100%';
    if (!this.$('.button.save').hasClass('saving')) {
      this.$('.button.save').html('SAVE');
      this.$('.button.save').removeClass('inactive error');
    }
  },

  _save: function(e) {
    if (!this.dirty) return false;
    e.preventDefault();
    this.updatePost('Updated '+ this.model.file);
  },

  _toggleView: function(e) {
    this.toggleView($(e.currentTarget).attr('data-view'));

    // Refresh editors to overcome CodeMirror tipsiness
    this.editor.refresh();
    if (this.metadataEditor) this.metadataEditor.refresh();
    return false;
  },

  _toggleMeta: function(e) {
    if (e) e.preventDefault();
    $('.toggle.meta').toggleClass('active');
    $('.metadata').toggle();

    return false;
  },

  toggleView: function(view) {
    this.view = view;
    if (view === 'preview') {
      this.model.preview = true;
      this.$('.post-content').html(marked(this.model.content));
    } else {
      this.model.preview = false;
    }
    this.updateURL();
    $('.toggle').removeClass('active');
    $('.toggle.'+view).addClass('active');

    $('.document .surface').removeClass('preview cheatsheet compose');
    $('.document .surface').addClass(view);
  },

  right: function() {
    var view = $('.toggle.active').attr('data-view');
    if (view === 'preview') return;
    if (view === 'compose') return this.toggleView('preview');
    return this.toggleView('compose');
  },

  left: function() {
    var view = $('.toggle.active').attr('data-view');
    if (view === 'cheatsheet') return;
    if (view === 'compose') return this.toggleView('cheatsheet');
    return this.toggleView('compose');
  },

  initialize: function() {
    this.mode = "edit";
    if (!window.shortcutsRegistered) {
      key('⌘+s, ctrl+s', _.bind(function() { this.updatePost("Updated " + this.model.file); return false; }, this));
      key('ctrl+shift+right', _.bind(function() { this.right(); return false; }, this));
      key('ctrl+shift+left', _.bind(function() { this.left(); return false; }, this));
      key('esc', _.bind(function() { this.toggleView('compose'); return false; }, this));
      window.shortcutsRegistered = true;
    }
  },

  parseMetadata: function(metadata) {
    var metadata = this.metadataEditor.getValue();
    if (!metadata) return {};
    try {
      return jsyaml.load(metadata);
    } catch(err) {
      return null;
    }
  },

  // TODO: remove comments and simplify after we are sure that we don't want to parse metadata
  updateMetaData: function() {

    // Update published
    function updatePublished(yamlStr, published) {
      var regex = /published: (false|true)/;
      if (yamlStr.match(regex)) {
        return yamlStr.replace(regex, "published: " + !!published);
      } else {
        return yamlStr + "\npublished: " + !!published;
      }
    }

    this.model.raw_metadata = this.metadataEditor.getValue();
    var published = this.$('#post_published').prop('checked');
    var metadata = this.parseMetadata(this.model.raw_metadata);
    if (metadata) {
      metadata.published = published;
      this.model.metadata = metadata;
      this.model.raw_metadata = updatePublished(this.model.raw_metadata, published);
      this.metadataEditor.setValue(this.model.raw_metadata);

      if (this.model.metadata.published) {
        $('#post').addClass('published');
      } else {
        $('#post').removeClass('published');
      }
      return true;
    } else {
      return false;
    }
  },

  updatePost: function(message) {
    var file = $('input.filename').val();
    var that = this;

    function updateState(label, classes) {
      $('.button.save').html(label)
                       .removeClass('inactive error saving')
                       .addClass(classes);
    }

    function save() {
      if (!app.state.jekyll || that.updateMetaData()) {
        saveFile(app.state.user, app.state.repo, app.state.branch, that.model.path, that.model.file, that.model.raw_metadata, that.editor.getValue(), message, function(err) {
          if (err) {
            _.delay(function() { that._makeDirty() }, 3000);
            updateState('! Try again in 30 seconds', 'error');
            return;
          }
          that.dirty = false;
          that.model.persisted = true;
          that.updateURL();
          updateState('SAVED', 'inactive');
        });
      } else {
        updateState('! Metadata', 'error');
      }
    }

    updateState('SAVING ...', 'inactive saving');
    that.$('.document-menu-content .options').hide();

    if (file === this.model.file) return save();
    this.updateFilename(file, function(err) {
      err ? updateState('! Filename', 'error') : save();
    });
  },

  keyMap: function() {
    var that = this;
    return {
      "Shift-Ctrl-Left": function(codemirror) {
        that.left();
      },
      "Shift-Ctrl-Right": function(codemirror) {
        that.right();
      },
      "Shift-Ctrl-M": function(codemirror) {
        that._toggleMeta();
      },
      "Ctrl-S": function(codemirror) {
        that.updatePost("Updated " + that.model.file);
      }
    };
  },

  initEditor: function() {
    var that = this;
    setTimeout(function() {
      if (app.state.jekyll) {
        that.metadataEditor = CodeMirror($('#raw_metadata')[0], {
          mode: 'yaml',
          value: that.model.raw_metadata,
          theme: 'prose-dark',
          lineWrapping: true,
          extraKeys: that.keyMap(),
          onChange: _.bind(that._makeDirty, that)
        });
        $('#post .metadata').hide();
      }

      that.editor = CodeMirror($('#code')[0], {
        mode: that.model.markdown ? "markdown" : null,
        value: that.model.content,
        lineWrapping: true,
        extraKeys: that.keyMap(),
        matchBrackets: true,
        theme: 'prose-bright',
        onChange: _.bind(that._makeDirty, that)
      });

    }, 100);
  },

  // UpdateHeight
  updateHeight: function() {
    $('.personalities-wrapper').height(this.$('.content .CodeMirror').height());
  },

  render: function() {
    var that = this;
    $(this.el).html(templates.post(_.extend(this.model, { mode: this.mode, jekyll: app.state.jekyll })));
    if (this.model.metadata.published) $(this.el).addClass('published');
    this.initEditor();
    return this;
  }
});

}).apply(this, window.args);
<commit_msg>Use proper commit message for newly created files.<commit_after>(function(config, models, views, routers, utils, templates) {

views.Post = Backbone.View.extend({

  id: 'post',

  events: {
    'click .save': '_save',
    'click a.toggle.view': '_toggleView',
    'click a.toggle.meta': '_toggleMeta',
    'change input': '_makeDirty',
    'change #post_published': 'updateMetaData',
    'click .delete': '_delete',
    'click .toggle-options': '_toggleOptions'
  },

  _toggleOptions: function() {
    $('.options').toggle();
    return false;
  },

  _delete: function() {
    if (confirm("Are you sure you want to delete that document?")) {
      deletePost(app.state.user, app.state.repo, app.state.branch, this.model.path, this.model.file, _.bind(function(err) {
        if (err) return alert('Error during deletion. Please wait 30 seconds and try again.');
        router.navigate([app.state.user, app.state.repo, app.state.branch, this.model.path].join('/'), true);
      }, this));
    }
    return false;
  },

  updateURL: function() {
    var url = _.compact([app.state.user, app.state.repo, app.state.branch, this.model.path, this.model.file]);

    if (!this.model.preview) url.push('edit');
    router.navigate(url.join('/'), false);
  },

  updateFilename: function(file, cb) {
    var that = this;

    if (!_.validFilename(file)) return cb('error');
    app.state.path = this.model.path;
    app.state.file = file;
    // rerender header to reflect the filename change
    app.instance.header.render();
    this.model.file = file;

    function finish() {
      that.updateURL();
      app.state.path = that.model.path + "/" + file;
    }

    if (this.model.persisted) {
      movePost(app.state.user, app.state.repo, app.state.branch, this.model.path + "/" + this.model.file, this.model.path + "/" + file, _.bind(function(err) {
        if (!err) finish()
        err ? cb('error') : cb(null)
      }, this));
    } else {
      finish();
      cb(null);
    }
  },

  _makeDirty: function(e) {
    this.dirty = true;
    if (this.editor) this.model.content = this.editor.getValue();
    if (this.metadataEditor) this.model.raw_metadata = this.metadataEditor.getValue();
    if (!this.$('.button.save').hasClass('saving')) {
      this.$('.button.save').html('SAVE');
      this.$('.button.save').removeClass('inactive error');
    }
  },

  _save: function(e) {
    if (!this.dirty) return false;
    e.preventDefault();
    this.updatePost();
  },

  _toggleView: function(e) {
    this.toggleView($(e.currentTarget).attr('data-view'));

    // Refresh CodeMirror instances
    this.editor.refresh();
    if (this.metadataEditor) this.metadataEditor.refresh();
    return false;
  },

  _toggleMeta: function(e) {
    if (e) e.preventDefault();
    $('.toggle.meta').toggleClass('active');
    $('.metadata').toggle();

    return false;
  },

  toggleView: function(view) {
    this.view = view;
    if (view === 'preview') {
      this.model.preview = true;
      this.$('.post-content').html(marked(this.model.content));
    } else {
      this.model.preview = false;
    }
    this.updateURL();
    $('.toggle').removeClass('active');
    $('.toggle.'+view).addClass('active');

    $('.document .surface').removeClass('preview cheatsheet compose');
    $('.document .surface').addClass(view);
  },

  right: function() {
    var view = $('.toggle.active').attr('data-view');
    if (view === 'preview') return;
    if (view === 'compose') return this.toggleView('preview');
    return this.toggleView('compose');
  },

  left: function() {
    var view = $('.toggle.active').attr('data-view');
    if (view === 'cheatsheet') return;
    if (view === 'compose') return this.toggleView('cheatsheet');
    return this.toggleView('compose');
  },

  initialize: function() {
    this.mode = "edit";
    if (!window.shortcutsRegistered) {
      key('⌘+s, ctrl+s', _.bind(function() { this.updatePost(); return false; }, this));
      key('ctrl+shift+right', _.bind(function() { this.right(); return false; }, this));
      key('ctrl+shift+left', _.bind(function() { this.left(); return false; }, this));
      key('esc', _.bind(function() { this.toggleView('compose'); return false; }, this));
      window.shortcutsRegistered = true;
    }
  },

  parseMetadata: function(metadata) {
    var metadata = this.metadataEditor.getValue();
    if (!metadata) return {};
    try {
      return jsyaml.load(metadata);
    } catch(err) {
      return null;
    }
  },

  // TODO: remove comments and simplify after we are sure that we don't want to parse metadata
  updateMetaData: function() {

    // Update published
    function updatePublished(yamlStr, published) {
      var regex = /published: (false|true)/;
      if (yamlStr.match(regex)) {
        return yamlStr.replace(regex, "published: " + !!published);
      } else {
        return yamlStr + "\npublished: " + !!published;
      }
    }

    this.model.raw_metadata = this.metadataEditor.getValue();
    var published = this.$('#post_published').prop('checked');
    var metadata = this.parseMetadata(this.model.raw_metadata);
    if (metadata) {
      metadata.published = published;
      this.model.metadata = metadata;
      this.model.raw_metadata = updatePublished(this.model.raw_metadata, published);
      this.metadataEditor.setValue(this.model.raw_metadata);

      if (this.model.metadata.published) {
        $('#post').addClass('published');
      } else {
        $('#post').removeClass('published');
      }
      return true;
    } else {
      return false;
    }
  },

  updatePost: function() {
    var file = $('input.filename').val();
    var that = this;
    var message = this.model.persisted ? "Updated " + file : "Created " + file;

    function updateState(label, classes) {
      $('.button.save').html(label)
                       .removeClass('inactive error saving')
                       .addClass(classes);
    }

    function save() {
      if (!app.state.jekyll || that.updateMetaData()) {

        saveFile(app.state.user, app.state.repo, app.state.branch, that.model.path, file, that.model.raw_metadata, that.editor.getValue(), message, function(err) {
          if (err) {
            _.delay(function() { that._makeDirty() }, 3000);
            updateState('! Try again in 30 seconds', 'error');
            return;
          }
          that.dirty = false;
          that.model.persisted = true;
          that.model.file = file;
          that.updateURL();
          updateState('SAVED', 'inactive');
        });
      } else {
        updateState('! Metadata', 'error');
      }
    }

    updateState('SAVING ...', 'inactive saving');
    that.$('.document-menu-content .options').hide();

    if (file === this.model.file) return save();
    this.updateFilename(file, function(err) {
      err ? updateState('! Filename', 'error') : save();
    });
  },

  keyMap: function() {
    var that = this;
    return {
      "Shift-Ctrl-Left": function(codemirror) {
        that.left();
      },
      "Shift-Ctrl-Right": function(codemirror) {
        that.right();
      },
      "Shift-Ctrl-M": function(codemirror) {
        that._toggleMeta();
      },
      "Ctrl-S": function(codemirror) {
        that.updatePost();
      }
    };
  },

  initEditor: function() {
    var that = this;
    setTimeout(function() {
      if (app.state.jekyll) {
        that.metadataEditor = CodeMirror($('#raw_metadata')[0], {
          mode: 'yaml',
          value: that.model.raw_metadata,
          theme: 'prose-dark',
          lineWrapping: true,
          extraKeys: that.keyMap(),
          onChange: _.bind(that._makeDirty, that)
        });
        $('#post .metadata').hide();
      }

      that.editor = CodeMirror($('#code')[0], {
        mode: that.model.markdown ? "markdown" : null,
        value: that.model.content,
        lineWrapping: true,
        extraKeys: that.keyMap(),
        matchBrackets: true,
        theme: 'prose-bright',
        onChange: _.bind(that._makeDirty, that)
      });

    }, 100);
  },

  // UpdateHeight
  updateHeight: function() {
    $('.personalities-wrapper').height(this.$('.content .CodeMirror').height());
  },

  render: function() {
    var that = this;
    $(this.el).html(templates.post(_.extend(this.model, { mode: this.mode, jekyll: app.state.jekyll })));
    if (this.model.metadata.published) $(this.el).addClass('published');
    this.initEditor();
    return this;
  }
});

}).apply(this, window.args);
<|endoftext|>