<commit_before>/**
 * js/com/Element.js
 * Author: H.Alper Tuna <halpertuna@gmail.com>
 * Date: 12.04.2016
 */

'use strict';

define(['../core/EventHandler', '../core/Utils', './TextElement'], function(EventHandler, Utils, TextElement){
    return EventHandler.extend({
        'init': function(tag){
            if(!tag) tag = 'div';

            this.set('dom', Utils.isString(tag) ? document.createElement(tag) : tag);
            this.set('children', []);
            this.handle('show');
            this.handle('hide');
            this.on('show', function(){this.removeClass('jb-hidden')});
            this.on('hide', function(){this.addClass('jb-hidden')});
        },

        /*
         * Attribute Managing
         *===========================================================*/
        'getAttr': function(attr){
            return this.getDom().getAttribute(attr);
        },
        'setAttr':  function(attr, value){
            this.getDom().setAttribute(attr, value);
            return this.ref;
        },
        'removeAttr': function(attr){
            this.getDom().removeAttribute(attr);
            return this.ref;
        },
        'getStyle': function(key){
            var styles = this.getAttr('style');
            if(styles == null) return;

            styles = styles.split(';');
            for(var i in styles){
                if(styles[i] == '') continue;
                var style = styles[i].split(':');
                if(style[0] == key) return style[1];
            }
        },
        'setStyle': function(key, value){
            var newStyles;
            if(Utils.isSet(value)){
                newStyles = {}
                newStyles[key] = value;
            }else if(Utils.isObject(key))
                newStyles = key;

            var oldStyles = this.getAttr('style');
            var styles = {}
            if(oldStyles != null){
                oldStyles = oldStyles.split(';');
                for(var i in oldStyles){
                    if(oldStyles[i] == '') continue;
                    var style = oldStyles[i].split(':');
                    styles[style[0]] = style[1];
                }
            }

            Utils.extend(styles, newStyles);

            var stylesAttr = '';
            for(var i in styles){
                if(Utils.isNumber(styles[i])) styles[i] += 'px';
                stylesAttr += i + ':' + styles[i] + ';';
            }

            this.setAttr('style', stylesAttr);

            return this.ref;
        },
        'addClass': function(newClasses){
            var classList = this.getDom().classList;
            newClasses = newClasses.split(' ');
            for(var i in newClasses)
                classList.add(newClasses[i]);

            return this.ref;
        },
        'removeClass': function(oldClasses){
            var classList = this.getDom().classList;
            if(classList.length == 0)
                return this.ref;

            oldClasses = oldClasses.split(' ');
            for(var i in oldClasses)
                classList.remove(oldClasses[i]);

            return this.ref;
        },
        'hasClass': function(className){
            return this.getDom().classList.contains(className);
        },
        'toggleClass': function(className){
            if(this.hasClass(className))
                return this.removeClass(className);
            return this.addClass(className);
        },

        /*
         * Content Managing
         *===========================================================*/
        'clear': function(){
            this.getDom().innerHTML = '';
            return this.ref;
        },
        'add': function(){
            Utils.each(arguments, function(element){
                if(Utils.isNumber(element)) element = Utils.toString(element);
                if(!Utils.isString(element) && (!element || !element.getDom))
                    //TODO Error
                    throw 'Child has to be an Element, string or number.';

                if(Utils.isString(element))
                    element = TextElement.new(element);

                var dom = this.get('dom');
                dom.appendChild(element.getDom());

                element.set('parent', this);
                this.get('children').push(element);
            }, this);

            return this.ref;
        },
        'prepend': function(){
            Utils.each(arguments, function(element){
                if(Utils.isNumber(element)) element = Utils.toString(element);
                if(!Utils.isString(element) && (!element || !element.getDom))
                    //TODO Error
                    throw 'Child has to be an Element, string or number.';

                if(Utils.isString(element))
                    element = TextElement.new(element);

                var dom = this.getDom();
                dom.insertBefore(element.getDom(), dom.firstChild);

                element.set('parent', this);
                this.get('children').unshift(element);
            }, this);

            return this.ref;
        },
        'remove': function(element){
            //Remove element
            if(element){
                this.getDom().removeChild(element.getDom());

                element.unset('parent');
                var children = this.get('children');
                children.splice(children.indexOf(element), -1);
                return this.ref;
            }

            //Remove this from parent
            this.get('parent').remove(this);

            return this.ref;
        },

        /*
         * Event Handling
         *===========================================================*/
        'on': function(action, func){
            try{
                this.super.on(action, func);
            }catch(e){
                this.getDom().addEventListener(action, func);
            }
            return this.ref;
        },
        'off': function(action, func){
            try{
                this.super.off(action, func);
            }catch(e){
                this.getDom().removeEventListener(action, func);
            }
            return this.ref;
        },
        'trigger': function(action, event){
            try{
                this.super.trigger(action, event);
            }catch(e){
                this.getDom().dispatchEvent(new Event(action));
            }
            return this.ref;
        },

        /*
         * Ready-to-use handled events
         *===========================================================*/
        'hide': function(){
            return this.trigger('hide');
        },
        'show': function(){
            return this.trigger('show');
        },

        /*'animate': function(property, value, unit, duration){
            var clock = this.get('animationClock');
            if(Utils.isSet(clock)) clearInterval(clock);

            if(!unit) unit = 'px';
            if(!duration) duration = 200;
            var FRAME_RATE = 50;
            var frameNumber = Math.round(FRAME_RATE/1000*duration);
            var frameDuration = Math.round(1000/FRAME_RATE);
            var currentFrame = 0;

            [>var rect = this.getDom().getBoundingClientRect();
              var diff = value - rect[property];<]
            var from = Utils.toFloat(this.style(property));
            var diff = value - from;
            var clock = setInterval((function(){
                currentFrame++;
                var rate = currentFrame / frameNumber;
                this.style(property, (from - diff * rate * (rate - 2)) + unit);
                if(currentFrame == frameNumber){
                    clearInterval(clock);
                    this.set('animationClock', null);
                }
            }).bind(this), frameDuration);
            this.set('animationClock', clock);

            return this.ref;
        },*/

        /*
         * Dom returner
         *===========================================================*/
        'getDom': function(){
            return this.get('dom');
        }
    });
});
<commit_msg>Added 'addAt' method to Element class.<commit_after>/**
 * js/com/Element.js
 * Author: H.Alper Tuna <halpertuna@gmail.com>
 * Date: 12.04.2016
 */

'use strict';

define(['../core/EventHandler', '../core/Utils', './TextElement'], function(EventHandler, Utils, TextElement){
    return EventHandler.extend({
        'init': function(tag){
            if(!tag) tag = 'div';

            this.set('dom', Utils.isString(tag) ? document.createElement(tag) : tag);
            this.set('children', []);
            this.handle('show');
            this.handle('hide');
            this.on('show', function(){this.removeClass('jb-hidden')});
            this.on('hide', function(){this.addClass('jb-hidden')});
        },

        /*
         * Attribute Managing
         *===========================================================*/
        'getAttr': function(attr){
            return this.getDom().getAttribute(attr);
        },
        'setAttr':  function(attr, value){
            this.getDom().setAttribute(attr, value);
            return this.ref;
        },
        'removeAttr': function(attr){
            this.getDom().removeAttribute(attr);
            return this.ref;
        },
        'getStyle': function(key){
            var styles = this.getAttr('style');
            if(styles == null) return;

            styles = styles.split(';');
            for(var i in styles){
                if(styles[i] == '') continue;
                var style = styles[i].split(':');
                if(style[0] == key) return style[1];
            }
        },
        'setStyle': function(key, value){
            var newStyles;
            if(Utils.isSet(value)){
                newStyles = {}
                newStyles[key] = value;
            }else if(Utils.isObject(key))
                newStyles = key;

            var oldStyles = this.getAttr('style');
            var styles = {}
            if(oldStyles != null){
                oldStyles = oldStyles.split(';');
                for(var i in oldStyles){
                    if(oldStyles[i] == '') continue;
                    var style = oldStyles[i].split(':');
                    styles[style[0]] = style[1];
                }
            }

            Utils.extend(styles, newStyles);

            var stylesAttr = '';
            for(var i in styles){
                if(Utils.isNumber(styles[i])) styles[i] += 'px';
                stylesAttr += i + ':' + styles[i] + ';';
            }

            this.setAttr('style', stylesAttr);

            return this.ref;
        },
        'addClass': function(newClasses){
            var classList = this.getDom().classList;
            newClasses = newClasses.split(' ');
            for(var i in newClasses)
                classList.add(newClasses[i]);

            return this.ref;
        },
        'removeClass': function(oldClasses){
            var classList = this.getDom().classList;
            if(classList.length == 0)
                return this.ref;

            oldClasses = oldClasses.split(' ');
            for(var i in oldClasses)
                classList.remove(oldClasses[i]);

            return this.ref;
        },
        'hasClass': function(className){
            return this.getDom().classList.contains(className);
        },
        'toggleClass': function(className){
            if(this.hasClass(className))
                return this.removeClass(className);
            return this.addClass(className);
        },

        /*
         * Content Managing
         *===========================================================*/
        'clear': function(){
            this.getDom().innerHTML = '';
            return this.ref;
        },
        'add': function(){
            Utils.each(arguments, function(element){
                if(Utils.isNumber(element)) element = Utils.toString(element);
                if(!Utils.isString(element) && (!element || !element.getDom))
                    //TODO Error
                    throw 'Child has to be an Element, string or number.';

                if(Utils.isString(element))
                    element = TextElement.new(element);

                var dom = this.get('dom');
                dom.appendChild(element.getDom());

                element.set('parent', this);
                this.get('children').push(element);
            }, this);

            return this.ref;
        },
        'prepend': function(){
            Utils.each(arguments, function(element){
                if(Utils.isNumber(element)) element = Utils.toString(element);
                if(!Utils.isString(element) && (!element || !element.getDom))
                    //TODO Error
                    throw 'Child has to be an Element, string or number.';

                if(Utils.isString(element))
                    element = TextElement.new(element);

                var dom = this.getDom();
                dom.insertBefore(element.getDom(), dom.firstChild);

                element.set('parent', this);
                this.get('children').unshift(element);
            }, this);

            return this.ref;
        },
        'addAt': function(element, index){
            var children = this.get('children');
            if(index == children.length) return this.add(element);

            if(Utils.isNumber(element)) element = Utils.toString(element);
            if(!Utils.isString(element) && (!element || !element.getDom))
                //TODO Error
                throw 'Child has to be an Element, string or number.';

            if(Utils.isString(element))
                element = TextElement.new(element);

            var dom = this.getDom();
            dom.insertBefore(element.getDom(), children[index]);

            element.set('parent', this);
            children.splice(index, 0, element);

            return this.ref;
        },
        'remove': function(element){
            //Remove element
            if(element){
                this.getDom().removeChild(element.getDom());

                element.unset('parent');
                var children = this.get('children');
                children.splice(children.indexOf(element), -1);
                return this.ref;
            }

            //Remove this from parent
            this.get('parent').remove(this);

            return this.ref;
        },

        /*
         * Event Handling
         *===========================================================*/
        'on': function(action, func){
            try{
                this.super.on(action, func);
            }catch(e){
                this.getDom().addEventListener(action, func);
            }
            return this.ref;
        },
        'off': function(action, func){
            try{
                this.super.off(action, func);
            }catch(e){
                this.getDom().removeEventListener(action, func);
            }
            return this.ref;
        },
        'trigger': function(action, event){
            try{
                this.super.trigger(action, event);
            }catch(e){
                this.getDom().dispatchEvent(new Event(action));
            }
            return this.ref;
        },

        /*
         * Ready-to-use handled events
         *===========================================================*/
        'hide': function(){
            return this.trigger('hide');
        },
        'show': function(){
            return this.trigger('show');
        },

        /*'animate': function(property, value, unit, duration){
            var clock = this.get('animationClock');
            if(Utils.isSet(clock)) clearInterval(clock);

            if(!unit) unit = 'px';
            if(!duration) duration = 200;
            var FRAME_RATE = 50;
            var frameNumber = Math.round(FRAME_RATE/1000*duration);
            var frameDuration = Math.round(1000/FRAME_RATE);
            var currentFrame = 0;

            [>var rect = this.getDom().getBoundingClientRect();
              var diff = value - rect[property];<]
            var from = Utils.toFloat(this.style(property));
            var diff = value - from;
            var clock = setInterval((function(){
                currentFrame++;
                var rate = currentFrame / frameNumber;
                this.style(property, (from - diff * rate * (rate - 2)) + unit);
                if(currentFrame == frameNumber){
                    clearInterval(clock);
                    this.set('animationClock', null);
                }
            }).bind(this), frameDuration);
            this.set('animationClock', clock);

            return this.ref;
        },*/

        /*
         * Dom returner
         *===========================================================*/
        'getDom': function(){
            return this.get('dom');
        }
    });
});
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

