<commit_before>/**
 *
 */
/* globals ENTITY_ENGINE */

module.exports = (function () {
	return {
		moveTo : moveTo,
		setCoords : setCoords,
		getCoords : getCoords,
		say : say,
		getName : getName,
		forceMove : forceMove
	};

	function moveTo (entity, coords) {
		ENTITY_ENGINE.moveTo(entity, coords);
	}

	function setCoords (entity, coords) {
		ENTITY_ENGINE.setCoords(entity, coords);
	}

	function getCoords (entity) {
		return ENTITY_ENGINE.getCoords(entity);
	}

	function say (entity, message) {
		ENTITY_ENGINE.say(entity, message);
	}

	function getName (entity) {
		return ENTITY_ENGINE.getName(entity);
	}

	function forceMove (entity, coords, length) {
		ENTITY_ENGINE.forceMove(entity, coords, length);
	}

})();<commit_msg>Added extra params to forceMove() in entity api<commit_after>/**
 *
 */
/* globals ENTITY_ENGINE */

module.exports = (function () {
	return {
		moveTo : moveTo,
		setCoords : setCoords,
		getCoords : getCoords,
		say : say,
		getName : getName,
		forceMove : forceMove
	};

	function moveTo (entity, coords) {
		ENTITY_ENGINE.moveTo(entity, coords);
	}

	function setCoords (entity, coords) {
		ENTITY_ENGINE.setCoords(entity, coords);
	}

	function getCoords (entity) {
		return ENTITY_ENGINE.getCoords(entity);
	}

	function say (entity, message) {
		ENTITY_ENGINE.say(entity, message);
	}

	function getName (entity) {
		return ENTITY_ENGINE.getName(entity);
	}

	function forceMove (entity, coords, length, finalCoords, totalLength) {
		if (typeof(finalCoords) !== "undefined") {
			ENTITY_ENGINE.forceMove(entity, coords, length, finalCoords, totalLength);
		} else {
			ENTITY_ENGINE.forceMove(entity, coords, length);
		}
	}

})();<|endoftext|>


<commit_before>//---------------------------------------------------------------------
//
// This source file is part of the Meta:Magical project.
//
// See LICENCE for licence information.
// See CONTRIBUTORS for the list of contributors to the project.
//
//---------------------------------------------------------------------

// --[ Dependencies ]--------------------------------------------------
const Refinable       = require('refinable');
const marked          = require('marked');
const TerminalDisplay = require('./terminal-display');
const {
  Nil, Text,
  Sequence, Block, Title, Subtitle, Quote, Code, List, Table, HorizontalLine,
  Strong, Emphasis, Good, Error, Warning, Detail, Label,
  Markdown
} = require('./ast');

// --[ Helpers ]-------------------------------------------------------
function isNil(x) {
  return x && Nil.hasInstance(x);
}

function startsWith(prefix, text) {
  return text.indexOf(prefix) === 0;
}

function collapseNils(xs) {
  return xs.reduce((l, r) => {
    if (isNil(l[l.length - 1]) && isNil(r)) {
      return l;
    } else {
      return l.concat([r]);
    }
  }, []);
}

function ellipsis(max, text) {
  const x = text.trim();

  return x.length >= max ?  `${x.slice(0, max - 1)}…`
  :      /* else */         x
}

function definitionList(object) {
  return List(Object.keys(object).map(key =>
    Sequence([
      Label(Text(key)),
      Text(': '),
      Text(object[key])
    ])
  ));
}

function deprecated({ since, reason }) {
  return Quote(Block(0, [
    Error(Strong(Text(`Deprecated since ${since}`))),
    Nil(),
    Text(reason)
  ]));
}

// --[ The Browser ]---------------------------------------------------
/*~
 * The Meta:Magical browser allows inspecting annotated objects and
 * learning how to use them.
 *
 * The Browser is parameterised on an Interface, and a Display. The
 * Interface tells the Browser how to access metadata, whereas the
 * Display tells the Browser how to show that metadata.
 *
 * See the `State & Configuration` section for more details.
 *
 * ---
 * isModule  : true
 * stability : experimental
 * category  : Browsing Metadata
 */
const Browser = Refinable.refine({

  // ---[ State & Configuration ]--------------------------------------
  /*~
   * The metadata that should be displayed by this browser.
   *
   * This is an instance of `metamagical-interface`'s Interface, pointing
   * to the object that this browser should display. For example, in order
   * to see the summary of this Browser, one could refine it in the
   * following way:
   *
   *     const Interface = require('metamagical-interface');
   *     Browser.refine({ metadata: Interface.for(Browser) }).summary()
   *
   * It's better to use the `.for(Interface)` method of the Browser to
   * refine it than refine it directly, however:
   *
   *     Browser.for(Interface.for(Browser)).summary()
   *
   * ---
   * isRequired : true
   * category   : State & Configuration
   * stability  : experimental
   * type: |
   *   Interface
   */
  get metadata() {
    throw new Error('Unimplemented.');
  },

  /*~
   * How the metadata should be presented to the user.
   *
   * By default this Browser uses a Terminal display, which shows the
   * data with some formatting using terminal escape characters.
   *
   * Any other display may be provided, however, and this can be used
   * for generating static documentation, for example, by providing a
   * display that computes HTML or Markdown, instead of outputing it
   * to the screen.
   *
   * A display is a type that has a single method, `show(tree)`, which
   * takes a tree from a Browser AST, and returns the result of showing
   * that tree. In essence, Displays must fulfil the following interface:
   *
   *     type Display = {
   *       show : (BrowserAST) => Any
   *     }
   *
   * Since the Terminal display just outputs it on the terminal, it just
   * returns undefined. The Browser itself does nothing with the result,
   * it only returns it. So your Display could also return richer data
   * than a String, if it makes post-processing easier.
   *
   * In order to provide a Display to the browser, it has to be refined:
   *
   *     const HTMLBrowser = Browser.refine({ display: HTMLDisplay });
   *
   * ---
   * category  : State & Configuration
   * stability : experimental
   * type: |
   *   { show : (BrowserAST) => Any }
   */
  get display() {
    return TerminalDisplay;
  },

  // ---[ Navigating in the browser ]----------------------------------
  /*~
   * Changes the Interface for metadata this browser is showing.
   *
   * This should be an instane of `metamagical-interface`'s Interface
   * pointing to the object this browser should display. See `metadata`
   * for more information.
   *
   * Example:
   *
   *     const Interface = require('metamagical-interface');
   *     const browserBrowser = Browser.for(Interface.for(Browser));
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   * type: |
   *   Browser.(Interface) => Browser
   */
  for(meta) {
    return this.refine({ metadata: meta });
  },

  /*~
   * Browses the object at the given property of the current object.
   *
   * Example:
   *
   *     const forPropertyBrowser = Browser.forProperty("forProperty");
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   *
   * throws:
   *   Error: when the property doesn't exist in the object.
   *
   * type: |
   *   Browser.(String) => Browser :: (throws Error)
   */
  forProperty(name) {
    return this.metadata.property(name).map(x => this.for(x))
               .orElse(_ => { throw new Error(`No property for ${name}`) })
               .get();
  },

  /*~
   * Browses the getter with the given name in the current object.
   *
   * Example:
   *
   *     const newBrowser = Browser.forGetter("metadata");
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   *
   * throws:
   *   Error: when the getter doesn't exist in the object.
   *
   * type: |
   *   Browser.(String) => Browser :: (throws Error)
   */
  forGetter(name) {
    return this.metadata.getter(name).map(x => this.for(x))
               .orElse(_ => { throw new Error(`No getter for ${name}`) })
               .get();
  },

  /*~
   * Browses the setter with the given name in the current object.
   *
   * Example:
   *
   *     let foo = {
   *       _x: 0,
   *       set x(value) { this._x = value }
   *     };
   *     const newBrowser = Browser.for(Interface.for(foo))
   *                               .forSetter("x");
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   *
   * throws:
   *   Error: when the setter doesn't exist in the object.
   *
   * type: |
   *   Browser.(String) => Browser :: (throws Error)
   */
  forSetter(name) {
    return this.metadata.setter(name).map(x => this.for(x))
               .orElse(_ => { throw new Error(`No setter for ${name}`) })
               .get();
  },

  /*~
   * Browses the prototype of the current object.
   *
   * Example:
   *
   *     const newBrowser = Browser.forPrototype();
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   *
   * throws:
   *   Error: when the object doesn't have a `[[Prototype]]`
   *
   * type: |
   *   Browser.() => Browser :: (throws Error)
   */
  forPrototype() {
    return this.metadata.prototype().map(x => this.for(x))
               .orElse(_ => { throw new Error('No prototype') })
               .get();
  },

  // ---[ Auxiliary operations ]---------------------------------------
  getMetadata(name) {
    return this.metadata.get(this.metadata.fields[name]);
  },

  getSignature() {
    return this.getMetadata('signature')
               .orElse(_ => this.getMetadata('name'))
               .getOrElse('(Anonymous)');
  },

  _section(title, content) {
    return Block(0, [
      Title(1, title),
      Nil(),
      content
    ]);
  },

  _synopsis() {
    return this.getMetadata('documentation').map(doc => {
      const maybeParagraph = marked.lexer(doc)[0];
      if (maybeParagraph && maybeParagraph.type === 'paragraph') {
        return maybeParagraph.text;
      } else {
        return '(No synopsis)';
      }
    });
  },

  _withSignature(prefix) {
    return Sequence([
      Text(prefix),
      Text(' '),
      Text(this.getSignature())
    ]);
  },

  _maybeDefinition(label, content) {
    return content.cata({
      Nothing: _ => Nil(),
      Just:    v => Sequence([
        Label(Text(label)),
        Text(' '),
        v
      ])
    });
  },

  _stabilityFormat: {
    deprecated:   Error,
    experimental: Warning,
    stable:       Good,
    locked:       Good
  },

  _location() {
    return this.getMetadata('location').map(loc => {
      return Text([
        loc.filename ? loc.filename : '',
        loc.start    ? `at line ${loc.start.line}, column ${loc.start.column}` : null
      ].filter(x => x !== null).join(' '));
    });
  },

  _stabilitySummary() {
    return this.getMetadata('stability').map(s => {
      const format = this._stabilityFormat[s];
      const stability = this.metadata.Stability.fromIdentifier(s);

      return format(Text(`${stability.index} - ${stability.name}`));
    });
  },

  _executionMeta() {
    return Block(0, [
      this._maybeDefinition('Stability:', this._stabilitySummary()),
      this._maybeDefinition('Platforms:', this.getMetadata('platforms').map(xs => List(xs.map(Text)))),
      this._maybeDefinition('Complexity:', this.getMetadata('complexity').map(Text)),
      this._maybeDefinition('Returns:', this.getMetadata('returns').map(Text)),
      this._maybeDefinition('Throws:', this.getMetadata('throws').map(definitionList)),
      this._maybeDefinition('Parameters:', this.getMetadata('parameters').map(definitionList))
    ].filter(x => !isNil(x)));
  },

  _generalMetadata() {
    return Block(0, [
      this._maybeDefinition('Available since:', this.getMetadata('since').map(Text)),
      this._maybeDefinition('From:', this._location()),
      this._maybeDefinition('In package:', this.getMetadata('npmPackage').map(Text)),
      this._maybeDefinition('In module:', this.getMetadata('module').map(Text)),
      this._maybeDefinition('In object:', this.getMetadata('belongsTo').map(f =>
        Text(this.for(this.metadata.for(f())).getSignature())
      )),
      Text(''),
      this._maybeDefinition('Portability:', this.getMetadata('portable').map(v =>
        Text(v ? 'portable' : 'not portable')
      )),
      this._maybeDefinition('Copyright:', this.getMetadata('copyright').map(Text)),
      this._maybeDefinition('Licence:', this.getMetadata('licence').map(Text)),
      this._maybeDefinition('Repository:', this.getMetadata('repository').map(Text)),
      this._maybeDefinition('Web Site:', this.getMetadata('homepage').map(Text)),
      Text(''),
      this._maybeDefinition('Authors:', this.getMetadata('authors').map(xs => List(xs.map(Text)))),
      this._maybeDefinition('Maintainers:', this.getMetadata('maintainers').map(xs => List(xs.map(Text)))),
    ].filter(x => !isNil(x)));
  },

  _renderProperties(level, properties) {
    return Block(0,
      properties.map(({ category, members }) => {
        return Block(0, [
          Nil(),
          Title(level, Text(category)),
          List(members.map(member => {
            const meta      = this.metadata.for(member.value);
            const suffix    = meta.getByName('isRequired').map(v =>
                                true ? Error(Text(' (required, but missing)')) : Nil()
                              ).getOrElse(Nil());
            const signature = meta.get(meta.fields.signature).getOrElse(member.name)
                                  .replace(/^(get|set) /, '');
            const modifier  = member.kind === 'getter' ? 'get '
                            : member.kind === 'setter' ? 'set '
                            : /* otherwise */            '';
            const prefix    = startsWith(member.name, signature) ? Nil() : Text(`${member.name}: `);
            const synopsis  = ellipsis(120, this.for(meta)._synopsis().getOrElse('(No documentation)'));

            return Block(0, [
              Sequence([Text(modifier), Strong(prefix), Strong(Text(signature)), suffix]),
              Detail(Sequence([Text('   | '), Text(synopsis)])),
              Nil()
            ]);
          }))
        ]);
      })
    );
  },

  // ---[ Inspecting metadata ]----------------------------------------

  /*~
   * Shows the full documentation of the current object.
   *
   * ---
   * category  : Inspecting metadata
   * stability : experimental
   * type: |
   *   Browser.() => Any
   */
  documentation() {
    return this.display.show(
      this._section(
        this._withSignature('Documentation for'),
        Markdown(
          this.getMetadata('documentation').getOrElse('(No documentation)')
        )
      )
    );
  },

  /*~
   * Shows the source code of the current object.
   *
   * ---
   * category  : Inspecting metadata
   * stability : experimental
   * type: |
   *   Browser.() => Any
   */
  source() {
    return this.getMetadata('source').map(source =>
      this.display.show(
        this._section(
          this._withSignature('Source for'),
          Block(0, [
            ...[
              this._maybeDefinition('From:', this._location()),
              this._maybeDefinition('NPM package:', this.getMetadata('npmPackage').map(Text)),
              this._maybeDefinition('In module:', this.getMetadata('module').map(Text)),
              this._maybeDefinition('In object:', this.getMetadata('belongsTo').map(f =>
                Text(this.for(this.metadata.for(f())).getSignature())
              ))
            ].filter(v => !Nil.hasInstance(v)),
            Nil(),
            Code('javascript', source)
          ])
        )
      )
    ).getOrElse(undefined);
  },

  /*~
   * Shows the stability of the current object.
   *
   * ---
   * category  : Inspecting metadata
   * stability : experimental
   * type: |
   *   Browser.() => Any
   */
  stability() {
    return this.getMetadata('stability').map(id => {
      const stability = this.metadata.Stability.fromIdentifier(id);
      const format = this._stabilityFormat[id];

      return this.display.show(
        this._section(
          this._withSignature('Stability for'),
          Block(0, [
            Strong(format(Text(`${stability.index} - ${stability.name}`))),
            Nil(),
            Markdown(stability.description)
          ])
        )
      );
    }).getOrElse(undefined);
  },

  /*~
   * Shows a summary of the current object, with signature, synopsis, and
   * properties.
   *
   * ---
   * category  : Inspecting metadata
   * stability : experimental
   * type: |
   *   Browser.() => Any
   */
  summary() {
    return this.display.show(
      this._section(
        Text(this.getSignature()),
        Block(0, collapseNils([
          this.getMetadata('type').map(v => Code('mli', v)).getOrElse(null),
          Nil(),
          this.getMetadata('deprecated').map(deprecated).getOrElse(null),
          Nil(),
          this._executionMeta(),
          Nil(),
          this._synopsis().map(Text).getOrElse(null),
          Nil(),
          Quote(Text('(run `.documentation()` for the full docs)')),
          Nil(),
          Block(0, [
            Title(2, Text('Properties')),
            this._renderProperties(3, this.metadata.allProperties())
          ]),
          Nil(),
          HorizontalLine(),
          Nil(),
          this._generalMetadata()
        ].filter(x => x !== null)))
      )
    );
  },

});

