<commit_before>'use babel';

import {
  CompositeDisposable,
  Directory,
  Range,
  Point
} from 'atom';
import Config from './configuration.coffee';
import SourceView from './source-view';
import ExpansionSet from './expansion-set';

import glob from 'glob';
import child_process from 'child_process'; // eslint-disable-line camelcase
import yaml from 'yaml-js';

export default {
  config: Config.config,
  subscriptions: null,
  root: null,
  guessDirectory: null,
  hasGuess: false,
  watches: [],
  flags: {},
  flagsFile: null,
  notYetParsed: true,
  expansions: {},

  /**
   * Activates the package and is slow.
   */
  activate(state) {
    const self = this;
    this.root = atom.project.getDirectories()[0];
    this.flagsFile = this.root.getFile('.clang-expand');

    // Once the file starts to exist, we reparse asynchronously.
    // That way we don't have to parse when calling clang-expand anymore.
    this.watches.push(this.flagsFile.onDidChange(() => self.parseFlagsFile()));

    this.subscriptions = new CompositeDisposable();
    this.subscriptions.add(atom.commands.add(
      'atom-workspace', {
        'atom-clang-expand:expand': () => this.expand(),
        'atom-clang-expand:unexpand': () => this.unexpand(),
        'atom-clang-expand:unexpand-all': () => this.unexpandAll(),
        'atom-clang-expand:go-to-definition': () => this.goToDefinition(),
        'atom-clang-expand:go-to-declaration': () => this.goToDeclaration(),
        'atom-clang-expand:show-definition': () => this.showDefinition(),
        'atom-clang-expand:show-declaration': () => this.showDeclaration(),
      }));
  },

  deactivate() {
    this.watches.forEach(watch => watch.dispose());
    this.subscriptions.dispose();
  },

  serialize() {
    return {};
  },

  globOptions(cwd, nodir) {
    return {
      cwd: cwd || this.root.getPath(),
      dot: false,
      nosort: true,
      silent: true,
      nodir: (nodir === undefined) ? true : nodir
    };
  },

  setupGuess() {
    const self = this;
    return new Promise(resolve => {
      if (self.hasGuess) resolve();

      self.hasGuess = true;
      const rootPath = self.root.getPath();
      const options = self.globOptions(rootPath, false);

      glob(`${rootPath}/@(include|inc|header?)/`, options, headerPaths => {
        // Always look for headers under root.
        self.flags.extra = ['', rootPath].concat(headerPaths).join(' -I');
        const basename = self.root.getBaseName();
        glob(`${rootPath}/*(src?|source?|${basename}|lib)/`, options, sourcePaths => {
          if (sourcePaths.length === 0) return;
          // Some projects like LLVM and clang have 'lib' as their source directory.
          // But most projects would have 'lib' as their directory for third party
          // code. So only pick 'lib' if none of the other options were found.
          if ('lib' in sourcePaths && sourcePaths.length > 1) {
            sourcePaths = sourcePaths.filter(path !== 'lib');
          }
          self.guessDirectory = new Directory(sourcePaths[0]);
          self.watches.push(self.guessDirectory.onDidChange(() => self.guessSources()));
        });
      });
    });
  },

  guessSources() {
    const self = this;
    return new Promise(resolve => {
      const options = self.globOptions();
      // Always look under root.
      glob('*.*(cpp|c|cc|cxx)', options, sources => {
        self.flags.sources = sources;
        if (self.guessDirectory) return;
        options.cwd = self.guessDirectory.getPath();
        glob('**/*.*(cpp|c|cc|cxx)', options, moreSources => {
          self.flags.sources.concat(moreSources);
        });
      });
    });
  },

  parseFlagsFile() {
    const self = this;
    return new Promise((resolve, reject) => {
      // read and parse and set sources and headers
      this.flagsFile.read(false).then(text => {
        try {
          // Insert newlines into code portions because LLVM outputs
          // strings in a way that does not respect newlines.
          const config = yaml.load(text);

          if (typeof config.sources === 'string') config.sources = [config.sources];
          if (typeof config.extra === 'string') config.extra = [config.extra];

          const options = self.globOptions();
          self.flags.sources = config.sources
            .map(pattern => glob.sync(pattern, options))
            .reduce((left, right) => left.concat(right));

          self.flags.extra = config.extra.join(' ');
          resolve();
        } catch (error) {
          self.addError(`Error reading ${self.flagsFile.getBaseName()}`, error);
          reject();
        }
      });
    });
  },

  updateFlags() {
    const self = this;
    return new Promise(resolve => {
      self.flagsFile.exists().then(exists => {
        if (exists) {
          if (self.notYetParsed) {
            self.parseFlagsFile().then(resolve);
            self.notYetParsed = false;
          } else {
            resolve();
          }
        } else {
          self.setupGuess().then(() => self.guessSources().then(resolve));
        }
      });
    });
  },

  getCursorTriple() {
    const editor = atom.workspace.getActiveTextEditor();
    const position = editor.getCursorScreenPosition();
    // The position returned by the editor is 0-indexed, but clang needs
    // 1-indexed lines and columns.
    return {
      file: editor.getPath(),
      line: position.row + 1,
      column: position.column + 1,
    };
  },

  getCommand(cursor, options) {
    const executable = atom.config.get('atom-clang-expand.executable');
    const sources = this.flags.sources.join(' ');
    const extra = this.flags.extra;

    let flags = `-file=${cursor.file} `;
    flags += `-line=${cursor.line} `;
    flags += `-column=${cursor.column}`;

    for (const option of ['call', 'rewrite', 'declaration', 'definition']) {
      if (option in options) {
        flags += ` -${option}=${options[option]}`;
      }
    }

    return `${executable} ${flags} ${sources} -- ${extra}`;
  },

  addError(message, detail) {
    console.error(message, detail);
    atom.notifications.addError(message, {
      detail
    });
  },

  parseResult(result) {
    try {
      // Insert newlines into code portions because LLVM outputs
      // strings in a way that does not respect newlines.
      result = result.replace(/'(.|\n)*?'/g, m => m.replace(/\n/g, '\\n').replace(/'/g, '"'));
      return yaml.load(result);
    } catch (error) {
      this.addError('Error parsing clang-expand result', error);
    }
  },

  goTo(location, message) {
    // Our (clang) locations are 1-indexed, but atom's are 0-indexed.
    atom.workspace.open(location.file, {
      initialLine: location.line - 1,
      initialColumn: location.column - 1,
    }).then(editor => {
      if (message) atom.notifications.addSuccess(message);
    });
  },

  show(code) {
    const editor = atom.workspace.getActiveTextEditor();
    const cursor = editor.getCursorBufferPosition();
    const marker = editor.markBufferPosition(cursor, {
      invalidate: 'touch'
    });
    editor.decorateMarker(marker, {
      type: 'overlay',
      onlyNonEmpty: true,
      item: new SourceView(code, () => marker.destroy())
    });
  },

  cleanStderr(stderr) {
    // Get rid of warnings
    stderr = stderr.replace(/warning:.*/, '');

    // If the code has syntax errors, clang will emit compilation errors.
    const errors = stderr.match(/error:.*/);

    // Errors may be null if there were no errors, in which case clang-expand
    // just reported an issue (e.g. no token at location) and returned with a
    // non-zero exit code. In that case stderr is actually what we want.
    return errors ? errors.join('\n') : stderr;
  },

  getClangExpandOptions(overrides) {
    let options = {
      call: false,
      declaration: false,
      definition: false,
      rewrite: false
    };

    for (const key in overrides) {
      if (overrides.hasOwnProperty(key)) {
        options[key] = overrides[key];
      }
    }

    return Object.freeze(options);
  },

  clangExpand(overrides, callback) {
    const self = this;
    this.updateFlags().then(() => {
      const options = self.getClangExpandOptions(overrides);
      const cursor = self.getCursorTriple();
      const command = self.getCommand(cursor, options);
      const execOptions = {
        cwd: self.root.getPath()
      };
      child_process.exec(command, execOptions, (error, stdout, stderr) => {
        if (error) {
          const message = self.cleanStderr(stderr);
          self.addError('Error executing clang-expand', message);
        } else {
          const result = self.parseResult(stdout);
          callback(result);
        }
      });
    });
  },

  goToDeclaration() {
    const self = this;
    this.clangExpand({
      declaration: true
    }, result => {
      self.goTo(result.declaration.location, 'Found Declaration');
    });
  },

  goToDefinition() {
    const self = this;
    this.clangExpand({
      definition: true
    }, result => {
      self.goTo(result.definition.location, 'Found Definition');
    });
  },

  showDeclaration() {
    const self = this;
    this.clangExpand({
      declaration: true
    }, result => self.show(result.declaration));
  },

  showDefinition() {
    const self = this;
    this.clangExpand({
      definition: true
    }, result => self.show(result.definition));
  },

  getActualTextRange(editor, range) {
    let copy = range.copy();

    editor.setCursorBufferPosition(range.start);
    editor.moveToFirstCharacterOfLine();
    copy.start = editor.getCursorBufferPosition();

    editor.setCursorBufferPosition(range.end);
    editor.moveToEndOfLine();
    editor.moveToPreviousWordBoundary();
    copy.end = editor.getCursorBufferPosition();

    return copy;
  },

  highlightRange(range) {
    const editor = atom.workspace.getActiveTextEditor();
    const textRange = this.getActualTextRange(editor, range);
    const marker = editor.markBufferRange(textRange, {
      invalidate: 'overlap'
    });
    editor.decorateMarker(marker, {
      type: 'line',
      onlyNonEmpty: true,
      class: 'clang-expand-highlight'
    });

    return marker;
  },

  selectCallRange(editor, call) {
    const range = new Range(
      new Point(call.begin.line - 1, call.begin.column - 1),
      new Point(call.end.line - 1, call.end.column)
    );
    editor.setSelectedBufferRange(range);
    return editor.getSelectedText();
  },

  activeExpansions() {
    const path = atom.workspace.getActiveTextEditor().getPath();
    let expansions = this.expansions[path];
    if (expansions === undefined) {
      expansions = this.expansions[path] = new ExpansionSet();
    }
    return expansions;
  },

  expand() {
    const editor = atom.workspace.getActiveTextEditor();
    // Save first, otherwise the locations will be wrong.
    editor.save();
    this.clangExpand({
      call: true,
      rewrite: true
    }, result => {
      const originalText = this.selectCallRange(editor, result.call);
      editor.transact(0, () => {
        const range = editor.insertText(result.definition.rewritten, {
          select: true
        });
        editor.selectToBeginningOfLine();
        editor.selectToEndOfLine();
        editor.autoIndentSelectedRows();
        const marker = this.highlightRange(range[0]);
        this.activeExpansions().add(marker, originalText);
      });
      atom.notifications.addSuccess('Expanded successfully');
    });
  },

  unexpand() {
    const editor = atom.workspace.getActiveTextEditor();
    const cursor = editor.getCursorBufferPosition();
    const expansion = this.activeExpansions().remove(cursor);
    if (!expansion) {
      atom.notifications.addError('Nothing to unexpand there');
      return;
    }

    expansion.unexpand(editor);

    atom.notifications.addSuccess('Unexpansion successful');
  },

  unexpandAll() {
    const editor = atom.workspace.getActiveTextEditor();
    const path = editor.getPath();
    if (path in this.expansions) {
      this.expansions[path].clear();
      delete this.expansions[path];
      atom.notifications.addSuccess('Undid all expansions');
    }
  }
};
<commit_msg>Small formatting change<commit_after>'use babel';

import {
  CompositeDisposable,
  Directory,
  Range,
  Point
} from 'atom';
import Config from './configuration.coffee';
import SourceView from './source-view';
import ExpansionSet from './expansion-set';

import glob from 'glob';
import child_process from 'child_process'; // eslint-disable-line camelcase
import yaml from 'yaml-js';

export default {
  config: Config.config,
  subscriptions: null,
  root: null,
  guessDirectory: null,
  hasGuess: false,
  watches: [],
  flags: {},
  flagsFile: null,
  notYetParsed: true,
  expansions: {},

  /**
   * Activates the package and is slow.
   */
  activate(state) {
    const self = this;
    this.root = atom.project.getDirectories()[0];
    this.flagsFile = this.root.getFile('.clang-expand');

    // Once the file starts to exist, we reparse asynchronously.
    // That way we don't have to parse when calling clang-expand anymore.
    this.watches.push(this.flagsFile.onDidChange(() => self.parseFlagsFile()));

    this.subscriptions = new CompositeDisposable();
    this.subscriptions.add(atom.commands.add(
      'atom-workspace', {
        'atom-clang-expand:expand': () => this.expand(),
        'atom-clang-expand:unexpand': () => this.unexpand(),
        'atom-clang-expand:unexpand-all': () => this.unexpandAll(),
        'atom-clang-expand:go-to-definition': () => this.goToDefinition(),
        'atom-clang-expand:go-to-declaration': () => this.goToDeclaration(),
        'atom-clang-expand:show-definition': () => this.showDefinition(),
        'atom-clang-expand:show-declaration': () => this.showDeclaration(),
      }));
  },

  deactivate() {
    this.watches.forEach(watch => watch.dispose());
    this.subscriptions.dispose();
  },

  serialize() {
    return {};
  },

  globOptions(cwd, nodir) {
    return {
      cwd: cwd || this.root.getPath(),
      dot: false,
      nosort: true,
      silent: true,
      nodir: (nodir === undefined) ? true : nodir
    };
  },

  setupGuess() {
    const self = this;
    return new Promise(resolve => {
      if (self.hasGuess) resolve();

      self.hasGuess = true;
      const rootPath = self.root.getPath();
      const options = self.globOptions(rootPath, false);

      glob(`${rootPath}/@(include|inc|header?)/`, options, headerPaths => {
        // Always look for headers under root.
        self.flags.extra = ['', rootPath].concat(headerPaths).join(' -I');
        const basename = self.root.getBaseName();
        glob(`${rootPath}/*(src?|source?|${basename}|lib)/`, options, sourcePaths => {
          if (sourcePaths.length === 0) return;
          // Some projects like LLVM and clang have 'lib' as their source directory.
          // But most projects would have 'lib' as their directory for third party
          // code. So only pick 'lib' if none of the other options were found.
          if ('lib' in sourcePaths && sourcePaths.length > 1) {
            sourcePaths = sourcePaths.filter(path !== 'lib');
          }
          self.guessDirectory = new Directory(sourcePaths[0]);
          self.watches.push(self.guessDirectory.onDidChange(() => self.guessSources()));
        });
      });
    });
  },

  guessSources() {
    const self = this;
    return new Promise(resolve => {
      const options = self.globOptions();
      // Always look under root.
      glob('*.*(cpp|c|cc|cxx)', options, sources => {
        self.flags.sources = sources;
        if (self.guessDirectory) return;
        options.cwd = self.guessDirectory.getPath();
        glob('**/*.*(cpp|c|cc|cxx)', options, moreSources => {
          self.flags.sources.concat(moreSources);
        });
      });
    });
  },

  parseFlagsFile() {
    const self = this;
    return new Promise((resolve, reject) => {
      // read and parse and set sources and headers
      this.flagsFile.read(false).then(text => {
        try {
          // Insert newlines into code portions because LLVM outputs
          // strings in a way that does not respect newlines.
          const config = yaml.load(text);

          if (typeof config.sources === 'string') config.sources = [config.sources];
          if (typeof config.extra === 'string') config.extra = [config.extra];

          const options = self.globOptions();
          self.flags.sources = config.sources
            .map(pattern => glob.sync(pattern, options))
            .reduce((left, right) => left.concat(right));

          self.flags.extra = config.extra.join(' ');
          resolve();
        } catch (error) {
          self.addError(`Error reading ${self.flagsFile.getBaseName()}`, error);
          reject();
        }
      });
    });
  },

  updateFlags() {
    const self = this;
    return new Promise(resolve => {
      self.flagsFile.exists().then(exists => {
        if (exists) {
          if (self.notYetParsed) {
            self.parseFlagsFile().then(resolve);
            self.notYetParsed = false;
          } else {
            resolve();
          }
        } else {
          self.setupGuess().then(() => self.guessSources().then(resolve));
        }
      });
    });
  },

  getCursorTriple() {
    const editor = atom.workspace.getActiveTextEditor();
    const position = editor.getCursorScreenPosition();
    // The position returned by the editor is 0-indexed, but clang needs
    // 1-indexed lines and columns.
    return {
      file: editor.getPath(),
      line: position.row + 1,
      column: position.column + 1,
    };
  },

  getCommand(cursor, options) {
    const executable = atom.config.get('atom-clang-expand.executable');
    const sources = this.flags.sources.join(' ');
    const extra = this.flags.extra;

    let flags = `-file=${cursor.file} `;
    flags += `-line=${cursor.line} `;
    flags += `-column=${cursor.column}`;

    for (const option of ['call', 'rewrite', 'declaration', 'definition']) {
      if (option in options) {
        flags += ` -${option}=${options[option]}`;
      }
    }

    return `${executable} ${flags} ${sources} -- ${extra}`;
  },

  addError(message, detail) {
    console.error(message, detail);
    atom.notifications.addError(message, {
      detail
    });
  },

  parseResult(result) {
    try {
      // Insert newlines into code portions because LLVM outputs
      // strings in a way that does not respect newlines.
      result = result.replace(/'(.|\n)*?'/g, m => m.replace(/\n/g, '\\n').replace(/'/g, '"'));
      return yaml.load(result);
    } catch (error) {
      this.addError('Error parsing clang-expand result', error);
    }
  },

  goTo(location, message) {
    // Our (clang) locations are 1-indexed, but atom's are 0-indexed.
    atom.workspace.open(location.file, {
      initialLine: location.line - 1,
      initialColumn: location.column - 1,
    }).then(editor => {
      if (message) atom.notifications.addSuccess(message);
    });
  },

  show(code) {
    const editor = atom.workspace.getActiveTextEditor();
    const cursor = editor.getCursorBufferPosition();
    const marker = editor.markBufferPosition(cursor, {
      invalidate: 'touch'
    });
    editor.decorateMarker(marker, {
      type: 'overlay',
      onlyNonEmpty: true,
      item: new SourceView(code, () => marker.destroy())
    });
  },

  cleanStderr(stderr) {
    // Get rid of warnings
    stderr = stderr.replace(/warning:.*/, '');

    // If the code has syntax errors, clang will emit compilation errors.
    const errors = stderr.match(/error:.*/);

    // Errors may be null if there were no errors, in which case clang-expand
    // just reported an issue (e.g. no token at location) and returned with a
    // non-zero exit code. In that case stderr is actually what we want.
    return errors ? errors.join('\n') : stderr;
  },

  getClangExpandOptions(overrides) {
    let options = {
      call: false,
      declaration: false,
      definition: false,
      rewrite: false
    };

    for (const key in overrides) {
      if (overrides.hasOwnProperty(key)) {
        options[key] = overrides[key];
      }
    }

    return Object.freeze(options);
  },

  clangExpand(overrides, callback) {
    const self = this;
    this.updateFlags().then(() => {
      const options = self.getClangExpandOptions(overrides);
      const cursor = self.getCursorTriple();
      const command = self.getCommand(cursor, options);
      const execOptions = {
        cwd: self.root.getPath()
      };
      child_process.exec(command, execOptions, (error, stdout, stderr) => {
        if (error) {
          const message = self.cleanStderr(stderr);
          self.addError('Error executing clang-expand', message);
        } else {
          const result = self.parseResult(stdout);
          callback(result);
        }
      });
    });
  },

  goToDeclaration() {
    const self = this;
    this.clangExpand({
      declaration: true
    }, result => {
      self.goTo(result.declaration.location, 'Found Declaration');
    });
  },

  goToDefinition() {
    const self = this;
    this.clangExpand({
      definition: true
    }, result => {
      self.goTo(result.definition.location, 'Found Definition');
    });
  },

  showDeclaration() {
    const self = this;
    this.clangExpand({
      declaration: true
    }, result => self.show(result.declaration));
  },

  showDefinition() {
    const self = this;
    this.clangExpand({
      definition: true
    }, result => self.show(result.definition));
  },

  getActualTextRange(editor, range) {
    let copy = range.copy();

    editor.setCursorBufferPosition(range.start);
    editor.moveToFirstCharacterOfLine();
    copy.start = editor.getCursorBufferPosition();

    editor.setCursorBufferPosition(range.end);
    editor.moveToEndOfLine();
    editor.moveToPreviousWordBoundary();
    copy.end = editor.getCursorBufferPosition();

    return copy;
  },

  highlightRange(range) {
    const editor = atom.workspace.getActiveTextEditor();
    const textRange = this.getActualTextRange(editor, range);
    const marker = editor.markBufferRange(textRange, {
      invalidate: 'overlap'
    });
    editor.decorateMarker(marker, {
      type: 'line',
      onlyNonEmpty: true,
      class: 'clang-expand-highlight'
    });

    return marker;
  },

  selectCallRange(editor, call) {
    const range = new Range(
      new Point(call.begin.line - 1, call.begin.column - 1),
      new Point(call.end.line - 1, call.end.column)
    );
    editor.setSelectedBufferRange(range);
    return editor.getSelectedText();
  },

  activeExpansions() {
    const path = atom.workspace.getActiveTextEditor().getPath();
    let expansions = this.expansions[path];
    if (expansions === undefined) {
      expansions = this.expansions[path] = new ExpansionSet();
    }
    return expansions;
  },

  expand() {
    const editor = atom.workspace.getActiveTextEditor();
    // Save first, otherwise the locations will be wrong.
    editor.save();
    this.clangExpand({call: true, rewrite: true}, result => {
      const originalText = this.selectCallRange(editor, result.call);
      editor.transact(0, () => {
        const range = editor.insertText(result.definition.rewritten, {
          select: true
        });
        editor.selectToBeginningOfLine();
        editor.selectToEndOfLine();
        editor.autoIndentSelectedRows();
        const marker = this.highlightRange(range[0]);
        this.activeExpansions().add(marker, originalText);
      });
      atom.notifications.addSuccess('Expanded successfully');
    });
  },

  unexpand() {
    const editor = atom.workspace.getActiveTextEditor();
    const cursor = editor.getCursorBufferPosition();
    const expansion = this.activeExpansions().remove(cursor);
    if (!expansion) {
      atom.notifications.addError('Nothing to unexpand there');
      return;
    }

    expansion.unexpand(editor);

    atom.notifications.addSuccess('Unexpansion successful');
  },

  unexpandAll() {
    const editor = atom.workspace.getActiveTextEditor();
    const path = editor.getPath();
    if (path in this.expansions) {
      this.expansions[path].clear();
      delete this.expansions[path];
      atom.notifications.addSuccess('Undid all expansions');
    }
  }
};
<|endoftext|>


<commit_before>/**
 * A simple WebDAV server.
 */

var pronto = require('pronto');
var webdav = require('./lib');
var fsdav = require('./lib/fs');

var register = new pronto.Registry();
var initialContext = new pronto.Context({
  baseURI: '/test'
});

register
  // Operations common across the board.
  .route('@bootstrap')
    .does(webdav.http.GetNormalizedPath, 'path')
      .using('baseURI').from('cxt:baseURI')
    .does(fsdav.LoadFSBridge, 'bridge')
      .using('root', './data')
  // ================================================================
  // HTTP Operations.
  // ================================================================
  .route('OPTIONS')
    .includes('@bootstrap')
    .does(webdav.backend.LoadResource, 'resource')
      .using('resourceBridge').from('cxt:bridge')
      .using('name').from('cxt:path')
    .does(webdav.http.HandleOptions, 'options')
      .using('resource').from('cxt:resource')
    .does(pronto.commands.HTTPResponse)
      .using('headers').from('cxt:options')
      .using('code', 200)
  .route('GET')
    .includes('@bootstrap')
    .does(pronto.commands.HTTPResponse)
      .using('headers', {}).from('cxt:options')
      .using('code', 200)
  .route('HEAD')
    .includes('@bootstrap')
  .route('DELETE')
    .includes('@bootstrap')
  .route('PROPFIND')
    .includes('@bootstrap')
  .route('MKCOL')
    .includes('@bootstrap')
  .route('PUT')
    .includes('@bootstrap')
  .route('PROPPATCH')
    .includes('@bootstrap')
  .route('COPY')
    .includes('@bootstrap')
  .route('MOVE')
    .includes('@bootstrap')
  .route('REPORT')
    .includes('@bootstrap')
;

// TODO: Need top-level error handling.
var resolver = new webdav.http.MethodBasedRequestResolver()
var server = pronto.HTTPServer.createServer(register, initialContext);
server.setResolver(resolver);
server.listen(8000, 'localhost');
process.on('SIGINT', function () {server.close();});
<commit_msg>Working on GET request.<commit_after>/**
 * A simple WebDAV server.
 */

var pronto = require('pronto');
var webdav = require('./lib');
var fsdav = require('./lib/fs');

var register = new pronto.Registry();
var initialContext = new pronto.Context({
  baseURI: '/test'
});

register
  // Operations common across the board.
  .route('@bootstrap')
    .does(webdav.http.GetNormalizedPath, 'path')
      .using('baseURI').from('cxt:baseURI')
    .does(fsdav.LoadFSBridge, 'bridge')
      .using('root', './data')
  // ================================================================
  // HTTP Operations.
  // ================================================================
  .route('OPTIONS')
    .includes('@bootstrap')
    .does(webdav.backend.LoadResource, 'resource')
      .using('resourceBridge').from('cxt:bridge')
      .using('name').from('cxt:path')
    .does(webdav.http.HandleOptions, 'options')
      .using('resource').from('cxt:resource')
    .does(pronto.commands.HTTPResponse)
      .using('headers').from('cxt:options')
      .using('code', 200)
  .route('GET')
    .includes('@bootstrap')
    .does(webdav.backend.LoadResource, 'resource')
      .using('resourceBridge').from('cxt:bridge')
      .using('name').from('cxt:path')
    .does(webdav.http.HandleGet, 'get')
      .using('resource').from('cxt:resource')
    .does(pronto.commands.HTTPResponse)
      .using('headers', {}).from('cxt:httpHeaders')
      .using('code', 404).from('cxt:get')
  .route('HEAD')
    .includes('@bootstrap')
  .route('DELETE')
    .includes('@bootstrap')
  .route('PROPFIND')
    .includes('@bootstrap')
  .route('MKCOL')
    .includes('@bootstrap')
  .route('PUT')
    .includes('@bootstrap')
  .route('PROPPATCH')
    .includes('@bootstrap')
  .route('COPY')
    .includes('@bootstrap')
  .route('MOVE')
    .includes('@bootstrap')
  .route('REPORT')
    .includes('@bootstrap')
;

// TODO: Need top-level error handling.
var resolver = new webdav.http.MethodBasedRequestResolver()
var server = pronto.HTTPServer.createServer(register, initialContext);
server.setResolver(resolver);
server.listen(8000, 'localhost');
process.on('SIGINT', function () {server.close();});
<|endoftext|>


<commit_before>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

module.exports = function (grunt) {
    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    // configurable paths
    var yeomanConfig = {
        app: 'app',
        dev: 'dev',
        dist: 'dist'
    };

    <% if (wordpress === true) { %>
    var yeomanConfig = {
        app: 'app/<%= slugSiteName %>',
        dev: 'dev/<%= slugSiteName %>',
        dist: 'dist/<%= slugSiteName %>'
    };
    <% } %>

    grunt.initConfig({
        yeoman: yeomanConfig,

        clean: {
            dev: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.dev %>/*',
                        '!<%%= yeoman.dev %>/.git*'
                    ]
                }]
            },

            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.dist %>/*',
                        '!<%%= yeoman.dist %>/.git*'
                    ]
                }]
            }
        },

        useminPrepare: {
            options: {
                dest: '<%%= yeoman.dist %>'
            },
            html: '<%%= yeoman.app %>/index.html',
            css: '<%%= yeoman.app %>/assets/scss/**/*.scss'
        },

        watch: {
            options: {
                livereload: true
            },
            css: {
                files: ['<%%= yeoman.app %>/assets/scss/*.scss'],
                /* TO DO: this should be conditional depending on the framework chosen */
                tasks: ['compass:dev']
            },
            html: {
                files: ['<%%= yeoman.app %>{,*/}*.html'],
                tasks: ['copy:html', 'replace', 'processhtml:dev']
            },
            sprites: {
                files: ['<%%= yeoman.app %>/assets/img/sprite-assets/*.png'],
                tasks: ['spriteHD', 'copy:dev']
            }
        },

        connect: {
            options: {
                port: 9000,
                livereload: 35729,
                hostname: '0.0.0.0',
                base: '<%%= yeoman.dev %>'
            },
            livereload: {
                options: {
                    open: 'http://localhost:<%%= connect.options.port %>',
                    base: [
                        '<%%= yeoman.dev %>'
                    ]
                }
            }
        },

        open: {
            server: {
                path: 'http://localhost:<%%= connect.options.port %>'
            }
        },

        copy: {
            dev: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['**', '!**/scss/**', '!.htaccess', '!**/languages/**'], dest: '<%%= yeoman.dev %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>/assets/scss/fonts', src: ['**'], dest: '<%%= yeoman.dev %>/assets/css/fonts'}<% if (wordpress === true) { %>,
                    {expand: true, cwd: '<%%= yeoman.app %>/languages', src: ['_s.pot'], dest: '<%%= yeoman.dev %>/languages', rename: function (dest) {
                        return dest + '/<%= slugSiteName %>.pot';
                    }}<% } %>
                ]
            },

            dist: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['**', '!**/img/sprite-assets/**', '!**/scss/**', '!**/js/*.js'], dest: '<%%= yeoman.dist %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['.htaccess'], dest: '<%%= yeoman.dist %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>/assets/scss/fonts', src: ['**'], dest: '<%%= yeoman.dist %>/assets/css/fonts'},
                    {expand: true, cwd: 'bower_components/jquery', src: ['jquery.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib'},
                    {expand: true, cwd: 'bower_components/jquery-legacy', src: ['jquery.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib', rename: function (dest) {
                        return dest + '/jquery-legacy.min.js';
                    }},
                    // Only copy over the minified migrate plugin
                    {expand: true, cwd: 'bower_components/jquery-migrate', src: ['jquery-migrate.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib'}<% if (wordpress === true) { %>,
                    {expand: true, cwd: '<%%= yeoman.app %>/languages', src: ['_s.pot'], dest: '<%%= yeoman.dist %>/languages', rename: function (dest) {
                        return dest + '/<%= slugSiteName %>.pot';
                    }}<% } %>
                ]
            },

            html: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['{,*/}*.html'], dest: '<%%= yeoman.dev %>'}
                ]
            }
        },

        <% if (cssFramework === 'compassSusy') { %>
        compass: {
            dev: {
                options: {
                    sassDir: '<%%= yeoman.app %>/assets/scss',
                    <% if (wordpress === true) { %>
                    cssDir: '<%%= yeoman.dev %>',
                    <% } else { %>
                    cssDir: '<%%= yeoman.dev %>/assets/css',
                    <% } %>
                    environment: 'development'
                }
            },

            dist: {
                options: {
                    sassDir: '<%%= yeoman.app %>/assets/scss',
                    <% if (wordpress === true) { %>
                    cssDir: '<%%= yeoman.dist %>',
                    <% } else { %>
                    cssDir: '<%%= yeoman.dist %>/assets/css',
                    <% } %>
                    environment: 'production'
                }
            }
        },
        <% } %>

        <% if (cssFramework !== 'compassSusy') { %>
        sass: {
            dev: {
                expand: true,
                cwd: '<%%= yeoman.app %>/assets/scss',
                src: ['*.scss'],
                dest: '<%%= yeoman.dev %>/assets/css',
                ext: '.css'
            },

            dist: {
                expand: true,
                cwd: '<%%= yeoman.app %>/assets/scss',
                src: ['*.scss'],
                dest: '<%%= yeoman.dist %>/assets/css',
                ext: '.css'
            }
        },
        <% } %>

        replace: {
            <% if (wordpress === true) { %>
            options: {
                patterns: [{
                    match: '/\'_s\'/g',
                    replacement: function () {
                        return "'<%= slugSiteName %>'";
                    },
                    expression: true
                }, {
                    match: '/_s_/g',
                    replacement: function () {
                        return "<%= slugSiteName %>_";
                    },
                    expression: true
                }, {
                    match: '/ _s/g',
                    replacement: function () {
                        var toCapital = "<%= slugSiteName %>";
                        var capitalized = toCapital.charAt(0).toUpperCase() + toCapital.slice(1);
                        return ' ' + capitalized;
                    },
                    expression: true
                }, {
                    match: '/_s-/g',
                    replacement: function () {
                        return "<%= slugSiteName %>-";
                    },
                    expression: true
                }]
            },

            dev: {
                files: [
                    {expand: true, src: ['<%%= yeoman.dev %>/**', '<%%= yeoman.dev %>/languages/<%= slugSiteName %>.pot']}
                ]
            },

            dist: {
                files: [
                    {expand: true, src: ['<%%= yeoman.dist %>/**', '<%%= yeoman.dist %>/languages/<%= slugSiteName %>.pot']}
                ]
            }
            <% } else { %>
            options: {
                patterns: [{
                    match: '/@jquery-cdn/g',
                    replacement: function () {
                        var jQConf = grunt.file.readJSON('bower_components/jquery/bower.json');
                        return '//ajax.googleapis.com/ajax/libs/jquery/' + jQConf.version + '/jquery.min.js';
                    },
                    expression: true
                }, {
                    match: '/@jquery-legacy-cdn/g',
                    replacement: function () {
                        var jQLegConf = grunt.file.readJSON('bower_components/jquery-legacy/bower.json');
                        return '//ajax.googleapis.com/ajax/libs/jquery/' + jQLegConf.version + '/jquery.min.js';
                    },
                    expression: true
                }]
            },

            dev: {
                files: [
                    {src: ['dev/index.html'], dest: 'dev/index.html'}
                ]
            },

            dist: {
                files: [
                    {src: ['dist/index.html'], dest: 'dist/index.html'}
                ]
            }
            <% } %>
        },

        processhtml: {
            options: {
                process: true,
                templateSettings: {
                    opener: '{!',
                    closer: '!}'
                }
            },
            dev: {
                options: {
                    data: {
                        jqMinLocal: 'bower_components/jquery/jquery.min.js',
                        jqLegMinLocal: 'bower_components/jquery-legacy/jquery.min.js',
                        jqMigrate: 'bower_components/jquery-migrate/jquery-migrate.js'
                    }
                },
                files: {
                    '<%%= yeoman.dev %>/index.html': ['<%%= yeoman.dev %>/index.html']
                }
            },
            dist: {
                options: {
                    data: {
                        jqMinLocal: 'assets/js/lib/jquery.min.js',
                        jqLegMinLocal: 'assets/js/lib/jquery-legacy.min.js',
                        jqMigrate: 'assets/js/lib/jquery-migrate.min.js'
                    }
                },
                files: {
                    '<%%= yeoman.dist %>/index.html': ['<%%= yeoman.dist %>/index.html']
                }
            }
        },

        modernizr: {
            devFile: 'bower_components/modernizr/modernizr.js',
            outputFile: '<%%= yeoman.dist %>/assets/js/lib/modernizr-custom.min.js',
            files: ['<%%= yeoman.dist %>/**/*.js', '<%%= yeoman.dist %>/**/*.css', '<%%= yeoman.dist %>/**/*.scss']
        },

        svgmin: {
            options: {
                plugins: [{
                    removeViewBox: false
                }]
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/assets/img',
                    src: ['{,*/}*.svg'],
                    dest: '<%%= yeoman.app %>/assets/img/',
                    ext: '.svg'
                }]
            }
        },

        svg2png: {
            dist: {
                files: [
                    { src: ['<%%= yeoman.app %>/assets/img/{,*/}*.svg'] }
                ]
            }
        },

        rev: {
            dist: {
                files: {
                    src: [
                        '<%%= yeoman.dist %>/assets/js/{,*/}*.js',
                        '<%%= yeoman.dist %>/assets/css/{,*/}*.css',
                        '<%%= yeoman.dist %>/assets/img/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
                        '<%%= yeoman.dist %>/assets/css/fonts/*'
                    ]
                }
            }
        },

        spriteHD: {
            options: {
                destImg: '<%%= yeoman.app %>/assets/img',
                destCSS: '<%%= yeoman.app %>/assets/scss/global',
                imgUrl: '../img'
            },

            all: {
                src: '<%%= yeoman.app %>/assets/img/sprite-assets/*',
                spriteName: 'sheet'
            }
        },

        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/assets/img/',
                    src: ['**/*.{png,jpg,jpeg,gif,svg}', '!sprite-assets/*.png'],
                    dest: '<%%= yeoman.app %>/assets/img/'
                }]
            }
        },

        usemin: {
            options: {
                dirs: ['<%%= yeoman.dist %>']
            },
            html: ['<%%= yeoman.dist %>/*.html'],
            css: '<%%= yeoman.dist %>/assets/css/*.css'
        }
    });

    grunt.registerTask('server', [
        'dev',
        'connect:livereload',
        'watch'
    ]);

    grunt.registerTask('dev', [
        'clean:dev',
        'copy:dev',
        'spriteHD',<% if (cssFramework === 'compassSusy') { %>
        'compass:dev',<% } %><% if (cssFramework !== 'compassSusy') { %>
        'sass:dev',<% } %>
        'processhtml:dev',
        'replace:dev'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'useminPrepare',
        'svgmin',
        'imagemin:dist',
        'svg2png',
        'spriteHD',<% if (cssFramework === 'compassSusy') { %>
        'compass:dist',<% } %><% if (cssFramework !== 'compassSusy') { %>
        'sass:dist',<% } %>
        'concat',
        'uglify',
        'modernizr',
        'copy:dist',
        'processhtml:dist',
        'replace:dist',
        'rev',
        'usemin',
    ]);
};<commit_msg>dist now doesn't copy over _s.pot<commit_after>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