var Palette = this.Palette = Base.extend(Callback, /** @lends Palette# */{
	_events: [ 'onChange' ],

	initialize: function(title, components, values) {
		var parent = DomElement.find('.palettejs-panel')
			|| DomElement.find('body').appendChild(
				DomElement.create('div', { 'class': 'palettejs-panel' }));
		this._element = parent.appendChild(
			DomElement.create('table', { 'class': 'palettejs-pane' })),
		this._title = title;
		if (!values)
			values = {};
		for (var name in (this._components = components)) {
			var component = components[name];
			if (!(component instanceof Component)) {
				if (component.value == null)
					component.value = values[name];
				component.name = name;
				component = components[name] = new Component(component);
			}
			this._element.appendChild(component._element);
			component.palette = this;
			// Make sure each component has an entry in values, so observers get
			// installed further down.
			if (values[name] === undefined)
				values[name] = null;
		}
		// Now replace each entry in values with a getter / setters so we can
		// observe change.
		});
		this._values = Base.each(values, function(value, name) {
			Base.define(values, name, {
				enumerable: true,
				configurable: true,
				writable: true,
				get: function() {
					return value;
				},
				set: function(val) {
					value = val;
					components[name].setValue(val);
				}
			});
		});
	},

	reset: function() {
		for (var i in this._components)
			this._components[i].reset();
	},

	remove: function() {
		DomElement.remove(this._element);
	}
});
<commit_msg>Expose Palettes through PaperScope#palettes.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

var Palette = this.Palette = Base.extend(Callback, /** @lends Palette# */{
	_events: [ 'onChange' ],

	initialize: function(title, components, values) {
		var parent = DomElement.find('.palettejs-panel')
			|| DomElement.find('body').appendChild(
				DomElement.create('div', { 'class': 'palettejs-panel' }));
		this._element = parent.appendChild(
			DomElement.create('table', { 'class': 'palettejs-pane' })),
		this._title = title;
		if (!values)
			values = {};
		for (var name in (this._components = components)) {
			var component = components[name];
			if (!(component instanceof Component)) {
				if (component.value == null)
					component.value = values[name];
				component.name = name;
				component = components[name] = new Component(component);
			}
			this._element.appendChild(component._element);
			component.palette = this;
			// Make sure each component has an entry in values, so observers get
			// installed further down.
			if (values[name] === undefined)
				values[name] = null;
		}
		// Now replace each entry in values with a getter / setters so we can
		// observe change.
		});
		this._values = Base.each(values, function(value, name) {
			Base.define(values, name, {
				enumerable: true,
				configurable: true,
				writable: true,
				get: function() {
					return value;
				},
				set: function(val) {
					value = val;
					components[name].setValue(val);
				}
			});
		});
		if (window.paper)
			paper.palettes.push(this);
	},

	reset: function() {
		for (var i in this._components)
			this._components[i].reset();
	},

	remove: function() {
		DomElement.remove(this._element);
	}
});
<|endoftext|>


<commit_before>const path = require('path')
const semver = require('semver')
const fse = require('fs-extra')
const simpleGet = require('simple-get')
const decompress = require('decompress')
const resolveFrom = require('resolve-from')
const validateNpmPackageName = require('validate-npm-package-name')
const {pathTools} = require('@sanity/util')
const dynamicRequire = require('../../util/dynamicRequire')
const pkg = require('../../../package.json')
const debug = require('../../debug')

const {absolutify, pathIsEmpty} = pathTools

module.exports = async (context, url) => {
  const {prompt, workDir} = context
  let inProjectContext = false
  try {
    const projectManifest = await fse.readJson(path.join(workDir, 'sanity.json'))
    inProjectContext = Boolean(projectManifest.root)
  } catch (err) {
    // Intentional noop
  }

  let zip
  try {
    zip = await getZip(url)
  } catch (err) {
    err.message = `Failed to get template: ${err.message}`
    throw err
  }

  const manifest = zip.find(
    file =>
      path.basename(file.path) === 'package.json'
      && !file.path.includes('node_modules')
  )

  if (!manifest) {
    throw new Error('Could not find `package.json` in template')
  }

  const baseDir = path.join(path.dirname(manifest.path), 'template')
  debug('Base directory resolved to %s', baseDir)

  const templateFiles = zip.filter(file => file.type === 'file' && file.path.indexOf(baseDir) === 0)
  const manifestContent = manifest.data.toString()
  const tplVars = parseJson(manifestContent).sanityTemplate || {}
  const {minimumBaseVersion} = tplVars

  if (minimumBaseVersion) {
    const installed = getSanityVersion(workDir)
    if (semver.lt(installed, minimumBaseVersion)) {
      throw new Error(
        `Template requires Sanity at version ${minimumBaseVersion}, installed is ${installed}`
      )
    }
  }

  const name = await prompt.single({
    type: 'input',
    message: 'Plugin name:',
    default: tplVars.suggestedName || '',
    validate: async pkgName => {
      const {validForNewPackages, errors} = validateNpmPackageName(pkgName)
      if (!validForNewPackages) {
        return errors[0]
      }

      const outputPath = path.join(workDir, 'plugins', pkgName)
      const isEmpty = await pathIsEmpty(outputPath)
      if (inProjectContext && !isEmpty) {
        return 'Plugin with given name already exists in project'
      }

      return true
    }
  })

  let outputPath = path.join(workDir, 'plugins', name)
  if (!inProjectContext) {
    const cwdIsEmpty = await pathIsEmpty(workDir)
    outputPath = await prompt.single({
      type: 'input',
      message: 'Output path:',
      default: cwdIsEmpty ? workDir : path.join(workDir, name),
      validate: validateEmptyPath,
      filter: absolutify
    })
  }

  let createConfig = tplVars.requiresConfig
  if (typeof createConfig === 'undefined') {
    createConfig = await prompt.single({
      type: 'confirm',
      message: 'Does the plugin need a configuration file?',
      default: false
    })
  }

  await fse.ensureDir(outputPath)
  await Promise.all(
    templateFiles.map(file => {
      const filename = file.path.slice(baseDir.length)
      return fse.outputFile(path.join(outputPath, filename), file.data)
    })
  )

  return {name, outputPath, inPluginsPath: inProjectContext, dependencies: tplVars.dependencies}
}

async function validateEmptyPath(dir) {
  const isEmpty = await pathIsEmpty(dir)
  return isEmpty ? true : 'Path is not empty'
}

function getZip(url) {
  return new Promise((resolve, reject) => {
    simpleGet.concat(url, (err, res, data) => {
      if (err) {
        reject(err)
        return
      }

      resolve(decompress(data))
    })
  })
}

function parseJson(json) {
  try {
    return JSON.parse(json)
  } catch (err) {
    return {}
  }
}

function getSanityVersion(workDir) {
  const basePkg = resolveFrom.silent(workDir, '@sanity/base/package.json')
  return basePkg ? dynamicRequire(basePkg).version : pkg.version
}
<commit_msg>[cli] Allow specifying a minimum CLI version for templates<commit_after>const path = require('path')
const semver = require('semver')
const fse = require('fs-extra')
const simpleGet = require('simple-get')
const decompress = require('decompress')
const resolveFrom = require('resolve-from')
const validateNpmPackageName = require('validate-npm-package-name')
const {pathTools} = require('@sanity/util')
const dynamicRequire = require('../../util/dynamicRequire')
const pkg = require('../../../package.json')
const debug = require('../../debug')

const {absolutify, pathIsEmpty} = pathTools