// --[ Exports ]-------------------------------------------------------
module.exports = Browser;

<commit_msg>(new repl) Make `summary` shorter moving properties and metadata away<commit_after>//---------------------------------------------------------------------
//
// This source file is part of the Meta:Magical project.
//
// See LICENCE for licence information.
// See CONTRIBUTORS for the list of contributors to the project.
//
//---------------------------------------------------------------------

// --[ Dependencies ]--------------------------------------------------
const Refinable       = require('refinable');
const marked          = require('marked');
const TerminalDisplay = require('./terminal-display');
const {
  Nil, Text,
  Sequence, Block, Title, Subtitle, Quote, Code, List, Table, HorizontalLine,
  Strong, Emphasis, Good, Error, Warning, Detail, Label,
  Markdown
} = require('./ast');

// --[ Helpers ]-------------------------------------------------------
function isNil(x) {
  return x && Nil.hasInstance(x);
}

function startsWith(prefix, text) {
  return text.indexOf(prefix) === 0;
}

function collapseNils(xs) {
  return xs.reduce((l, r) => {
    if (isNil(l[l.length - 1]) && isNil(r)) {
      return l;
    } else {
      return l.concat([r]);
    }
  }, []);
}

function ellipsis(max, text) {
  const x = text.trim();

  return x.length >= max ?  `${x.slice(0, max - 1)}…`
  :      /* else */         x
}

function definitionList(object) {
  return List(Object.keys(object).map(key =>
    Sequence([
      Label(Text(key)),
      Text(': '),
      Text(object[key])
    ])
  ));
}

function deprecated({ since, reason }) {
  return Quote(Block(0, [
    Error(Strong(Text(`Deprecated since ${since}`))),
    Nil(),
    Text(reason)
  ]));
}

// --[ The Browser ]---------------------------------------------------
/*~
 * The Meta:Magical browser allows inspecting annotated objects and
 * learning how to use them.
 *
 * The Browser is parameterised on an Interface, and a Display. The
 * Interface tells the Browser how to access metadata, whereas the
 * Display tells the Browser how to show that metadata.
 *
 * See the `State & Configuration` section for more details.
 *
 * ---
 * isModule  : true
 * stability : experimental
 * category  : Browsing Metadata
 */