module.exports = function (grunt) {
    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    // configurable paths
    var yeomanConfig = {
        app: 'app',
        dev: 'dev',
        dist: 'dist'
    };

    <% if (wordpress === true) { %>
    var yeomanConfig = {
        app: 'app/<%= slugSiteName %>',
        dev: 'dev/<%= slugSiteName %>',
        dist: 'dist/<%= slugSiteName %>'
    };
    <% } %>

    grunt.initConfig({
        yeoman: yeomanConfig,

        clean: {
            dev: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.dev %>/*',
                        '!<%%= yeoman.dev %>/.git*'
                    ]
                }]
            },

            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.dist %>/*',
                        '!<%%= yeoman.dist %>/.git*'
                    ]
                }]
            }
        },

        useminPrepare: {
            options: {
                dest: '<%%= yeoman.dist %>'
            },
            html: '<%%= yeoman.app %>/index.html',
            css: '<%%= yeoman.app %>/assets/scss/**/*.scss'
        },

        watch: {
            options: {
                livereload: true
            },
            css: {
                files: ['<%%= yeoman.app %>/assets/scss/*.scss'],
                /* TO DO: this should be conditional depending on the framework chosen */
                tasks: ['compass:dev']
            },
            html: {
                files: ['<%%= yeoman.app %>{,*/}*.html'],
                tasks: ['copy:html', 'replace', 'processhtml:dev']
            },
            sprites: {
                files: ['<%%= yeoman.app %>/assets/img/sprite-assets/*.png'],
                tasks: ['spriteHD', 'copy:dev']
            }
        },

        connect: {
            options: {
                port: 9000,
                livereload: 35729,
                hostname: '0.0.0.0',
                base: '<%%= yeoman.dev %>'
            },
            livereload: {
                options: {
                    open: 'http://localhost:<%%= connect.options.port %>',
                    base: [
                        '<%%= yeoman.dev %>'
                    ]
                }
            }
        },

        open: {
            server: {
                path: 'http://localhost:<%%= connect.options.port %>'
            }
        },

        copy: {
            dev: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['**', '!**/scss/**', '!.htaccess', '!**/languages/**'], dest: '<%%= yeoman.dev %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>/assets/scss/fonts', src: ['**'], dest: '<%%= yeoman.dev %>/assets/css/fonts'}<% if (wordpress === true) { %>,
                    {expand: true, cwd: '<%%= yeoman.app %>/languages', src: ['_s.pot'], dest: '<%%= yeoman.dev %>/languages', rename: function (dest) {
                        return dest + '/<%= slugSiteName %>.pot';
                    }}<% } %>
                ]
            },

            dist: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['**', '!**/img/sprite-assets/**', '!**/scss/**', '!**/js/*.js', '!**/languages/**'], dest: '<%%= yeoman.dist %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['.htaccess'], dest: '<%%= yeoman.dist %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>/assets/scss/fonts', src: ['**'], dest: '<%%= yeoman.dist %>/assets/css/fonts'},
                    {expand: true, cwd: 'bower_components/jquery', src: ['jquery.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib'},
                    {expand: true, cwd: 'bower_components/jquery-legacy', src: ['jquery.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib', rename: function (dest) {
                        return dest + '/jquery-legacy.min.js';
                    }},
                    // Only copy over the minified migrate plugin
                    {expand: true, cwd: 'bower_components/jquery-migrate', src: ['jquery-migrate.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib'}<% if (wordpress === true) { %>,
                    {expand: true, cwd: '<%%= yeoman.app %>/languages', src: ['_s.pot'], dest: '<%%= yeoman.dist %>/languages', rename: function (dest) {
                        return dest + '/<%= slugSiteName %>.pot';
                    }}<% } %>
                ]
            },

            html: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['{,*/}*.html'], dest: '<%%= yeoman.dev %>'}
                ]
            }
        },

        <% if (cssFramework === 'compassSusy') { %>
        compass: {
            dev: {
                options: {
                    sassDir: '<%%= yeoman.app %>/assets/scss',
                    <% if (wordpress === true) { %>
                    cssDir: '<%%= yeoman.dev %>',
                    <% } else { %>
                    cssDir: '<%%= yeoman.dev %>/assets/css',
                    <% } %>
                    environment: 'development'
                }
            },

            dist: {
                options: {
                    sassDir: '<%%= yeoman.app %>/assets/scss',
                    <% if (wordpress === true) { %>
                    cssDir: '<%%= yeoman.dist %>',
                    <% } else { %>
                    cssDir: '<%%= yeoman.dist %>/assets/css',
                    <% } %>
                    environment: 'production'
                }
            }
        },
        <% } %>

        <% if (cssFramework !== 'compassSusy') { %>
        sass: {
            dev: {
                expand: true,
                cwd: '<%%= yeoman.app %>/assets/scss',
                src: ['*.scss'],
                dest: '<%%= yeoman.dev %>/assets/css',
                ext: '.css'
            },

            dist: {
                expand: true,
                cwd: '<%%= yeoman.app %>/assets/scss',
                src: ['*.scss'],
                dest: '<%%= yeoman.dist %>/assets/css',
                ext: '.css'
            }
        },
        <% } %>

        replace: {
            <% if (wordpress === true) { %>
            options: {
                patterns: [{
                    match: '/\'_s\'/g',
                    replacement: function () {
                        return "'<%= slugSiteName %>'";
                    },
                    expression: true
                }, {
                    match: '/_s_/g',
                    replacement: function () {
                        return "<%= slugSiteName %>_";
                    },
                    expression: true
                }, {
                    match: '/ _s/g',
                    replacement: function () {
                        var toCapital = "<%= slugSiteName %>";
                        var capitalized = toCapital.charAt(0).toUpperCase() + toCapital.slice(1);
                        return ' ' + capitalized;
                    },
                    expression: true
                }, {
                    match: '/_s-/g',
                    replacement: function () {
                        return "<%= slugSiteName %>-";
                    },
                    expression: true
                }]
            },

            dev: {
                files: [
                    {expand: true, src: ['<%%= yeoman.dev %>/**', '<%%= yeoman.dev %>/languages/<%= slugSiteName %>.pot']}
                ]
            },

            dist: {
                files: [
                    {expand: true, src: ['<%%= yeoman.dist %>/**', '<%%= yeoman.dist %>/languages/<%= slugSiteName %>.pot']}
                ]
            }
            <% } else { %>
            options: {
                patterns: [{
                    match: '/@jquery-cdn/g',
                    replacement: function () {
                        var jQConf = grunt.file.readJSON('bower_components/jquery/bower.json');
                        return '//ajax.googleapis.com/ajax/libs/jquery/' + jQConf.version + '/jquery.min.js';
                    },
                    expression: true
                }, {
                    match: '/@jquery-legacy-cdn/g',
                    replacement: function () {
                        var jQLegConf = grunt.file.readJSON('bower_components/jquery-legacy/bower.json');
                        return '//ajax.googleapis.com/ajax/libs/jquery/' + jQLegConf.version + '/jquery.min.js';
                    },
                    expression: true
                }]
            },

            dev: {
                files: [
                    {src: ['dev/index.html'], dest: 'dev/index.html'}
                ]
            },

            dist: {
                files: [
                    {src: ['dist/index.html'], dest: 'dist/index.html'}
                ]
            }
            <% } %>
        },

        processhtml: {
            options: {
                process: true,
                templateSettings: {
                    opener: '{!',
                    closer: '!}'
                }
            },
            dev: {
                options: {
                    data: {
                        jqMinLocal: 'bower_components/jquery/jquery.min.js',
                        jqLegMinLocal: 'bower_components/jquery-legacy/jquery.min.js',
                        jqMigrate: 'bower_components/jquery-migrate/jquery-migrate.js'
                    }
                },
                files: {
                    '<%%= yeoman.dev %>/index.html': ['<%%= yeoman.dev %>/index.html']
                }
            },
            dist: {
                options: {
                    data: {
                        jqMinLocal: 'assets/js/lib/jquery.min.js',
                        jqLegMinLocal: 'assets/js/lib/jquery-legacy.min.js',
                        jqMigrate: 'assets/js/lib/jquery-migrate.min.js'
                    }
                },
                files: {
                    '<%%= yeoman.dist %>/index.html': ['<%%= yeoman.dist %>/index.html']
                }
            }
        },

        modernizr: {
            devFile: 'bower_components/modernizr/modernizr.js',
            outputFile: '<%%= yeoman.dist %>/assets/js/lib/modernizr-custom.min.js',
            files: ['<%%= yeoman.dist %>/**/*.js', '<%%= yeoman.dist %>/**/*.css', '<%%= yeoman.dist %>/**/*.scss']
        },

        svgmin: {
            options: {
                plugins: [{
                    removeViewBox: false
                }]
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/assets/img',
                    src: ['{,*/}*.svg'],
                    dest: '<%%= yeoman.app %>/assets/img/',
                    ext: '.svg'
                }]
            }
        },

        svg2png: {
            dist: {
                files: [
                    { src: ['<%%= yeoman.app %>/assets/img/{,*/}*.svg'] }
                ]
            }
        },

        rev: {
            dist: {
                files: {
                    src: [
                        '<%%= yeoman.dist %>/assets/js/{,*/}*.js',
                        '<%%= yeoman.dist %>/assets/css/{,*/}*.css',
                        '<%%= yeoman.dist %>/assets/img/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
                        '<%%= yeoman.dist %>/assets/css/fonts/*'
                    ]
                }
            }
        },

        spriteHD: {
            options: {
                destImg: '<%%= yeoman.app %>/assets/img',
                destCSS: '<%%= yeoman.app %>/assets/scss/global',
                imgUrl: '../img'
            },

            all: {
                src: '<%%= yeoman.app %>/assets/img/sprite-assets/*',
                spriteName: 'sheet'
            }
        },

        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/assets/img/',
                    src: ['**/*.{png,jpg,jpeg,gif,svg}', '!sprite-assets/*.png'],
                    dest: '<%%= yeoman.app %>/assets/img/'
                }]
            }
        },

        usemin: {
            options: {
                dirs: ['<%%= yeoman.dist %>']
            },
            html: ['<%%= yeoman.dist %>/*.html'],
            css: '<%%= yeoman.dist %>/assets/css/*.css'
        }
    });

    grunt.registerTask('server', [
        'dev',
        'connect:livereload',
        'watch'
    ]);

    grunt.registerTask('dev', [
        'clean:dev',
        'copy:dev',
        'spriteHD',<% if (cssFramework === 'compassSusy') { %>
        'compass:dev',<% } %><% if (cssFramework !== 'compassSusy') { %>
        'sass:dev',<% } %>
        'processhtml:dev',
        'replace:dev'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'useminPrepare',
        'svgmin',
        'imagemin:dist',
        'svg2png',
        'spriteHD',<% if (cssFramework === 'compassSusy') { %>
        'compass:dist',<% } %><% if (cssFramework !== 'compassSusy') { %>
        'sass:dist',<% } %>
        'concat',
        'uglify',
        'modernizr',
        'copy:dist',
        'processhtml:dist',
        'replace:dist',
        'rev',
        'usemin',
    ]);
};<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
import LanguageIcon from 'material-ui/svg-icons/action/language';
import TimerIcon from 'material-ui/svg-icons/image/timer';
import TextFormatIcon from 'material-ui/svg-icons/content/text-format';
import Slider from 'material-ui/Slider';
import {connect} from 'react-redux';
import {injectIntl} from 'react-intl';

