<commit_before>var $ = require('jquery-browserify');
var chosen = require('chosen-jquery-browserify');
var _ = require('underscore');
var util = require('../util');
var Backbone = require('backbone');
var toolbar = require('../toolbar/markdown.js');
var upload = require('../upload');
var templates = require('../../dist/templates');

module.exports = Backbone.View.extend({
  template: templates.toolbar,

  events: {
    'click .group a': 'markdownSnippet',
    'click .publish-flag': 'togglePublishing',
    'change #upload': 'fileInput',
    'click .dialog .insert': 'dialogInsert',
    'click .draft-to-post': 'draft'
  },

  initialize: function(options) {
    var self = this;
    this.file = options.file;
    this.view = options.view;
    this.collection = options.collection;
    var config = options.config;

    if (config && config.prose) {
      this.hasMedia = (config.media) ? true : false;
      this.siteUrl = (config.siteUrl) ? true : false;

      if (config.prose.media) {
        // Fetch the media directory to display its contents
        this.mediaDirectoryPath = config.prose.media;
        var match = new RegExp(this.mediaDirectoryPath);

        this.media = this.collection.filter(function(m) {
          if (m.attributes.type === 'blob') {
            return match.test(m.attributes.path);
          }
        });
      }

      if (config.prose.relativeLinks) {
        $.ajax({
          cache: true,
          dataType: 'jsonp',
          jsonp: false,
          jsonpCallback: config.prose.relativeLinks.split('?callback=')[1] || 'callback',
          url: config.prose.relativeLinks,
          success: function(links) {
            self.relativeLinks = links;
          }
        });
      }
    }
  },

  render: function() {

    var toolbar = {
      markdown: this.file.get('markdown'),
      writable: this.file.get('writable'),
      lang: this.file.get('lang'),
      draft: this.file.get('draft'),
      metadata: this.file.get('metadata')
    };

    this.$el.html(_.template(this.template, toolbar, { variable: 'toolbar' }));
    return this;
  },

  fileInput: function(e) {
    var view = this;
    upload.fileSelect(e, function(e, file, content) {
      var path = (view.mediaDirectoryPath) ? view.mediaDirectoryPath : util.extractFilename(view.file.attributes.path)[0];
      var src = path + '/' + encodeURIComponent(file.name);

      view.$el.find('input[name="url"]').val(src);
      view.$el.find('input[name="alt"]').val('');
      view.trigger('updateImageInsert', e);
    });

    return false;
  },

  highlight: function(type) {
    this.$el.find('.group a').removeClass('active');
    if (arguments) this.$el.find('[data-key="' + type + '"]').addClass('active');
  },

  draft: function(e) {
    view.trigger('draft', e);
    return false;
  },

  markdownSnippet: function(e) {
    var self = this;
    var $target = $(e.target).closest('a');
    var $dialog = this.$el.find('#dialog');
    var $snippets = this.$el.find('.group a');
    var key = $target.data('key');
    var snippet = $target.data('snippet');
    var selection = util.trim(this.view.editor.getSelection());

    $dialog.removeClass().empty();

    if (snippet) {
      $snippets.removeClass('on');

      if (selection) {
        switch (key) {
        case 'bold':
          this.bold(selection);
          break;
        case 'italic':
          this.italic(selection);
          break;
        case 'heading':
          this.heading(selection);
          break;
        case 'sub-heading':
          this.subHeading(selection);
          break;
        case 'quote':
          this.quote(selection);
          break;
        default:
          this.view.editor.replaceSelection(snippet);
          break;
        }
        this.view.editor.focus();
      } else {
        this.view.editor.replaceSelection(snippet);
        this.view.editor.focus();
      }
    } else if ($target.data('dialog')) {

      var tmpl, className;
      if (key === 'media' && !this.mediaDirectoryPath ||
          key === 'media' && !this.media.length) {
          className = key + ' no-directory';
      } else {
          className = key;
      }

      // This condition handles the link and media link in the toolbar.
      if ($target.hasClass('on')) {
        $target.removeClass('on');
        $dialog.removeClass().empty();
      } else {
        $snippets.removeClass('on');
        $target.addClass('on');
        $dialog
          .removeClass()
          .addClass('dialog ' + className)
          .empty();

        switch(key) {
          case 'link':
            tmpl = _(templates.dialogs.link).template();

            $dialog.append(tmpl({
              relativeLinks: self.relativeLinks
            }));

            if (self.relativeLinks) {
              $('.chzn-select', $dialog).chosen().change(function() {
                $('.chzn-single span').text('Insert a local link.');

                var parts = $(this).val().split(',');
                $('input[name=href]', $dialog).val(parts[0]);
                $('input[name=text]', $dialog).val(parts[1]);
              });
            }

            if (selection) {
              // test if this is a markdown link: [text](link)
              var link = /\[([^\]]+)\]\(([^)]+)\)/;
              var quoted = /".*?"/;

              var text = selection;
              var href;
              var title;

              if (link.test(selection)) {
                var parts = link.exec(selection);
                text = parts[1];
                href = parts[2];

                // Search for a title attrbute within the url string
                if (quoted.test(parts[2])) {
                  href = parts[2].split(quoted)[0];

                  // TODO: could be improved
                  title = parts[2].match(quoted)[0].replace(/"/g, '');
                }
              }

              $('input[name=text]', $dialog).val(text);
              if (href) $('input[name=href]', $dialog).val(href);
              if (title) $('input[name=title]', $dialog).val(title);
            }
          break;
          case 'media':
            tmpl = _(templates.dialogs.media).template();
            $dialog.append(tmpl({
              description: t('dialogs.media.description', {
                input: '<input id="upload" class="upload" type="file" />'
              }),
              assetsDirectory: (self.media && self.media.length) ? true : false,
              writable: self.file.get('writable')
            }));

            if (self.media && self.media.length) self.renderMedia(self.media);

            if (selection) {
              var image = /\!\[([^\[]*)\]\(([^\)]+)\)/;
              var src;
              var alt;

              if (image.test(selection)) {
                var imageParts = image.exec(selection);
                alt = imageParts[1];
                src = imageParts[2];

                $('input[name=url]', $dialog).val(src);
                if (alt) $('input[name=alt]', $dialog).val(alt);
              }
            }
          break;
          case 'help':
            tmpl = _(templates.dialogs.help).template();
            $dialog.append(tmpl({
              help: toolbar.help
            }));

            // Page through different help sections
            var $mainMenu = this.$el.find('.main-menu a');
            var $subMenu = this.$el.find('.sub-menu');
            var $content = this.$el.find('.help-content');

            $mainMenu.on('click', function() {
              if (!$(this).hasClass('active')) {

                $mainMenu.removeClass('active');
                $content.removeClass('active');
                $subMenu
                    .removeClass('active')
                    .find('a')
                    .removeClass('active');

                $(this).addClass('active');

                // Add the relavent sub menu
                var parent = $(this).data('id');
                $('.' + parent).addClass('active');

                // Add an active class and populate the
                // content of the first list item.
                var $firstSubElement = $('.' + parent + ' a:first', this.el);
                $firstSubElement.addClass('active');

                var subParent = $firstSubElement.data('id');
                $('.help-' + subParent).addClass('active');
              }
              return false;
            });

            $subMenu.find('a').on('click', function() {
              if (!$(this).hasClass('active')) {

                $subMenu.find('a').removeClass('active');
                $content.removeClass('active');
                $(this).addClass('active');

                // Add the relavent content section
                var parent = $(this).data('id');
                $('.help-' + parent).addClass('active');
              }

              return false;
            });

          break;
        }
      }
    }

    return false;
  },

  publishState: function() {
    if (this.$el.find('publish-state') === 'true') {
      return true;
    } else {
      return false;
    }
  },

  updatePublishState: function() {
    // Update the publish key wording depening on what was saved
    var $publishkey = this.$el.find('.publish-flag');
    var key = $publishKey.attr('data-state');

    if (key === 'true') {
      $publishKey.html(t('actions.publishing.published') +
                      '');
    } else {
      $publishKey.html(t('actions.publishing.unpublished') +
                      '');
    }
  },

  togglePublishing: function(e) {
    var $target = $(e.target).hasClass('checkmark') ? $(e.target).parent() : $(e.target);

    // TODO: remove HTML from view
    // Toggling publish state when the current file is published live
    if (this.file.get('metadata').published) {
      if ($target.hasClass('published')) {
        $target
          .empty()
          .append(t('actions.publishing.unpublish') +
                '' +
                '' +
                t('actions.publishing.unpublishInfo') +
                '')
          .removeClass('published')
          .attr('data-state', false);
      } else {
        $target
          .empty()
          .append(t('actions.publishing.published') +
                '')
          .addClass('published')
          .attr('data-state', true);
      }
    } else {
      if ($target.hasClass('published')) {
        $target
          .empty()
          .append(t('actions.publishing.unpublished') +
                '')
          .removeClass('published')
          .attr('data-state', false);
      } else {
        $target
          .empty()
          .append(t('actions.publishing.publish') +
                '' +
                '' +
                t('actions.publishing.publishInfo') +
                '')
          .addClass('published')
          .attr('data-state', true);
      }
    }

    this.view.makeDirty();
    return false;
  },

  dialogInsert: function(e) {
    var $dialog = $('#dialog', this.el);
    var $target = $(e.target, this.el);
    var type = $target.data('type');

    if (type === 'link') {
      var href = $('input[name="href"]').val();
      var text = $('input[name="text"]').val();
      var title = $('input[name="title"]').val();

      if (!text) text = href;

      if (title) {
        this.view.editor.replaceSelection('[' + text + '](' + href + ' "' + title + '")');
      } else {
        this.view.editor.replaceSelection('[' + text + '](' + href + ')');
      }

      this.view.editor.focus();
    }

    if (type === 'media') {
      if (this.queue) {
        var userDefinedPath = $('input[name="url"]').val();
        this.view.upload(this.queue.e, this.queue.file, this.queue.content, userDefinedPath);

        // Finally, clear the queue object
        this.queue = undefined;
      } else {
        var src = $('input[name="url"]').val();
        var alt = $('input[name="alt"]').val();
        this.view.editor.replaceSelection('![' + alt + '](/' + src + ')');
        this.view.editor.focus();
      }
    }

    return false;
  },

  heading: function(s) {
    if (s.charAt(0) === '#' && s.charAt(2) !== '#') {
      this.view.editor.replaceSelection(_.lTrim(s.replace(/#/g, '')));
    } else {
      this.view.editor.replaceSelection('## ' + s.replace(/#/g, ''));
    }
  },

  subHeading: function(s) {
    if (s.charAt(0) === '#' && s.charAt(3) !== '#') {
      this.view.editor.replaceSelection(_.lTrim(s.replace(/#/g, '')));
    } else {
      this.view.editor.replaceSelection('### ' + s.replace(/#/g, ''));
    }
  },

  italic: function(s) {
    if (s.charAt(0) === '_' && s.charAt(s.length - 1 === '_')) {
      this.view.editor.replaceSelection(s.replace(/_/g, ''));
    } else {
      this.view.editor.replaceSelection('_' + s.replace(/_/g, '') + '_');
    }
  },

  bold: function(s) {
    if (s.charAt(0) === '*' && s.charAt(s.length - 1 === '*')) {
      this.view.editor.replaceSelection(s.replace(/\*/g, ''));
    } else {
      this.view.editor.replaceSelection('**' + s.replace(/\*/g, '') + '**');
    }
  },

  quote: function(s) {
    if (s.charAt(0) === '>') {
      this.view.editor.replaceSelection(util.lTrim(s.replace(/\>/g, '')));
    } else {
      this.view.editor.replaceSelection('> ' + s.replace(/\>/g, ''));
    }
  },

  renderMedia: function(data, back) {
    var self = this;
    var $media = this.$el.find('#media');
    var tmpl = _(templates.dialogs.mediadirectory).template();

    // Reset some stuff
    $media.empty();

    if (back && (back.join() !== this.assetsDirectory)) {
      var link = back.slice(0, back.length - 1).join('/');
      $media.append('
Back
');
    }

    data.each(function(d) {
      var parts = d.get('path').split('/');
      var path = parts.slice(0, parts.length - 1).join('/');

      $media.append(tmpl({
        name: d.get('name'),
        type: d.get('type'),
        path: path + '/' + encodeURIComponent(d.get('name')),
        isMedia: util.isMedia(d.get('name').split('.').pop())
      }));
    });

    $('.asset a', $media).on('click', function(e) {
      var href = $(this).attr('href');
      var alt = util.trim($(this).text());

      if (util.isImage(href.split('.').pop())) {
        self.$el.find('input[name="url"]').val(href);
        self.$el.find('input[name="alt"]').val(alt);
      } else {
        self.view.editor.replaceSelection(href);
        self.view.editor.focus();
      }
      return false;
    });
  }
});
<commit_msg>Fix reference to config. Closes #526<commit_after>var $ = require('jquery-browserify');
var chosen = require('chosen-jquery-browserify');
var _ = require('underscore');
var util = require('../util');
var Backbone = require('backbone');
var toolbar = require('../toolbar/markdown.js');
var upload = require('../upload');
var templates = require('../../dist/templates');

module.exports = Backbone.View.extend({
  template: templates.toolbar,

  events: {
    'click .group a': 'markdownSnippet',
    'click .publish-flag': 'togglePublishing',
    'change #upload': 'fileInput',
    'click .dialog .insert': 'dialogInsert',
    'click .draft-to-post': 'draft'
  },

  initialize: function(options) {
    var self = this;
    this.file = options.file;
    this.view = options.view;
    this.collection = options.collection;
    var config = options.config;

    if (config) {
      this.hasMedia = (config.media) ? true : false;
      this.siteUrl = (config.siteUrl) ? true : false;

      if (config.media) {
        // Fetch the media directory to display its contents
        this.mediaDirectoryPath = config.media;
        var match = new RegExp(this.mediaDirectoryPath);

        this.media = this.collection.filter(function(m) {
          if (m.attributes.type === 'blob') {
            return match.test(m.attributes.path);
          }
        });
      }

      if (config.relativeLinks) {
        $.ajax({
          cache: true,
          dataType: 'jsonp',
          jsonp: false,
          jsonpCallback: config.relativeLinks.split('?callback=')[1] || 'callback',
          url: config.relativeLinks,
          success: function(links) {
            self.relativeLinks = links;
          }
        });
      }
    }
  },

  render: function() {

    var toolbar = {
      markdown: this.file.get('markdown'),
      writable: this.file.get('writable'),
      lang: this.file.get('lang'),
      draft: this.file.get('draft'),
      metadata: this.file.get('metadata')
    };

    this.$el.html(_.template(this.template, toolbar, { variable: 'toolbar' }));
    return this;
  },

  fileInput: function(e) {
    var view = this;
    upload.fileSelect(e, function(e, file, content) {
      var path = (view.mediaDirectoryPath) ? view.mediaDirectoryPath : util.extractFilename(view.file.attributes.path)[0];
      var src = path + '/' + encodeURIComponent(file.name);

      view.$el.find('input[name="url"]').val(src);
      view.$el.find('input[name="alt"]').val('');
      view.trigger('updateImageInsert', e);
    });

    return false;
  },

  highlight: function(type) {
    this.$el.find('.group a').removeClass('active');
    if (arguments) this.$el.find('[data-key="' + type + '"]').addClass('active');
  },

  draft: function(e) {
    view.trigger('draft', e);
    return false;
  },

  markdownSnippet: function(e) {
    var self = this;
    var $target = $(e.target).closest('a');
    var $dialog = this.$el.find('#dialog');
    var $snippets = this.$el.find('.group a');
    var key = $target.data('key');
    var snippet = $target.data('snippet');
    var selection = util.trim(this.view.editor.getSelection());

    $dialog.removeClass().empty();

    if (snippet) {
      $snippets.removeClass('on');

      if (selection) {
        switch (key) {
        case 'bold':
          this.bold(selection);
          break;
        case 'italic':
          this.italic(selection);
          break;
        case 'heading':
          this.heading(selection);
          break;
        case 'sub-heading':
          this.subHeading(selection);
          break;
        case 'quote':
          this.quote(selection);
          break;
        default:
          this.view.editor.replaceSelection(snippet);
          break;
        }
        this.view.editor.focus();
      } else {
        this.view.editor.replaceSelection(snippet);
        this.view.editor.focus();
      }
    } else if ($target.data('dialog')) {

      var tmpl, className;
      if (key === 'media' && !this.mediaDirectoryPath ||
          key === 'media' && !this.media.length) {
          className = key + ' no-directory';
      } else {
          className = key;
      }

      // This condition handles the link and media link in the toolbar.
      if ($target.hasClass('on')) {
        $target.removeClass('on');
        $dialog.removeClass().empty();
      } else {
        $snippets.removeClass('on');
        $target.addClass('on');
        $dialog
          .removeClass()
          .addClass('dialog ' + className)
          .empty();

        switch(key) {
          case 'link':
            tmpl = _(templates.dialogs.link).template();

            $dialog.append(tmpl({
              relativeLinks: self.relativeLinks
            }));

            if (self.relativeLinks) {
              $('.chzn-select', $dialog).chosen().change(function() {
                $('.chzn-single span').text('Insert a local link.');

                var parts = $(this).val().split(',');
                $('input[name=href]', $dialog).val(parts[0]);
                $('input[name=text]', $dialog).val(parts[1]);
              });
            }

            if (selection) {
              // test if this is a markdown link: [text](link)
              var link = /\[([^\]]+)\]\(([^)]+)\)/;
              var quoted = /".*?"/;

              var text = selection;
              var href;
              var title;

              if (link.test(selection)) {
                var parts = link.exec(selection);
                text = parts[1];
                href = parts[2];

                // Search for a title attrbute within the url string
                if (quoted.test(parts[2])) {
                  href = parts[2].split(quoted)[0];

                  // TODO: could be improved
                  title = parts[2].match(quoted)[0].replace(/"/g, '');
                }
              }

              $('input[name=text]', $dialog).val(text);
              if (href) $('input[name=href]', $dialog).val(href);
              if (title) $('input[name=title]', $dialog).val(title);
            }
          break;
          case 'media':
            tmpl = _(templates.dialogs.media).template();
            $dialog.append(tmpl({
              description: t('dialogs.media.description', {
                input: '<input id="upload" class="upload" type="file" />'
              }),
              assetsDirectory: (self.media && self.media.length) ? true : false,
              writable: self.file.get('writable')
            }));

            if (self.media && self.media.length) self.renderMedia(self.media);

            if (selection) {
              var image = /\!\[([^\[]*)\]\(([^\)]+)\)/;
              var src;
              var alt;

              if (image.test(selection)) {
                var imageParts = image.exec(selection);
                alt = imageParts[1];
                src = imageParts[2];

                $('input[name=url]', $dialog).val(src);
                if (alt) $('input[name=alt]', $dialog).val(alt);
              }
            }
          break;
          case 'help':
            tmpl = _(templates.dialogs.help).template();
            $dialog.append(tmpl({
              help: toolbar.help
            }));

            // Page through different help sections
            var $mainMenu = this.$el.find('.main-menu a');
            var $subMenu = this.$el.find('.sub-menu');
            var $content = this.$el.find('.help-content');

            $mainMenu.on('click', function() {
              if (!$(this).hasClass('active')) {

                $mainMenu.removeClass('active');
                $content.removeClass('active');
                $subMenu
                    .removeClass('active')
                    .find('a')
                    .removeClass('active');

                $(this).addClass('active');

                // Add the relavent sub menu
                var parent = $(this).data('id');
                $('.' + parent).addClass('active');

                // Add an active class and populate the
                // content of the first list item.
                var $firstSubElement = $('.' + parent + ' a:first', this.el);
                $firstSubElement.addClass('active');

                var subParent = $firstSubElement.data('id');
                $('.help-' + subParent).addClass('active');
              }
              return false;
            });

            $subMenu.find('a').on('click', function() {
              if (!$(this).hasClass('active')) {

                $subMenu.find('a').removeClass('active');
                $content.removeClass('active');
                $(this).addClass('active');

                // Add the relavent content section
                var parent = $(this).data('id');
                $('.help-' + parent).addClass('active');
              }

              return false;
            });

          break;
        }
      }
    }

    return false;
  },

  publishState: function() {
    if (this.$el.find('publish-state') === 'true') {
      return true;
    } else {
      return false;
    }
  },

  updatePublishState: function() {
    // Update the publish key wording depening on what was saved
    var $publishkey = this.$el.find('.publish-flag');
    var key = $publishKey.attr('data-state');

    if (key === 'true') {
      $publishKey.html(t('actions.publishing.published') +
                      '');
    } else {
      $publishKey.html(t('actions.publishing.unpublished') +
                      '');
    }
  },

  togglePublishing: function(e) {
    var $target = $(e.target).hasClass('checkmark') ? $(e.target).parent() : $(e.target);

    // TODO: remove HTML from view
    // Toggling publish state when the current file is published live
    if (this.file.get('metadata').published) {
      if ($target.hasClass('published')) {
        $target
          .empty()
          .append(t('actions.publishing.unpublish') +
                '' +
                '' +
                t('actions.publishing.unpublishInfo') +
                '')
          .removeClass('published')
          .attr('data-state', false);
      } else {
        $target
          .empty()
          .append(t('actions.publishing.published') +
                '')
          .addClass('published')
          .attr('data-state', true);
      }
    } else {
      if ($target.hasClass('published')) {
        $target
          .empty()
          .append(t('actions.publishing.unpublished') +
                '')
          .removeClass('published')
          .attr('data-state', false);
      } else {
        $target
          .empty()
          .append(t('actions.publishing.publish') +
                '' +
                '' +
                t('actions.publishing.publishInfo') +
                '')
          .addClass('published')
          .attr('data-state', true);
      }
    }

    this.view.makeDirty();
    return false;
  },

  dialogInsert: function(e) {
    var $dialog = $('#dialog', this.el);
    var $target = $(e.target, this.el);
    var type = $target.data('type');

    if (type === 'link') {
      var href = $('input[name="href"]').val();
      var text = $('input[name="text"]').val();
      var title = $('input[name="title"]').val();

      if (!text) text = href;

      if (title) {
        this.view.editor.replaceSelection('[' + text + '](' + href + ' "' + title + '")');
      } else {
        this.view.editor.replaceSelection('[' + text + '](' + href + ')');
      }

      this.view.editor.focus();
    }

    if (type === 'media') {
      if (this.queue) {
        var userDefinedPath = $('input[name="url"]').val();
        this.view.upload(this.queue.e, this.queue.file, this.queue.content, userDefinedPath);

        // Finally, clear the queue object
        this.queue = undefined;
      } else {
        var src = $('input[name="url"]').val();
        var alt = $('input[name="alt"]').val();
        this.view.editor.replaceSelection('![' + alt + '](/' + src + ')');
        this.view.editor.focus();
      }
    }

    return false;
  },

  heading: function(s) {
    if (s.charAt(0) === '#' && s.charAt(2) !== '#') {
      this.view.editor.replaceSelection(_.lTrim(s.replace(/#/g, '')));
    } else {
      this.view.editor.replaceSelection('## ' + s.replace(/#/g, ''));
    }
  },

  subHeading: function(s) {
    if (s.charAt(0) === '#' && s.charAt(3) !== '#') {
      this.view.editor.replaceSelection(_.lTrim(s.replace(/#/g, '')));
    } else {
      this.view.editor.replaceSelection('### ' + s.replace(/#/g, ''));
    }
  },

  italic: function(s) {
    if (s.charAt(0) === '_' && s.charAt(s.length - 1 === '_')) {
      this.view.editor.replaceSelection(s.replace(/_/g, ''));
    } else {
      this.view.editor.replaceSelection('_' + s.replace(/_/g, '') + '_');
    }
  },

  bold: function(s) {
    if (s.charAt(0) === '*' && s.charAt(s.length - 1 === '*')) {
      this.view.editor.replaceSelection(s.replace(/\*/g, ''));
    } else {
      this.view.editor.replaceSelection('**' + s.replace(/\*/g, '') + '**');
    }
  },

  quote: function(s) {
    if (s.charAt(0) === '>') {
      this.view.editor.replaceSelection(util.lTrim(s.replace(/\>/g, '')));
    } else {
      this.view.editor.replaceSelection('> ' + s.replace(/\>/g, ''));
    }
  },

  renderMedia: function(data, back) {
    var self = this;
    var $media = this.$el.find('#media');
    var tmpl = _(templates.dialogs.mediadirectory).template();

    // Reset some stuff
    $media.empty();

    if (back && (back.join() !== this.assetsDirectory)) {
      var link = back.slice(0, back.length - 1).join('/');
      $media.append('
Back
');
    }

    data.each(function(d) {
      var parts = d.get('path').split('/');
      var path = parts.slice(0, parts.length - 1).join('/');

      $media.append(tmpl({
        name: d.get('name'),
        type: d.get('type'),
        path: path + '/' + encodeURIComponent(d.get('name')),
        isMedia: util.isMedia(d.get('name').split('.').pop())
      }));
    });

    $('.asset a', $media).on('click', function(e) {
      var href = $(this).attr('href');
      var alt = util.trim($(this).text());

      if (util.isImage(href.split('.').pop())) {
        self.$el.find('input[name="url"]').val(href);
        self.$el.find('input[name="alt"]').val(alt);
      } else {
        self.view.editor.replaceSelection(href);
        self.view.editor.focus();
      }
      return false;
    });
  }
});
<|endoftext|>


<commit_before>var gulp = require('gulp');
var path = require('path');
var brunch = require('brunch');
var del = require('del');

gulp.task("clean", function() {
  return del([
    path.resolve(__dirname, '../SingularityService/target/generated-resources/assets/static/**'),
    path.resolve(__dirname, '../SingularityService/target/generated-resources/assets/index.html')], {force: true});
});

gulp.task("build", function(cb) {
  brunch.build({}, function () {
    cb();
  });
});

gulp.task("default", ["clean", "build"])<commit_msg>better way to brunch<commit_after>var gulp = require('gulp');
var path = require('path');
var del = require('del');
var child_process = require('child_process');

var dest = path.resolve(__dirname, '../SingularityService/target/generated-resources/assets');

gulp.task("clean", function() {
  return del([
    path.resolve(dest, 'static/**'),
    path.resolve(dest, 'index.html')], {force: true});
});

gulp.task("build", function(cb) {
  var brunch = child_process.execFile('node_modules/brunch/bin/brunch', ['build', '--production']);

  var hasStderrOutput = false;

  brunch.stdout.pipe(process.stdout);
  brunch.stderr.pipe(process.stderr);

  brunch.stderr.on('data', function () {
    hasStderrOutput = true;
  });

  brunch.on('error', cb);

  brunch.on('exit', function (code) {
    if (hasStderrOutput) {
      cb(new Error("Brunch build failed"));
    } else if (code != 0) {
      cb(new Error("Brunch exited with code " + code));
    } else {
      cb();
    }
  });
});

gulp.task("default", ["clean", "build"]);
<|endoftext|>


<commit_before>// Neuroscape_Diagnostic.js
//
// Created by Milad Nazeri and Liv Erikson on 2018-07-16
//
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html

"use strict";
/* eslint-disable indent */
//
//  Dance-App
//
//  Created by Milad Nazeri on 2018-10-11
//  with Mmdified Code from Howard Stearns
//  Copyright 2016 High Fidelity, Inc.
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* globals Tablet, Script, HMD, Controller, Menu */

(function () { // BEGIN LOCAL_SCOPE
    // Dependencies
    // /////////////////////////////////////////////////////////////////////////
        var
            AppUi = Script.require('./AppUi.js?' + Date.now()),
            Helper = Script.require("../../Helper.js")
        ;

    // Consts
    // /////////////////////////////////////////////////////////////////////////
        var
            URL = Script.resolvePath("./Tablet/Dance-App_Tablet.html"),
            BUTTON_NAME = "BUTTON_NAME",

            PREVIEW_DANCE = "preview_dance",
            PREVIEW_DANCE_STOP = "preview_dance_stop",
            STOP_DANCE = "stop_dance",
            START_DANCING = "start_dancing",
            TRY_DANCE = "try_dance",
            ADD_DANCE = "add_dance",
            REMOVE_DANCE = "remove_dance",
            UPDATE_DANCE_ARRAY = "update_dance_array",
            CURRENT_DANCE = "current_dance",
            DEFAULT_DURATION = "1500",
            DEFAULT_START_FRAME = 0,
            EVENT_BRIDGE_OPEN_MESSAGE = "eventBridgeOpen"
        ;

    // Init
    // /////////////////////////////////////////////////////////////////////////
        var
            rustDancing = false,
            overlay = null,
            ui
        ;

    // Constructor
    // /////////////////////////////////////////////////////////////////////////
        function DanceAnimation(name, url, frames, fps) {
            this.name = name;
            this.url = url;
            this.startFrame = DEFAULT_START_FRAME;
            this.endFrame = frames;
            this.fps = fps;
        }

        function DanceListEntry(name, url, startFrame, endFrame, duration, fps) {
            this.name = name;
            this.url = url;
            this.startFrame = startFrame;
            this.endFrame = endFrame;
            this.duration = duration;
            this.fps = fps;
        }

    // Collections
    // /////////////////////////////////////////////////////////////////////////
        var
            danceUrls = Script.require("./Dance-URLS.js?"+ Date.now()),
            dataStore = {
                shouldBeRunning: true,
                danceArray: [],
                currentIndex: 0,
                ui: {
                    currentDance: false,
                    danceArray: false
                }
            },
            danceObjects = []
        ;

    // Helper Functions
    // /////////////////////////////////////////////////////////////////////////
        function splitDanceUrls() {
            var regex = /(https:\/\/.*\/)([a-zA-Z0-9 ]+) (\d+)(.fbx)/;
            danceUrls.sort(function(a,b) {
                if (a < b) return -1;
                else if (a > b) return 1;
                return 0;
            }).forEach(function(dance) {
                var regMatch = regex.exec(dance);
                danceObjects.push(
                    new DanceAnimation(
                        regMatch[2],
                        dance,
                        regMatch[3],
                        30
                    )
                );
            });
        }

        function vec(x, y, z) {
            var obj = {};
            obj.x = x;
            obj.y = y;
            obj.z = z;
            return obj;
        }

    // Procedural Functions
    // /////////////////////////////////////////////////////////////////////////
        function previewDanceAnimation(danceObj) {
            var localOffset = vec(0,0,-2),
                worldOffset = VEC3.multiplyQbyV(MyAvatar.orientation, localOffset),
                modelPosition = VEC3.sum(MyAvatar.position, worldOffset);

            overlay = Overlays.addOverlay("model", {
                url: MyAvatar.skeletonModelURL,
                position: modelPosition,
                animationSettings: {
                    url: danceObj.url,
                    fps: danceObj.fps,
                    loop: true,
                    running: true,
                    lastFrame: danceObj.frames
                }
            });
        }

        function stopPreviewDanceAnimation() {
            Overlays.deleteOverlay(overlay);
        }

        function addDanceAnimation(danceObj) {
            dataStore.danceArray.push(
                new DanceListEntry(
                    danceObj.name,
                    danceObj.url,
                    danceObj.startFrame,
                    danceObj.endFrame,
                    DEFAULT_DURATION,
                    danceObj.fps
                )
            );
            dataStore.ui.danceArray = true;
            ui.updateUI(dataStore);
        }

        function removeDanceAnimations(danceObj) {
            dataStore.danceArray = [];
            dataStore.ui.danceArray = false;
            ui.updateUI(dataStore);
        }

        function removeDanceAnimation(index) {
            dataStore.danceArray.splice(index,1);
            if (dataStore.danceArray.length === 0) {
                stopDanceAnimation();
                dataStore.ui.danceArray = false;
            }
            ui.updateUI(dataStore);
        }

        function playDanceArray(){
            dataStore.shouldBeRunning = true;
            dataStore.currentIndex = 0;
            playNextDance(dataStore.currentIndex);
            ui.updateUI(dataStore);
        }

        function playNextDance(index) {
            if ( index >= dataStore.danceArray.length) {
                index = 0;
            }
            var danceArrayObject = dataStore.danceArray[index];
            dataStore.currentIndex++;
            dataStore.currentIndex =
                dataStore.currentIndex >= dataStore.danceArray.length
                    ? 0
                    : dataStore.currentIndex;

            tryDanceAnimation(danceArrayObject);
            Script.setTimeout(function(){
                if (dataStore.shouldBeRunning) {
                    playNextDance(dataStore.currentIndex);
                }
            }, danceArrayObject.duration);

            ui.updateUI(dataStore);
        }

        function tryDanceAnimation(danceObj) {
            rustDancing = Settings.getValue("isDancing", false);
            MyAvatar.overrideAnimation(danceObj.url, danceObj.fps, true, danceObj.startFrame, danceObj.endFrame);
            Settings.setValue("isDancing", true);
            dataStore.ui.currentDance = true;
            dataStore.currentDance = danceObj;
            ui.updateUI(dataStore, {slice: CURRENT_DANCE});
        }

        function stopDanceAnimation() {
            MyAvatar.restoreAnimation();
            Settings.setValue("isDancing", false);
            dataStore.ui.currentDance = false;
            dataStore.currentDance = null;
            dataStore.shouldBeRunning = false;
            ui.updateUI(dataStore);
        }

        function updateDanceArray(danceArray) {
            dataStore.danceArray = danceArray;
            ui.updateUI(dataStore);
        }

    // Tablet
    // /////////////////////////////////////////////////////////////////////////
        function startup() {
            ui = new AppUi({
                buttonName: BUTTON_NAME,
                sortOrder: 6,
                home: URL,
                onMessage: onMessage
            });
        }

        function onMessage(data) {
            // EventBridge message from HTML script.
            switch (data.type) {
                case EVENT_BRIDGE_OPEN_MESSAGE:
                    ui.updateUI(dataStore);
                    break;
                case ADD_DANCE:
                    addDanceAnimation(data.value);
                    break;
                case REMOVE_DANCE:
                    removeDanceAnimation(data.value);
                    break;
                case START_DANCING:
                    playDanceArray();
                    break;
                case TRY_DANCE:
                    tryDanceAnimation(data.value);
                    break;
                case UPDATE_DANCE_ARRAY:
                    updateDanceArray(data.value);
                    break;
                case STOP_DANCE:
                    stopDanceAnimation(data.value);
                    break;
                case PREVIEW_DANCE:
                    previewDanceAnimation(data.value);
                    break;
                case PREVIEW_DANCE_STOP:
                    stopPreviewDanceAnimation();
                    break;
            }
        }

    // Main
    // /////////////////////////////////////////////////////////////////////////
        dataStore.danceObjects = danceObjects;
        splitDanceUrls();
        startup();
        for (var key in ui) {
            print ("ui key: " + key);
        }

}()); // END LOCAL_SCOPE
<commit_msg>in the process of converting dance app to new ui format<commit_after>// Neuroscape_Diagnostic.js
//
// Created by Milad Nazeri and Liv Erikson on 2018-07-16
//
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html

"use strict";
/* eslint-disable indent */
//
//  Dance-App
//
//  Created by Milad Nazeri on 2018-10-11
//  with Mmdified Code from Howard Stearns
//  Copyright 2016 High Fidelity, Inc.
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* globals Tablet, Script, HMD, Controller, Menu */

(function () { // BEGIN LOCAL_SCOPE
    // Dependencies
    // /////////////////////////////////////////////////////////////////////////
        var
            AppUi = Script.require('./AppUi.js?' + Date.now()),
        ;

    // Consts
    // /////////////////////////////////////////////////////////////////////////
        var
            URL = Script.resolvePath("./Tablet/Dance-App_Tablet.html"),
            BUTTON_NAME = "BUTTON_NAME",

            PREVIEW_DANCE = "preview_dance",
            PREVIEW_DANCE_STOP = "preview_dance_stop",
            STOP_DANCE = "stop_dance",
            START_DANCING = "start_dancing",
            TRY_DANCE = "try_dance",
            ADD_DANCE = "add_dance",
            REMOVE_DANCE = "remove_dance",
            UPDATE_DANCE_ARRAY = "update_dance_array",
            CURRENT_DANCE = "current_dance",
            DEFAULT_DURATION = "1500",
            DEFAULT_START_FRAME = 0,
            EVENT_BRIDGE_OPEN_MESSAGE = "eventBridgeOpen"
        ;

    // Init
    // /////////////////////////////////////////////////////////////////////////
        var
            rustDancing = false,
            overlay = null,
            ui
        ;

    // Constructor
    // /////////////////////////////////////////////////////////////////////////
        function DanceAnimation(name, url, frames, fps) {
            this.name = name;
            this.url = url;
            this.startFrame = DEFAULT_START_FRAME;
            this.endFrame = frames;
            this.fps = fps;
        }

        function DanceListEntry(name, url, startFrame, endFrame, duration, fps) {
            this.name = name;
            this.url = url;
            this.startFrame = startFrame;
            this.endFrame = endFrame;
            this.duration = duration;
            this.fps = fps;
        }

    // Collections
    // /////////////////////////////////////////////////////////////////////////
        var
            danceUrls = Script.require("./Dance-URLS.js?"+ Date.now()),
            dataStore = {
                shouldBeRunning: true,
                danceArray: [],
                currentIndex: 0,
                ui: {
                    currentDance: false,
                    danceArray: false
                }
            },
            danceObjects = []
        ;

    // Helper Functions
    // /////////////////////////////////////////////////////////////////////////
        function splitDanceUrls() {
            var regex = /(https:\/\/.*\/)([a-zA-Z0-9 ]+) (\d+)(.fbx)/;
            danceUrls.sort(function(a,b) {
                if (a < b) return -1;
                else if (a > b) return 1;
                return 0;
            }).forEach(function(dance) {
                var regMatch = regex.exec(dance);
                danceObjects.push(
                    new DanceAnimation(
                        regMatch[2],
                        dance,
                        regMatch[3],
                        30
                    )
                );
            });
        }

        function vec(x, y, z) {
            var obj = {};
            obj.x = x;
            obj.y = y;
            obj.z = z;
            return obj;
        }

    // Procedural Functions
    // /////////////////////////////////////////////////////////////////////////
        function previewDanceAnimation(danceObj) {
            var localOffset = vec(0,0,-2),
                worldOffset = VEC3.multiplyQbyV(MyAvatar.orientation, localOffset),
                modelPosition = VEC3.sum(MyAvatar.position, worldOffset);

            overlay = Overlays.addOverlay("model", {
                url: MyAvatar.skeletonModelURL,
                position: modelPosition,
                animationSettings: {
                    url: danceObj.url,
                    fps: danceObj.fps,
                    loop: true,
                    running: true,
                    lastFrame: danceObj.frames
                }
            });
        }

        function stopPreviewDanceAnimation() {
            Overlays.deleteOverlay(overlay);
        }

        function addDanceAnimation(danceObj) {
            dataStore.danceArray.push(
                new DanceListEntry(
                    danceObj.name,
                    danceObj.url,
                    danceObj.startFrame,
                    danceObj.endFrame,
                    DEFAULT_DURATION,
                    danceObj.fps
                )
            );
            dataStore.ui.danceArray = true;
            ui.updateUI(dataStore);
        }

        function removeDanceAnimations(danceObj) {
            dataStore.danceArray = [];
            dataStore.ui.danceArray = false;
            ui.updateUI(dataStore);
        }

        function removeDanceAnimation(index) {
            dataStore.danceArray.splice(index,1);
            if (dataStore.danceArray.length === 0) {
                stopDanceAnimation();
                dataStore.ui.danceArray = false;
            }
            ui.updateUI(dataStore);
        }

        function playDanceArray(){
            dataStore.shouldBeRunning = true;
            dataStore.currentIndex = 0;
            playNextDance(dataStore.currentIndex);
            ui.updateUI(dataStore);
        }

        function playNextDance(index) {
            if ( index >= dataStore.danceArray.length) {
                index = 0;
            }
            var danceArrayObject = dataStore.danceArray[index];
            dataStore.currentIndex++;
            dataStore.currentIndex =
                dataStore.currentIndex >= dataStore.danceArray.length
                    ? 0
                    : dataStore.currentIndex;

            tryDanceAnimation(danceArrayObject);
            Script.setTimeout(function(){
                if (dataStore.shouldBeRunning) {
                    playNextDance(dataStore.currentIndex);
                }
            }, danceArrayObject.duration);

            ui.updateUI(dataStore);
        }

        function tryDanceAnimation(danceObj) {
            rustDancing = Settings.getValue("isDancing", false);
            MyAvatar.overrideAnimation(danceObj.url, danceObj.fps, true, danceObj.startFrame, danceObj.endFrame);
            Settings.setValue("isDancing", true);
            dataStore.ui.currentDance = true;
            dataStore.currentDance = danceObj;
            ui.updateUI(dataStore, {slice: CURRENT_DANCE});
        }

        function stopDanceAnimation() {
            MyAvatar.restoreAnimation();
            Settings.setValue("isDancing", false);
            dataStore.ui.currentDance = false;
            dataStore.currentDance = null;
            dataStore.shouldBeRunning = false;
            ui.updateUI(dataStore);
        }

        function updateDanceArray(danceArray) {
            dataStore.danceArray = danceArray;
            ui.updateUI(dataStore);
        }

    // Tablet
    // /////////////////////////////////////////////////////////////////////////
        function startup() {
            ui = new AppUi({
                buttonName: BUTTON_NAME,
                sortOrder: 6,
                home: URL,
                onMessage: onMessage
            });
        }

        function onMessage(data) {
            // EventBridge message from HTML script.
            switch (data.type) {
                case EVENT_BRIDGE_OPEN_MESSAGE:
                    ui.updateUI(dataStore);
                    break;
                case ADD_DANCE:
                    addDanceAnimation(data.value);
                    break;
                case REMOVE_DANCE:
                    removeDanceAnimation(data.value);
                    break;
                case START_DANCING:
                    playDanceArray();
                    break;
                case TRY_DANCE:
                    tryDanceAnimation(data.value);
                    break;
                case UPDATE_DANCE_ARRAY:
                    updateDanceArray(data.value);
                    break;
                case STOP_DANCE:
                    stopDanceAnimation(data.value);
                    break;
                case PREVIEW_DANCE:
                    previewDanceAnimation(data.value);
                    break;
                case PREVIEW_DANCE_STOP:
                    stopPreviewDanceAnimation();
                    break;
            }
        }

    // Main
    // /////////////////////////////////////////////////////////////////////////
        dataStore.danceObjects = danceObjects;
        splitDanceUrls();
        startup();

}()); // END LOCAL_SCOPE
<|endoftext|>


<commit_before>/*
---
name: ART.Widget
description: ART Widget Class
requires: [UI.Widget, Core/Class, Core/Element, Core/Element.Event, ART/ART.Base]
provides: ART.Widget
...
*/

(function(){

var Widget = ART.Widget = new Class({
	Extends: UI.Widget,
	options: {
		/*
			element: null,
		*/
		tabIndex: -1,
		onHide: function(){
			$(this).setStyle('display', 'none');
		},
		onShow: function(){
			$(this).setStyle('display', 'inline-block');
		}
	},

	initialize: function(options){
		this._createElement(options);
		this.canvas = new ART;
		$(this.canvas).setStyles({position: 'absolute', top: 0, left: 0}).inject(this.element);

		this.currentSheet = {};

		this.parent(options);

		this.setTabIndex(this.options.tabIndex);

		var self = this;

		this.element.addEvents({

			focus: function(){
				if (!self.getState('focus')) self.focus();
			},

			blur: function(){
				if (self.getState('focus')) self.blur();
			}

		});

		widgets.push(this);

	},

	_createElement: function(){
		return new Element('div').setStyles({display: 'inline-block', position: 'relative', outline: 'none'});
	},

	/* tab indices */

	setTabIndex: function(index){
		this.element.tabIndex = this.tabIndex = index;
	},

	getTabIndex: function(){
		return this.tabIndex;
	},

	/* ARTSY Stuff */

	resize: function(width, height){
		this.element.setStyles({width: width, height: height});
		this.canvas.resize(width, height);
		return this;
	},

	draw: function(newSheet){
		var sheet = $merge(this.diffSheet(), newSheet || {});
		for (var property in sheet) this.currentSheet[property] = sheet[property];
		return sheet;
	},

	deferDraw: function(){
		if (!this.element.parentNode || this.getState('hidden')) return;
		var self = this;
		clearTimeout(this.drawTimer);
		this.drawTimer = setTimeout(function(){
			self.draw();
		}, 1);
	},

	/* ID */

	setID: function(id){
		this.parent(id);
		this.element.set('id', id);
		this.deferDraw();
		return this;
	},

	/* classNames */

	addClass: function(className){
		this.parent(className);
		this.element.addClass(className);
		this.deferDraw();
		return this;
	},

	removeClass: function(className){
		this.parent(className);
		this.element.removeClass(className);
		this.deferDraw();
		return this;
	},

	/* states */

	_states: {
		hidden: false
	},

	enable: function(){
		if (!this.parent()) return false;
		this.setTabIndex(this.oldTabIndex);
		this.deferDraw();
		return true;
	},

	disable: function(){
		if (!this.parent()) return false;
		this.oldTabIndex = this.tabIndex;
		this.setTabIndex(-1);
		this.deferDraw();
		return true;
	},

	focus: function(){
		if (!this.parent()) return false;
		this.element.focus();
		this.deferDraw();
		return true;
	},

	blur: function(){
		if (!this.parent()) return false;
		this.element.blur();
		this.deferDraw();
		return true;
	},

	activate: function(){
		if (!this.parent()) return false;
		this.deferDraw();
		return true;
	},

	deactivate: function(){
		if (!this.parent()) return false;
		this.deferDraw();
		return true;
	},

	hide: function(){
		if (!this.getState('hidden')){
			this.setState('hidden', true);
			this.fireEvent('hide');
			this.deferDraw();
		}
		return this;
	},

	show: function(){
		if (this.getState('hidden')){
			this.setState('hidden', false);
			this.fireEvent('hide');
			this.deferDraw();
		}
		return this;
	},

	/* DOM + Registration */

	inject: function(widget, element){
		element = (element) ? $(element) : $(widget);

		if (element && this.element.parentNode !== element){
			this.register(widget);
			this.element.inject(element);
			this.deferDraw();
		}

		return this;
	},

	eject: function(){
		if (this.element.parentNode){ // continue only if the element is in the dom
			this.element.dispose();
			this.unregister();
			// even though deferDraw will not fire when the element is not in the dom, this will cancel any pre-existing draw request.
			clearTimeout(this.drawTimer);
		}
		return this;
	},

	/* $ */

	toElement: function(){
		return this.element;
	}

});

})();
<commit_msg>allow art.widgets to register themselves with another widget without injecting it<commit_after>/*
---
name: ART.Widget
description: ART Widget Class
requires: [UI.Widget, Core/Class, Core/Element, Core/Element.Event, ART/ART.Base]
provides: ART.Widget
...
*/

(function(){

var Widget = ART.Widget = new Class({
	Extends: UI.Widget,
	options: {
		/*
			element: null,
		*/
		tabIndex: -1,
		onHide: function(){
			$(this).setStyle('display', 'none');
		},
		onShow: function(){
			$(this).setStyle('display', 'inline-block');
		}
	},

	initialize: function(options){
		this._createElement(options);
		this.canvas = new ART;
		$(this.canvas).setStyles({position: 'absolute', top: 0, left: 0}).inject(this.element);

		this.currentSheet = {};

		this.parent(options);

		this.setTabIndex(this.options.tabIndex);

		var self = this;

		this.element.addEvents({

			focus: function(){
				if (!self.getState('focus')) self.focus();
			},

			blur: function(){
				if (self.getState('focus')) self.blur();
			}

		});

		widgets.push(this);

	},

	_createElement: function(){
		return new Element('div').setStyles({display: 'inline-block', position: 'relative', outline: 'none'});
	},

	/* tab indices */

	setTabIndex: function(index){
		this.element.tabIndex = this.tabIndex = index;
	},

	getTabIndex: function(){
		return this.tabIndex;
	},

	/* ARTSY Stuff */

	resize: function(width, height){
		this.element.setStyles({width: width, height: height});
		this.canvas.resize(width, height);
		return this;
	},

	draw: function(newSheet){
		var sheet = $merge(this.diffSheet(), newSheet || {});
		for (var property in sheet) this.currentSheet[property] = sheet[property];
		return sheet;
	},

	deferDraw: function(){
		if (!this.element.parentNode || this.getState('hidden')) return;
		var self = this;
		clearTimeout(this.drawTimer);
		this.drawTimer = setTimeout(function(){
			self.draw();
		}, 1);
	},

	/* ID */

	setID: function(id){
		this.parent(id);
		this.element.set('id', id);
		this.deferDraw();
		return this;
	},

	/* classNames */

	addClass: function(className){
		this.parent(className);
		this.element.addClass(className);
		this.deferDraw();
		return this;
	},

	removeClass: function(className){
		this.parent(className);
		this.element.removeClass(className);
		this.deferDraw();
		return this;
	},

	/* states */

	_states: {
		hidden: false
	},

	enable: function(){
		if (!this.parent()) return false;
		this.setTabIndex(this.oldTabIndex);
		this.deferDraw();
		return true;
	},

	disable: function(){
		if (!this.parent()) return false;
		this.oldTabIndex = this.tabIndex;
		this.setTabIndex(-1);
		this.deferDraw();
		return true;
	},

	focus: function(){
		if (!this.parent()) return false;
		this.element.focus();
		this.deferDraw();
		return true;
	},

	blur: function(){
		if (!this.parent()) return false;
		this.element.blur();
		this.deferDraw();
		return true;
	},

	activate: function(){
		if (!this.parent()) return false;
		this.deferDraw();
		return true;
	},

	deactivate: function(){
		if (!this.parent()) return false;
		this.deferDraw();
		return true;
	},

	hide: function(){
		if (!this.getState('hidden')){
			this.setState('hidden', true);
			this.fireEvent('hide');
			this.deferDraw();
		}
		return this;
	},

	show: function(){
		if (this.getState('hidden')){
			this.setState('hidden', false);
			this.fireEvent('hide');
			this.deferDraw();
		}
		return this;
	},

	/* DOM + Registration */

	inject: function(widget, element){
		element = (element) ? $(element) : $(widget);

		if (element && this.element.parentNode !== element){
			this.element.inject(element);
			this.register(widget);
		}

		return this;
	},

	register: function(widget) {
		this.parent(widget);
		this.deferDraw();
	},

	eject: function(){
		if (this.element.parentNode){ // continue only if the element is in the dom
			this.element.dispose();
			this.unregister();
			// even though deferDraw will not fire when the element is not in the dom, this will cancel any pre-existing draw request.
			clearTimeout(this.drawTimer);
		}
		return this;
	},

	/* $ */

	toElement: function(){
		return this.element;
	}

});

})();
<|endoftext|>


<commit_before>/*
Script: ART.Widget.js

License:
	MIT-style license.
*/

// Base widget class. Based on » http://gist.github.com/85837

ART.Widget = new Class({

	Implements: [Options, Events],

	ns: 'art',
	name: 'widget',

	options: {
		// onShow: $empty,
		// onHide: $empty,
		// onFocus: $empty,
		// onBlur: $empty,
		// onEnable: $empty,
		// onDisable: $empty,
		// onDestroy: $empty,
		// onAdoption: $empty(parentWidget),
		// onOrphan: $empty(previousParent),
		// id: null,
		// style: null,
		className: '',
		keyboardOptions: {
			active: true
		}
	},

	initialize: function(options){
		if (options) this.setOptions(options);
		this.prefix = this.ns + '-' + this.name;
		this.element = new Element('div', {
			id: this.options.id || this.prefix+new Date().getTime(),
			'class': this.options.className
		}).store(this.prefix, this);
		this.element.addClass(this.ns).addClass(this.prefix);
		this.classes = this.options.classes;
		this.classes = (this.options.className) ? this.options.className.split(' ') : [];
		this.pseudos = [];
		this.childWidgets = [];
		// initial render
		this.keyboard = new Keyboard(this.options.keyboardOptions);
		this.keyboard.widget = this;
		this.render();
	},

	getSelector: function(){
		var selector = (this.parentWidget) ? this.parentWidget.getSelector() + ' ' : '';
		selector += this.name;
		if (this.classes.length) selector += '.' + this.classes.join('.');
		if (this.pseudos.length) selector += ':' + this.pseudos.join(':');
		return selector;
	},

	addPseudo: function(pseudo){
		this.pseudos.include(pseudo);
	},

	removePseudo: function(pseudo){
		this.pseudos.erase(pseudo);
	},

	setParent: function(widget){
		this.removeParent();
		this.parentWidget = widget;
		widget.childWidgets.include(this);
		this.parentWidget.keyboard.manage(this.keyboard);
		this.render();
		this.fireEvent('adoption', widget);
		return this;
	},

	removeParent: function(){
		if (!this.parentWidget) return;
		var prevParent = this.parentWidget;
		this.parentWidget.childWidgets.erase(this);
		Keyboard.manager.manage(this.keyboard);
		this.parentWidget = null;
		this.fireEvent('orphan', prevParent);
	},

	// render

	render: function(){
		this.childWidgets.each(function(child){
			child.render();
		});
		return this;
	},

	// special states

	hide: function(){
		if (!this.hidden){
			this.hidden = true;
			this.fireEvent('hide');
			this.element.addClass(this.prefix + '-hidden');
			this.addPseudo('hidden');
			this.render();
		}
		return this;
	},

	activate: function(){
		if (!this.active){
			this.active = true;
			this.fireEvent('activate');
			this.element.addClass(this.prefix + '-active');
			this.addPseudo('active');
			this.keyboard.activate();
			this.render();
		}
		return this;
	},

	focus: function(){
		if (!this.focused){
			this.focused = true;
			this.fireEvent('focus');
			this.element.addClass(this.prefix + '-focused');
			this.addPseudo('focus');
			this.keyboard.activate();
			if (this.parentWidget) {
				this.parentWidget.childWidgets.each(function(child) {
					if (child != this) {
						child.blur();
					}
				}, this);
			}
			this.render();
		}
		return this;
	},

	disable: function(){
		if (!this.disabled){
			this.disabled = true;
			this.fireEvent('disable');
			this.childWidgets.each(function(child){
				child.disable();
			});
			this.element.addClass(this.prefix + '-disabled');
			this.addPseudo('disabled');
			this.render();
		}
		return this;
	},

	// normal states

	show: function(){
		if (this.hidden){
			this.hidden = false;
			this.fireEvent('show');
			this.element.removeClass(this.prefix + '-hidden');
			this.removePseudo('hidden');
			this.render();
		}
		return this;
	},

	deactivate: function(){
		if (this.active){
			this.active = false;
			this.fireEvent('deactivate');
			this.element.removeClass(this.prefix + '-active');
			this.removePseudo('active');
			this.render();
		}
		return this;
	},

	blur: function(){
		if (this.focused){
			this.focused = false;
			this.fireEvent('blur');
			this.element.removeClass(this.prefix + '-focused');
			this.removePseudo('focus');
			this.render();
		}
		return this;
	},

	enable: function(){
		if (this.disabled){
			this.disabled = false;
			this.childWidgets.each(function(child){
				child.enable();
			});
			this.fireEvent('enable');
			this.element.removeClass(this.prefix + '-disabled');
			this.removePseudo('disabled');
			this.render();
		}
		return this;
	},

	attachKeys: function(events){
		this.keyboard.addEvents(events);
	},

	detachKeys: function(events) {
		this.keyboard.removeEvents(events);
	},

	destroy: function(){
		this.removeParent();
		this.element.destroy();
		return this.fireEvent('destroy');
	},

	// toElement

	toElement: function(){
		return this.element;
	}

});
<commit_msg>adding a destroyed property to widget<commit_after>/*
Script: ART.Widget.js

License:
	MIT-style license.
*/

// Base widget class. Based on » http://gist.github.com/85837

ART.Widget = new Class({

	Implements: [Options, Events],

	ns: 'art',
	name: 'widget',

	options: {
		// onShow: $empty,
		// onHide: $empty,
		// onFocus: $empty,
		// onBlur: $empty,
		// onEnable: $empty,
		// onDisable: $empty,
		// onDestroy: $empty,
		// onAdoption: $empty(parentWidget),
		// onOrphan: $empty(previousParent),
		// id: null,
		// style: null,
		className: '',
		keyboardOptions: {
			active: true
		}
	},

	initialize: function(options){
		if (options) this.setOptions(options);
		this.prefix = this.ns + '-' + this.name;
		this.element = new Element('div', {
			id: this.options.id || this.prefix+new Date().getTime(),
			'class': this.options.className
		}).store(this.prefix, this);
		this.element.addClass(this.ns).addClass(this.prefix);
		this.classes = this.options.classes;
		this.classes = (this.options.className) ? this.options.className.split(' ') : [];
		this.pseudos = [];
		this.childWidgets = [];
		// initial render
		this.keyboard = new Keyboard(this.options.keyboardOptions);
		this.keyboard.widget = this;
		this.render();
	},

	getSelector: function(){
		var selector = (this.parentWidget) ? this.parentWidget.getSelector() + ' ' : '';
		selector += this.name;
		if (this.classes.length) selector += '.' + this.classes.join('.');
		if (this.pseudos.length) selector += ':' + this.pseudos.join(':');
		return selector;
	},

	addPseudo: function(pseudo){
		this.pseudos.include(pseudo);
	},

	removePseudo: function(pseudo){
		this.pseudos.erase(pseudo);
	},

	setParent: function(widget){
		this.removeParent();
		this.parentWidget = widget;
		widget.childWidgets.include(this);
		this.parentWidget.keyboard.manage(this.keyboard);
		this.render();
		this.fireEvent('adoption', widget);
		return this;
	},

	removeParent: function(){
		if (!this.parentWidget) return;
		var prevParent = this.parentWidget;
		this.parentWidget.childWidgets.erase(this);
		Keyboard.manager.manage(this.keyboard);
		this.parentWidget = null;
		this.fireEvent('orphan', prevParent);
	},

	// render

	render: function(){
		this.childWidgets.each(function(child){
			child.render();
		});
		return this;
	},

	// special states

	hide: function(){
		if (!this.hidden){
			this.hidden = true;
			this.fireEvent('hide');
			this.element.addClass(this.prefix + '-hidden');
			this.addPseudo('hidden');
			this.render();
		}
		return this;
	},

	activate: function(){
		if (!this.active){
			this.active = true;
			this.fireEvent('activate');
			this.element.addClass(this.prefix + '-active');
			this.addPseudo('active');
			this.keyboard.activate();
			this.render();
		}
		return this;
	},

	focus: function(){
		if (!this.focused){
			this.focused = true;
			this.fireEvent('focus');
			this.element.addClass(this.prefix + '-focused');
			this.addPseudo('focus');
			this.keyboard.activate();
			if (this.parentWidget) {
				this.parentWidget.childWidgets.each(function(child) {
					if (child != this) {
						child.blur();
					}
				}, this);
			}
			this.render();
		}
		return this;
	},

	disable: function(){
		if (!this.disabled){
			this.disabled = true;
			this.fireEvent('disable');
			this.childWidgets.each(function(child){
				child.disable();
			});
			this.element.addClass(this.prefix + '-disabled');
			this.addPseudo('disabled');
			this.render();
		}
		return this;
	},

	// normal states

	show: function(){
		if (this.hidden){
			this.hidden = false;
			this.fireEvent('show');
			this.element.removeClass(this.prefix + '-hidden');
			this.removePseudo('hidden');
			this.render();
		}
		return this;
	},

	deactivate: function(){
		if (this.active){
			this.active = false;
			this.fireEvent('deactivate');
			this.element.removeClass(this.prefix + '-active');
			this.removePseudo('active');
			this.render();
		}
		return this;
	},

	blur: function(){
		if (this.focused){
			this.focused = false;
			this.fireEvent('blur');
			this.element.removeClass(this.prefix + '-focused');
			this.removePseudo('focus');
			this.render();
		}
		return this;
	},

	enable: function(){
		if (this.disabled){
			this.disabled = false;
			this.childWidgets.each(function(child){
				child.enable();
			});
			this.fireEvent('enable');
			this.element.removeClass(this.prefix + '-disabled');
			this.removePseudo('disabled');
			this.render();
		}
		return this;
	},

	attachKeys: function(events){
		this.keyboard.addEvents(events);
	},

	detachKeys: function(events) {
		this.keyboard.removeEvents(events);
	},

	destroy: function(){
		this.removeParent();
		this.element.destroy();
		this.destroyed = true;
		return this.fireEvent('destroy');
	},

	// toElement

	toElement: function(){
		return this.element;
	}

});
<|endoftext|>


<commit_before>/*global define*/
define(['Core/DeveloperError'
       ],function(
         DeveloperError) {
    "use strict";
    var _prefix;
    var _supportsFullScreen;
    var _browserPrefixes = ['webkit', 'moz', 'o', 'ms', 'khtml'];

    /**
     * Encapsulates browser dependent methods for working with the
     * full screen standard.
     *
     * @exports FullScreen
     *
     * @see W3C Fullscreen Living Specification
     */
    var FullScreen = {
        /**
         * Detects whether the browser supports the full screen standard.
         *
         * @returns true if the supports the full screen standard, false if otherwise.
         */
        supportsFullScreen : function() {
            if (typeof _supportsFullScreen === 'undefined') {
                _supportsFullScreen = false;
                // check for native support
                if (typeof document.exitFullscreen !== 'undefined') {
                    _supportsFullScreen = true;
                    _prefix = '';
                } else {
                    // check for full screen support by vendor prefix
                    for ( var i = 0; i < _browserPrefixes.length; i++) {
                        _prefix = _browserPrefixes[i];

                        if (typeof document[_prefix + 'CancelFullScreen'] !== 'undefined') {
                            _supportsFullScreen = true;
                            break;
                        }
                    }
                }
            }
            return _supportsFullScreen;
        },

        /**
         * Gets the name of the event that is fired when full screen is entered or exited or undefined if full screen is not supported.
         *
         * @returns the name of the event that is fired when full screen is entered or exited or undefined if full screen is not supported.
         */
        getFullScreenChangeEventName : function() {
            return FullScreen.supportsFullScreen() ? 'on' + _prefix + 'fullscreenchange' : undefined;
        },

        /**
         * Gets the name of the event that is fired when a full screen error occurs or undefined if full screen is not supported.
         *
         * @returns the name of the event that is fired when a full screen error occurs or undefined if full screen is not supported.
         */
        getFullScreenErrorEventName : function() {
            return FullScreen.supportsFullScreen() ? 'on' + _prefix + 'fullscreenerror' : undefined;
        },

        /**
         * Detects whether the browser is currently in full screen mode.
         *
         * @returns true if the browser is in full screen mode, false if not, and undefined if the browser does not support full screen mode.
         */
        isFullscreenEnabled : function() {
            if (FullScreen.supportsFullScreen()) {
                switch (_prefix) {
                case '':
                    return document.fullscreenEnabled;
                case 'webkit':
                    return document.webkitIsFullScreen;
                default:
                    return document[_prefix + 'FullScreen'];
                }
            }
            return undefined;
        },

        /**
         * Queues a request for full screen mode if the browser is currently not in full screen, does nothing otherwise.
         */
        requestFullScreen : function(element) {
            if (FullScreen.supportsFullScreen()) {
                return (_prefix === '') ? element.requestFullScreen(element) : element[_prefix + 'RequestFullScreen'](element);
            }
        },

        /**
         * Exits full screen mode if the browser is currently in full screen, does nothing otherwise.
         */
        exitFullscreen : function() {
            if (FullScreen.supportsFullScreen()) {
                return typeof document.exitFullscreen !== 'undefined' ? document.exitFullscreen() : document[_prefix + 'CancelFullScreen']();
            }
        }
    };

    return FullScreen;
});<commit_msg>Add doc example and missing parameter, move browserPrefixes to only function it is used.<commit_after>/*global define*/
define(['Core/DeveloperError'
       ],function(
         DeveloperError) {
    "use strict";
    var _prefix, _supportsFullScreen;

    /**
     * Encapsulates browser dependent methods for working with the
     * full screen standard.
     *
     * @exports FullScreen
     *
     * @see W3C Fullscreen Living Specification
     */
    var FullScreen = {
        /**
         * Detects whether the browser supports the full screen standard.
         *
         * @returns true if the supports the full screen standard, false if otherwise.
         */
        supportsFullScreen : function() {
            if (typeof _supportsFullScreen === 'undefined') {
                _supportsFullScreen = false;
                // check for native support
                if (typeof document.exitFullscreen !== 'undefined') {
                    _supportsFullScreen = true;
                    _prefix = '';
                } else {
                    // check for full screen support by vendor prefix
                    var prefixes = ['webkit', 'moz', 'o', 'ms', 'khtml'];
                    for ( var i = 0; i < prefixes.length; i++) {
                        _prefix = prefixes[i];

                        if (typeof document[_prefix + 'CancelFullScreen'] !== 'undefined') {
                            _supportsFullScreen = true;
                            break;
                        }
                    }
                }
            }
            return _supportsFullScreen;
        },

        /**
         * Gets the name of the event that is fired when full screen is entered or exited or undefined if full screen is not supported.
         *
         * @returns the name of the event that is fired when full screen is entered or exited or undefined if full screen is not supported.
         */
        getFullScreenChangeEventName : function() {
            return FullScreen.supportsFullScreen() ? 'on' + _prefix + 'fullscreenchange' : undefined;
        },

        /**
         * Gets the name of the event that is fired when a full screen error occurs or undefined if full screen is not supported.
         *
         * @returns the name of the event that is fired when a full screen error occurs or undefined if full screen is not supported.
         */
        getFullScreenErrorEventName : function() {
            return FullScreen.supportsFullScreen() ? 'on' + _prefix + 'fullscreenerror' : undefined;
        },

        /**
         * Detects whether the browser is currently in full screen mode.
         *
         * @returns true if the browser is in full screen mode, false if not, and undefined if the browser does not support full screen mode.
         */
        isFullscreenEnabled : function() {
            if (FullScreen.supportsFullScreen()) {
                switch (_prefix) {
                case '':
                    return document.fullscreenEnabled;
                case 'webkit':
                    return document.webkitIsFullScreen;
                default:
                    return document[_prefix + 'FullScreen'];
                }
            }
            return undefined;
        },

        /**
         * Queues a request for full screen mode if the browser is currently not in full screen, does nothing otherwise.
         * @param {Object} element The HTML element which will be placed into full-screen.
         *
         * @example
         * // Put the entire page into full screen.
         * FullScreen.requestFullScreen(document.body)
         *
         * // Place only the Cesium canvas into full screen.
         * FullScreen.requestFullScreen(scene.getCanvas())
         */
        requestFullScreen : function(element) {
            if (FullScreen.supportsFullScreen()) {
                return (_prefix === '') ? element.requestFullScreen(element) : element[_prefix + 'RequestFullScreen'](element);
            }
        },

        /**
         * Exits full screen mode if the browser is currently in full screen, does nothing otherwise.
         */
        exitFullscreen : function() {
            if (FullScreen.supportsFullScreen()) {
                return typeof document.exitFullscreen !== 'undefined' ? document.exitFullscreen() : document[_prefix + 'CancelFullScreen']();
            }
        }
    };

    return FullScreen;
});<|endoftext|>


<commit_before>/*
---
name    : SheetParser.CSS

authors   : Thomas Aylott
copyright : © 2010 Thomas Aylott
license   : MIT

provides : SheetParser.CSS
requires : combineRegExp
...
*/
;(function(exports){

/*<depend>*/
var UNDEF = {undefined:1}
if (!exports.SheetParser) exports.SheetParser = {}

/*<CommonJS>*/
var combineRegExp = UNDEF[typeof require]
	?	exports.combineRegExp
	:	require('./sg-regex-tools').combineRegExp
var SheetParser = exports.SheetParser
/*</CommonJS>*/

/*<debug>*/;if (UNDEF[typeof combineRegExp]) throw new Error('Missing required function: "combineRegExp"');/*</debug>*/
/*</depend>*/

var CSS = SheetParser.CSS = {version: '1.0.2 dev'}

CSS.camelCase = function(string){
	return ('' + string).replace(camelCaseSearch, camelCaseReplace)
}
var camelCaseSearch = /-\D/g
function camelCaseReplace(match){
	return match.charAt(1).toUpperCase()
}

CSS.parse = function(cssText){
	var	found
	,	rule
	,	rules = {length:0}
	,	keyIndex = -1
	,	regex = this.parser
	,	names = CSS.parser.names
	,	i,r,l
	,	ruleCount

	rules.cssText = cssText = ('' + cssText)

	regex.lastIndex = 0
	while ((found = regex.exec(cssText))){
		// avoid an infinite loop on zero-length keys
		if (regex.lastIndex == found.index) ++ regex.lastIndex

		// key:value
		if (found[names._key]){
			rules[rules.length ++] = found[names._key]
			rules[found[names._key]] = found[names._value]
			rules[CSS.camelCase(found[names._key])] = found[names._value]
			continue
		}

		rules[rules.length++] = rule = {}
		for (i = -1, l = names.length; i < l; ++i){
			if (!found[i]) continue
			rule[names[i-1]] = found[i]
		}
	}

	for (i = -1, l = rules.length; i < l; ++i){
		if (!rules[i] || !rules[i].style_cssText) continue

		rules[i].style = CSS.parse(rules[i].style_cssText)

		for (ruleCount = -1, r = -1, rule; rule = rules[i].style[++r];){
			if (typeof rule == 'string') continue
			rules[i][r] = (rules[i].cssRules || (rules[i].cssRules = {}))[++ ruleCount]  = rule
			rules[i].cssRules.length = ruleCount + 1
			rules[i].rules = rules[i].cssRules
		}
	}

	return rules
}

var x = combineRegExp

;(CSS.at = x(/\s*(@[-a-zA-Z0-9]+)\s+([^;{]*)/))
.names=[         'kind',              'name']

CSS.atRule = x([CSS.at, ';'])

;(CSS.keyValue = x(/\s*([-a-zA-Z0-9]+):\s*(.*?)(?:;|(?=\})|$)/))
.names=[               '_key',               '_value']

;(CSS.comment = x(/\/\*\s*((?:[^*]|\*(?!\/))*)\s*\*\//))
.names=[                   'comment']

;(CSS.selector = x(/\s*((\d+%)|[^\{}]+?)\s*/))
.names=[               'selectorText','keyText']

;(CSS.block = x(/\{\s*((?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*\})*)\s*\}/))
.names=[               'style_cssText']

CSS.selectorBlock = x([CSS.selector, CSS.block])

CSS.atBlock = x([CSS.at, CSS.block])

var OR = '|'

CSS.parser = x
(
	[	x(CSS.comment)
	,	OR
	,	x(CSS.atBlock)
	,	OR
	,	x(CSS.atRule)
	,	OR
	,	x(CSS.selectorBlock)
	,	OR
	,	x(CSS.keyValue)
	]
,	'cssText'
)

})(typeof exports != 'undefined' ? exports : this);
<commit_msg>FIXED many comment parsing bugs<commit_after>/*
---
name    : SheetParser.CSS

authors   : Thomas Aylott
copyright : © 2010 Thomas Aylott
license   : MIT

provides : SheetParser.CSS
requires : combineRegExp
...
*/
;(function(exports){

/*<depend>*/
var UNDEF = {undefined:1}
if (!exports.SheetParser) exports.SheetParser = {}

/*<CommonJS>*/
var combineRegExp = UNDEF[typeof require]
	?	exports.combineRegExp
	:	require('./sg-regex-tools').combineRegExp
var SheetParser = exports.SheetParser
/*</CommonJS>*/

/*<debug>*/;if (UNDEF[typeof combineRegExp]) throw new Error('Missing required function: "combineRegExp"');/*</debug>*/
/*</depend>*/

var CSS = SheetParser.CSS = {version: '1.0.2 dev'}

CSS.camelCase = function(string){
	return ('' + string).replace(camelCaseSearch, camelCaseReplace)
}
var camelCaseSearch = /-\D/g
function camelCaseReplace(match){
	return match.charAt(1).toUpperCase()
}

CSS.parse = function(cssText){
	var	found
	,	rule
	,	rules = {length:0}
	,	keyIndex = -1
	,	regex = this.parser
	,	names = CSS.parser.names
	,	i,r,l
	,	ruleCount

	rules.cssText = cssText = ('' + cssText)

	// strip comments
	cssText = cssText.replace(CSS.comment, '');

	regex.lastIndex = 0
	while ((found = regex.exec(cssText))){
		// avoid an infinite loop on zero-length keys
		if (regex.lastIndex == found.index) ++ regex.lastIndex

		// key:value
		if (found[names._key]){
			rules[rules.length ++] = found[names._key]
			rules[found[names._key]] = found[names._value]
			rules[CSS.camelCase(found[names._key])] = found[names._value]
			continue
		}

		rules[rules.length++] = rule = {}
		for (i = -1, l = names.length; i < l; ++i){
			if (!found[i]) continue
			rule[names[i-1]] = found[i]
		}
	}

	for (i = -1, l = rules.length; i < l; ++i){
		if (!rules[i] || !rules[i].style_cssText) continue

		rules[i].style = CSS.parse(rules[i].style_cssText)

		for (ruleCount = -1, r = -1, rule; rule = rules[i].style[++r];){
			if (typeof rule == 'string') continue
			rules[i][r] = (rules[i].cssRules || (rules[i].cssRules = {}))[++ ruleCount]  = rule
			rules[i].cssRules.length = ruleCount + 1
			rules[i].rules = rules[i].cssRules
		}
	}

	return rules
}

var x = combineRegExp

;(CSS.at = x(/\s*(@[-a-zA-Z0-9]+)\s+([^;{]*)/))
.names=[         'kind',              'name']

CSS.atRule = x([CSS.at, ';'])

;(CSS.keyValue = x(/\s*([-a-zA-Z0-9]+):\s*(.*?)(?:;|(?=\})|$)/))
.names=[               '_key',               '_value']

;(CSS.comment = x(/\/\*\s*((?:[^*]|\*(?!\/))*)\s*\*\//))
.names=[                   'comment']

;(CSS.selector = x(/\s*((\d+%)|[^\{}]+?)\s*/))
.names=[               'selectorText','keyText']

;(CSS.block = x(/\{\s*((?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*\})*)\s*\}/))
.names=[               'style_cssText']

CSS.selectorBlock = x([CSS.selector, CSS.block])

CSS.atBlock = x([CSS.at, CSS.block])

var OR = '|'

CSS.parser = x
(
	[	x(CSS.comment)
	,	OR
	,	x(CSS.atBlock)
	,	OR
	,	x(CSS.atRule)
	,	OR
	,	x(CSS.selectorBlock)
	,	OR
	,	x(CSS.keyValue)
	]
,	'cssText'
)

})(typeof exports != 'undefined' ? exports : this);
<|endoftext|>


<commit_before>var mooFormElements = new Class({
  Implements: [ Options ],

  options: {
    checkbox: {
      height:   25
    },
    radio: {
      height:   25
    },
    select: {
      width:    190
    },
    with_class: 'styled'
  },

  initialize: function (options)
  {
    this.setOptions(options);

    this.hideElementsToStyle();

    // Sort out checkboxes and radio buttons
    $$('input[type=radio].styled, input[type=checkbox].styled').each(this.replaceButtonWidget.bind(this));
    // Sort out selects
    $$('select.styled:not([multiple])').each(this.replaceSelectWidget.bind(this));
  },

  /**
   * Hide the actual form elements with class 'styled'
   **/
  hideElementsToStyle: function ()
  {
    $$('input.'+this.options.with_class).setStyle('display','none');
    $$('select:not([multiple]).'+this.options.with_class).setStyles({
      'width':    this.options.select.width,
      'opacity':  0,
      'border': '1px solid transparent',
      'z-index': 2000
    })
    $$('input.disabled, select.disabled').setStyle('opacity',0.5);
  },

  /**
   * Replaces select widget with stuff and binds events
   **/
  replaceSelectWidget: function (input)
  {
    selected  = this.getSelectedOptionText(input);

    replacement = new Element('span',{
      'text':     selected,
      'class':    'select',
      'id':       'select'+input.get('name')
    });

    replacement.inject(input,'before');

    if (input.get('disabled'))
    {
      replacement.addClass('disabled');
    }
    else
    {
      input.addEvent('change',this.selectChoose.bind(this));
    }
  },

  /**
   * Gets the text of a selected option in a <select>
   **/
  getSelectedOptionText: function (input)
  {
    selected = input.getSelected();
    return selected[0].get('text');
  },

  selectChoose: function (ev)
  {
    input     = ev.target
    trigger   = input.getPrevious('span.select');
    selected  = this.getSelectedOptionText(ev.target);
    trigger.set('text',selected);
  },

  /**
   * Replace radio and checkbox elements with styled spans, injecting them
   * before the widget itself, binding mouse events to trigger changes to the
   * inputs themselves
   **/
  replaceButtonWidget: function (widget)
  {
    replacement = new Element('span',{
      'class':    widget.get('type')
    });

    if (widget.checked)
    {
      switch (widget.get('type'))
      {
        case 'checkbox':
          replacement.setStyle('background-position','0 -'+(this.options.checkbox.height*2)+'px');
          break;
        case 'radio':
          replacement.setStyle('background-position','0 -'+(this.options.radio.height*2)+'px');
          break;
      }
    }

    replacement.inject(widget,'before');

    if (widget.get('disabled'))
    {
      replacement.addClass('disabled');
    }
    else
    {
      replacement.addEvents({
        'mousedown':    this.widgetMouseEvent.bind(this),
        'mouseup':      this.widgetMouseEvent.bind(this)
      });
    }
    widget.addEvent('change', this.widgetClear.bind(this));
  },

  /**
   * Delegates mouse(up|down) events on radio and checkbox widgets
   **/
  widgetMouseEvent: function (ev)
  {
    trigger = ev.target;
    input   = trigger.getNext();

    switch (ev.type)
    {
      case 'mousedown':
        this.widgetMouseDown(trigger,input);
        break;
      case 'mouseup':
        this.widgetMouseUp(trigger,input);
        break;
    }
  },

  /**
   * Handle a mousedown event on a checkbox or radio button. 'trigger' is the
   * span, input is the actual form widget
   **/
  widgetMouseDown: function (trigger,input)
  {
    if (input.checked)
    {
      switch (input.get('type'))
      {
        case 'checkbox':
          trigger.setStyle('background-position','0 -'+ this.options.checkbox.height*3 +'px');
          break;
        case 'radio':
          trigger.setStyle('background-position','0 -'+ this.options.checkbox.height*3 +'px');
          break;
      }
    }
    else
    {
      switch (input.get('type'))
      {
        case 'checkbox':
          trigger.setStyle('background-position','0 -'+ this.options.checkbox.height +'px');
          break;
        case 'radio':
          trigger.setStyle('background-position','0 -'+ this.options.radio.height +'px');
          break;
      }
    }
  },

  /**
   * Handle a mouseup event on a checkbox or radio button. 'trigger' is the
   * span, input is the actual form widget
   **/
  widgetMouseUp: function (trigger,input)
  {
    if (input.checked)
    {
      switch (input.get('type'))
      {
        case 'checkbox':
          trigger.setStyle('background-position','0 0');
          input.set('checked',false);
          break;
        case 'radio':
          trigger.setStyle('background-position','0 -'+ this.options.radio.height*3 +'px');
          break;
      }
    }
    else
    {
      switch (input.get('type'))
      {
        case 'checkbox':
          trigger.setStyle('background-position','0 -'+ this.options.checkbox.height*2 +'px');
          break;
        // Radio buttons are more complex as they exist as part of a group
        case 'radio':
          trigger.setStyle('background-position','0 -'+ this.options.checkbox.height*3 +'px');
          group = input.get('name');
          $$('input[name='+ group +']').each(
            function (grouped_input)
            {
              if (grouped_input == input) return; // don't action the clicked one
              grouped_input.getPrevious('span.radio').setStyle('background-position','0 0');
            }
          );
          break;
      }
      input.set('checked','true');
    }
  },

  widgetClear:    function (ev)
  {
    $$('input[type=checkbox].styled, input[type=radio].styled').each(
      function (input)
      {
        trigger = input.getPrevious('span.'+input.get('type'));
        if (input.checked)
        {
          switch (input.get('type'))
          {
            case 'checkbox':
              trigger.setStyle('background-position','0 -'+ this.options.checkbox.height*2 + 'px');
              break;
            case 'radio':
              trigger.setStyle('background-position','0 -'+ this.options.radio.height*2 + 'px');
              break;
          }
        }
        else
        {
          trigger.setStyle('background-position','0 0');
        }
      }
    )
  }
});<commit_msg>Ooops - referencing wrong height<commit_after>var mooFormElements = new Class({
  Implements: [ Options ],

  options: {
    checkbox: {
      height:   25
    },
    radio: {
      height:   25
    },
    select: {
      width:    190
    },
    with_class: 'styled'
  },

  initialize: function (options)
  {
    this.setOptions(options);

    this.hideElementsToStyle();

    // Sort out checkboxes and radio buttons
    $$('input[type=radio].styled, input[type=checkbox].styled').each(this.replaceButtonWidget.bind(this));
    // Sort out selects
    $$('select.styled:not([multiple])').each(this.replaceSelectWidget.bind(this));
  },

  /**
   * Hide the actual form elements with class 'styled'
   **/
  hideElementsToStyle: function ()
  {
    $$('input.'+this.options.with_class).setStyle('display','none');
    $$('select:not([multiple]).'+this.options.with_class).setStyles({
      'width':    this.options.select.width,
      'opacity':  0,
      'border': '1px solid transparent',
      'z-index': 2000
    })
    $$('input.disabled, select.disabled').setStyle('opacity',0.5);
  },

  /**
   * Replaces select widget with stuff and binds events
   **/
  replaceSelectWidget: function (input)
  {
    selected  = this.getSelectedOptionText(input);

    replacement = new Element('span',{
      'text':     selected,
      'class':    'select',
      'id':       'select'+input.get('name')
    });

    replacement.inject(input,'before');

    if (input.get('disabled'))
    {
      replacement.addClass('disabled');
    }
    else
    {
      input.addEvent('change',this.selectChoose.bind(this));
    }
  },

  /**
   * Gets the text of a selected option in a <select>
   **/
  getSelectedOptionText: function (input)
  {
    selected = input.getSelected();
    return selected[0].get('text');
  },

  selectChoose: function (ev)
  {
    input     = ev.target
    trigger   = input.getPrevious('span.select');
    selected  = this.getSelectedOptionText(ev.target);
    trigger.set('text',selected);
  },

  /**
   * Replace radio and checkbox elements with styled spans, injecting them
   * before the widget itself, binding mouse events to trigger changes to the
   * inputs themselves
   **/
  replaceButtonWidget: function (widget)
  {
    replacement = new Element('span',{
      'class':    widget.get('type')
    });

    if (widget.checked)
    {
      switch (widget.get('type'))
      {
        case 'checkbox':
          replacement.setStyle('background-position','0 -'+(this.options.checkbox.height*2)+'px');
          break;
        case 'radio':
          replacement.setStyle('background-position','0 -'+(this.options.radio.height*2)+'px');
          break;
      }
    }

    replacement.inject(widget,'before');

    if (widget.get('disabled'))
    {
      replacement.addClass('disabled');
    }
    else
    {
      replacement.addEvents({
        'mousedown':    this.widgetMouseEvent.bind(this),
        'mouseup':      this.widgetMouseEvent.bind(this)
      });
    }
    widget.addEvent('change', this.widgetClear.bind(this));
  },

  /**
   * Delegates mouse(up|down) events on radio and checkbox widgets
   **/
  widgetMouseEvent: function (ev)
  {
    trigger = ev.target;
    input   = trigger.getNext();

    switch (ev.type)
    {
      case 'mousedown':
        this.widgetMouseDown(trigger,input);
        break;
      case 'mouseup':
        this.widgetMouseUp(trigger,input);
        break;
    }
  },

  /**
   * Handle a mousedown event on a checkbox or radio button. 'trigger' is the
   * span, input is the actual form widget
   **/
  widgetMouseDown: function (trigger,input)
  {
    if (input.checked)
    {
      switch (input.get('type'))
      {
        case 'checkbox':
          trigger.setStyle('background-position','0 -'+ this.options.checkbox.height*3 +'px');
          break;
        case 'radio':
          trigger.setStyle('background-position','0 -'+ this.options.radio.height*3 +'px');
          break;
      }
    }
    else
    {
      switch (input.get('type'))
      {
        case 'checkbox':
          trigger.setStyle('background-position','0 -'+ this.options.checkbox.height +'px');
          break;
        case 'radio':
          trigger.setStyle('background-position','0 -'+ this.options.radio.height +'px');
          break;
      }
    }
  },

  /**
   * Handle a mouseup event on a checkbox or radio button. 'trigger' is the
   * span, input is the actual form widget
   **/
  widgetMouseUp: function (trigger,input)
  {
    if (input.checked)
    {
      switch (input.get('type'))
      {
        case 'checkbox':
          trigger.setStyle('background-position','0 0');
          input.set('checked',false);
          break;
        case 'radio':
          trigger.setStyle('background-position','0 -'+ this.options.radio.height*3 +'px');
          break;
      }
    }
    else
    {
      switch (input.get('type'))
      {
        case 'checkbox':
          trigger.setStyle('background-position','0 -'+ this.options.checkbox.height*2 +'px');
          break;
        // Radio buttons are more complex as they exist as part of a group
        case 'radio':
          trigger.setStyle('background-position','0 -'+ this.options.radio.height*3 +'px');
          group = input.get('name');
          $$('input[name='+ group +']').each(
            function (grouped_input)
            {
              if (grouped_input == input) return; // don't action the clicked one
              grouped_input.getPrevious('span.radio').setStyle('background-position','0 0');
            }
          );
          break;
      }
      input.set('checked','true');
    }
  },

  widgetClear:    function (ev)
  {
    $$('input[type=checkbox].styled, input[type=radio].styled').each(
      function (input)
      {
        trigger = input.getPrevious('span.'+input.get('type'));
        if (input.checked)
        {
          switch (input.get('type'))
          {
            case 'checkbox':
              trigger.setStyle('background-position','0 -'+ this.options.checkbox.height*2 + 'px');
              break;
            case 'radio':
              trigger.setStyle('background-position','0 -'+ this.options.radio.height*2 + 'px');
              break;
          }
        }
        else
        {
          trigger.setStyle('background-position','0 0');
        }
      }
    )
  }
});<|endoftext|>