const Browser = Refinable.refine({

  // ---[ State & Configuration ]--------------------------------------
  /*~
   * The metadata that should be displayed by this browser.
   *
   * This is an instance of `metamagical-interface`'s Interface, pointing
   * to the object that this browser should display. For example, in order
   * to see the summary of this Browser, one could refine it in the
   * following way:
   *
   *     const Interface = require('metamagical-interface');
   *     Browser.refine({ metadata: Interface.for(Browser) }).summary()
   *
   * It's better to use the `.for(Interface)` method of the Browser to
   * refine it than refine it directly, however:
   *
   *     Browser.for(Interface.for(Browser)).summary()
   *
   * ---
   * isRequired : true
   * category   : State & Configuration
   * stability  : experimental
   * type: |
   *   Interface
   */
  get metadata() {
    throw new Error('Unimplemented.');
  },

  /*~
   * How the metadata should be presented to the user.
   *
   * By default this Browser uses a Terminal display, which shows the
   * data with some formatting using terminal escape characters.
   *
   * Any other display may be provided, however, and this can be used
   * for generating static documentation, for example, by providing a
   * display that computes HTML or Markdown, instead of outputing it
   * to the screen.
   *
   * A display is a type that has a single method, `show(tree)`, which
   * takes a tree from a Browser AST, and returns the result of showing
   * that tree. In essence, Displays must fulfil the following interface:
   *
   *     type Display = {
   *       show : (BrowserAST) => Any
   *     }
   *
   * Since the Terminal display just outputs it on the terminal, it just
   * returns undefined. The Browser itself does nothing with the result,
   * it only returns it. So your Display could also return richer data
   * than a String, if it makes post-processing easier.
   *
   * In order to provide a Display to the browser, it has to be refined:
   *
   *     const HTMLBrowser = Browser.refine({ display: HTMLDisplay });
   *
   * ---
   * category  : State & Configuration
   * stability : experimental
   * type: |
   *   { show : (BrowserAST) => Any }
   */
  get display() {
    return TerminalDisplay;
  },

  // ---[ Navigating in the browser ]----------------------------------
  /*~
   * Changes the Interface for metadata this browser is showing.
   *
   * This should be an instane of `metamagical-interface`'s Interface
   * pointing to the object this browser should display. See `metadata`
   * for more information.
   *
   * Example:
   *
   *     const Interface = require('metamagical-interface');
   *     const browserBrowser = Browser.for(Interface.for(Browser));
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   * type: |
   *   Browser.(Interface) => Browser
   */
  for(meta) {
    return this.refine({ metadata: meta });
  },

  /*~
   * Browses the object at the given property of the current object.
   *
   * Example:
   *
   *     const forPropertyBrowser = Browser.forProperty("forProperty");
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   *
   * throws:
   *   Error: when the property doesn't exist in the object.
   *
   * type: |
   *   Browser.(String) => Browser :: (throws Error)
   */
  forProperty(name) {
    return this.metadata.property(name).map(x => this.for(x))
               .orElse(_ => { throw new Error(`No property for ${name}`) })
               .get();
  },

  /*~
   * Browses the getter with the given name in the current object.
   *
   * Example:
   *
   *     const newBrowser = Browser.forGetter("metadata");
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   *
   * throws:
   *   Error: when the getter doesn't exist in the object.
   *
   * type: |
   *   Browser.(String) => Browser :: (throws Error)
   */
  forGetter(name) {
    return this.metadata.getter(name).map(x => this.for(x))
               .orElse(_ => { throw new Error(`No getter for ${name}`) })
               .get();
  },

  /*~
   * Browses the setter with the given name in the current object.
   *
   * Example:
   *
   *     let foo = {
   *       _x: 0,
   *       set x(value) { this._x = value }
   *     };
   *     const newBrowser = Browser.for(Interface.for(foo))
   *                               .forSetter("x");
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   *
   * throws:
   *   Error: when the setter doesn't exist in the object.
   *
   * type: |
   *   Browser.(String) => Browser :: (throws Error)
   */
  forSetter(name) {
    return this.metadata.setter(name).map(x => this.for(x))
               .orElse(_ => { throw new Error(`No setter for ${name}`) })
               .get();
  },

  /*~
   * Browses the prototype of the current object.
   *
   * Example:
   *
   *     const newBrowser = Browser.forPrototype();
   *
   * ---
   * category  : Navigating in the browser
   * stability : experimental
   *
   * throws:
   *   Error: when the object doesn't have a `[[Prototype]]`
   *
   * type: |
   *   Browser.() => Browser :: (throws Error)
   */
  forPrototype() {
    return this.metadata.prototype().map(x => this.for(x))
               .orElse(_ => { throw new Error('No prototype') })
               .get();
  },

  // ---[ Auxiliary operations ]---------------------------------------
  getMetadata(name) {
    return this.metadata.get(this.metadata.fields[name]);
  },

  getSignature() {
    return this.getMetadata('signature')
               .orElse(_ => this.getMetadata('name'))
               .getOrElse('(Anonymous)');
  },

  _section(title, content) {
    return Block(0, [
      Title(1, title),
      Nil(),
      content
    ]);
  },

  _synopsis() {
    return this.getMetadata('documentation').map(doc => {
      const maybeParagraph = marked.lexer(doc)[0];
      if (maybeParagraph && maybeParagraph.type === 'paragraph') {
        return maybeParagraph.text;
      } else {
        return '(No synopsis)';
      }
    });
  },

  _withSignature(prefix) {
    return Sequence([
      Text(prefix),
      Text(' '),
      Text(this.getSignature())
    ]);
  },

  _maybeDefinition(label, content) {
    return content.cata({
      Nothing: _ => Nil(),
      Just:    v => Sequence([
        Label(Text(label)),
        Text(' '),
        v
      ])
    });
  },

  _stabilityFormat: {
    deprecated:   Error,
    experimental: Warning,
    stable:       Good,
    locked:       Good
  },

  _location() {
    return this.getMetadata('location').map(loc => {
      return Text([
        loc.filename ? loc.filename : '',
        loc.start    ? `at line ${loc.start.line}, column ${loc.start.column}` : null
      ].filter(x => x !== null).join(' '));
    });
  },

  _stabilitySummary() {
    return this.getMetadata('stability').map(s => {
      const format = this._stabilityFormat[s];
      const stability = this.metadata.Stability.fromIdentifier(s);

      return format(Text(`${stability.index} - ${stability.name}`));
    });
  },

  _executionMeta() {
    return Block(0, [
      this._maybeDefinition('Stability:', this._stabilitySummary()),
      this._maybeDefinition('Platforms:', this.getMetadata('platforms').map(xs => List(xs.map(Text)))),
      this._maybeDefinition('Complexity:', this.getMetadata('complexity').map(Text)),
      this._maybeDefinition('Returns:', this.getMetadata('returns').map(Text)),
      this._maybeDefinition('Throws:', this.getMetadata('throws').map(definitionList)),
      this._maybeDefinition('Parameters:', this.getMetadata('parameters').map(definitionList))
    ].filter(x => !isNil(x)));
  },

  _generalMetadata() {
    return Block(0, [
      this._maybeDefinition('Available since:', this.getMetadata('since').map(Text)),
      this._maybeDefinition('From:', this._location()),
      this._maybeDefinition('In package:', this.getMetadata('npmPackage').map(Text)),
      this._maybeDefinition('In module:', this.getMetadata('module').map(Text)),
      this._maybeDefinition('In object:', this.getMetadata('belongsTo').map(f =>
        Text(this.for(this.metadata.for(f())).getSignature())
      )),
      Text(''),
      this._maybeDefinition('Portability:', this.getMetadata('portable').map(v =>
        Text(v ? 'portable' : 'not portable')
      )),
      this._maybeDefinition('Copyright:', this.getMetadata('copyright').map(Text)),
      this._maybeDefinition('Licence:', this.getMetadata('licence').map(Text)),
      this._maybeDefinition('Repository:', this.getMetadata('repository').map(Text)),
      this._maybeDefinition('Web Site:', this.getMetadata('homepage').map(Text)),
      Text(''),
      this._maybeDefinition('Authors:', this.getMetadata('authors').map(xs => List(xs.map(Text)))),
      this._maybeDefinition('Maintainers:', this.getMetadata('maintainers').map(xs => List(xs.map(Text)))),
    ].filter(x => !isNil(x)));
  },

  _renderProperties(level, properties) {
    return Block(0,
      properties.map(({ category, members }) => {
        return Block(0, [
          Nil(),
          Title(level, Text(category)),
          List(members.map(member => {
            const meta      = this.metadata.for(member.value);
            const suffix    = meta.getByName('isRequired').map(v =>
                                true ? Error(Text(' (required, but missing)')) : Nil()
                              ).getOrElse(Nil());
            const signature = meta.get(meta.fields.signature).getOrElse(member.name)
                                  .replace(/^(get|set) /, '');
            const modifier  = member.kind === 'getter' ? 'get '
                            : member.kind === 'setter' ? 'set '
                            : /* otherwise */            '';
            const prefix    = startsWith(member.name, signature) ? Nil() : Text(`${member.name}: `);
            const synopsis  = ellipsis(120, this.for(meta)._synopsis().getOrElse('(No documentation)'));

            return Block(0, [
              Sequence([Text(modifier), Strong(prefix), Strong(Text(signature)), suffix]),
              Detail(Sequence([Text('   | '), Text(synopsis)])),
              Nil()
            ]);
          }))
        ]);
      })
    );
  },

  // ---[ Inspecting metadata ]----------------------------------------

  /*~
   * Shows the full documentation of the current object.
   *
   * ---
   * category  : Inspecting metadata
   * stability : experimental
   * type: |
   *   Browser.() => Any
   */
  documentation() {
    return this.display.show(
      this._section(
        this._withSignature('Documentation for'),
        Markdown(
          this.getMetadata('documentation').getOrElse('(No documentation)')
        )
      )
    );
  },

  /*~
   * Shows the source code of the current object.
   *
   * ---
   * category  : Inspecting metadata
   * stability : experimental
   * type: |
   *   Browser.() => Any
   */
  source() {
    return this.getMetadata('source').map(source =>
      this.display.show(
        this._section(
          this._withSignature('Source for'),
          Block(0, [
            ...[
              this._maybeDefinition('From:', this._location()),
              this._maybeDefinition('NPM package:', this.getMetadata('npmPackage').map(Text)),
              this._maybeDefinition('In module:', this.getMetadata('module').map(Text)),
              this._maybeDefinition('In object:', this.getMetadata('belongsTo').map(f =>
                Text(this.for(this.metadata.for(f())).getSignature())
              ))
            ].filter(v => !Nil.hasInstance(v)),
            Nil(),
            Code('javascript', source)
          ])
        )
      )
    ).getOrElse(undefined);
  },

  /*~
   * Shows the stability of the current object.
   *
   * ---
   * category  : Inspecting metadata
   * stability : experimental
   * type: |
   *   Browser.() => Any
   */
  stability() {
    return this.getMetadata('stability').map(id => {
      const stability = this.metadata.Stability.fromIdentifier(id);
      const format = this._stabilityFormat[id];

      return this.display.show(
        this._section(
          this._withSignature('Stability for'),
          Block(0, [
            Strong(format(Text(`${stability.index} - ${stability.name}`))),
            Nil(),
            Markdown(stability.description)
          ])
        )
      );
    }).getOrElse(undefined);
  },

  /*~
   * Shows a summary of the current object, with signature, synopsis, and
   * properties.
   *
   * ---
   * category  : Inspecting metadata
   * stability : experimental
   * type: |
   *   Browser.() => Any
   */
  summary() {
    return this.display.show(
      this._section(
        Text(this.getSignature()),
        Block(0, collapseNils([
          this.getMetadata('type').map(v => Code('mli', v)).getOrElse(null),
          Nil(),
          this.getMetadata('deprecated').map(deprecated).getOrElse(null),
          Nil(),
          this._executionMeta(),
          Nil(),
          this._synopsis().map(Text).getOrElse(null),
          Nil(),
          Quote(Text('(run `.documentation()` for the full docs)')),
          Nil(),
          Block(0, [
            Title(2, Text('Properties')),
            this._renderProperties(3, this.metadata.properties())
          ]),
        ].filter(x => x !== null)))
      )
    );
  },

  /*~
   * Shows all properties that are accessible from the object.
   *
   * ---
   * category  : Inspecting metadata
   * stability : experimental
   * type: |
   *   Browser.() => Any
   */
  properties() {
    return this.display.show(
      this._section(
        Text(`Properties accessible from ${this.getSignature()}`),
        this._renderProperties(2, this.metadata.allProperties())
      )
    );
  }

});

// --[ Exports ]-------------------------------------------------------
module.exports = Browser;

<|endoftext|>


<commit_before>import Ember from 'ember';
import $ from 'jquery';
import {
  moduleForComponent,
  test
} from 'ember-qunit';

var show = false;
var stepsTemplate = [
  {
    id: 'intro',
    options: {
      attachTo: '.test-element bottom',
      builtInButtons: [
        {
          classes: 'shepherd-button-secondary',
          text: 'Exit',
          type: 'cancel'
        },
        {
          classes: 'shepherd-button-primary',
          text: 'Next',
          type: 'next'
        }
      ],
      classes: 'shepherd shepherd-open shepherd-theme-arrows shepherd-transparent-text',
      copyStyles: false,
      title: 'Welcome to Ember-Shepherd!',
      text: ['Test text'],
      when: {
        show: function() {
          show = true;
        }.bind(this),
        hide: function() {
          console.log('hide step');
        }.bind(this)
      }
    }
  }
];

moduleForComponent('ember-shepherd', {
  // specify the other units that are required for this test
  // needs: ['component:foo', 'helper:bar']
  afterEach: function() {
    show = false;
  }
});

test('it renders', function(assert) {
  assert.expect(2);

  // creates the component instance
  var component = this.subject();
  assert.equal(component._state, 'preRender');

  // renders the component to the page
  this.render();
  assert.equal(component._state, 'inDOM');
});