import APP_LANGS from './../../constants/appLangs';
import APP_FONTS from './../../constants/appFonts';
import {setIntl, setAppFont, setWriteDelay} from './../../redux/modules/main';
import injectF from './../../helpers/injectF';

const styles = require('./PageSettings.scss');

@connect(({main}) => ({
  appLocale: main.get('appLocale'),
  appFont: main.get('appFont'),
  writeDelay: main.get('writeDelay')
}), {setIntl, setWriteDelay, setAppFont})
@injectIntl
@injectF
export default class PageSettings extends Component {

  static propTypes = {
    f: PropTypes.func.isRequired,
    appLocale: PropTypes.string.isRequired,
    appFont: PropTypes.string.isRequired,
    setIntl: PropTypes.func.isRequired,
    setAppFont: PropTypes.func.isRequired,
    writeDelay: PropTypes.number.isRequired,
    setWriteDelay: PropTypes.func.isRequired
  };

  renderLangMenuItems() {
    return APP_LANGS.map(({value, text}) => {
      return <MenuItem key={`option-lang-${value}`} value={value} primaryText={text} />;
    });
  }

  renderFontMenuItems() {
    return APP_FONTS.map(({value, text}) => {
      return <MenuItem key={`option-font-${value}`} value={value} primaryText={text} />;
    });
  }