module.exports = async (context, url) => {
  const {prompt, workDir} = context
  let inProjectContext = false
  try {
    const projectManifest = await fse.readJson(path.join(workDir, 'sanity.json'))
    inProjectContext = Boolean(projectManifest.root)
  } catch (err) {
    // Intentional noop
  }

  let zip
  try {
    zip = await getZip(url)
  } catch (err) {
    err.message = `Failed to get template: ${err.message}`
    throw err
  }

  const manifest = zip.find(
    file =>
      path.basename(file.path) === 'package.json'
      && !file.path.includes('node_modules')
  )

  if (!manifest) {
    throw new Error('Could not find `package.json` in template')
  }

  const baseDir = path.join(path.dirname(manifest.path), 'template')
  debug('Base directory resolved to %s', baseDir)

  const templateFiles = zip.filter(file => file.type === 'file' && file.path.indexOf(baseDir) === 0)
  const manifestContent = manifest.data.toString()
  const tplVars = parseJson(manifestContent).sanityTemplate || {}
  const {minimumBaseVersion, minimumCliVersion} = tplVars

  if (minimumBaseVersion) {
    const installed = getSanityVersion(workDir)
    if (semver.lt(installed, minimumBaseVersion)) {
      throw new Error(
        `Template requires Sanity at version ${minimumBaseVersion}, installed is ${installed}`
      )
    }
  }

  if (minimumCliVersion && semver.lt(pkg.version, minimumCliVersion)) {
    throw new Error(
      `Template requires @sanity/cli at version ${minimumCliVersion}, installed is ${pkg.version}`
    )
  }

  const name = await prompt.single({
    type: 'input',
    message: 'Plugin name:',
    default: tplVars.suggestedName || '',
    validate: async pkgName => {
      const {validForNewPackages, errors} = validateNpmPackageName(pkgName)
      if (!validForNewPackages) {
        return errors[0]
      }

      const outputPath = path.join(workDir, 'plugins', pkgName)
      const isEmpty = await pathIsEmpty(outputPath)
      if (inProjectContext && !isEmpty) {
        return 'Plugin with given name already exists in project'
      }

      return true
    }
  })

  let outputPath = path.join(workDir, 'plugins', name)
  if (!inProjectContext) {
    const cwdIsEmpty = await pathIsEmpty(workDir)
    outputPath = await prompt.single({
      type: 'input',
      message: 'Output path:',
      default: cwdIsEmpty ? workDir : path.join(workDir, name),
      validate: validateEmptyPath,
      filter: absolutify
    })
  }

  let createConfig = tplVars.requiresConfig
  if (typeof createConfig === 'undefined') {
    createConfig = await prompt.single({
      type: 'confirm',
      message: 'Does the plugin need a configuration file?',
      default: false
    })
  }

  await fse.ensureDir(outputPath)
  await Promise.all(
    templateFiles.map(file => {
      const filename = file.path.slice(baseDir.length)
      return fse.outputFile(path.join(outputPath, filename), file.data)
    })
  )

  return {name, outputPath, inPluginsPath: inProjectContext, dependencies: tplVars.dependencies}
}

async function validateEmptyPath(dir) {
  const isEmpty = await pathIsEmpty(dir)
  return isEmpty ? true : 'Path is not empty'
}

function getZip(url) {
  return new Promise((resolve, reject) => {
    simpleGet.concat(url, (err, res, data) => {
      if (err) {
        reject(err)
        return
      }

      resolve(decompress(data))
    })
  })
}

function parseJson(json) {
  try {
    return JSON.parse(json)
  } catch (err) {
    return {}
  }
}

function getSanityVersion(workDir) {
  const basePkg = resolveFrom.silent(workDir, '@sanity/base/package.json')
  return basePkg ? dynamicRequire(basePkg).version : pkg.version
}
<|endoftext|>


<commit_before>// @name         Pogdesign-Widgets.require
// @namespace    https://github.com/fabiencrassat
// @version      1.0.0
// @description  Add the core object for the Pogdesign-Widgets.user.js
// @author       Fabien Crassat <fabien@crassat.com>

/*global $, fabiencrassat */
"use strict";

function checkProtocol() {
    if (location.protocol === "http:") {
        window.location.replace("https:" + window.location.href.substring(5));
    }
}
checkProtocol();

var tools = function() {
    function addZeroToOneNumber(number) {
        if (number.length < 2) { number = "0" + number; }
        return number;
    }
    function getPixelStyle(key, value) {
        if (key && value) {
            return " " + key + ": " + value + "px;";
        }
        return "";
    }

    return {
        addZeroToOneNumber,
        getPixelStyle
    };
};

var model = function() {
    var tools = fabiencrassat.tools;

    var show = {
        title: "",
        season: "",
        episode: "",
        getTitle() { return show.title; },
        setTitle(title) { show.title = title; },
        getSeason() { return show.season; },
        setSeason(season) {
            show.season = tools.addZeroToOneNumber(season);
        },
        getEpisode() { return show.episode; },
        setEpisode(episode) {
            show.episode = tools.addZeroToOneNumber(episode);
        },
        getSeasonAndEpisode() { return "S" + show.getSeason() + "E" + show.getEpisode(); },
        setSeasonAndEpisode() {
            if (arguments.length === 1) {
                var regex = /^s(\d{1,})e(\d{1,})/gi;
                show.setSeason(arguments[0].replace(regex, "$1"));
                show.setEpisode(arguments[0].replace(regex, "$2"));
                return;
            }
            if (arguments.length === 2) {
                show.setSeason(arguments[0]);
                show.setEpisode(arguments[1]);
                return;
            }
            throw new RangeError("Exception in setSeasonAndEpisode");
        },

        getSearch() {
            return show.getTitle().replace(/ /gm, ".") + "." + show.getSeasonAndEpisode();
        }
    };

    return {
        show: {
            getSearch: show.getSearch,
            getTitle: show.getTitle,
            setTitle: show.setTitle,
            getSeason: show.getSeason,
            getSeasonAndEpisode: show.getSeasonAndEpisode,
            setSeasonAndEpisode: show.setSeasonAndEpisode
        }
    };
};

var view = function() {
    var tools = fabiencrassat.tools;
    var show = fabiencrassat.model.show;

    var popup = {
        links: [
            {name: "Streaming",
                sites : [
                    {name: "google",
                        icon: "",
                        url() { return "https://www.google.fr/search?q=" + show.getSearch() + "+vostfr+streaming"; }
                    }
                ]
            },
            {name: "Download",
                sites: [
                    {name: "google",
                        icon: "",
                        url() { return "https://www.google.fr/search?q=" + show.getSearch() + "+direct+download"; }
                    },
                    {name: "yourserie",
                        icon: "",
                        url() { return "http://www.yourserie.com/?s=" + show.getTitle() + "+season+" + show.getSeason(); }
                    },
                    {name: "binsearch",
                        icon: "",
                        url() { return "https://binsearch.info/?q=" + show.getSearch(); }
                    }
                ]
            },
            {name: "Subtitle",
                sites : [
                    {name: "subscene",
                        icon: "",
                        url() { return "https://subscene.com/subtitles/release?q=" + show.getSearch(); }
                    }
                ]
            }
        ],
        getLinks() {
            var links = "";
            for (var i = 0; i < this.links.length; i++) {
                links += this.links[i].name + ": ";
                for (var j = 0; j < this.links[i].sites.length; j++) {
                    if (j !== 0) links += " | ";
                    links += "" + this.links[i].sites[j].name + "";
                }
                links += "
";
            }
            links += "";
            return links;
        },

        popupId: "fcr-external-links-element",
        getContainer() {
            return $("#" + popup.popupId);
        },
        close() {
            var container = popup.getContainer();
            if(container) {
                container.remove();
            }
        },
        removeOnOutsideClickEvent() {
            $(document).mouseup(function (event) {
                var container = popup.getContainer();
                if (!container.is(event.target) &&          // if the target of the click isn't the container
                container.has(event.target).length === 0) { // nor a descendant of the container
                    container.remove();
                }
            });
        },
        create(element, cssClass, cssDisplay, top, left) {
            var result = `
            <div id='` + popup.popupId + `'
            style='position: absolute; width: 350px; z-index: 97; display: ` + cssDisplay + ";" + tools.getPixelStyle("top", top) + tools.getPixelStyle("left", left) + `'
            class='cluetip ui-widget ui-widget-content ui-cluetip clue-right-default cluetip-default ` + cssClass + `'>

                    X
                    ` + show.getTitle() + " " + show.getSeasonAndEpisode() + `

` + popup.getLinks() + `

` + show.getSearch() + `

`;
            return(result);
        }
    };

    return {
        externalLinks : {
            removeOnOutsideClickEvent: popup.removeOnOutsideClickEvent,
            close: popup.close,
            create: popup.create
        }
    };
};

var main = function() {
    var externalLinks = fabiencrassat.view.externalLinks;
    var show = fabiencrassat.model.show;

    var page = {
        controller: {
            insertStylesheets(stylesheets) {
                var style = document.createElement("style");
                style.appendChild(document.createTextNode(stylesheets));
                (document.body || document.head || document.documentElement).appendChild(style);
            },
            extractTitle(pageElement, element) {
                var title = $.trim(pageElement.extractTitle(element));
                show.setTitle(title);
            },
            extractSeasonAndEpisode(pageElement, element) {
                var seasonAndEpisode = pageElement.extractSeasonAndEpisode(element);
                if (typeof seasonAndEpisode === "string") {
                    show.setSeasonAndEpisode(seasonAndEpisode);
                    return;
                }
                show.setSeasonAndEpisode(seasonAndEpisode.season, seasonAndEpisode.episode);
            },
            extractShow(pageElement, element) {
                page.controller.extractTitle(pageElement, element);
                page.controller.extractSeasonAndEpisode(pageElement, element);
            },
            getExternalLinksPopup(pageElement, element) {
                page.controller.extractShow(pageElement, element);
                pageElement.displayExternalLinksPopup(element);
            },
            loadClickEventOnLinkElement(pageElement) {
                $("." + page.shared.externalLinksLinkClass).on("click", function(event) {
                    event.preventDefault();
                    externalLinks.close();
                    page.controller.getExternalLinksPopup(pageElement, $(this));
                });
                externalLinks.removeOnOutsideClickEvent();
            },
            isInLocationPage(regex) {
              return regex.test(window.location.href);
            },
            canAddExternalLink(isInLocationPage, element) {
                if (!isInLocationPage()) { return false; }
                if ($(element).length === 0) { return false; }
                return true;
            },
            addExternalLink(pageElement, element) {
                if (!page.controller.canAddExternalLink(pageElement.isInLocationPage, element)) { return; }
                page.controller.insertStylesheets(page.shared.stylesheets(pageElement));
                pageElement.insertExternalLink(element);
                page.controller.loadClickEventOnLinkElement(pageElement);
            }
        },
        shared: {
            linkImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTM0A1t6AAAA20lEQVQoU33RuQrCQBDG8YgHeIIHinhgZyNWgg8iCoqIpW/jg5nG0oew8b7j/wsZCSkM/Nbs7MzuuHE8z/snhlxIyhbaGEb0MMAb9myUvMAJR1xwxQEvJLCCPVsVKKGOMqqBAipIw8UTOskv0E55WHtGyRsocYYlXC3cUEQ0WTsrWS1bPKNBx9VCQSXv8MEEHZTgr2t4oGkBdKFLGAdz/cd58O4XnBFtKRN6V8tTm2tQS7pvSwjTh9tjZDENfehY7XSHbk2/immzNVT4K5A4smghGcwb0DexHHjOFwrY3c0uEFwZAAAAAElFTkSuQmCC",
            stylesheets(pageElement) {
                return `a.fcr-closePopup {
                    float: right;
                    color: #66bbff !important;
                }` + pageElement.stylesheets();
            },
            externalLinksLinkClass: "fcr-externalLinksLink",
            externalLink(classText, linkText) {
                return "" +
                        linkText +
                    "";
            },
            externalImageLink() {
                return page.shared.externalLink("fcr-externalLink-image", "");
            },
            externalTextLink() {
                return page.shared.externalLink("", "<Links>");
            }
        }
    };

    return {
        controller: {
            isInLocationPage: page.controller.isInLocationPage,
            addExternalLink: page.controller.addExternalLink
        },
        shared: {
          linkImage: page.shared.linkImage,
          externalImageLink: page.shared.externalImageLink,
          externalTextLink: page.shared.externalTextLink
        }
    };
};