test('tour starts', function(assert) {
  assert.expect(3);
  var component = this.subject({
    template: Ember.Handlebars.compile('

')
  });

  this.render();
  var steps = stepsTemplate;

  Ember.run(function() {
    component.set('steps', steps);
    component.set('start', true);
  });

  assert.equal($('body').hasClass('shepherd-active'), true);
  assert.equal(this.$().children().hasClass('shepherd-enabled'), true);
  assert.equal(show, true);
});

test('attachTo works with object when element is string', function(assert) {
  assert.expect(3);

  var component = this.subject({
    template: Ember.Handlebars.compile('

')
  });

  this.render();
  var steps = stepsTemplate;
  stepsTemplate.options.attachTo = {
    element: '.test-element',
    on: 'bottom'
  };

  Ember.run(function() {
    component.set('steps', steps);
    component.set('start', true);
  });

  assert.equal($('body').hasClass('shepherd-active'), true);
  assert.equal(this.$().children().hasClass('shepherd-enabled'), true);
  assert.equal(show, true);
});

test('attachTo works with object when element is jQuery object', function(assert) {
  assert.expect(3);

  var component = this.subject({
    template: Ember.Handlebars.compile('

')
  });

  const element = $('.test-elemebt');

  this.render();
  var steps = stepsTemplate;
  stepsTemplate.options.attachTo = {
    element: element,
    on: 'bottom'
  };

  Ember.run(function() {
    component.set('steps', steps);
    component.set('start', true);
  });

  assert.equal($('body').hasClass('shepherd-active'), true);
  assert.equal(this.$().children().hasClass('shepherd-enabled'), true);
  assert.equal(show, true);
});

<commit_msg>Fix unit tests<commit_after>import Ember from 'ember';
import $ from 'jquery';
import {
  moduleForComponent,
  test
} from 'ember-qunit';

moduleForComponent('ember-shepherd', {
  // specify the other units that are required for this test
  // needs: ['component:foo', 'helper:bar']
});

test('it renders', function(assert) {
  assert.expect(2);

  // creates the component instance
  var component = this.subject();
  assert.equal(component._state, 'preRender');

  // renders the component to the page
  this.render();
  assert.equal(component._state, 'inDOM');
});

test('tour starts', function(assert) {
  assert.expect(3);
  var component = this.subject({
    template: Ember.Handlebars.compile('

')
  });

  this.render();
  var show = false;
  var steps = [
    {
      id: 'intro',
      options: {
        attachTo: '.test-element bottom',
        builtInButtons: [
          {
            classes: 'shepherd-button-secondary',
            text: 'Exit',
            type: 'cancel'
          },
          {
            classes: 'shepherd-button-primary',
            text: 'Next',
            type: 'next'
          }
        ],
        classes: 'shepherd shepherd-open shepherd-theme-arrows shepherd-transparent-text',
        copyStyles: false,
        title: 'Welcome to Ember-Shepherd!',
        text: ['Test text'],
        when: {
          show: function() {
            show = true;
          }.bind(this)
        }
      }
    }
  ];

  Ember.run(function() {
    component.set('steps', steps);
    component.set('start', true);
  });

  assert.equal($('body').hasClass('shepherd-active'), true, 'Body has correct class');
  assert.equal(this.$().children().hasClass('shepherd-enabled'), true, 'Element has correct class');
  assert.equal(show, true, 'Popup is shown');
});

test('attachTo works with object when element is string', function(assert) {
  assert.expect(3);

  var component = this.subject({
    template: Ember.Handlebars.compile('

')
  });

  this.render();
  var show = false;
  var steps = [
    {
      id: 'intro',
      options: {
        attachTo: {
          element: '.test-element',
          on: 'bottom'
        },
        builtInButtons: [
          {
            classes: 'shepherd-button-secondary',
            text: 'Exit',
            type: 'cancel'
          },
          {
            classes: 'shepherd-button-primary',
            text: 'Next',
            type: 'next'
          }
        ],
        classes: 'shepherd shepherd-open shepherd-theme-arrows shepherd-transparent-text',
        copyStyles: false,
        title: 'Welcome to Ember-Shepherd!',
        text: ['Test text'],
        when: {
          show: function() {
            show = true;
          }.bind(this)
        }
      }
    }
  ];

  Ember.run(function() {
    component.set('steps', steps);
    component.set('start', true);
  });

  assert.equal($('body').hasClass('shepherd-active'), true, 'Body has correct class');
  assert.equal(this.$().children().hasClass('shepherd-enabled'), true, 'Element has correct class');
  assert.equal(show, true, 'Popup is shown');
});

test('attachTo works with object when element is jQuery object', function(assert) {
  assert.expect(3);

  var component = this.subject({
    template: Ember.Handlebars.compile('

')
  });

  this.render();
  const element = $('.test-element');
  var show = false;
  var steps = [
    {
      id: 'intro',
      options: {
        attachTo: {
          element: element,
          on: 'bottom'
        },
        builtInButtons: [
          {
            classes: 'shepherd-button-secondary',
            text: 'Exit',
            type: 'cancel'
          },
          {
            classes: 'shepherd-button-primary',
            text: 'Next',
            type: 'next'
          }
        ],
        classes: 'shepherd shepherd-open shepherd-theme-arrows shepherd-transparent-text',
        copyStyles: false,
        title: 'Welcome to Ember-Shepherd!',
        text: ['Test text'],
        when: {
          show: function() {
            show = true;
          }.bind(this)
        }
      }
    }
  ];

  Ember.run(function() {
    component.set('steps', steps);
    component.set('start', true);
  });

  assert.equal($('body').hasClass('shepherd-active'), true, 'Body has correct class');
  assert.equal(this.$().children().hasClass('shepherd-enabled'), true, 'Element has correct class');
  assert.equal(show, true, 'Popup is shown');
});

<|endoftext|>


<commit_before>
import Debug from 'debug'
import getWindow from 'get-window'
import { findDOMNode } from 'react-dom'

import HOTKEYS from '../constants/hotkeys'
import {
  IS_FIREFOX,
  IS_IOS,
  IS_ANDROID,
  SUPPORTED_EVENTS
} from '../constants/environment'
import findNode from '../utils/find-node'

/**
 * Debug.
 *
 * @type {Function}
 */

const debug = Debug('slate:before')

/**
 * The core before plugin.
 *
 * @return {Object}
 */

function BeforePlugin() {
  let compositionCount = 0
  let isComposing = false
  let isCopying = false
  let isDragging = false

  /**
   * On before input.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onBeforeInput(event, change, editor) {
    if (editor.props.readOnly) return true

    // COMPAT: React's `onBeforeInput` synthetic event is based on the native
    // `keypress` and `textInput` events. In browsers that support the native
    // `beforeinput` event, we instead use that event to trigger text insertion,
    // since it provides more useful information about the range being affected
    // and also preserves compatibility with iOS autocorrect, which would be
    // broken if we called `preventDefault()` on React's synthetic event here.
    // Since native `onbeforeinput` mainly benefits autocorrect and spellcheck
    // for mobile, on desktop it brings IME issue, limit its scope for now.
    if ((IS_IOS || IS_ANDROID) && SUPPORTED_EVENTS.beforeinput) return true

    debug('onBeforeInput', { event })
  }

  /**
   * On blur.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onBlur(event, change, editor) {
    if (isCopying) return true
    if (editor.props.readOnly) return true

    const { value } = change
    const focusTarget = event.relatedTarget

    // If focusTarget is null, the blur event is due to the window itself being
    // blurred (eg. when changing tabs) so we should ignore the event, since we
    // want to maintain focus when returning.
    if (!focusTarget) return true

    const el = findDOMNode(editor)

    // The event should also be ignored if the focus returns to the editor from
    // an embedded editable element (eg. an input element inside a void node),
    if (focusTarget == el) return true

    // when the focus moved from the editor to a void node spacer...
    if (focusTarget.hasAttribute('data-slate-spacer')) return true

    // or to an editable element inside the editor but not into a void node
    // (eg. a list item of the check list example).
    if (
      el.contains(focusTarget) &&
      !findNode(focusTarget, value).isVoid
    ) {
      return true
    }

    debug('onBlur', { event })
  }

  /**
   * On change.
   *
   * @param {Change} change
   * @param {Editor} editor
   */

  function onChange(change, editor) {
    const { value } = change

    // If the value's schema isn't the editor's schema, update it. This can
    // happen on the initialization of the editor, or if the schema changes.
    // This change isn't save into history since only schema is updated.
    if (value.schema != editor.schema) {
      change
        .setValue({ schema: editor.schema }, { save: false })
        .normalize()
    }

    debug('onChange')
  }

  /**
   * On composition end.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onCompositionEnd(event, change, editor) {
    const n = compositionCount

    // The `count` check here ensures that if another composition starts
    // before the timeout has closed out this one, we will abort unsetting the
    // `isComposing` flag, since a composition is still in affect.
    setTimeout(() => {
      if (compositionCount > n) return
      isComposing = false

      // HACK: we need to re-render the editor here so that it will update its
      // placeholder in case one is currently rendered. This should be handled
      // differently ideally, in a less invasive way?
      editor.setState({ isComposing: false })
    })

    debug('onCompositionEnd', { event })
  }

  /**
   * On composition start.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onCompositionStart(event, change, editor) {
    isComposing = true
    compositionCount++

    // HACK: we need to re-render the editor here so that it will update its
    // placeholder in case one is currently rendered. This should be handled
    // differently ideally, in a less invasive way?
    editor.setState({ isComposing: true })

    debug('onCompositionStart', { event })
  }

  /**
   * On copy.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onCopy(event, change, editor) {
    const window = getWindow(event.target)
    isCopying = true
    window.requestAnimationFrame(() => isCopying = false)

    debug('onCopy', { event })
  }

  /**
   * On cut.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onCut(event, change, editor) {
    if (editor.props.readOnly) return true

    const window = getWindow(event.target)
    isCopying = true
    window.requestAnimationFrame(() => isCopying = false)

    debug('onCut', { event })
  }

  /**
   * On drag end.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragEnd(event, change, editor) {
    isDragging = false

    debug('onDragEnd', { event })
  }

  /**
   * On drag enter.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragEnter(event, change, editor) {
    debug('onDragEnter', { event })
  }

  /**
   * On drag exit.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragExit(event, change, editor) {
    debug('onDragExit', { event })
  }

  /**
   * On drag leave.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragLeave(event, change, editor) {
    debug('onDragLeave', { event })
  }

  /**
   * On drag over.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragOver(event, change, editor) {
    // If the target is inside a void node, and only in this case,
    // call `preventDefault` to signal that drops are allowed.
    // When the target is editable, dropping is already allowed by
    // default, and calling `preventDefault` hides the cursor.
    const node = findNode(event.target, editor.value)
    if (node.isVoid) event.preventDefault()

    // If a drag is already in progress, don't do this again.
    if (isDragging) return true

    isDragging = true
    event.nativeEvent.dataTransfer.dropEffect = 'move'

    debug('onDragOver', { event })
  }

  /**
   * On drag start.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragStart(event, change, editor) {
    isDragging = true

    debug('onDragStart', { event })
  }

  /**
   * On drop.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDrop(event, change, editor) {
    // Stop propagation so the event isn't visible to parent editors.
    event.stopPropagation()

    // Nothing happens in read-only mode.
    if (editor.props.readOnly) return true

    // Prevent default so the DOM's value isn't corrupted.
    event.preventDefault()

    debug('onDrop', { event })
  }

  /**
   * On focus.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onFocus(event, change, editor) {
    if (isCopying) return true
    if (editor.props.readOnly) return true

    const el = findDOMNode(editor)

    // COMPAT: If the editor has nested editable elements, the focus can go to
    // those elements. In Firefox, this must be prevented because it results in
    // issues with keyboard navigation. (2017/03/30)
    if (IS_FIREFOX && event.target != el) {
      el.focus()
      return true
    }

    debug('onFocus', { event })
  }

  /**
   * On input.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onInput(event, change, editor) {
    if (isComposing) return true
    if (change.value.isBlurred) return true

    debug('onInput', { event })
  }

  /**
   * On key down.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onKeyDown(event, change, editor) {
    if (editor.props.readOnly) return true

    // When composing, these characters commit the composition but also move the
    // selection before we're able to handle it, so prevent their default,
    // selection-moving behavior.
    if (isComposing && HOTKEYS.COMPOSING(event)) {
      event.preventDefault()
      return true
    }

    // Certain hotkeys have native behavior in contenteditable elements which
    // will cause our value to be out of sync, so prevent them.
    if (HOTKEYS.CONTENTEDITABLE(event)) {
      event.preventDefault()
    }

    debug('onKeyDown', { event })
  }

  /**
   * On paste.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onPaste(event, change, editor) {
    if (editor.props.readOnly) return true

    // Prevent defaults so the DOM state isn't corrupted.
    event.preventDefault()

    debug('onPaste', { event })
  }

  /**
   * On select.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onSelect(event, change, editor) {
    if (isCopying) return true
    if (isComposing) return true
    if (editor.props.readOnly) return true

    debug('onSelect', { event })
  }

  /**
   * Return the plugin.
   *
   * @type {Object}
   */

  return {
    onBeforeInput,
    onBlur,
    onChange,
    onCompositionEnd,
    onCompositionStart,
    onCopy,
    onCut,
    onDragEnd,
    onDragEnter,
    onDragExit,
    onDragLeave,
    onDragOver,
    onDragStart,
    onDrop,
    onFocus,
    onInput,
    onKeyDown,
    onPaste,
    onSelect,
  }
}

/**
 * Export.
 *
 * @type {Object}
 */

export default BeforePlugin
<commit_msg>fix blur not triggering (#1342)<commit_after>
import Debug from 'debug'
import getWindow from 'get-window'
import { findDOMNode } from 'react-dom'

import HOTKEYS from '../constants/hotkeys'
import {
  IS_FIREFOX,
  IS_IOS,
  IS_ANDROID,
  SUPPORTED_EVENTS
} from '../constants/environment'
import findNode from '../utils/find-node'

/**
 * Debug.
 *
 * @type {Function}
 */

const debug = Debug('slate:before')

/**
 * The core before plugin.
 *
 * @return {Object}
 */

function BeforePlugin() {
  let compositionCount = 0
  let isComposing = false
  let isCopying = false
  let isDragging = false

  /**
   * On before input.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onBeforeInput(event, change, editor) {
    if (editor.props.readOnly) return true

    // COMPAT: React's `onBeforeInput` synthetic event is based on the native
    // `keypress` and `textInput` events. In browsers that support the native
    // `beforeinput` event, we instead use that event to trigger text insertion,
    // since it provides more useful information about the range being affected
    // and also preserves compatibility with iOS autocorrect, which would be
    // broken if we called `preventDefault()` on React's synthetic event here.
    // Since native `onbeforeinput` mainly benefits autocorrect and spellcheck
    // for mobile, on desktop it brings IME issue, limit its scope for now.
    if ((IS_IOS || IS_ANDROID) && SUPPORTED_EVENTS.beforeinput) return true

    debug('onBeforeInput', { event })
  }

  /**
   * On blur.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onBlur(event, change, editor) {
    if (isCopying) return true
    if (editor.props.readOnly) return true

    const { value } = change
    const focusTarget = event.relatedTarget

    // focusTarget may be null when window itself being blurred
    // (eg. when changing tabs), or when user clicks on elements
    // without`tabindex` attribute.
    if (focusTarget) {
      const el = findDOMNode(editor)
      // The event should be ignored if the focus returns to the editor from an
      // embedded editable element (eg. an input element inside a void node).
      if (focusTarget == el) return true

      // when the focus moved from the editor to a void node spacer...
      if (focusTarget.hasAttribute('data-slate-spacer')) return true

      // or to an editable element inside the editor but not into a void node
      // (eg. a list item of the check list example).
      if (
        el.contains(focusTarget) &&
        !findNode(focusTarget, value).isVoid
      ) {
        return true
      }
    }

    debug('onBlur', { event })
  }

  /**
   * On change.
   *
   * @param {Change} change
   * @param {Editor} editor
   */

  function onChange(change, editor) {
    const { value } = change

    // If the value's schema isn't the editor's schema, update it. This can
    // happen on the initialization of the editor, or if the schema changes.
    // This change isn't save into history since only schema is updated.
    if (value.schema != editor.schema) {
      change
        .setValue({ schema: editor.schema }, { save: false })
        .normalize()
    }

    debug('onChange')
  }

  /**
   * On composition end.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onCompositionEnd(event, change, editor) {
    const n = compositionCount

    // The `count` check here ensures that if another composition starts
    // before the timeout has closed out this one, we will abort unsetting the
    // `isComposing` flag, since a composition is still in affect.
    setTimeout(() => {
      if (compositionCount > n) return
      isComposing = false

      // HACK: we need to re-render the editor here so that it will update its
      // placeholder in case one is currently rendered. This should be handled
      // differently ideally, in a less invasive way?
      editor.setState({ isComposing: false })
    })

    debug('onCompositionEnd', { event })
  }

  /**
   * On composition start.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onCompositionStart(event, change, editor) {
    isComposing = true
    compositionCount++

    // HACK: we need to re-render the editor here so that it will update its
    // placeholder in case one is currently rendered. This should be handled
    // differently ideally, in a less invasive way?
    editor.setState({ isComposing: true })

    debug('onCompositionStart', { event })
  }

  /**
   * On copy.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onCopy(event, change, editor) {
    const window = getWindow(event.target)
    isCopying = true
    window.requestAnimationFrame(() => isCopying = false)

    debug('onCopy', { event })
  }

  /**
   * On cut.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onCut(event, change, editor) {
    if (editor.props.readOnly) return true

    const window = getWindow(event.target)
    isCopying = true
    window.requestAnimationFrame(() => isCopying = false)

    debug('onCut', { event })
  }

  /**
   * On drag end.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragEnd(event, change, editor) {
    isDragging = false

    debug('onDragEnd', { event })
  }

  /**
   * On drag enter.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragEnter(event, change, editor) {
    debug('onDragEnter', { event })
  }

  /**
   * On drag exit.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragExit(event, change, editor) {
    debug('onDragExit', { event })
  }

  /**
   * On drag leave.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragLeave(event, change, editor) {
    debug('onDragLeave', { event })
  }

  /**
   * On drag over.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragOver(event, change, editor) {
    // If the target is inside a void node, and only in this case,
    // call `preventDefault` to signal that drops are allowed.
    // When the target is editable, dropping is already allowed by
    // default, and calling `preventDefault` hides the cursor.
    const node = findNode(event.target, editor.value)
    if (node.isVoid) event.preventDefault()

    // If a drag is already in progress, don't do this again.
    if (isDragging) return true

    isDragging = true
    event.nativeEvent.dataTransfer.dropEffect = 'move'

    debug('onDragOver', { event })
  }

  /**
   * On drag start.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDragStart(event, change, editor) {
    isDragging = true

    debug('onDragStart', { event })
  }

  /**
   * On drop.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onDrop(event, change, editor) {
    // Stop propagation so the event isn't visible to parent editors.
    event.stopPropagation()

    // Nothing happens in read-only mode.
    if (editor.props.readOnly) return true

    // Prevent default so the DOM's value isn't corrupted.
    event.preventDefault()

    debug('onDrop', { event })
  }

  /**
   * On focus.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onFocus(event, change, editor) {
    if (isCopying) return true
    if (editor.props.readOnly) return true

    const el = findDOMNode(editor)

    // COMPAT: If the editor has nested editable elements, the focus can go to
    // those elements. In Firefox, this must be prevented because it results in
    // issues with keyboard navigation. (2017/03/30)
    if (IS_FIREFOX && event.target != el) {
      el.focus()
      return true
    }

    debug('onFocus', { event })
  }

  /**
   * On input.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onInput(event, change, editor) {
    if (isComposing) return true
    if (change.value.isBlurred) return true

    debug('onInput', { event })
  }

  /**
   * On key down.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onKeyDown(event, change, editor) {
    if (editor.props.readOnly) return true

    // When composing, these characters commit the composition but also move the
    // selection before we're able to handle it, so prevent their default,
    // selection-moving behavior.
    if (isComposing && HOTKEYS.COMPOSING(event)) {
      event.preventDefault()
      return true
    }

    // Certain hotkeys have native behavior in contenteditable elements which
    // will cause our value to be out of sync, so prevent them.
    if (HOTKEYS.CONTENTEDITABLE(event)) {
      event.preventDefault()
    }

    debug('onKeyDown', { event })
  }

  /**
   * On paste.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onPaste(event, change, editor) {
    if (editor.props.readOnly) return true

    // Prevent defaults so the DOM state isn't corrupted.
    event.preventDefault()

    debug('onPaste', { event })
  }

  /**
   * On select.
   *
   * @param {Event} event
   * @param {Change} change
   * @param {Editor} editor
   */

  function onSelect(event, change, editor) {
    if (isCopying) return true
    if (isComposing) return true
    if (editor.props.readOnly) return true

    debug('onSelect', { event })
  }

  /**
   * Return the plugin.
   *
   * @type {Object}
   */

  return {
    onBeforeInput,
    onBlur,
    onChange,
    onCompositionEnd,
    onCompositionStart,
    onCopy,
    onCut,
    onDragEnd,
    onDragEnter,
    onDragExit,
    onDragLeave,
    onDragOver,
    onDragStart,
    onDrop,
    onFocus,
    onInput,
    onKeyDown,
    onPaste,
    onSelect,
  }
}

/**
 * Export.
 *
 * @type {Object}
 */

export default BeforePlugin
<|endoftext|>


<commit_before>'use strict';

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

exports.up = function(next) {

  var sqls = [
    'CREATE TABLE IF NOT EXISTS user_config ( ' +
    'id serial PRIMARY KEY, ' +
    'type text NOT NULL, ' +
    'data json NOT NULL ' +
    ')',

    'CREATE TABLE IF NOT EXISTS devices ( ' +
    'id serial PRIMARY KEY, ' +
    'fingerprint text NOT NULL UNIQUE, ' +
    'name text, ' +
    'authorized boolean, ' +
    'unpair boolean NOT NULL DEFAULT false' +
    ')',

    'CREATE TABLE IF NOT EXISTS pairing_tokens (' +
    'id serial PRIMARY KEY, ' +
    'token text, ' +
    'created timestamp NOT NULL DEFAULT now() ' +
    ')',

    'CREATE TABLE IF NOT EXISTS users ( ' +
    'id serial PRIMARY KEY, ' +
    'userName text NOT NULL UNIQUE, ' +
    'salt text NOT NULL, ' +
    'pwdHash text NOT NULL ' +
    ')'
  ];

  db.multi(sqls, next);
};

exports.down = function(next) {
  next();
};
<commit_msg>populate user_config in migrations<commit_after>'use strict'

var db = require('./db')

var exchanges = {
  exchanges: {
    settings: {
      commission: 1.0,
      compliance: {
        maximum: {
          limit: null
        }
      }
    },
    plugins: {
      current: {
        ticker: 'bitpay',
        transfer: 'bitgo'
      },
      settings: {
        bitpay: {},
        bitgo: {}
      }
    }
  }
}

var unit = {
  brain: {
    locale: {
      currency: 'USD',
      localeInfo: {
        primaryLocale: 'en-US',
        primaryLocales: ['en-US']
      }
    }
  }
}

exports.up = function (next) {
  var sqls = [
    'CREATE TABLE IF NOT EXISTS user_config ( ' +
    'id serial PRIMARY KEY, ' +
    'type text NOT NULL, ' +
    'data json NOT NULL ' +
    ')',

    'CREATE TABLE IF NOT EXISTS devices ( ' +
    'id serial PRIMARY KEY, ' +
    'fingerprint text NOT NULL UNIQUE, ' +
    'name text, ' +
    'authorized boolean, ' +
    'unpair boolean NOT NULL DEFAULT false' +
    ')',

    'CREATE TABLE IF NOT EXISTS pairing_tokens (' +
    'id serial PRIMARY KEY, ' +
    'token text, ' +
    'created timestamp NOT NULL DEFAULT now() ' +
    ')',

    'CREATE TABLE IF NOT EXISTS users ( ' +
    'id serial PRIMARY KEY, ' +
    'userName text NOT NULL UNIQUE, ' +
    'salt text NOT NULL, ' +
    'pwdHash text NOT NULL ' +
    ')',

    'INSERT INTO user_config (type, data) ' +
    "VALUES ('exchanges', '" + JSON.stringify(exchanges) + "')",

    'INSERT INTO user_config (type, data) ' +
    "VALUES ('unit', '" + JSON.stringify(unit) + "')"
  ]

  db.multi(sqls, next)
}

exports.down = function (next) {
  next()
}
<|endoftext|>


<commit_before>const defaultSearchProviders = [
  {
    id: 'ob1',
    name: 'OB1',
    logo: '../imgs/ob1searchLogo.png',
    localLogo: '../imgs/ob1searchLogo.png',
    listings: 'https://search.ob1.io/listings/search',
    torlistings: 'http://my7nrnmkscxr32zo.onion/listings/search',
    vendors: 'https://search.ob1.io/profiles/search?type=vendor',
    reports: 'https://search.ob1.io/reports',
  },
];

export default defaultSearchProviders;
<commit_msg>add tor endpoints<commit_after>const defaultSearchProviders = [
  {
    id: 'ob1',
    name: 'OB1',
    logo: '../imgs/ob1searchLogo.png',
    localLogo: '../imgs/ob1searchLogo.png',
    listings: 'https://search.ob1.io/listings/search',
    torlistings: 'http://my7nrnmkscxr32zo.onion/listings/search',
    vendors: 'https://search.ob1.io/profiles/search?type=vendor',
    torVendors: 'http://my7nrnmkscxr32zo.onion/profiles/search?type=vendor',
    reports: 'https://search.ob1.io/reports',
    torReports: 'http://my7nrnmkscxr32zo.onion/reports',
  },
];

export default defaultSearchProviders;
<|endoftext|>


<commit_before>var co = require('co')
var os = require('os')
var fs = require('fs')
var path = require('path')
var http = require('http')

var request = require('..')

var tmpdir = os.tmpdir()
var uri = 'https://raw.github.com/component/domify/84b1917ea5a9451f5add48c5f61e477f2788532b/component.json'
var redirect = 'https://raw.github.com/jonathanong/inherits/master/component.json'

describe('cogent', function () {
  it('should work with HTTPS', co(function* () {
    var res = yield* request(uri)
    res.statusCode.should.equal(200)
    res.headers['content-encoding'].should.equal('gzip')
    res.resume()
  }))

  it('should save to a file', co(function* () {
    var destination = path.join(tmpdir, Math.random().toString(36).slice(2))
    var res = yield* request(uri, destination)
    res.statusCode.should.equal(200)
    res.destination.should.equal(destination)
    fs.statSync(destination)
  }))

  it('should resolve redirects', co(function* () {
    var res = yield* request(redirect, true)
    res.urls.length.should.equal(2)
    res.statusCode.should.equal(200)
    res.body.name.should.equal('inherits')
  }))

  it('should work with retries', co(function* () {
    var res = yield* request(uri, {
      retries: 2
    })
    res.statusCode.should.equal(200)
    res.headers['content-encoding'].should.equal('gzip')
    res.resume()
  }))
})
<commit_msg>add test<commit_after>var co = require('co')
var os = require('os')
var fs = require('fs')
var path = require('path')
var http = require('http')

var request = require('..')

var tmpdir = os.tmpdir()
var uri = 'https://raw.github.com/component/domify/84b1917ea5a9451f5add48c5f61e477f2788532b/component.json'
var redirect = 'https://raw.github.com/jonathanong/inherits/master/component.json'

describe('cogent', function () {
  it('should work with HTTPS', co(function* () {
    var res = yield* request(uri)
    res.statusCode.should.equal(200)
    res.headers['content-encoding'].should.equal('gzip')
    res.resume()
  }))

  it('should save to a file', co(function* () {
    var destination = path.join(tmpdir, Math.random().toString(36).slice(2))
    var res = yield* request(uri, destination)
    res.statusCode.should.equal(200)
    res.destination.should.equal(destination)
    fs.statSync(destination)
  }))

  it('should resolve redirects', co(function* () {
    var res = yield* request(redirect, true)
    res.urls.length.should.equal(2)
    res.statusCode.should.equal(200)
    res.body.name.should.equal('inherits')
  }))

  it('should not resolve redirects', co(function* () {
    var res = yield* request(redirect, {string: true, redirects: 0, method: 'GET'})
    res.statusCode.should.equal(301)
  }))

  it('should work with retries', co(function* () {
    var res = yield* request(uri, {
      retries: 2
    })
    res.statusCode.should.equal(200)
    res.headers['content-encoding'].should.equal('gzip')
    res.resume()
  }))
})
<|endoftext|>


<commit_before>// imageSelected = 'http://images.is.ed.ac.uk/luna/servlet/iiif/UoEwmm~2~2~77099~164515/info.json'
// imageSelected = 'http://images.is.ed.ac.uk/luna/servlet/iiif/UoEsha~4~4~65346~164252page31/info.json'

var polyanno_setup_options = {
  'highlighting': true,
  'minimising': true,
  'voting': true
}

// this is assuming the defaults of storage URLs using the web page url and polyanno_storage for storage and no users
polyanno_setup(polyanno_setup_options)
<commit_msg>comment selected image for polyanno<commit_after>// imageSelected = 'http://images.is.ed.ac.uk/luna/servlet/iiif/UoEwmm~2~2~77099~164515/info.json'
// imageSelected = 'http://images.is.ed.ac.uk/luna/servlet/iiif/UoEsha~4~4~65346~164252page31/info.json'
// imageSelected = 'http://images.is.ed.ac.uk/luna/servlet/iiif/UoEsha~4~4~65346~164252page0/info.json'

var polyanno_setup_options = {
  'highlighting': true,
  'minimising': true,
  'voting': true
}

// this is assuming the defaults of storage URLs using the web page url and polyanno_storage for storage and no users
polyanno_setup(polyanno_setup_options)
<|endoftext|>


<commit_before>/* @flow strict-local */
import React from 'react';
import type { ComponentType } from 'react';

import type { Narrow } from '../types';
import {
  isHomeNarrow,
  isPrivateNarrow,
  isGroupNarrow,
  isSpecialNarrow,
  isStreamNarrow,
  isTopicNarrow,
} from '../utils/narrow';
import InfoNavButtonStream from './InfoNavButtonStream';
import InfoNavButtonPrivate from './InfoNavButtonPrivate';
import InfoNavButtonGroup from './InfoNavButtonGroup';
import ExtraNavButtonStream from './ExtraNavButtonStream';
import ExtraNavButtonTopic from './ExtraNavButtonTopic';
import { ViewPlaceholder } from '../common';

type Props = {| color: string, narrow: Narrow |};
type NarrowNavButton = ComponentType<Props>;
type NarrowNavButtonCandidate = {
  isFunc: Narrow => boolean,
  ButtonComponent: NarrowNavButton | null,
};

const infoButtonHandlers: NarrowNavButtonCandidate[] = [
  { isFunc: isHomeNarrow, ButtonComponent: null },
  { isFunc: isSpecialNarrow, ButtonComponent: null },
  { isFunc: isStreamNarrow, ButtonComponent: InfoNavButtonStream },
  { isFunc: isTopicNarrow, ButtonComponent: InfoNavButtonStream },
  { isFunc: isPrivateNarrow, ButtonComponent: InfoNavButtonPrivate },
  { isFunc: isGroupNarrow, ButtonComponent: InfoNavButtonGroup },
];

const extraButtonHandlers: NarrowNavButtonCandidate[] = [
  { isFunc: isHomeNarrow, ButtonComponent: null },
  { isFunc: isSpecialNarrow, ButtonComponent: null },
  { isFunc: isStreamNarrow, ButtonComponent: ExtraNavButtonStream },
  { isFunc: isTopicNarrow, ButtonComponent: ExtraNavButtonTopic },
  { isFunc: isPrivateNarrow, ButtonComponent: null },
  { isFunc: isGroupNarrow, ButtonComponent: null },
];

const makeButton = (handlers): NarrowNavButton => props => {
  const handler = handlers.find(x => x.isFunc(props.narrow));
  const SpecificButton = handler && handler.ButtonComponent;
  return SpecificButton ? <SpecificButton {...props} /> : <ViewPlaceholder width={44} />;
};

export const InfoButton = makeButton(infoButtonHandlers);

export const ExtraButton = makeButton(extraButtonHandlers);
<commit_msg>title-buttons: Drop use of placeholder when no button needed.<commit_after>/* @flow strict-local */
import React from 'react';
import type { ComponentType } from 'react';

import type { Narrow } from '../types';
import {
  isHomeNarrow,
  isPrivateNarrow,
  isGroupNarrow,
  isSpecialNarrow,
  isStreamNarrow,
  isTopicNarrow,
} from '../utils/narrow';
import InfoNavButtonStream from './InfoNavButtonStream';
import InfoNavButtonPrivate from './InfoNavButtonPrivate';
import InfoNavButtonGroup from './InfoNavButtonGroup';
import ExtraNavButtonStream from './ExtraNavButtonStream';
import ExtraNavButtonTopic from './ExtraNavButtonTopic';

type Props = {| color: string, narrow: Narrow |};
type NarrowNavButton = ComponentType<Props>;
type NarrowNavButtonCandidate = {
  isFunc: Narrow => boolean,
  ButtonComponent: NarrowNavButton | null,
};

const infoButtonHandlers: NarrowNavButtonCandidate[] = [
  { isFunc: isHomeNarrow, ButtonComponent: null },
  { isFunc: isSpecialNarrow, ButtonComponent: null },
  { isFunc: isStreamNarrow, ButtonComponent: InfoNavButtonStream },
  { isFunc: isTopicNarrow, ButtonComponent: InfoNavButtonStream },
  { isFunc: isPrivateNarrow, ButtonComponent: InfoNavButtonPrivate },
  { isFunc: isGroupNarrow, ButtonComponent: InfoNavButtonGroup },
];

const extraButtonHandlers: NarrowNavButtonCandidate[] = [
  { isFunc: isHomeNarrow, ButtonComponent: null },
  { isFunc: isSpecialNarrow, ButtonComponent: null },
  { isFunc: isStreamNarrow, ButtonComponent: ExtraNavButtonStream },
  { isFunc: isTopicNarrow, ButtonComponent: ExtraNavButtonTopic },
  { isFunc: isPrivateNarrow, ButtonComponent: null },
  { isFunc: isGroupNarrow, ButtonComponent: null },
];

const makeButton = (handlers): NarrowNavButton => props => {
  const handler = handlers.find(x => x.isFunc(props.narrow)) || null;
  const SpecificButton = handler && handler.ButtonComponent;
  return SpecificButton && <SpecificButton {...props} />;
};

export const InfoButton = makeButton(infoButtonHandlers);

export const ExtraButton = makeButton(extraButtonHandlers);
<|endoftext|>


<commit_before>import {renderAst} from '../dist/src/index.js';
import {parse} from '../dist/test/html-utils.js';
import Benchmark from 'benchmark';

// Returns an HTML document with N body nodes.
function getDoc(n) {
  const nodes = new Array(n).fill('<bento-node></bento-node>').join('');
  return parse(`<html><head></head><body>${nodes}</body></html>`);
}

const doc1 = getDoc(1);
const doc10 = getDoc(10);
const doc100 = getDoc(100);
const doc1000 = getDoc(1000);
const doc10000 = getDoc(10000);

var suite = new Benchmark.Suite();
suite
  .add('Document: 1 node', function () {
    renderAst(doc1, {});
  })
  .add('Document: 10 nodes', function () {
    renderAst(doc10, {});
  })
  .add('Document: 100 nodes', function () {
    renderAst(doc100, {});
  })
  .add('Document: 1000 nodes', function () {
    renderAst(doc1000, {});
  })
  // TODO: uncomment when this doesn't crash.
  // .add('Document: 10000 nodes', function () {
  //   renderAst(doc10000, {});
  // })
  .on('complete', function () {
    const results = Array.from(this);
    console.log(results.map((r) => r.toString()).join('\n'));
  })
  .run();
<commit_msg>i did not know<commit_after>import {renderAst} from '../dist/src/index.js';
import {parse} from '../dist/test/html-utils.js';
import Benchmark from 'benchmark';

// Returns an HTML document with N body nodes.
function getDoc(n) {
  const nodes = new Array(n).fill('<bento-node></bento-node>').join('');
  return parse(`<html><head></head><body>${nodes}</body></html>`);
}

const doc1 = getDoc(1);
const doc10 = getDoc(10);
const doc100 = getDoc(100);
const doc1000 = getDoc(1000);
const doc10000 = getDoc(10000);

var suite = new Benchmark.Suite();
suite
  .add('Document: 1 node', function () {
    renderAst(doc1, {});
  })
  .add('Document: 10 nodes', function () {
    renderAst(doc10, {});
  })
  .add('Document: 100 nodes', function () {
    renderAst(doc100, {});
  })
  .add('Document: 1000 nodes', function () {
    renderAst(doc1000, {});
  })
  // TODO: uncomment when this doesn't crash.
  // .add('Document: 10000 nodes', function () {
  //   renderAst(doc10000, {});
  // })
  .on('complete', function () {
    const results = Array.from(this);
    console.log(results.join('\n'));
  })
  .run();
<|endoftext|>


<commit_before>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2015, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(Application, Window, GUI, Dialogs, Utils, API, VFS) {
  'use strict';

  /////////////////////////////////////////////////////////////////////////////
  // LOCALES
  /////////////////////////////////////////////////////////////////////////////

  var _Locales = {
    no_NO : {
      'Theme' : 'Tema',
      'Background' : 'Bakgrunn',
      'Desktop' : 'Skrivebord',
      'Background Type' : 'Bakgrunn type',
      'Image (Repeat)' : 'Bilde (Gjenta)',
      'Image (Centered)' : 'Bilde (Sentrert)',
      'Image (Fill)' : 'Bilde (Fyll)',
      'Image (Streched)' : 'Bilde (Strekk)',
      'Desktop Margin ({0}px)' : 'Skrivebord Margin ({0}px)',
      'Panel' : 'Panel',
      'Position' : 'Posisjon',
      'Ontop' : 'Topp',
      'Items' : 'Objekter',
      'Enable Animations' : 'Bruk animasjoner',
      'Language (requires restart)' : 'Språk (krever omstart)',
      'Enable Sounds' : 'Skru på lyder',
      'Enable Window Switcher' : 'Skru på Vindu-bytter',
      'Enable Hotkeys' : 'Skru på Hurtigtaster',
      'Enable Icon View' : 'Skru på Ikonvisning',
      'Remove shortcut' : 'Fjern snarvei',
      'General' : 'Generelt'
    },
    pl_PL : {
      'Theme' : 'Temat',
      'Background' : 'Tło',
      'Desktop' : 'Pulpit',
      'Background Type' : 'Typ Tła',
      'Image (Repeat)' : 'Powtarzający się',
      'Image (Centered)' : 'Wycentrowany',
      'Image (Fill)' : 'Wypełniony',
      'Image (Streched)' : 'Rozciągnięty',
      'Desktop Margin ({0}px)' : 'Margines Pulpitu ({0}px)',
      'Panel' : 'Panel',
      'Position' : 'Pozycja',
      'Ontop' : 'Na górze',
      'Items' : 'Obiekty',
      'Enable Animations' : 'Właczone Animacje',
      'Language (requires restart)' : 'Język (wymaga restart)',
      'Enable Sounds' : 'Włączone Dźwięki',
      'Enable Window Switcher' : 'Właczony Switcher Okien',
      'Enable Hotkeys' : 'Włączone Skróty Klawiaturowe',
      'Enable Icon View' : 'Właczony Widok Ikon',
      'Remove shortcut' : 'Usuwanie skrótu',
      'General' : 'Ogólne'
    },
    de_DE : {
      'Theme' : 'Thema',
      'Background' : 'Hintergrund',
      'Desktop' : 'Arbeitsoberflächen',
      'Background Type' : 'Hintergrundtyp',
      'Image (Repeat)' : 'Bild (Wiederholend)',
      'Image (Centered)' : 'Bild (Zentriert)',
      'Image (Fill)' : 'Bild (Ausgefüllt)',
      'Image (Streched)' : 'Bild (Gestreckt)',
      'Desktop Margin ({0}px)' : 'Arbeitsoberflächen Margin ({0}px)',
      'Panel' : 'Panel',
      'Position' : 'Position',
      'Ontop' : 'Vordergrund',
      'Items' : 'Items',
      'Enable Animations' : 'Animationen verwenden',
      'Language (requires restart)' : 'Sprache (benötigt Neustart)',
      'Enable Sounds' : 'Aktiviere Sounds',
      'Enable Window Switcher' : 'Aktiviere Fensterwechsler',
      'Enable Hotkeys' : 'Aktiviere Hotkeys',
      'Enable Icon View' : 'Aktiviere Icon-Ansicht',
      'General': 'General'
    },
    es_ES : {
      'Theme' : 'Tema',
      'Background' : 'Fondo',
      'Desktop' : 'Escritorio',
      'Background Type' : 'Tipo de fondo',
      'Image (Repeat)' : 'Imagen (Repetir)',
      'Image (Centered)' : 'Imagen (Centrada)',
      'Image (Fill)' : 'Imagen (Estirar)',
      'Image (Streched)' : 'Imagen (Ajustar)',
      'Desktop Margin ({0}px)' : 'Margen del escritorio ({0}px)',
      'Panel' : 'Panel',
      'Position' : 'Posición',
      'Ontop' : 'Primer plano',
      'Items' : 'Elementos',
      'Enable Animations' : 'Habilitar animaciones',
      'Language (requires restart)' : 'Idioma (requiere reiniciar)',
      'Enable Sounds' : 'Activar sonidos',
      'Enable Window Switcher' : 'Activar el alternador de ventanas',
      'Enable Hotkeys' : 'Activar Hotkeys',
      'Enable Icon View' : 'Activar la vista de icono',
      'General': 'General'
    },
    fr_FR : {
    },
    ru_RU : {
      'Theme' : 'Тема',
      'Background' : 'Фон',
      'Desktop' : 'Настройки',
      'Background Type' : 'Тип фона',
      'Image (Repeat)' : 'Изображение(повторяющееся)',
      'Image (Centered)' : 'Изображение(по центру)',
      'Image (Fill)' : 'Изображение(заполнить)',
      'Image (Streched)' : 'Изображение(растянуть)',
      'Desktop Margin ({0}px)' : 'Отсутуп рабочего стола ({0}px)',
      'Panel' : 'Панель',
      'Position' : 'Расположение',
      'Ontop' : 'Вверху',
      'Items' : 'Элементы',
      'Enable Animations' : 'Использовать анимацию',
      'TouchMenu' : 'Крупное меню',
      'Language (requires restart)' : 'Язык (необходим перезапуск)',
      'Enable Sounds' : 'Включить звук',
      'Enable Window Switcher' : 'Включить растягивание окон',
      'Enable Hotkeys' : 'Включить горячии клавиши',
      'Enable Icon View' : 'Включить ярлыки',
      'Icon View' : 'Ярлыки рабочего стола',
      'Invert Text Color' : 'Обратить цвет текста',
      'Autohide' : 'Автоматически скрывать',
      'Opacity' : 'Прозрачность',
      'General' : 'Основные',
      'Debug' : 'Отладка'
    },
    nl_NL : {
      'Theme' : 'Thema',
      'Background' : 'Achtergrond',
      'Desktop' : 'Buroblad',
      'Background Type' : 'Achtergrond soort',
      'Image (Repeat)' : 'Afbeelding (Herhalend)',
      'Image (Centered)' : 'Afbeelding (Gecentreerd)',
      'Image (Fill)' : 'Afbeelding (Passend)',
      'Image (Streched)' : 'Afbeelding (Gestreched)',
      'Desktop Margin ({0}px)' : 'Achtergrond kantlijn ({0}px)',
      'Panel' : 'Paneel',
      'Position' : 'Positie',
      'Ontop' : 'Voorgrond',
      'Items' : 'Items',
      'Enable Animations' : 'Animaties gebruiken',
      'Language (requires restart)' : 'Spraak (Herstarten)',
      'Enable Sounds' : 'Geluiden actief',
      'Enable Window Switcher' : 'Activeer venster wisselaar',
      'Enable Hotkeys' : 'Activeer hotkeys',
      'Enable Icon View' : 'Activeer Iconen-weergave',
      'General': 'Algemeen'
    },
    vi_VN : {
      'Theme' : 'Giao diện',
      'Background' : 'Ảnh nền',
      'Desktop' : 'Màn hình chính',
      'Background Type' : 'Kiểu nền',
      'Image (Repeat)' : 'Lặp lại',
      'Image (Centered)' : 'Căn giữa',
      'Image (Fill)' : 'Lấp đầy',
      'Image (Streched)' : 'Trải dài',
      'Desktop Margin ({0}px)' : 'Phần biên màn hình ({0}px)',
      'Panel' : 'Khung',
      'Position' : 'Vị trí',
      'Ontop' : 'Ở trên',
      'Items' : 'Các mục',
      'Enable Animations' : 'Bật hiệu ứng',
      'Language (requires restart)' : 'Ngôn ngữ (cần khởi động lại)',
      'Enable Sounds' : 'Bật âm thanh',
      'Enable Window Switcher' : 'Bật chuyển đổi cửa sổ',
      'Enable Hotkeys' : 'Bật phím nóng',
      'Enable Icon View' : 'Bật kiểu xem biểu tượng',
      'General': 'Tổng quát'
    }
  };

  function _() {
    var args = Array.prototype.slice.call(arguments, 0);
    args.unshift(_Locales);
    return API.__.apply(this, args);
  }

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  OSjs.Applications = OSjs.Applications || {};
  OSjs.Applications.ApplicationSettings = OSjs.Applications.ApplicationSettings || {};
  OSjs.Applications.ApplicationSettings._ = _;

})(OSjs.Core.Application, OSjs.Core.Window, OSjs.GUI, OSjs.Dialogs, OSjs.Utils, OSjs.API, OSjs.VFS);
<commit_msg>Removed file that is not supposed to be here<commit_after><|endoftext|>


<commit_before>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"), require("./foldcode"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror", "./foldcode"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
  "use strict";

  CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
    if (old && old != CodeMirror.Init) {
      cm.clearGutter(cm.state.foldGutter.options.gutter);
      cm.state.foldGutter = null;
      cm.off("gutterClick", onGutterClick);
      cm.off("changes", onChange);
      cm.off("viewportChange", onViewportChange);
      cm.off("fold", onFold);
      cm.off("unfold", onFold);
      cm.off("swapDoc", onChange);
    }
    if (val) {
      cm.state.foldGutter = new State(parseOptions(val));
      updateInViewport(cm);
      cm.on("gutterClick", onGutterClick);
      cm.on("changes", onChange);
      cm.on("viewportChange", onViewportChange);
      cm.on("fold", onFold);
      cm.on("unfold", onFold);
      cm.on("swapDoc", onChange);
    }
  });

  var Pos = CodeMirror.Pos;

  function State(options) {
    this.options = options;
    this.from = this.to = 0;
  }

  function parseOptions(opts) {
    if (opts === true) opts = {};
    if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
    if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
    if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
    return opts;
  }

  function isFolded(cm, line) {
    var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
    for (var i = 0; i < marks.length; ++i) {
      if (marks[i].__isFold) {
        var fromPos = marks[i].find(-1);
        if (fromPos && fromPos.line === line)
          return marks[i];
      }
    }
  }

  function marker(spec) {
    if (typeof spec == "string") {
      var elt = document.createElement("div");
      elt.className = spec + " CodeMirror-guttermarker-subtle";
      return elt;
    } else {
      return spec.cloneNode(true);
    }
  }

  function updateFoldInfo(cm, from, to) {
    var opts = cm.state.foldGutter.options, cur = from;
    var minSize = cm.foldOption(opts, "minFoldSize");
    var func = cm.foldOption(opts, "rangeFinder");
    cm.eachLine(from, to, function(line) {
      var mark = null;
      if (isFolded(cm, cur)) {
        mark = marker(opts.indicatorFolded);
      } else {
        var pos = Pos(cur, 0);
        var range = func && func(cm, pos);
        if (range && range.to.line - range.from.line >= minSize)
          mark = marker(opts.indicatorOpen);
      }
      cm.setGutterMarker(line, opts.gutter, mark);
      ++cur;
    });
  }

  function updateInViewport(cm) {
    var vp = cm.getViewport(), state = cm.state.foldGutter;
    if (!state) return;
    cm.operation(function() {
      updateFoldInfo(cm, vp.from, vp.to);
    });
    state.from = vp.from; state.to = vp.to;
  }

  function onGutterClick(cm, line, gutter) {
    var state = cm.state.foldGutter;
    if (!state) return;
    var opts = state.options;
    if (gutter != opts.gutter) return;
    var folded = isFolded(cm, line);
    if (folded) folded.clear();
    else cm.foldCode(Pos(line, 0), opts);
  }

  function onChange(cm) {
    var state = cm.state.foldGutter;
    if (!state) return;
    var opts = state.options;
    state.from = state.to = 0;
    clearTimeout(state.changeUpdate);
    state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
  }

  function onViewportChange(cm) {
    var state = cm.state.foldGutter;
    if (!state) return;
    var opts = state.options;
    clearTimeout(state.changeUpdate);
    state.changeUpdate = setTimeout(function() {
      var vp = cm.getViewport();
      if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
        updateInViewport(cm);
      } else {
        cm.operation(function() {
          if (vp.from < state.from) {
            updateFoldInfo(cm, vp.from, state.from);
            state.from = vp.from;
          }
          if (vp.to > state.to) {
            updateFoldInfo(cm, state.to, vp.to);
            state.to = vp.to;
          }
        });
      }
    }, opts.updateViewportTimeSpan || 400);
  }

  function onFold(cm, from) {
    var state = cm.state.foldGutter;
    if (!state) return;
    var line = from.line;
    if (line >= state.from && line < state.to)
      updateFoldInfo(cm, line, line + 1);
  }
});
<commit_msg>[foldgutter] reuse old markers if indicatorOpen/Folded is string<commit_after>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"), require("./foldcode"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror", "./foldcode"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
  "use strict";

  CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
    if (old && old != CodeMirror.Init) {
      cm.clearGutter(cm.state.foldGutter.options.gutter);
      cm.state.foldGutter = null;
      cm.off("gutterClick", onGutterClick);
      cm.off("changes", onChange);
      cm.off("viewportChange", onViewportChange);
      cm.off("fold", onFold);
      cm.off("unfold", onFold);
      cm.off("swapDoc", onChange);
    }
    if (val) {
      cm.state.foldGutter = new State(parseOptions(val));
      updateInViewport(cm);
      cm.on("gutterClick", onGutterClick);
      cm.on("changes", onChange);
      cm.on("viewportChange", onViewportChange);
      cm.on("fold", onFold);
      cm.on("unfold", onFold);
      cm.on("swapDoc", onChange);
    }
  });

  var Pos = CodeMirror.Pos;

  function State(options) {
    this.options = options;
    this.from = this.to = 0;
  }

  function parseOptions(opts) {
    if (opts === true) opts = {};
    if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
    if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
    if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
    return opts;
  }

  function isFolded(cm, line) {
    var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
    for (var i = 0; i < marks.length; ++i) {
      if (marks[i].__isFold) {
        var fromPos = marks[i].find(-1);
        if (fromPos && fromPos.line === line)
          return marks[i];
      }
    }
  }

  function marker(spec) {
    if (typeof spec == "string") {
      var elt = document.createElement("div");
      elt.className = spec + " CodeMirror-guttermarker-subtle";
      return elt;
    } else {
      return spec.cloneNode(true);
    }
  }

  function updateFoldInfo(cm, from, to) {
    var opts = cm.state.foldGutter.options, cur = from - 1;
    var minSize = cm.foldOption(opts, "minFoldSize");
    var func = cm.foldOption(opts, "rangeFinder");
    // we can reuse the built-in indicator element if its className matches the new state
    var clsFolded = typeof opts.indicatorFolded == "string" && classTest(opts.indicatorFolded);
    var clsOpen = typeof opts.indicatorOpen == "string" && classTest(opts.indicatorOpen);
    cm.eachLine(from, to, function(line) {
      ++cur;
      var mark = null;
      var old = line.gutterMarkers;
      if (old) old = old[opts.gutter];
      if (isFolded(cm, cur)) {
        if (clsFolded && old && clsFolded.test(old.className)) return;
        mark = marker(opts.indicatorFolded);
      } else {
        var pos = Pos(cur, 0);
        var range = func && func(cm, pos);
        if (range && range.to.line - range.from.line >= minSize) {
          if (clsOpen && old && clsOpen.test(old.className)) return;
          mark = marker(opts.indicatorOpen);
        }
      }
      if (!mark && !old) return;
      cm.setGutterMarker(line, opts.gutter, mark);
    });
  }

  // copied from CodeMirror/src/util/dom.js
  function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }

  function updateInViewport(cm) {
    var vp = cm.getViewport(), state = cm.state.foldGutter;
    if (!state) return;
    cm.operation(function() {
      updateFoldInfo(cm, vp.from, vp.to);
    });
    state.from = vp.from; state.to = vp.to;
  }

  function onGutterClick(cm, line, gutter) {
    var state = cm.state.foldGutter;
    if (!state) return;
    var opts = state.options;
    if (gutter != opts.gutter) return;
    var folded = isFolded(cm, line);
    if (folded) folded.clear();
    else cm.foldCode(Pos(line, 0), opts);
  }

  function onChange(cm) {
    var state = cm.state.foldGutter;
    if (!state) return;
    var opts = state.options;
    state.from = state.to = 0;
    clearTimeout(state.changeUpdate);
    state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
  }

  function onViewportChange(cm) {
    var state = cm.state.foldGutter;
    if (!state) return;
    var opts = state.options;
    clearTimeout(state.changeUpdate);
    state.changeUpdate = setTimeout(function() {
      var vp = cm.getViewport();
      if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
        updateInViewport(cm);
      } else {
        cm.operation(function() {
          if (vp.from < state.from) {
            updateFoldInfo(cm, vp.from, state.from);
            state.from = vp.from;
          }
          if (vp.to > state.to) {
            updateFoldInfo(cm, state.to, vp.to);
            state.to = vp.to;
          }
        });
      }
    }, opts.updateViewportTimeSpan || 400);
  }

  function onFold(cm, from) {
    var state = cm.state.foldGutter;
    if (!state) return;
    var line = from.line;
    if (line >= state.from && line < state.to)
      updateFoldInfo(cm, line, line + 1);
  }
});
<|endoftext|>