  handleLangSelectFieldChange = (event, index, value) => {
    this.props.setIntl(value);
  };

  handleFontSelectFieldChange = (event, index, value) => {
    this.props.setAppFont(value);
  };

  handleWriteDelaySliderChange = (event, newValue) => {
    this.props.setWriteDelay(newValue);
  };

  render() {

    const {appLocale, appFont, f, writeDelay} = this.props;

    return (

{f('settings')}

          <LanguageIcon style={{marginRight: '21px', marginBottom: '12px'}} />
          <SelectField floatingLabelStyle={{fontSize: '20px'}} floatingLabelText={f('app-language')} onChange={this.handleLangSelectFieldChange} value={appLocale}>
            {this.renderLangMenuItems()}
          </SelectField>

          <TextFormatIcon style={{marginRight: '21px', marginBottom: '12px'}} />
          <SelectField floatingLabelStyle={{fontSize: '20px'}} floatingLabelText={f('app-font')} onChange={this.handleFontSelectFieldChange} value={appFont}>
            {this.renderFontMenuItems()}
          </SelectField>

          <TimerIcon style={{marginRight: '21px', marginBottom: '12px'}} />

            {f('write-delay-with-num', {writeDelay: `${writeDelay}`})}
            <Slider sliderStyle={{marginTop: '7px', marginBottom: 0}} step={1} style={{width: 240}} min={0} max={1000} defaultValue={writeDelay} onChange={this.handleWriteDelaySliderChange} />

    );
  }
}
<commit_msg>add interface font size slider<commit_after>import React, {Component, PropTypes} from 'react';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
import LanguageIcon from 'material-ui/svg-icons/action/language';
import TimerIcon from 'material-ui/svg-icons/image/timer';
import TextFormatIcon from 'material-ui/svg-icons/content/text-format';
import FormatSizeIcon from 'material-ui/svg-icons/editor/format-size';
import Slider from 'material-ui/Slider';
import {connect} from 'react-redux';
import {injectIntl} from 'react-intl';