var script = document.createElement("script");
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.tools = ("+ tools +")();"));
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.model = ("+ model +")();"));
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.view = ("+ view +")();"));
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.main = ("+ main +")();"));
(document.body || document.head || document.documentElement).appendChild(script);

<commit_msg>Curly braces around statements<commit_after>// @name         Pogdesign-Widgets.require
// @namespace    https://github.com/fabiencrassat
// @version      1.0.0
// @description  Add the core object for the Pogdesign-Widgets.user.js
// @author       Fabien Crassat <fabien@crassat.com>

/*global $, fabiencrassat */
"use strict";

function checkProtocol() {
    if (location.protocol === "http:") {
        window.location.replace("https:" + window.location.href.substring(5));
    }
}
checkProtocol();

var tools = function() {
    function addZeroToOneNumber(number) {
        if (number.length < 2) { number = "0" + number; }
        return number;
    }
    function getPixelStyle(key, value) {
        if (key && value) {
            return " " + key + ": " + value + "px;";
        }
        return "";
    }

    return {
        addZeroToOneNumber,
        getPixelStyle
    };
};

var model = function() {
    var tools = fabiencrassat.tools;

    var show = {
        title: "",
        season: "",
        episode: "",
        getTitle() { return show.title; },
        setTitle(title) { show.title = title; },
        getSeason() { return show.season; },
        setSeason(season) {
            show.season = tools.addZeroToOneNumber(season);
        },
        getEpisode() { return show.episode; },
        setEpisode(episode) {
            show.episode = tools.addZeroToOneNumber(episode);
        },
        getSeasonAndEpisode() { return "S" + show.getSeason() + "E" + show.getEpisode(); },
        setSeasonAndEpisode() {
            if (arguments.length === 1) {
                var regex = /^s(\d{1,})e(\d{1,})/gi;
                show.setSeason(arguments[0].replace(regex, "$1"));
                show.setEpisode(arguments[0].replace(regex, "$2"));
                return;
            }
            if (arguments.length === 2) {
                show.setSeason(arguments[0]);
                show.setEpisode(arguments[1]);
                return;
            }
            throw new RangeError("Exception in setSeasonAndEpisode");
        },

        getSearch() {
            return show.getTitle().replace(/ /gm, ".") + "." + show.getSeasonAndEpisode();
        }
    };

    return {
        show: {
            getSearch: show.getSearch,
            getTitle: show.getTitle,
            setTitle: show.setTitle,
            getSeason: show.getSeason,
            getSeasonAndEpisode: show.getSeasonAndEpisode,
            setSeasonAndEpisode: show.setSeasonAndEpisode
        }
    };
};

var view = function() {
    var tools = fabiencrassat.tools;
    var show = fabiencrassat.model.show;

    var popup = {
        links: [
            {name: "Streaming",
                sites : [
                    {name: "google",
                        icon: "",
                        url() { return "https://www.google.fr/search?q=" + show.getSearch() + "+vostfr+streaming"; }
                    }
                ]
            },
            {name: "Download",
                sites: [
                    {name: "google",
                        icon: "",
                        url() { return "https://www.google.fr/search?q=" + show.getSearch() + "+direct+download"; }
                    },
                    {name: "yourserie",
                        icon: "",
                        url() { return "http://www.yourserie.com/?s=" + show.getTitle() + "+season+" + show.getSeason(); }
                    },
                    {name: "binsearch",
                        icon: "",
                        url() { return "https://binsearch.info/?q=" + show.getSearch(); }
                    }
                ]
            },
            {name: "Subtitle",
                sites : [
                    {name: "subscene",
                        icon: "",
                        url() { return "https://subscene.com/subtitles/release?q=" + show.getSearch(); }
                    }
                ]
            }
        ],
        getLinks() {
            var links = "";
            for (var i = 0; i < this.links.length; i++) {
                links += this.links[i].name + ": ";
                for (var j = 0; j < this.links[i].sites.length; j++) {
                    if (j !== 0) {
                        links += " | ";
                    }
                    links += "" + this.links[i].sites[j].name + "";
                }
                links += "
";
            }
            links += "";
            return links;
        },

        popupId: "fcr-external-links-element",
        getContainer() {
            return $("#" + popup.popupId);
        },
        close() {
            var container = popup.getContainer();
            if(container) {
                container.remove();
            }
        },
        removeOnOutsideClickEvent() {
            $(document).mouseup(function (event) {
                var container = popup.getContainer();
                if (!container.is(event.target) &&          // if the target of the click isn't the container
                container.has(event.target).length === 0) { // nor a descendant of the container
                    container.remove();
                }
            });
        },
        create(element, cssClass, cssDisplay, top, left) {
            var result = `
            <div id='` + popup.popupId + `'
            style='position: absolute; width: 350px; z-index: 97; display: ` + cssDisplay + ";" + tools.getPixelStyle("top", top) + tools.getPixelStyle("left", left) + `'
            class='cluetip ui-widget ui-widget-content ui-cluetip clue-right-default cluetip-default ` + cssClass + `'>

                    X
                    ` + show.getTitle() + " " + show.getSeasonAndEpisode() + `

` + popup.getLinks() + `

` + show.getSearch() + `

`;
            return(result);
        }
    };

    return {
        externalLinks : {
            removeOnOutsideClickEvent: popup.removeOnOutsideClickEvent,
            close: popup.close,
            create: popup.create
        }
    };
};

var main = function() {
    var externalLinks = fabiencrassat.view.externalLinks;
    var show = fabiencrassat.model.show;

    var page = {
        controller: {
            insertStylesheets(stylesheets) {
                var style = document.createElement("style");
                style.appendChild(document.createTextNode(stylesheets));
                (document.body || document.head || document.documentElement).appendChild(style);
            },
            extractTitle(pageElement, element) {
                var title = $.trim(pageElement.extractTitle(element));
                show.setTitle(title);
            },
            extractSeasonAndEpisode(pageElement, element) {
                var seasonAndEpisode = pageElement.extractSeasonAndEpisode(element);
                if (typeof seasonAndEpisode === "string") {
                    show.setSeasonAndEpisode(seasonAndEpisode);
                    return;
                }
                show.setSeasonAndEpisode(seasonAndEpisode.season, seasonAndEpisode.episode);
            },
            extractShow(pageElement, element) {
                page.controller.extractTitle(pageElement, element);
                page.controller.extractSeasonAndEpisode(pageElement, element);
            },
            getExternalLinksPopup(pageElement, element) {
                page.controller.extractShow(pageElement, element);
                pageElement.displayExternalLinksPopup(element);
            },
            loadClickEventOnLinkElement(pageElement) {
                $("." + page.shared.externalLinksLinkClass).on("click", function(event) {
                    event.preventDefault();
                    externalLinks.close();
                    page.controller.getExternalLinksPopup(pageElement, $(this));
                });
                externalLinks.removeOnOutsideClickEvent();
            },
            isInLocationPage(regex) {
              return regex.test(window.location.href);
            },
            canAddExternalLink(isInLocationPage, element) {
                if (!isInLocationPage()) { return false; }
                if ($(element).length === 0) { return false; }
                return true;
            },
            addExternalLink(pageElement, element) {
                if (!page.controller.canAddExternalLink(pageElement.isInLocationPage, element)) { return; }
                page.controller.insertStylesheets(page.shared.stylesheets(pageElement));
                pageElement.insertExternalLink(element);
                page.controller.loadClickEventOnLinkElement(pageElement);
            }
        },
        shared: {
            linkImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTM0A1t6AAAA20lEQVQoU33RuQrCQBDG8YgHeIIHinhgZyNWgg8iCoqIpW/jg5nG0oew8b7j/wsZCSkM/Nbs7MzuuHE8z/snhlxIyhbaGEb0MMAb9myUvMAJR1xwxQEvJLCCPVsVKKGOMqqBAipIw8UTOskv0E55WHtGyRsocYYlXC3cUEQ0WTsrWS1bPKNBx9VCQSXv8MEEHZTgr2t4oGkBdKFLGAdz/cd58O4XnBFtKRN6V8tTm2tQS7pvSwjTh9tjZDENfehY7XSHbk2/immzNVT4K5A4smghGcwb0DexHHjOFwrY3c0uEFwZAAAAAElFTkSuQmCC",
            stylesheets(pageElement) {
                return `a.fcr-closePopup {
                    float: right;
                    color: #66bbff !important;
                }` + pageElement.stylesheets();
            },
            externalLinksLinkClass: "fcr-externalLinksLink",
            externalLink(classText, linkText) {
                return "" +
                        linkText +
                    "";
            },
            externalImageLink() {
                return page.shared.externalLink("fcr-externalLink-image", "");
            },
            externalTextLink() {
                return page.shared.externalLink("", "<Links>");
            }
        }
    };

    return {
        controller: {
            isInLocationPage: page.controller.isInLocationPage,
            addExternalLink: page.controller.addExternalLink
        },
        shared: {
          linkImage: page.shared.linkImage,
          externalImageLink: page.shared.externalImageLink,
          externalTextLink: page.shared.externalTextLink
        }
    };
};

var script = document.createElement("script");
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.tools = ("+ tools +")();"));
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.model = ("+ model +")();"));
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.view = ("+ view +")();"));
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.main = ("+ main +")();"));
(document.body || document.head || document.documentElement).appendChild(script);

<|endoftext|>


<commit_before>var hn = {
  'el': document.getElementById('hackernews')
};

hn.controller = function () {
  this.data = {};
  hn.el.addEventListener('hackernews', function (event) {
    var body = event.detail;
    if (body.items && body.items.length > 0) {
      body.items = body.items.slice(0, 10);
    }
    this.data = body;
    m.render(hn.el, hn.view(this));
  });
};

hn.view = function (c) {
  if (Object.keys(c.data).length === 0) {
    return m('p', 'Waiting for data');
  }
  var rows = c.data.items.map(function (item) {
    return m('tr', [
      m('td.title', jrvs.truncate(item.title, 24)),
      m('td.points', item.points)
    ]);
  });
  return [
    m('p.fade', 'Hacker News'),
    m('table', rows),
    m('p', {class: 'fade updated-at'}, 'Sist oppdatert: ' +
      c.data.updatedAt)
  ];
};

if (hn.el !== null) {
  m.module(hn.el, hn);
}
<commit_msg>Keep reference to controller<commit_after>var hn = {
  'el': document.getElementById('hackernews')
};

hn.controller = function () {
  var ctrl = this;
  ctrl.data = {};
  hn.el.addEventListener('hackernews', function (event) {
    var body = event.detail;
    if (body.items && body.items.length > 0) {
      body.items = body.items.slice(0, 10);
    }
    ctrl.data = body;
    m.render(hn.el, hn.view(ctrl));
  });
};