<commit_before>import Ember from 'ember';

import {
  test,
  moduleForComponent
} from 'ember-qunit';

var testNotification = {options: {type: 'error', twitch: true}};

moduleForComponent('growl-instance', 'Growl Instance');

test('assert that the element class exists', function() {
  expect(1);

  ok(this.subject().classNames.indexOf('growl-instance') > -1, 'CSS class exists');
});

test('assert that the notification type is reflected as a classname', function() {
  expect(1);
  var subject = this.subject();

  subject.set('notification', testNotification);
  equal(subject._classStringForProperty('type'), 'error', 'The instance has a class of error');
});

test('assert that the instance will close when clicked', function() {
  expect(3);

  var subject = this.subject();
  subject.set('notification', testNotification);
  subject.sendAction = function(name, value) {
    equal(name, 'action', 'The parent action was called');
    equal(value, testNotification, 'The notification is passed to the parent action');
  };

  subject.click();

  // now override destroyAlert to make sure it is what called the action
  subject.destroyAlert = function() {
    ok(true, 'The instance was closed');
  };

  subject.click();
});
<commit_msg>this test doesn't work in ember 1.9<commit_after>import Ember from 'ember';

import {
  test,
  moduleForComponent
} from 'ember-qunit';

var testNotification = {options: {type: 'error', twitch: true}};

moduleForComponent('growl-instance', 'Growl Instance');

test('assert that the element class exists', function() {
  expect(1);

  ok(this.subject().classNames.indexOf('growl-instance') > -1, 'CSS class exists');
});

test('assert that the instance will close when clicked', function() {
  expect(3);

  var subject = this.subject();
  subject.set('notification', testNotification);
  subject.sendAction = function(name, value) {
    equal(name, 'action', 'The parent action was called');
    equal(value, testNotification, 'The notification is passed to the parent action');
  };

  subject.click();

  // now override destroyAlert to make sure it is what called the action
  subject.destroyAlert = function() {
    ok(true, 'The instance was closed');
  };

  subject.click();
});
<|endoftext|>


<commit_before><commit_msg>add pubstream<commit_after><|endoftext|>