import APP_LANGS from './../../constants/appLangs';
import APP_FONTS from './../../constants/appFonts';
import {setIntl, setAppFont, setWriteDelay, setInterfaceFontSize} from './../../redux/modules/main';
import injectF from './../../helpers/injectF';

const styles = require('./PageSettings.scss');

@connect(({main}) => ({
  appLocale: main.get('appLocale'),
  appFont: main.get('appFont'),
  interfaceFontSize: main.get('interfaceFontSize'),
  writeDelay: main.get('writeDelay')
}), {setIntl, setWriteDelay, setAppFont, setInterfaceFontSize})
@injectIntl
@injectF
export default class PageSettings extends Component {

  static propTypes = {
    f: PropTypes.func.isRequired,
    appLocale: PropTypes.string.isRequired,
    interfaceFontSize: PropTypes.number.isRequired,
    appFont: PropTypes.string.isRequired,
    setIntl: PropTypes.func.isRequired,
    setInterfaceFontSize: PropTypes.func.isRequired,
    setAppFont: PropTypes.func.isRequired,
    writeDelay: PropTypes.number.isRequired,
    setWriteDelay: PropTypes.func.isRequired
  };

  renderLangMenuItems() {
    return APP_LANGS.map(({value, text}) => {
      return <MenuItem key={`option-lang-${value}`} value={value} primaryText={text} />;
    });
  }