hn.view = function (c) {
  if (Object.keys(c.data).length === 0) {
    return m('p', 'Waiting for data');
  }
  var rows = c.data.items.map(function (item) {
    return m('tr', [
      m('td.title', jrvs.truncate(item.title, 24)),
      m('td.points', item.points)
    ]);
  });
  return [
    m('p.fade', 'Hacker News'),
    m('table', rows),
    m('p', {class: 'fade updated-at'}, 'Sist oppdatert: ' +
      c.data.updatedAt)
  ];
};

if (hn.el !== null) {
  m.module(hn.el, hn);
}
<|endoftext|>


<commit_before>'use strict';
/* global snoowrap */
var REDDIT_APP_ID = '_s9Icw2TEXpmaw';
var REDIRECT_URI = 'https://pkmnbumba.github.io/reddit-thread-unnuke/';

var USER_AGENT = 'reddit thread un-nuke by /u/bumbalicious || https://github.com/pkmnbumba/reddit-thread-unnuke';
var REQUIRED_SCOPES = ['modposts', 'read'];
var cachedRequester;
var accessTokenPromise;
var removedCount;

var query = parseQueryString(location.search);
var cookies = parseCookieString(document.cookie);

function parseQueryString (str) {
  if (!str) {
    return {};
  }
  var obj = {};
  var pieces = str.slice(1).split('&');
  for (var i = 0; i < pieces.length; i++) {
    var pair = pieces[i].split('=');
    obj[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
  }
  return obj;
}

function parseCookieString (cookieString) {
  var obj = {};
  var splitCookies = cookieString.split('; ');
  splitCookies.forEach(function (cookie) {
    var pair = cookie.split('=');
    obj[pair[0]] = pair[1];
  });
  return obj;
}

var getAuthRedirect = function (state) {
  return `https://reddit.com/api/v1/authorize?client_id=${REDDIT_APP_ID}&response_type=code&state=${encodeURIComponent(state)}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&duration=temporary&scope=${REQUIRED_SCOPES.join('%2C')}`;
};

function parseUrl (url) {
  var matches = url.match(/^(?:http(?:s?):\/\/)?(?:\w*\.)?reddit\.com\/(?:r\/\w{1,21}\/)?comments\/(\w{1,10})(?:\/[^\/\?]{1,100})?(?:\/(\w{1,10}))?\/?(?:\?.*)?$/);
  if (!matches) {
    throw new TypeError('Invalid URL. Please enter the URL of a reddit Submission or Comment.');
  }
  return matches;
}

function getExpandedContent (requester, urlMatches) {
  return (urlMatches[2] ? requester.get_comment(urlMatches[2]) : requester.get_submission(urlMatches[1])).expand_replies();
}

function deepRemove (content, preserveDistinguished) {
  var replies = content.comments || content.replies;
  var removeCurrentItem = content.distinguished && preserveDistinguished || content.banned_by !== null
    ? Promise.resolve()
    : content.remove().tap(incrementCounter);
  return Promise.all(Array.from(replies).map(function (reply) {
    return deepRemove(reply, preserveDistinguished);
  }).concat([removeCurrentItem]));
}

function deepApprove (content, preserveRemoved) {
  var replies = content.comments || content.replies;
  cachedRequester.getMe().then(console.log);
  if (content.banned_by !== null) {
    console.log(content.banned_by['name']);
    var determineRemoved = preserveRemoved;
  }
  var approveCurrentItem = !content.removed || content.banned_by === null
    ? Promise.resolve()
    : content.approve().tap(incrementCounter);
  return Promise.all(Array.from(replies).map(function (reply) {
    return deepApprove(reply, preserveRemoved);
  }).concat([approveCurrentItem]));
}

function getAccessToken (code) {
  if (accessTokenPromise) {
    return accessTokenPromise;
  }
  accessTokenPromise = cookies.access_token && !code
    ? Promise.resolve(cookies.access_token)
    : snoowrap.prototype.credentialed_client_request.call({
      user_agent: USER_AGENT,
      client_id: REDDIT_APP_ID,
      client_secret: ''
    }, {
      method: 'post',
      url: 'https://www.reddit.com/api/v1/access_token',
      form: {grant_type: 'authorization_code', code, redirect_uri: REDIRECT_URI}
    }).then(function (response) {
      if (!response.access_token) {
        throw new Error('Authentication failed');
      }
      document.cookie = `access_token=${response.access_token}; max-age=3600; secure`;
      cookies.access_token = response.access_token;
      return response.access_token;
    });
  return accessTokenPromise;
}

function incrementCounter () {
  document.getElementById('removed-count').innerHTML = ++removedCount;
}

function getRequester (access_token) {
  if (cachedRequester) {
    return cachedRequester;
  }
  cachedRequester = new snoowrap({user_agent: USER_AGENT, access_token});
  cachedRequester.config({debug: true, continue_after_ratelimit_error: true});
  return cachedRequester;
}

function nukeThread (url, toNuke) {
  var parsedUrl;
  removedCount = 0;
  try {
    parsedUrl = parseUrl(url);
  } catch (err) {
    document.getElementById('url-error-message').innerHTML = err.message;
    document.getElementById('url-error-message').style.display = 'block';
    throw err;
  }
  document.getElementById('url-error-message').style.display = 'none';
  document.getElementById('error-output').style.display = 'none';
  document.getElementById('loading-message').style.display = 'block';
  document.getElementById('done-message').style.display = 'none';
  return getAccessToken(query.code)
    .then(getRequester)
    .then(function (r) {
      return getExpandedContent(r, parsedUrl);
    }).then(function (content) {
      if (toNuke === "nuke") {
        return deepRemove(content, document.getElementById('preserve-distinguished-checkbox').checked);
      } else {
        return deepApprove(content, document.getElementById('preserve-removed-checkbox').checked);
      }

    }).then(function () {
      document.getElementById('done-message').style.display = 'block';
    })
    .catch(function (err) {
      document.getElementById('error-output').style.display = 'block';
      document.getElementById('loading-message').style.display = 'none';
      document.getElementById('done-message').style.display = 'none';
      throw err;
    });
}

function onSubmitClicked () { // eslint-disable-line no-unused-vars
  var url = document.getElementById('thread-url-box').value;
  var preserveDistinguished = document.getElementById('preserve-distinguished-checkbox').checked;
  var e = document.getElementById("to-nuke");
  var toNuke = document.getElementById("to-nuke").value;
  if (cookies.access_token || query.code) {
    return nukeThread(url, toNuke);
  }
  location = getAuthRedirect(JSON.stringify({url, preserveDistinguished}));
}

document.addEventListener('DOMContentLoaded', function () {
  if (query.state && query.code) {
    var parsedState = JSON.parse(decodeURIComponent(query.state));
    var url = decodeURIComponent(parsedState.url);
    document.getElementById('thread-url-box').value = url;
    document.getElementById('preserve-distinguished-checkbox').checked = parsedState.preserveDistinguished;
    document.getElementById('preserve-removed-checkbox').checked = parsedState.preserveRemoved;
    var toNuke = document.getElementById("to-nuke").value;
    nukeThread(url, toNuke);
  }
});<commit_msg>undo test<commit_after>'use strict';
/* global snoowrap */
var REDDIT_APP_ID = '_s9Icw2TEXpmaw';
var REDIRECT_URI = 'https://pkmnbumba.github.io/reddit-thread-unnuke/';

var USER_AGENT = 'reddit thread un-nuke by /u/bumbalicious || https://github.com/pkmnbumba/reddit-thread-unnuke';
var REQUIRED_SCOPES = ['modposts', 'read'];
var cachedRequester;
var accessTokenPromise;
var removedCount;

var query = parseQueryString(location.search);
var cookies = parseCookieString(document.cookie);

function parseQueryString (str) {
  if (!str) {
    return {};
  }
  var obj = {};
  var pieces = str.slice(1).split('&');
  for (var i = 0; i < pieces.length; i++) {
    var pair = pieces[i].split('=');
    obj[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
  }
  return obj;
}

function parseCookieString (cookieString) {
  var obj = {};
  var splitCookies = cookieString.split('; ');
  splitCookies.forEach(function (cookie) {
    var pair = cookie.split('=');
    obj[pair[0]] = pair[1];
  });
  return obj;
}

var getAuthRedirect = function (state) {
  return `https://reddit.com/api/v1/authorize?client_id=${REDDIT_APP_ID}&response_type=code&state=${encodeURIComponent(state)}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&duration=temporary&scope=${REQUIRED_SCOPES.join('%2C')}`;
};

function parseUrl (url) {
  var matches = url.match(/^(?:http(?:s?):\/\/)?(?:\w*\.)?reddit\.com\/(?:r\/\w{1,21}\/)?comments\/(\w{1,10})(?:\/[^\/\?]{1,100})?(?:\/(\w{1,10}))?\/?(?:\?.*)?$/);
  if (!matches) {
    throw new TypeError('Invalid URL. Please enter the URL of a reddit Submission or Comment.');
  }
  return matches;
}

function getExpandedContent (requester, urlMatches) {
  return (urlMatches[2] ? requester.get_comment(urlMatches[2]) : requester.get_submission(urlMatches[1])).expand_replies();
}

function deepRemove (content, preserveDistinguished) {
  var replies = content.comments || content.replies;
  var removeCurrentItem = content.distinguished && preserveDistinguished || content.banned_by !== null
    ? Promise.resolve()
    : content.remove().tap(incrementCounter);
  return Promise.all(Array.from(replies).map(function (reply) {
    return deepRemove(reply, preserveDistinguished);
  }).concat([removeCurrentItem]));
}

function deepApprove (content, preserveRemoved) {
  var replies = content.comments || content.replies;
  if (content.banned_by !== null) {
    console.log(content.banned_by['name']);
    var determineRemoved = preserveRemoved;
  }
  var approveCurrentItem = !content.removed || content.banned_by === null
    ? Promise.resolve()
    : content.approve().tap(incrementCounter);
  return Promise.all(Array.from(replies).map(function (reply) {
    return deepApprove(reply, preserveRemoved);
  }).concat([approveCurrentItem]));
}

function getAccessToken (code) {
  if (accessTokenPromise) {
    return accessTokenPromise;
  }
  accessTokenPromise = cookies.access_token && !code
    ? Promise.resolve(cookies.access_token)
    : snoowrap.prototype.credentialed_client_request.call({
      user_agent: USER_AGENT,
      client_id: REDDIT_APP_ID,
      client_secret: ''
    }, {
      method: 'post',
      url: 'https://www.reddit.com/api/v1/access_token',
      form: {grant_type: 'authorization_code', code, redirect_uri: REDIRECT_URI}
    }).then(function (response) {
      if (!response.access_token) {
        throw new Error('Authentication failed');
      }
      document.cookie = `access_token=${response.access_token}; max-age=3600; secure`;
      cookies.access_token = response.access_token;
      return response.access_token;
    });
  return accessTokenPromise;
}

function incrementCounter () {
  document.getElementById('removed-count').innerHTML = ++removedCount;
}

function getRequester (access_token) {
  if (cachedRequester) {
    return cachedRequester;
  }
  cachedRequester = new snoowrap({user_agent: USER_AGENT, access_token});
  cachedRequester.config({debug: true, continue_after_ratelimit_error: true});
  return cachedRequester;
}

function nukeThread (url, toNuke) {
  var parsedUrl;
  removedCount = 0;
  try {
    parsedUrl = parseUrl(url);
  } catch (err) {
    document.getElementById('url-error-message').innerHTML = err.message;
    document.getElementById('url-error-message').style.display = 'block';
    throw err;
  }
  document.getElementById('url-error-message').style.display = 'none';
  document.getElementById('error-output').style.display = 'none';
  document.getElementById('loading-message').style.display = 'block';
  document.getElementById('done-message').style.display = 'none';
  return getAccessToken(query.code)
    .then(getRequester)
    .then(function (r) {
      return getExpandedContent(r, parsedUrl);
    }).then(function (content) {
      if (toNuke === "nuke") {
        return deepRemove(content, document.getElementById('preserve-distinguished-checkbox').checked);
      } else {
        return deepApprove(content, document.getElementById('preserve-removed-checkbox').checked);
      }

    }).then(function () {
      document.getElementById('done-message').style.display = 'block';
    })
    .catch(function (err) {
      document.getElementById('error-output').style.display = 'block';
      document.getElementById('loading-message').style.display = 'none';
      document.getElementById('done-message').style.display = 'none';
      throw err;
    });
}

function onSubmitClicked () { // eslint-disable-line no-unused-vars
  var url = document.getElementById('thread-url-box').value;
  var preserveDistinguished = document.getElementById('preserve-distinguished-checkbox').checked;
  var e = document.getElementById("to-nuke");
  var toNuke = document.getElementById("to-nuke").value;
  if (cookies.access_token || query.code) {
    return nukeThread(url, toNuke);
  }
  location = getAuthRedirect(JSON.stringify({url, preserveDistinguished}));
}

document.addEventListener('DOMContentLoaded', function () {
  if (query.state && query.code) {
    var parsedState = JSON.parse(decodeURIComponent(query.state));
    var url = decodeURIComponent(parsedState.url);
    document.getElementById('thread-url-box').value = url;
    document.getElementById('preserve-distinguished-checkbox').checked = parsedState.preserveDistinguished;
    document.getElementById('preserve-removed-checkbox').checked = parsedState.preserveRemoved;
    var toNuke = document.getElementById("to-nuke").value;
    nukeThread(url, toNuke);
  }
});<|endoftext|>


<commit_before>// ==UserScript==
// @name        Toggl-Button YouTrack
// @namespace   https://github.com/jurgenhaas/toggl-button-greasemonkey
// @version     0.01
// @include     http*://youtrack.*/*
// @include     http*://*/youtrack/*
// @grant       GM_xmlhttpRequest
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_setValue
// @require     https://raw.githubusercontent.com/jurgenhaas/toggl-button-greasemonkey/master/TogglLibrary.js
// @resource    togglStyle https://raw.githubusercontent.com/jurgenhaas/toggl-button-greasemonkey/master/TogglLibrary.css
// ==/UserScript==

TogglButton.fetchUser(TogglButton.$newApiUrl, function() {
  togglbutton.render('.issueContainer', {}, function (elem) {
    var link, description, projectIds = [],
      numElem = $('.issueId', elem),
      titleElem = $('.issue-summary', elem),
      projectElem = $('.something');

    description = titleElem.innerHTML;
    if (numElem !== null) {
      description = numElem.innerHTML + " " + description;
    }

    if (projectElem !== null) {
      projectIds.push(projectElem.textContent);
    }

    link = togglbutton.createTimerLink({
      className: 'youtrack',
      description: description,
      projectIds: projectIds,
      targetSelectors: {
        link: '.fsi-toolbar-content',
        projectSelect: '.fsi-toolbar-content'
      }
    });
  });
});
<commit_msg>Adjust project selectors for YouTrack<commit_after>// ==UserScript==
// @name        Toggl-Button YouTrack
// @namespace   https://github.com/jurgenhaas/toggl-button-greasemonkey
// @version     0.01
// @include     http*://youtrack.*/*
// @include     http*://*/youtrack/*
// @grant       GM_xmlhttpRequest
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_setValue
// @require     https://raw.githubusercontent.com/jurgenhaas/toggl-button-greasemonkey/master/TogglLibrary.js
// @resource    togglStyle https://raw.githubusercontent.com/jurgenhaas/toggl-button-greasemonkey/master/TogglLibrary.css
// ==/UserScript==

TogglButton.fetchUser(TogglButton.$newApiUrl, function() {
  togglbutton.render('.fsi-layout.container', {}, function (elem) {
    var link, description, projectIds = [],
      numElem = $('.issueId', elem),
      titleElem = $('.issue-summary', elem),
      projectElem = $('.fsi-properties .fsi-property .regCC a'),
      linkElem = $('.fsi-content .links-panel .links .link');

    description = titleElem.innerHTML;
    if (numElem !== null) {
      description = numElem.innerHTML + " " + description;
    }

    if (projectElem !== null) {
      projectIds.push(projectElem.textContent.trim());
    }
    if (linkElem !== null) {
      projectIds.push(linkElem.textContent.trim());
    }

    link = togglbutton.createTimerLink({
      className: 'youtrack',
      description: description,
      projectIds: projectIds,
      targetSelectors: {
        link: '.fsi-toolbar-content',
        projectSelect: '.fsi-toolbar-content'
      }
    });
  });
});
<|endoftext|>


<commit_before>if (!BS) BS = {};
if (!BS.Kube) BS.Kube = {};

if(!BS.Kube.ProfileSettingsForm) BS.Kube.ProfileSettingsForm = OO.extend(BS.PluginPropertiesForm, {

    testConnectionUrl: '',

    templates: {
        imagesTableRow: $j('
\
	\
	\
edit	\
delete	\

')},

    _dataKeys: [ 'dockerImage', 'pool', 'maxInstances' ],

    selectors: {
        rmImageLink: '.removeVmImageLink',
        editImageLink: '.editVmImageLink',
        imagesTableRow: '.imagesTableRow'
    },

    _errors: {
        badParam: 'Bad parameter',
        required: 'This field cannot be blank',
        nonNegative: 'Must be non-negative number'
    },

    _displayedErrors: {},

    initialize: function(){
        this.$imagesTable = $j('#kubeImagesTable');
        this.$imagesTableWrapper = $j('.imagesTableWrapper');
        this.$emptyImagesListMessage = $j('.emptyImagesListMessage');

        this.$showAddImageDialogButton = $j('#showAddImageDialogButton');
        this.$addImageButton = $j('#kubeAddImageButton');
        this.$cancelAddImageButton = $j('#kubeCancelAddImageButton');
        this.$authStrategySelector = $j('#authStrategy');

        this.$podSpecModeSelector = $j('#podTemplateMode');
        this.$dockerImage = $j('#dockerImage');
        this.$imagePullPolicy = $j('#imagePullPolicy');
        this.$dockerCommand = $j('#dockerCmd');
        this.$dockerArgs = $j('#dockerArgs');
        this.$deploymentName = $j('#source-deployment');
        this.$customPodTemplate = $j('#custom-pod-template');
        this.$maxInstances = $j('#maxInstances');

        this.$imagesDataElem = $j('#' + 'source_images_json');

        var self = this;
        var rawImagesData = this.$imagesDataElem.val() || '[]';
        this._lastImageId = this._imagesDataLength = 0;
        try {
            var imagesData = JSON.parse(rawImagesData);
            this.imagesData = imagesData.reduce(function (accumulator, imageDataStr) {
                accumulator[self._lastImageId++] = imageDataStr;
                self._imagesDataLength++;
                return accumulator;
            }, {});
        } catch (e) {
            this.imagesData = {};
            BS.Log.error('bad images data: ' + rawImagesData);
        }

        this._bindHandlers();
        this._renderImagesTable();
        this.$addImageButton.removeAttr('disabled');
        this._toggleAuth();

        this._resetDataAndDialog();

        BS.Clouds.Admin.CreateProfileForm.checkIfModified();
    },

    _bindHandlers: function () {
        var self = this;

        //// Click Handlers
        this.$showAddImageDialogButton.on('click', this._showDialogClickHandler.bind(this));
        this.$addImageButton.on('click', this._submitDialogClickHandler.bind(this));
        this.$cancelAddImageButton.on('click', this._cancelDialogClickHandler.bind(this));
        this.$imagesTable.on('click', this.selectors.rmImageLink, function () {
            var $this = $j(this),
                id = $this.data('image-id'),
                name = self.imagesData[id].dockerImage;

            if (confirm('Are you sure you want to remove the image "' + name + '"?')) {
                self.removeImage($this);
            }
            return false;
        });
        var editDelegates = this.selectors.imagesTableRow + ' .highlight, ' + this.selectors.editImageLink;
        var that = this;
        this.$imagesTable.on('click', editDelegates, function () {
            if (!that.$addImageButton.prop('disabled')) {
                self.showEditImageDialog($j(this));
            }
            return false;
        });

        this.$authStrategySelector.on('change', this._toggleAuth.bind(this));
        this.$podSpecModeSelector.on('change', this._togglePodSpecMode.bind(this));

        ///// Change handlers
        this.$dockerImage.on('change', function (e, value) {
            if (arguments.length === 1) {
                this._image['dockerImage'] = this.$dockerImage.val();
            } else {
                this.$dockerImage.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));

        this.$imagePullPolicy.on('change', function(e, value) {
            if (arguments.length === 1) {
                this._image['imagePullPolicy'] = this.$imagePullPolicy.val();
            } else {
                this.$imagePullPolicy.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));

        this.$dockerCommand.on('change', function (e, value) {
            if (arguments.length === 1) {
                this._image['dockerCommand'] = this.$dockerCommand.val();
            } else {
                this.$dockerCommand.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));

        this.$dockerArgs.on('change', function (e, value) {
            if (arguments.length === 1) {
                this._image['dockerArgs'] = this.$dockerArgs.val();
            } else {
                this.$dockerArgs.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));

        this.$maxInstances.on('change', function (e, value) {
            if (arguments.length === 1) {
                this._image['maxInstances'] = this.$maxInstances.val();
            } else {
                this.$maxInstances.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));
    },

    _showDialogClickHandler: function () {
        if (! this.$showAddImageDialogButton.attr('disabled')) {
            this.showAddImageDialog();
        }
        return false;
    },

    _cancelDialogClickHandler: function () {
        BS.Kube.ImageDialog.close();
        return false;
    },

    _submitDialogClickHandler: function() {
        if (this.validateOptions()) {
            if (this.$addImageButton.val().toLowerCase() === 'edit') {
                this.editImage(this.$addImageButton.data('image-id'));
            } else {
                this.addImage();
            }
            BS.Kube.ImageDialog.close();
        }
        return false;
    },

    _renderImagesTable: function () {
        this._clearImagesTable();

        if (this._imagesDataLength) {
            Object.keys(this.imagesData).forEach(function (imageId) {
                var src = this.imagesData[imageId]['source-id'];
                $j('#initial_images_list').val($j('#initial_images_list').val() + src + ",");
                this._renderImageRow(this.imagesData[imageId], imageId);
            }.bind(this));
        }

        this._toggleImagesTable();
        BS.Clouds.Admin.CreateProfileForm.checkIfModified();
    },

    _renderImageRow: function (props, id) {
        var $row = this.templates.imagesTableRow.clone().attr('data-image-id', id);

        this._dataKeys.forEach(function (className) {
            $row.find('.' + className).text(props[className]);
        });

        $row.find(this.selectors.rmImageLink).data('image-id', id);
        $row.find(this.selectors.editImageLink).data('image-id', id);
        this.$imagesTable.append($row);
    },

    _clearImagesTable: function () {
        this.$imagesTable.find('.imagesTableRow').remove();
    },

    _toggleImagesTable: function () {
        var toggle = !!this._imagesDataLength;
        this.$imagesTableWrapper.removeClass('hidden');
        this.$emptyImagesListMessage.toggleClass('hidden', toggle);
        this.$imagesTable.toggleClass('hidden', !toggle);
    },

    _toggleAuth: function () {
        var selectedStrategyId = this.$authStrategySelector.val();
        $j('.auth-ui').toggleClass('hidden', true);
        if(selectedStrategyId) {
            $j('.' + selectedStrategyId).removeClass('hidden');
        }
    },

    _togglePodSpecMode: function () {
        var selectedMode = this.$podSpecModeSelector.val();
        $j('.pod-spec-ui').toggleClass('hidden', true);
        if(selectedMode) {
            $j('.' + selectedMode).removeClass('hidden');
        }
    },

    validateOptions: function (options){
        var isValid = true;
        var maxInstances = this._image['maxInstances'];

        var validators = {
            dockerImage : function () {
                if (!this._image['dockerImage']) {
                    this.addOptionError('required', 'dockerImage');
                    isValid = false;
                }
            }.bind(this),

            maxInstances: function () {
                if (!$j.isNumeric(maxInstances) || maxInstances < 0 ) {
                    this.addOptionError('nonNegative', 'maxInstances');
                    isValid = false;
                }
            }.bind(this)
        };

        if (options && ! $j.isArray(options)) {
            options = [options];
        }

        this.clearOptionsErrors(options);

        (options || this._dataKeys).forEach(function(option) {
            if(validators[option]) validators[option]();
        });

        return isValid;
    },

    addOptionError: function (errorKey, optionName) {
        var html;

        if (errorKey && optionName) {
            this._displayedErrors[optionName] = this._displayedErrors[optionName] || [];

            if (typeof errorKey !== 'string') {
                html = this._errors[errorKey.key];
                Object.keys(errorKey.props).forEach(function(key) {
                    html = html.replace('%%'+key+'%%', errorKey.props[key]);
                });
                errorKey = errorKey.key;
            } else {
                html = this._errors[errorKey];
            }

            if (this._displayedErrors[optionName].indexOf(errorKey) === -1) {
                this._displayedErrors[optionName].push(errorKey);
                this.addError(html, $j('.option-error_' + optionName));
            }
        }
    },

    addError: function (errorHTML, target) {
        (target || this.$fetchOptionsError)
            .append($j('
').html(errorHTML));
    },

    clearOptionsErrors: function (options) {
        (options || this._dataKeys).forEach(function (optionName) {
            this.clearErrors(optionName);
        }.bind(this));
    },

    clearErrors: function (errorId) {
        var target = $j('.option-error_' + errorId);
        if (errorId) {
            delete this._displayedErrors[errorId];
        }
        target.empty();
    },

    testConnection: function() {
        BS.ajaxRequest(this.testConnectionUrl, {
            parameters: BS.Clouds.Admin.CreateProfileForm.serializeParameters(),
            onFailure: function (response) {
                BS.TestConnectionDialog.show(false, response, null);
            }.bind(this),
            onSuccess: function (response) {
                var wereErrors = BS.XMLResponse.processErrors(response.responseXML, {
                    onConnectionError: function(elem) {
                        BS.TestConnectionDialog.show(false, elem.firstChild.nodeValue, null);
                    }
                }, BS.PluginPropertiesForm.propertiesErrorsHandler);
                if(!wereErrors){
                    BS.TestConnectionDialog.show(true, "", null);
                }
            }.bind(this)
        });
    },

    showAddImageDialog: function () {
        $j('#KubeImageDialogTitle').text('Add Kubernetes Cloud Image');

        BS.Hider.addHideFunction('KubeImageDialog', this._resetDataAndDialog.bind(this));
        this.$addImageButton.val('Add').data('image-id', 'undefined');

        this._image = {};

        BS.Kube.ImageDialog.showCentered();
    },

    showEditImageDialog: function ($elem) {
        var imageId = $elem.parents(this.selectors.imagesTableRow).data('image-id');

        $j('#KubeImageDialogTitle').text('Edit Kubernetes Cloud Image');

        BS.Hider.addHideFunction('KubeImageDialog', this._resetDataAndDialog.bind(this));

        typeof imageId !== 'undefined' && (this._image = $j.extend({}, this.imagesData[imageId]));
        this.$addImageButton.val('Edit').data('image-id', imageId);
        if (imageId === 'undefined'){
            this.$addImageButton.removeData('image-id');
        }

        var image = this._image;

        this.$podSpecModeSelector.trigger('change', image['podTemplateMode'] || '');
        this.$dockerImage.trigger('change', image['dockerImage'] || '');
        this.$imagePullPolicy.trigger('change', image['imagePullPolicy'] || '');
        this.$dockerCommand.trigger('change', image['dockerCmd'] || '');
        this.$dockerArgs.trigger('change', image['dockerArgs'] || '');
        this.$deploymentName.trigger('change', image['source-deployment'] || '');
        this.$customPodTemplate.trigger('change', image['custom-pod-template'] || '');
        this.$maxInstances.trigger('change', image['maxInstances'] || '');

        BS.Kube.ImageDialog.showCentered();
    },

    addImage: function () {
        console.info('addimage called');
        var newImageId = this._lastImageId++,
            newImage = this._image;
        newImage['source-id'] = newImageId;
        this._renderImageRow(newImage, newImageId);
        this.imagesData[newImageId] = newImage;
        this._imagesDataLength += 1;
        this.saveImagesData();
        this._toggleImagesTable();
    },

    editImage: function (id) {
        this._image['source-id'] = id;
        this.imagesData[id] = this._image;
        this.saveImagesData();
        this.$imagesTable.find(this.selectors.imagesTableRow).remove();
        this._renderImagesTable();
    },

    removeImage: function ($elem) {
        delete this.imagesData[$elem.data('image-id')];
        this._imagesDataLength -= 1;
        $elem.parents(this.selectors.imagesTableRow).remove();
        this.saveImagesData();
        this._toggleImagesTable();
    },

    saveImagesData: function () {
        var imageData = Object.keys(this.imagesData).reduce(function (accumulator, id) {
            var _val = $j.extend({}, this.imagesData[id]);

            delete _val.$image;
            accumulator.push(_val);

            return accumulator;
        }.bind(this), []);
        this.$imagesDataElem.val(JSON.stringify(imageData));
    },

    _resetDataAndDialog: function () {
        console.info('_resetDataAndDialog called');

        this._image = {};

        this.$podSpecModeSelector.trigger('change', '0');
        this.$dockerImage.trigger('change', '');
        this.$imagePullPolicy.trigger('change', '');
        this.$dockerCommand.trigger('change', '');
        this.$dockerArgs.trigger('change', '');
        this.$deploymentName.trigger('change', '');
        this.$customPodTemplate.trigger('change', '');
        this.$maxInstances.trigger('change', '1');
    }
});

if(!BS.Kube.ImageDialog) BS.Kube.ImageDialog = OO.extend(BS.AbstractModalDialog, {
    getContainer: function() {
        return $('KubeImageDialog');
    }
});<commit_msg>max instances number for image validate right<commit_after>if (!BS) BS = {};
if (!BS.Kube) BS.Kube = {};

if(!BS.Kube.ProfileSettingsForm) BS.Kube.ProfileSettingsForm = OO.extend(BS.PluginPropertiesForm, {

    testConnectionUrl: '',

    templates: {
        imagesTableRow: $j('
\
	\
	\
edit	\
delete	\

')},

    _dataKeys: [ 'dockerImage', 'pool', 'maxInstances' ],

    selectors: {
        rmImageLink: '.removeVmImageLink',
        editImageLink: '.editVmImageLink',
        imagesTableRow: '.imagesTableRow'
    },

    _errors: {
        badParam: 'Bad parameter',
        required: 'This field cannot be blank',
        nonNegative: 'Must be non-negative number'
    },

    _displayedErrors: {},

    initialize: function(){
        this.$imagesTable = $j('#kubeImagesTable');
        this.$imagesTableWrapper = $j('.imagesTableWrapper');
        this.$emptyImagesListMessage = $j('.emptyImagesListMessage');

        this.$showAddImageDialogButton = $j('#showAddImageDialogButton');
        this.$addImageButton = $j('#kubeAddImageButton');
        this.$cancelAddImageButton = $j('#kubeCancelAddImageButton');
        this.$authStrategySelector = $j('#authStrategy');

        this.$podSpecModeSelector = $j('#podTemplateMode');
        this.$dockerImage = $j('#dockerImage');
        this.$imagePullPolicy = $j('#imagePullPolicy');
        this.$dockerCommand = $j('#dockerCmd');
        this.$dockerArgs = $j('#dockerArgs');
        this.$deploymentName = $j('#source-deployment');
        this.$customPodTemplate = $j('#custom-pod-template');
        this.$maxInstances = $j('#maxInstances');

        this.$imagesDataElem = $j('#' + 'source_images_json');

        var self = this;
        var rawImagesData = this.$imagesDataElem.val() || '[]';
        this._lastImageId = this._imagesDataLength = 0;
        try {
            var imagesData = JSON.parse(rawImagesData);
            this.imagesData = imagesData.reduce(function (accumulator, imageDataStr) {
                accumulator[self._lastImageId++] = imageDataStr;
                self._imagesDataLength++;
                return accumulator;
            }, {});
        } catch (e) {
            this.imagesData = {};
            BS.Log.error('bad images data: ' + rawImagesData);
        }

        this._bindHandlers();
        this._renderImagesTable();
        this.$addImageButton.removeAttr('disabled');
        this._toggleAuth();

        this._resetDataAndDialog();

        BS.Clouds.Admin.CreateProfileForm.checkIfModified();
    },

    _bindHandlers: function () {
        var self = this;

        //// Click Handlers
        this.$showAddImageDialogButton.on('click', this._showDialogClickHandler.bind(this));
        this.$addImageButton.on('click', this._submitDialogClickHandler.bind(this));
        this.$cancelAddImageButton.on('click', this._cancelDialogClickHandler.bind(this));
        this.$imagesTable.on('click', this.selectors.rmImageLink, function () {
            var $this = $j(this),
                id = $this.data('image-id'),
                name = self.imagesData[id].dockerImage;

            if (confirm('Are you sure you want to remove the image "' + name + '"?')) {
                self.removeImage($this);
            }
            return false;
        });
        var editDelegates = this.selectors.imagesTableRow + ' .highlight, ' + this.selectors.editImageLink;
        var that = this;
        this.$imagesTable.on('click', editDelegates, function () {
            if (!that.$addImageButton.prop('disabled')) {
                self.showEditImageDialog($j(this));
            }
            return false;
        });

        this.$authStrategySelector.on('change', this._toggleAuth.bind(this));
        this.$podSpecModeSelector.on('change', this._togglePodSpecMode.bind(this));

        ///// Change handlers
        this.$dockerImage.on('change', function (e, value) {
            if (arguments.length === 1) {
                this._image['dockerImage'] = this.$dockerImage.val();
            } else {
                this.$dockerImage.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));

        this.$imagePullPolicy.on('change', function(e, value) {
            if (arguments.length === 1) {
                this._image['imagePullPolicy'] = this.$imagePullPolicy.val();
            } else {
                this.$imagePullPolicy.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));

        this.$dockerCommand.on('change', function (e, value) {
            if (arguments.length === 1) {
                this._image['dockerCommand'] = this.$dockerCommand.val();
            } else {
                this.$dockerCommand.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));

        this.$dockerArgs.on('change', function (e, value) {
            if (arguments.length === 1) {
                this._image['dockerArgs'] = this.$dockerArgs.val();
            } else {
                this.$dockerArgs.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));

        this.$maxInstances.on('change', function (e, value) {
            if (arguments.length === 1) {
                this._image['maxInstances'] = this.$maxInstances.val();
            } else {
                this.$maxInstances.val(value);
            }
            this.validateOptions(e.target.getAttribute('data-id'));
        }.bind(this));
    },

    _showDialogClickHandler: function () {
        if (! this.$showAddImageDialogButton.attr('disabled')) {
            this.showAddImageDialog();
        }
        return false;
    },

    _cancelDialogClickHandler: function () {
        BS.Kube.ImageDialog.close();
        return false;
    },

    _submitDialogClickHandler: function() {
        if (this.validateOptions()) {
            if (this.$addImageButton.val().toLowerCase() === 'edit') {
                this.editImage(this.$addImageButton.data('image-id'));
            } else {
                this.addImage();
            }
            BS.Kube.ImageDialog.close();
        }
        return false;
    },

    _renderImagesTable: function () {
        this._clearImagesTable();

        if (this._imagesDataLength) {
            Object.keys(this.imagesData).forEach(function (imageId) {
                var src = this.imagesData[imageId]['source-id'];
                $j('#initial_images_list').val($j('#initial_images_list').val() + src + ",");
                this._renderImageRow(this.imagesData[imageId], imageId);
            }.bind(this));
        }

        this._toggleImagesTable();
        BS.Clouds.Admin.CreateProfileForm.checkIfModified();
    },

    _renderImageRow: function (props, id) {
        var $row = this.templates.imagesTableRow.clone().attr('data-image-id', id);

        this._dataKeys.forEach(function (className) {
            $row.find('.' + className).text(props[className]);
        });

        $row.find(this.selectors.rmImageLink).data('image-id', id);
        $row.find(this.selectors.editImageLink).data('image-id', id);
        this.$imagesTable.append($row);
    },

    _clearImagesTable: function () {
        this.$imagesTable.find('.imagesTableRow').remove();
    },

    _toggleImagesTable: function () {
        var toggle = !!this._imagesDataLength;
        this.$imagesTableWrapper.removeClass('hidden');
        this.$emptyImagesListMessage.toggleClass('hidden', toggle);
        this.$imagesTable.toggleClass('hidden', !toggle);
    },

    _toggleAuth: function () {
        var selectedStrategyId = this.$authStrategySelector.val();
        $j('.auth-ui').toggleClass('hidden', true);
        if(selectedStrategyId) {
            $j('.' + selectedStrategyId).removeClass('hidden');
        }
    },

    _togglePodSpecMode: function () {
        var selectedMode = this.$podSpecModeSelector.val();
        $j('.pod-spec-ui').toggleClass('hidden', true);
        if(selectedMode) {
            $j('.' + selectedMode).removeClass('hidden');
        }
    },

    validateOptions: function (options){
        var isValid = true;
        var maxInstances = this._image['maxInstances'];

        var validators = {
            dockerImage : function () {
                if (!this._image['dockerImage']) {
                    this.addOptionError('required', 'dockerImage');
                    isValid = false;
                }
            }.bind(this),

            maxInstances: function () {
                if (maxInstances && (!$j.isNumeric(maxInstances) || maxInstances < 0 )) {
                    this.addOptionError('nonNegative', 'maxInstances');
                    isValid = false;
                }
            }.bind(this)
        };

        if (options && ! $j.isArray(options)) {
            options = [options];
        }

        this.clearOptionsErrors(options);

        (options || this._dataKeys).forEach(function(option) {
            if(validators[option]) validators[option]();
        });

        return isValid;
    },

    addOptionError: function (errorKey, optionName) {
        var html;

        if (errorKey && optionName) {
            this._displayedErrors[optionName] = this._displayedErrors[optionName] || [];

            if (typeof errorKey !== 'string') {
                html = this._errors[errorKey.key];
                Object.keys(errorKey.props).forEach(function(key) {
                    html = html.replace('%%'+key+'%%', errorKey.props[key]);
                });
                errorKey = errorKey.key;
            } else {
                html = this._errors[errorKey];
            }

            if (this._displayedErrors[optionName].indexOf(errorKey) === -1) {
                this._displayedErrors[optionName].push(errorKey);
                this.addError(html, $j('.option-error_' + optionName));
            }
        }
    },

    addError: function (errorHTML, target) {
        (target || this.$fetchOptionsError)
            .append($j('
').html(errorHTML));
    },

    clearOptionsErrors: function (options) {
        (options || this._dataKeys).forEach(function (optionName) {
            this.clearErrors(optionName);
        }.bind(this));
    },

    clearErrors: function (errorId) {
        var target = $j('.option-error_' + errorId);
        if (errorId) {
            delete this._displayedErrors[errorId];
        }
        target.empty();
    },

    testConnection: function() {
        BS.ajaxRequest(this.testConnectionUrl, {
            parameters: BS.Clouds.Admin.CreateProfileForm.serializeParameters(),
            onFailure: function (response) {
                BS.TestConnectionDialog.show(false, response, null);
            }.bind(this),
            onSuccess: function (response) {
                var wereErrors = BS.XMLResponse.processErrors(response.responseXML, {
                    onConnectionError: function(elem) {
                        BS.TestConnectionDialog.show(false, elem.firstChild.nodeValue, null);
                    }
                }, BS.PluginPropertiesForm.propertiesErrorsHandler);
                if(!wereErrors){
                    BS.TestConnectionDialog.show(true, "", null);
                }
            }.bind(this)
        });
    },

    showAddImageDialog: function () {
        $j('#KubeImageDialogTitle').text('Add Kubernetes Cloud Image');

        BS.Hider.addHideFunction('KubeImageDialog', this._resetDataAndDialog.bind(this));
        this.$addImageButton.val('Add').data('image-id', 'undefined');

        this._image = {};

        BS.Kube.ImageDialog.showCentered();
    },

    showEditImageDialog: function ($elem) {
        var imageId = $elem.parents(this.selectors.imagesTableRow).data('image-id');

        $j('#KubeImageDialogTitle').text('Edit Kubernetes Cloud Image');

        BS.Hider.addHideFunction('KubeImageDialog', this._resetDataAndDialog.bind(this));

        typeof imageId !== 'undefined' && (this._image = $j.extend({}, this.imagesData[imageId]));
        this.$addImageButton.val('Edit').data('image-id', imageId);
        if (imageId === 'undefined'){
            this.$addImageButton.removeData('image-id');
        }

        var image = this._image;

        this.$podSpecModeSelector.trigger('change', image['podTemplateMode'] || '');
        this.$dockerImage.trigger('change', image['dockerImage'] || '');
        this.$imagePullPolicy.trigger('change', image['imagePullPolicy'] || '');
        this.$dockerCommand.trigger('change', image['dockerCmd'] || '');
        this.$dockerArgs.trigger('change', image['dockerArgs'] || '');
        this.$deploymentName.trigger('change', image['source-deployment'] || '');
        this.$customPodTemplate.trigger('change', image['custom-pod-template'] || '');
        this.$maxInstances.trigger('change', image['maxInstances'] || '');

        BS.Kube.ImageDialog.showCentered();
    },

    addImage: function () {
        console.info('addimage called');
        var newImageId = this._lastImageId++,
            newImage = this._image;
        newImage['source-id'] = newImageId;
        this._renderImageRow(newImage, newImageId);
        this.imagesData[newImageId] = newImage;
        this._imagesDataLength += 1;
        this.saveImagesData();
        this._toggleImagesTable();
    },

    editImage: function (id) {
        this._image['source-id'] = id;
        this.imagesData[id] = this._image;
        this.saveImagesData();
        this.$imagesTable.find(this.selectors.imagesTableRow).remove();
        this._renderImagesTable();
    },

    removeImage: function ($elem) {
        delete this.imagesData[$elem.data('image-id')];
        this._imagesDataLength -= 1;
        $elem.parents(this.selectors.imagesTableRow).remove();
        this.saveImagesData();
        this._toggleImagesTable();
    },

    saveImagesData: function () {
        var imageData = Object.keys(this.imagesData).reduce(function (accumulator, id) {
            var _val = $j.extend({}, this.imagesData[id]);

            delete _val.$image;
            accumulator.push(_val);

            return accumulator;
        }.bind(this), []);
        this.$imagesDataElem.val(JSON.stringify(imageData));
    },

    _resetDataAndDialog: function () {
        console.info('_resetDataAndDialog called');

        this._image = {};

        this.$podSpecModeSelector.trigger('change', '0');
        this.$dockerImage.trigger('change', '');
        this.$imagePullPolicy.trigger('change', '');
        this.$dockerCommand.trigger('change', '');
        this.$dockerArgs.trigger('change', '');
        this.$deploymentName.trigger('change', '');
        this.$customPodTemplate.trigger('change', '');
        this.$maxInstances.trigger('change', '');
    }
});

if(!BS.Kube.ImageDialog) BS.Kube.ImageDialog = OO.extend(BS.AbstractModalDialog, {
    getContainer: function() {
        return $('KubeImageDialog');
    }
});<|endoftext|>