  renderFontMenuItems() {
    return APP_FONTS.map(({value, text}) => {
      return <MenuItem key={`option-font-${value}`} value={value} primaryText={text} />;
    });
  }

  handleLangSelectFieldChange = (event, index, value) => {
    this.props.setIntl(value);
  };

  handleFontSelectFieldChange = (event, index, value) => {
    this.props.setAppFont(value);
  };

  handleWriteDelaySliderChange = (event, newValue) => {
    this.props.setWriteDelay(newValue);
  };

  handleInterfaceFontSizeSliderChange = (event, newValue) => {
    this.props.setInterfaceFontSize(newValue);
  };

  render() {

    const {appLocale, appFont, f, writeDelay, interfaceFontSize} = this.props;

    return (

{f('settings')}

          <LanguageIcon style={{marginRight: '21px', marginBottom: '12px'}} />
          <SelectField floatingLabelStyle={{fontSize: '20px'}} floatingLabelText={f('app-language')} onChange={this.handleLangSelectFieldChange} value={appLocale}>
            {this.renderLangMenuItems()}
          </SelectField>

          <TimerIcon style={{marginRight: '21px', marginBottom: '12px'}} />

            {f('write-delay-with-num', {writeDelay: `${writeDelay}`})}
            <Slider sliderStyle={{marginTop: '7px', marginBottom: 0}} step={1} style={{width: 240}} min={0} max={1000} defaultValue={writeDelay} onChange={this.handleWriteDelaySliderChange} />

          <TextFormatIcon style={{marginRight: '21px', marginBottom: '12px'}} />
          <SelectField floatingLabelStyle={{fontSize: '20px'}} floatingLabelText={f('app-font')} onChange={this.handleFontSelectFieldChange} value={appFont}>
            {this.renderFontMenuItems()}
          </SelectField>

          <FormatSizeIcon style={{marginRight: '21px', marginBottom: '12px'}} />

            {f('interface-font-size', {interfaceFontSize})}
            <Slider sliderStyle={{marginTop: '7px', marginBottom: 0}} step={1} style={{width: 240}} min={12} max={48} defaultValue={interfaceFontSize} onChange={this.handleInterfaceFontSizeSliderChange} />

    );
  }
}
<|endoftext|>


<commit_before>

function updateVideoInformation(json_url){
     $.ajax({
                url: json_url,
                type : 'GET',
                contentType: 'application/json',
                success: function(data){
                    var title = document.getElementById('player-title');
                    var subtitle = document.getElementById('player-subtitle');
                    var desc = document.getElementById('player-description');
                    var etags = document.getElementById('player-tags');
                    var poster = document.getElementById('player-holding-image');
                    var info = JSON.parse(data);
                    title.innerHTML = info['title'];
                    if(info['show']){
                        var show = info['show'];
                        title.innerHTML += ' video_library';
                        console.log(show['title']);
                    }
                    if(info['nowplaying']){
                        subtitle.innerHTML = info['nowplaying'];
                    }else{
                        subtitle.innerHTML = "";
                    }
                    desc.innerHTML = info['description'];
                    try{
                        poster.src = info['poster'];
                    }catch(err){
                        console.log(err.message);
                    }
                    etags.innerHTML = '';
                    var tagstring = info['tags'];
                    var taga = tagstring.split(' ');
                    for(n in taga){
                        if(taga[n].toString().length > 0){
                            var newtag = document.createElement('div');
                            newtag.className = "chip";
                            newtag.innerHTML = '' + taga[n] + '';
                            etags.appendChild(newtag);
                        }
                    }
                    document.tile = 'LCR - ' + info['title'];
                    console.log('Data refreshed');
                }
            });
}

function updateChannelPanes(){
    /* For homepage channel panes */
    json_url = config['publicphp'] + '?action=plugin_videomanager&list';
    $.ajax({
                url: json_url,
                type : 'GET',
                contentType: 'application/json',
                success: function(data){
                    data = JSON.parse(data);
                    var channelpanec = document.getElementById("live-channels");

                    for(n in data){

                        var channel = data[n];
                        var cid = channel['id'];
                        var json_url_2 = config['publicphp'] + '?action=plugin_videomanager&id=' + cid;

                        $.ajax({
                            url: json_url_2,
                            type : 'GET',
                            contentType: 'application/json',
                            success: function(data){

                                var info = JSON.parse(data);

                                var pane_id = 'channel_pane_' + info['channelID'];

                                var container = document.createElement('div');

                                container.id = pane_id;
                                container.className = "col s12 m6 l3 channel-pane";

                                var html = '
\
                                        \

\

\

\

\

' + info['channel_name'] + '
\

' + info['title'] + '
';
                                       if(info['nowplaying']){
                                           html += '
' + info['nowplaying'] + '
';
                                       }

                                html += '
\
                                        \

';

                                if(document.getElementById(pane_id)){
                                    var pane = document.getElementById(pane_id);
                                    pane.innerHTML = html;
                                }else{
                                    container.innerHTML = html;
                                    channelpanec.appendChild(container);
                                }
                            }
                        });

                    }

                    var panes = document.getElementsByClassName('channel-pane');
                    /* Set/unset pane visibility based on status */
                    for(p in panes){
                        var pane = panes[p];
                        var isLive = false;
                        var id = pane.id;

                        for(n in data){
                            var checkId = 'channel_pane_' + data[n]['id'];
                            if(checkId == id){
                                isLive = true;
                            }
                        }

                        try{
                            if(isLive){
                                pane.style.display = "block";
                            }else{
                                pane.style.display = "none";
                            }
                        }catch(err){
                        }
                    }
                }
            });
}

function updateChannelList(){
    /* For homepage channel panes */
    var json_url_c = config['publicphp'] + '?action=plugin_videomanager&list';
    $.ajax({
                url: json_url_c,
                type : 'GET',
                contentType: 'application/json',
                success: function(data){
                    data = JSON.parse(data);
                    var channelpanec = document.getElementById("channel-list");
                    var livelabel = document.getElementById("live-indicator");

                    livelabel.style.display = 'none';
                    for(n in data){
                        livelabel.style.display = 'block';
                        var channel = data[n];
                        var cid = channel['id'];
                        var json_url_2 = config['publicphp'] + '?action=plugin_videomanager&id=' + cid;

                        $.ajax({
                            url: json_url_2,
                            type : 'GET',
                            contentType: 'application/json',
                            success: function(data){

                                var info = JSON.parse(data);

                                var pane_id = 'channel_pane_' + info['channelID'];

                                var container = document.createElement('div');

                                container.id = pane_id;
                                container.className = "playlist-item z-depth-0 channel-pane";
                                container.setAttribute('onclick', "pages.loadPage('video&play=-" + info['channelID'] + "');");

                                var html = '
\

\
                                                \

\

\
                                                ' + info['channel_name'] + '\
                                                ' + info['title'] + '\
                                                ' + ((info['nowplaying'])? info['nowplaying']: '') +'\

';

                                if(document.getElementById(pane_id)){
                                    var pane = document.getElementById(pane_id);
                                    pane.innerHTML = html;
                                }else{
                                    container.innerHTML = html;
                                    channelpanec.appendChild(container);
                                }
                            }
                        });

                    }

                    var panes = document.getElementsByClassName('channel-pane');
                    /* Set/unset pane visibility based on status */
                    for(p in panes){
                        var pane = panes[p];
                        var isLive = false;
                        var id = pane.id;

                        for(n in data){
                            var checkId = 'channel_pane_' + data[n]['id'];
                            if(checkId == id){
                                isLive = true;
                            }
                        }

                        try{
                            if(isLive){
                                pane.style.display = "block";
                            }else{
                                pane.style.display = "none";
                            }
                        }catch(err){
                        }

                    }
                }
            });
}
<commit_msg>Fixed channel list styling<commit_after>

function updateVideoInformation(json_url){
     $.ajax({
                url: json_url,
                type : 'GET',
                contentType: 'application/json',
                success: function(data){
                    var title = document.getElementById('player-title');
                    var subtitle = document.getElementById('player-subtitle');
                    var desc = document.getElementById('player-description');
                    var etags = document.getElementById('player-tags');
                    var poster = document.getElementById('player-holding-image');
                    var info = JSON.parse(data);
                    title.innerHTML = info['title'];
                    if(info['show']){
                        var show = info['show'];
                        title.innerHTML += ' video_library';
                        console.log(show['title']);
                    }
                    if(info['nowplaying']){
                        subtitle.innerHTML = info['nowplaying'];
                    }else{
                        subtitle.innerHTML = "";
                    }
                    desc.innerHTML = info['description'];
                    try{
                        poster.src = info['poster'];
                    }catch(err){
                        console.log(err.message);
                    }
                    etags.innerHTML = '';
                    var tagstring = info['tags'];
                    var taga = tagstring.split(' ');
                    for(n in taga){
                        if(taga[n].toString().length > 0){
                            var newtag = document.createElement('div');
                            newtag.className = "chip";
                            newtag.innerHTML = '' + taga[n] + '';
                            etags.appendChild(newtag);
                        }
                    }
                    document.tile = 'LCR - ' + info['title'];
                    console.log('Data refreshed');
                }
            });
}

function updateChannelPanes(){
    /* For homepage channel panes */
    json_url = config['publicphp'] + '?action=plugin_videomanager&list';
    $.ajax({
                url: json_url,
                type : 'GET',
                contentType: 'application/json',
                success: function(data){
                    data = JSON.parse(data);
                    var channelpanec = document.getElementById("live-channels");

                    for(n in data){

                        var channel = data[n];
                        var cid = channel['id'];
                        var json_url_2 = config['publicphp'] + '?action=plugin_videomanager&id=' + cid;

                        $.ajax({
                            url: json_url_2,
                            type : 'GET',
                            contentType: 'application/json',
                            success: function(data){

                                var info = JSON.parse(data);

                                var pane_id = 'channel_pane_' + info['channelID'];

                                var container = document.createElement('div');

                                container.id = pane_id;
                                container.className = "col s12 m6 l3 channel-pane";

                                var html = '
\
                                        \

\

\

\

\

' + info['channel_name'] + '
\

' + info['title'] + '
';
                                       if(info['nowplaying']){
                                           html += '
' + info['nowplaying'] + '
';
                                       }

                                html += '
\
                                        \

';

                                if(document.getElementById(pane_id)){
                                    var pane = document.getElementById(pane_id);
                                    pane.innerHTML = html;
                                }else{
                                    container.innerHTML = html;
                                    channelpanec.appendChild(container);
                                }
                            }
                        });

                    }

                    var panes = document.getElementsByClassName('channel-pane');
                    /* Set/unset pane visibility based on status */
                    for(p in panes){
                        var pane = panes[p];
                        var isLive = false;
                        var id = pane.id;

                        for(n in data){
                            var checkId = 'channel_pane_' + data[n]['id'];
                            if(checkId == id){
                                isLive = true;
                            }
                        }

                        try{
                            if(isLive){
                                pane.style.display = "block";
                            }else{
                                pane.style.display = "none";
                            }
                        }catch(err){
                        }
                    }
                }
            });
}

function updateChannelList(){
    /* For video page channel panes */
    var json_url_c = config['publicphp'] + '?action=plugin_videomanager&list';
    $.ajax({
                url: json_url_c,
                type : 'GET',
                contentType: 'application/json',
                success: function(data){
                    data = JSON.parse(data);
                    var channelpanec = document.getElementById("channel-list");
                    var livelabel = document.getElementById("live-indicator");

                    livelabel.style.display = 'none';
                    for(n in data){
                        livelabel.style.display = 'block';
                        var channel = data[n];
                        var cid = channel['id'];
                        var json_url_2 = config['publicphp'] + '?action=plugin_videomanager&id=' + cid;

                        $.ajax({
                            url: json_url_2,
                            type : 'GET',
                            contentType: 'application/json',
                            success: function(data){

                                var info = JSON.parse(data);

                                var pane_id = 'channel_pane_' + info['channelID'];

                                var container = document.createElement('div');

                                container.id = pane_id;
                                container.className = "playlist-item z-depth-0 channel-pane";
                                container.setAttribute('onclick', "pages.loadPage('video&play=-" + info['channelID'] + "');");

                                var html = '
\

\
                                                    \

\

\
                                                    ' + info['channel_name'] + '\
                                                    ' + info['title'] + '\
                                                    ' + ((info['nowplaying'])? info['nowplaying']: '') +'\

\

';

                                if(document.getElementById(pane_id)){
                                    var pane = document.getElementById(pane_id);
                                    pane.innerHTML = html;
                                }else{
                                    container.innerHTML = html;
                                    channelpanec.appendChild(container);
                                }
                            }
                        });

                    }

                    var panes = document.getElementsByClassName('channel-pane');
                    /* Set/unset pane visibility based on status */
                    for(p in panes){
                        var pane = panes[p];
                        var isLive = false;
                        var id = pane.id;

                        for(n in data){
                            var checkId = 'channel_pane_' + data[n]['id'];
                            if(checkId == id){
                                isLive = true;
                            }
                        }

                        try{
                            if(isLive){
                                pane.style.display = "block";
                            }else{
                                pane.style.display = "none";
                            }
                        }catch(err){
                        }

                    }
                }
            });
}
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc directive
 * @name gridster:ngGridster
 *
 * @description
 * The `ngGridster` directive instantiates a template once per item from a collection and then instantiates Gridster.js
 * on the instantiated templates. Each template instance gets its own scope, where the given loop variable is set to
 * the current collection item, and `$index` is set to the item index.
 *
 * Special properties are exposed on the local scope of each template instance, including:
 *
 * | Variable  | Type            | Details                                                                     |
 * |-----------|-----------------|-----------------------------------------------------------------------------|
 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
 *
 * Although this works similarly to ngRepeat, this directive does not watch for changes in the collection after
 * it has been added to the DOM. It is expected that all DOM manipulation after the first draw happens
 * via the Gridster.js API.
 *
 * @element ANY
 * @scope
 * @priority 1000
 * @param {repeat_expression} ngGridster The expression indicating how to enumerate a collection.
 *
 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
 *     is a scope expression giving the collection to enumerate.
 *
 *     For example: `album in artist.albums`.
 *
 */

angular.module('gridster', [])
  .directive('ngGridster', ['$parse', '$animate', function($parse, $animate) {
    return {
      restrict: 'A',
      controller: ['$scope', function($scope) {
        var gridster;

        this.gridster = function(arg) {
          return gridster = arg || gridster;
        }

        this.serialize = function(fn, e, ui, $widget) {
          fn($scope, { serialized: this.gridster().serialize() });

          if ($widget) {
            $widget.scope().$broadcast('gridster-widget-resized', {
              height: this.gridster().resize_coords.data.height,
              width: this.gridster().resize_coords.data.width
            });
          }
        }
      }],
      link: function(scope, element, attr, controller) {
        scope.$on('gridster-repeat-complete', function(e) {
          e.stopPropagation();

          // Parse options
          var options = $parse(attr.ngGridster)(scope) || {};

          // Attach event listeners to drag/resize stop events to send resize events
          // to widgets and to invoke the changed function.
          var callback = $parse(attr.gridsterChanged);
          options.draggable = options.draggable || {};
          options.draggable.stop = controller.serialize.bind(controller, callback);
          options.resize = options.resize || {};
          options.resize.stop = controller.serialize.bind(controller, callback);

          // Create the gridster object in the DOM
          var gridster = element.gridster(options).data('gridster');

          // Disable dragging and resizing if editable is false. Default to true/editable.
          if (!$parse(attr.gridsterEditable || 'true')(scope)) {
            gridster.disable();

            if (options.resize && options.resize.enabled) {
              gridster.disable_resize();
            }
          }

          controller.gridster(gridster);

          element.find('li.gridster-widget').each(function(index, el) {
            var $widget = $(el);
            $widget.scope().$broadcast('gridster-widget-resized', {
              height: $widget.height(),
              width: $widget.width()
            });
          });
        });
      }
    }
  }])
  .directive('ngGridsterRepeat', ['$animate', '$parse', '$timeout', function($animate, $parse, $timeout) {
    return {
      restrict: 'A',
      transclude: 'element',
      require: '^ngGridster',
      terminal: true,
      link: function(scope, element, attr, controller, transclude) {
        var expression = attr.ngGridsterRepeat, // Get the repeat expression
            valueExp, collectionExp;

        // Make sure we have a 'item in something' expression
        var match = expression.match(/^\s*(.+)\s+in\s+(.*?)$/);

        if (!match) {
          throw new Error("Expected expression in form of '_item_ in _collection_' but got '" + expression + "'.");
        }

        valueExp = match[1];
        collectionExp = match[2];

        // Make sure we have a 'valid identifer in something' expression (ie: not '! in collection')
        match = valueExp.match(/^(?:([\$\w]+))$/);

        if (!match) {
          throw new Error("'_item_' in '_item_ in _collection_' should be an indentifier but got '" + valueExp + "'.");
        }

        var watcher = scope.$watchCollection(collectionExp, function(collection) {
          if (!collection) { return; }

          // Call the watcher function to stop watching the collection
          // After we finish with this function, gridster is going to handle the rest of the DOM manipulation
          watcher();

          var index = 0,
              length = collection.length,
              previousNode = element,
              childScope, value;

          // Double check that we have an array
          if (!Array.isArray(collection)) {
            throw new Error("'_collection_' in '_item_ in _collection_' should be an array but got '" + collection + "'.");
          }

          // This is used to keep track (and add) widgets that are not in the layout to the next empty row
          var maxRow = 1;

          for (; index < length; index++) {
            value = collection[index];
            childScope = scope.$new();

            // Populate child scope with ngRepeat-style variables
            childScope[valueExp] = value;
            childScope.$index = index;
            childScope.$first = (index === 0);
            childScope.$last = (index === (length - 1));
            childScope.$middle = !(childScope.$first || childScope.$last);
            childScope.$odd = !(childScope.$even = (index&1) === 0);

            transclude(childScope, function(clone) {
              // Add uniform css class
              clone.addClass('gridster-widget');

              // Parse the layout and set data-* gridster attributes
              var layout = $parse(attr.gridsterLayout)(childScope);

              if (layout) {
                if (Array.isArray(layout) && layout.length > index) {
                  layout = layout[index];
                } else if (Array.isArray(layout)) {
                  layout = {};
                }

                clone.attr('data-row', layout.row = layout.row || maxRow);
                clone.attr('data-col', layout.col = layout.col || 1);

                // Default to 1x1 is no size if specified
                clone.attr('data-sizex', layout.size_x = layout.size_x || 1);
                clone.attr('data-sizey', layout.size_y = layout.size_y || 1);

                // increment maxRow
                if ((layout.row + layout.size_y) >= maxRow) {
                  maxRow = layout.row + layout.size_y;
                }
              }

              // Add a comment to the cloned node to denote the end of a repeated DOM fragment
              clone[clone.length++] = document.createComment(' end ngGridster: ' + expression + ' ');

              // Add the cloned node into the DOM via $animate
              $animate.enter(clone, null, previousNode);

              // Move the previousNode to the one we just added
              previousNode = clone;
            });
          }

          // Need to wait until after the current $digest to instantiate gridster
          $timeout(function() {
            scope.$emit('gridster-repeat-complete');
          });
        });
      }
    };
  }]);
<commit_msg>Wrapping state-changing gridster methods to call serialize when done<commit_after>'use strict';

/**
 * @ngdoc directive
 * @name gridster:ngGridster
 *
 * @description
 * The `ngGridster` directive instantiates a template once per item from a collection and then instantiates Gridster.js
 * on the instantiated templates. Each template instance gets its own scope, where the given loop variable is set to
 * the current collection item, and `$index` is set to the item index.
 *
 * Special properties are exposed on the local scope of each template instance, including:
 *
 * | Variable  | Type            | Details                                                                     |
 * |-----------|-----------------|-----------------------------------------------------------------------------|
 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
 *
 * Although this works similarly to ngRepeat, this directive does not watch for changes in the collection after
 * it has been added to the DOM. It is expected that all DOM manipulation after the first draw happens
 * via the Gridster.js API.
 *
 * @element ANY
 * @scope
 * @priority 1000
 * @param {repeat_expression} ngGridster The expression indicating how to enumerate a collection.
 *
 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
 *     is a scope expression giving the collection to enumerate.
 *
 *     For example: `album in artist.albums`.
 *
 */

angular.module('gridster', [])
  .directive('ngGridster', ['$parse', '$animate', function($parse, $animate) {
    return {
      restrict: 'A',
      controller: ['$scope', function($scope) {
        var gridster;

        this.gridster = function(arg) {
          return gridster = arg || gridster;
        }

        this.serialize = function(fn, e, ui, $widget) {
          fn($scope, { serialized: this.gridster().serialize() });

          if ($widget) {
            $widget.scope().$broadcast('gridster-widget-resized', {
              height: this.gridster().resize_coords.data.height,
              width: this.gridster().resize_coords.data.width
            });
          }
        }
      }],
      link: function(scope, element, attr, controller) {
        scope.$on('gridster-repeat-complete', function(e) {
          e.stopPropagation();

          // Parse options
          var options = $parse(attr.ngGridster)(scope) || {};

          // Attach event listeners to drag/resize stop events to send resize events
          // to widgets and to invoke the changed function.
          var callback = $parse(attr.gridsterChanged);
          options.draggable = options.draggable || {};
          options.draggable.stop = controller.serialize.bind(controller, callback);
          options.resize = options.resize || {};
          options.resize.stop = controller.serialize.bind(controller, callback);

          // Create the gridster object in the DOM
          var gridster = element.gridster(options).data('gridster');

          // Override all methods that change grid state to call the serialize function after executing
          ['add_widget', 'resize_widget', 'remove_widget', 'remove_all_widgets'].forEach(function(name) {
            var fn = gridster[name];
            gridster[name] = function() {
              fn.apply(gridster, Array.prototype.slice.call(arguments));
              controller.serialize(callback);
            }
          });

          // Disable dragging and resizing if editable is false. Default to true/editable.
          if (!$parse(attr.gridsterEditable || 'true')(scope)) {
            gridster.disable();

            if (options.resize && options.resize.enabled) {
              gridster.disable_resize();
            }
          }

          controller.gridster(gridster);

          element.find('li.gridster-widget').each(function(index, el) {
            var $widget = $(el);
            $widget.scope().$broadcast('gridster-widget-resized', {
              height: $widget.height(),
              width: $widget.width()
            });
          });
        });
      }
    }
  }])
  .directive('ngGridsterRepeat', ['$animate', '$parse', '$timeout', function($animate, $parse, $timeout) {
    return {
      restrict: 'A',
      transclude: 'element',
      require: '^ngGridster',
      terminal: true,
      link: function(scope, element, attr, controller, transclude) {
        var expression = attr.ngGridsterRepeat, // Get the repeat expression
            valueExp, collectionExp;

        // Make sure we have a 'item in something' expression
        var match = expression.match(/^\s*(.+)\s+in\s+(.*?)$/);

        if (!match) {
          throw new Error("Expected expression in form of '_item_ in _collection_' but got '" + expression + "'.");
        }

        valueExp = match[1];
        collectionExp = match[2];

        // Make sure we have a 'valid identifer in something' expression (ie: not '! in collection')
        match = valueExp.match(/^(?:([\$\w]+))$/);

        if (!match) {
          throw new Error("'_item_' in '_item_ in _collection_' should be an indentifier but got '" + valueExp + "'.");
        }

        var watcher = scope.$watchCollection(collectionExp, function(collection) {
          if (!collection) { return; }

          // Call the watcher function to stop watching the collection
          // After we finish with this function, gridster is going to handle the rest of the DOM manipulation
          watcher();

          var index = 0,
              length = collection.length,
              previousNode = element,
              childScope, value;

          // Double check that we have an array
          if (!Array.isArray(collection)) {
            throw new Error("'_collection_' in '_item_ in _collection_' should be an array but got '" + collection + "'.");
          }

          // This is used to keep track (and add) widgets that are not in the layout to the next empty row
          var maxRow = 1;

          for (; index < length; index++) {
            value = collection[index];
            childScope = scope.$new();

            // Populate child scope with ngRepeat-style variables
            childScope[valueExp] = value;
            childScope.$index = index;
            childScope.$first = (index === 0);
            childScope.$last = (index === (length - 1));
            childScope.$middle = !(childScope.$first || childScope.$last);
            childScope.$odd = !(childScope.$even = (index&1) === 0);

            transclude(childScope, function(clone) {
              // Add uniform css class
              clone.addClass('gridster-widget');

              // Parse the layout and set data-* gridster attributes
              var layout = $parse(attr.gridsterLayout)(childScope);

              if (layout) {
                if (Array.isArray(layout) && layout.length > index) {
                  layout = layout[index];
                } else if (Array.isArray(layout)) {
                  layout = {};
                }

                clone.attr('data-row', layout.row = layout.row || maxRow);
                clone.attr('data-col', layout.col = layout.col || 1);

                // Default to 1x1 is no size if specified
                clone.attr('data-sizex', layout.size_x = layout.size_x || 1);
                clone.attr('data-sizey', layout.size_y = layout.size_y || 1);

                // increment maxRow
                if ((layout.row + layout.size_y) >= maxRow) {
                  maxRow = layout.row + layout.size_y;
                }
              }

              // Add a comment to the cloned node to denote the end of a repeated DOM fragment
              clone[clone.length++] = document.createComment(' end ngGridster: ' + expression + ' ');

              // Add the cloned node into the DOM via $animate
              $animate.enter(clone, null, previousNode);

              // Move the previousNode to the one we just added
              previousNode = clone;
            });
          }

          // Need to wait until after the current $digest to instantiate gridster
          $timeout(function() {
            scope.$emit('gridster-repeat-complete');
          });
        });
      }
    };
  }]);
<|endoftext|>


<commit_before>/**
 * Squid Core
 * Squid is a Github issues client on Mac OS X and IOS.
 *
 * @package    Core
 * @version    0.1.0
 * @author     Squid Development Team
 * @license    MIT License
 * @copyright  2015 Squid Development Team
 * @link       http://getsquiddone.com
 */

'use strict';

// Core App
// -----------
var core = require('./lib/core')

// Current version of the library from package file
core._VERSION = require( __dirname + '/package.json').version

module.exports = core
<commit_msg>add comment<commit_after>/**
 * Squid Core
 * Squid is a Github issues client on Mac OS X and IOS.
 *
 * @package    Core
 * @version    0.1.0
 * @author     Squid Development Team
 * @license    MIT License
 * @copyright  2015 Squid Development Team
 * @link       http://getsquiddone.com
 */

'use strict';

// Core App
// -----------

// Core instance
var core = require('./lib/core')

// Current version of the library from package file
core._VERSION = require( __dirname + '/package.json').version

module.exports = core
<|endoftext|>