<commit_before>/*!
 * jQuery Stepy - A Wizard Plugin
 *
 * The MIT License
 *
 * @author:  Washington Botelho
 * @doc:     wbotelhos.com/stepy
 * @version: 1.1.0
 *
 */

;(function($) {
  'use strict';

  var methods = {
    init: function(settings) {
      return this.each(function() {
        methods.destroy.call(this);

        this.opt = $.extend({}, $.fn.stepy.defaults, settings);

        var
          self = this,
          that = $(this),
          id   = that.attr('id');

        if (id === undefined || id === '') {
          var id = methods._hash.call(self);

          that.attr('id', id);
        }

        // Remove Validator...
        if (self.opt.validate) {
          jQuery.validator.setDefaults({ ignore: self.opt.ignore });

          that.append('
');
        }

        self.header = methods._header.call(self);
        self.steps  = that.children('fieldset');

        self.steps.each(function(index) {
          methods._createHead.call(self, this, index);
          methods._createButtons.call(self, this, index);
        });

        self.heads = self.header.children('li');

        self.heads.first().addClass('stepy-active');

        if (self.opt.finishButton) {
          methods._bindFinish.call(self);
        }

        if (self.opt.titleClick) {
          self.heads.click(function() {
            var
              array   = self.heads.filter('.stepy-active').attr('id').split('-'), // TODO: try keep the number in an attribute.
              current = parseInt(array[array.length - 1], 10),
              clicked = $(this).index();

            if (clicked > current) {
              if (self.opt.next && !methods._execute.call(that, self.opt.next, clicked)) {
                return false;
              }
            } else if (clicked < current) {
              if (self.opt.back && !methods._execute.call(that, self.opt.back, clicked)) {
                return false;
              }
            }

            if (clicked != current) {
              methods.step.call(self, (clicked) + 1);
            }
          });
        } else {
          self.heads.css('cursor', 'default');
        }

        if (self.opt.enter) {
          methods._bindEnter.call(self);
        }

        self.steps.first().find(':input:visible:enabled').first().select().focus();

        that.data({ 'settings': this.opt, 'stepy': true });
      });
    },

    _bindEnter: function() {
      var self = this;

      self.steps.delegate('input[type="text"], input[type="password"]', 'keypress', function(evt) {
        var key = (evt.keyCode ? evt.keyCode : evt.which);

        if (key == 13) {
          evt.preventDefault();

          var buttons = $(this).closest('fieldset').find('.stepy-navigator');

          if (buttons.length) {
            var next = buttons.children('.button-next');

            if (next.length) {
              next.click();
            } else if (self.finish) {
              self.finish.click();
            }
          }
        }
      });
    },

    _bindFinish: function() {
      var
        self   = this,
        that   = $(this),
        finish = that.children('input[type="submit"]');

      self.finish = (finish.length === 1) ? finish : that.children('.stepy-finish');

      if (self.finish.length) {
        var isForm   = that.is('form'),
            onSubmit = undefined;

        if (isForm && self.opt.finish) {
          onSubmit = that.attr('onsubmit');

          that.attr('onsubmit', 'return false;');
        }

        self.finish.on('click.stepy', function(evt) {
          if (self.opt.finish && !methods._execute.call(that, self.opt.finish, self.steps.length - 1)) {
            evt.preventDefault();
          } else if (isForm) {
            if (onSubmit) {
              that.attr('onsubmit', onSubmit);
            } else {
              that.removeAttr('onsubmit');
            }

            var isSubmit = self.finish.attr('type') === 'submit';

            if (!isSubmit && (!self.opt.validate || methods.validate.call(that, self.steps.length - 1))) {
              that.submit();
            }
          }
        });

        self.steps.last().children('.stepy-navigator').append(self.finish);
      } else {
        $.error('Submit button or element with class "stepy-finish" missing!');
      }
    },

    _createBackButton: function(nav, index) {
      var
        self       = this,
        that       = $(this),
        attributes = { href: '#', 'class': 'button-back', html: self.opt.backLabel };

      $('', attributes).on('click.stepy', function(e) {
        e.preventDefault();

        if (!self.opt.back || methods._execute.call(self, self.opt.back, index - 1)) {
          methods.step.call(self, (index - 1) + 1);
        }
      }).appendTo(nav);
    },

    _createButtons: function(step, index) {
      var nav = methods._navigator.call(this).appendTo(step);

      if (index === 0) {
        if (this.steps.length > 1) {
          methods._createNextButton.call(this, nav, index);
        }
      } else {
        $(step).hide();

        methods._createBackButton.call(this, nav, index);

        if (index < this.steps.length - 1) {
          methods._createNextButton.call(this, nav, index);
        }
      }
    },

    _createHead: function(step, index) {
      var
        step = $(step).attr('id', $(this).attr('id') + '-step-' + index).addClass('stepy-step'),
        head = methods._head.call(this, index);

      head.append(methods._title.call(this, step));

      if (this.opt.description) {
        head.append(methods._description.call(this, step));
      }

      this.header.append(head);
    },

    _createNextButton: function(nav, index) {
      var
        self       = this,
        that       = $(this),
        attributes = { href: '#', 'class': 'button-next', html: self.opt.nextLabel };

      $('', attributes).on('click.stepy', function(e) {
        e.preventDefault();

        if (!self.opt.next || methods._execute.call(that, self.opt.next, index + 1)) {
          methods.step.call(self, (index + 1) + 1);
        }
      }).appendTo(nav);
    },

    _description: function(step) {
      var legend = step.children('legend');

      if (!this.opt.legend) {
        legend.hide();
      }

      if (legend.length) {
        return $('', { html: legend.html() });
      }

      methods._error.call(this, '<legend /> element missing!');
    },

    _error: function(message) {
      $(this).html(message);

      $.error(message);
    },

    _execute: function(callback, index) {
      var isValid = callback.call(this, index + 1);

      return isValid || isValid === undefined;
    },

    _hash: function() {
      this.hash = 'stepy-' + Math.random().toString().substring(2)

      return this.hash;
    },

    _head: function(index) {
      return $('
', { id: $(this).attr('id') + '-head-' + index });
    },

    _header: function() {
      var header = $('
', { id: $(this).attr('id') + '-header', 'class': 'stepy-header' });

      if (this.opt.titleTarget) {
        header.appendTo(this.opt.titleTarget);
      } else {
        header.insertBefore(this);
      }

      return header;
    },

    _navigator: function(index) {
      return $('
');
    },

    _title: function(step) {
      return $('
', { html: step.attr('title') || '--' });
    },

    destroy: function() {
      return $(this).each(function() {
        var that = $(this);

        if (that.data('stepy')) {
          var steps = that.data('stepy', false).children('fieldset').css('display', '');

          that.children('.stepy-errors').remove();
          this.finish.appendTo(steps.last());
          steps.find('p.stepy-navigator').remove();
        }
      });
    },

    step: function(index) {
      var
        self = this
        that = $(this),
        opt  = that[0].opt;

      index--;

      var steps = that.children('fieldset');

      if (index > steps.length - 1) {
        index = steps.length - 1;
      }

      var max = index;

      if (opt.validate) {
        var isValid = true;

        for (var i = 0; i < index; i++) {
          isValid &= methods.validate.call(this, i);

          if (opt.block && !isValid) {
            max = i;
            break;
          }
        }
      }

      var stepsCount = steps.length;

      if (opt.transition == 'fade') {
        steps.fadeOut(opt.duration, function() {
          if (--stepsCount > 0) {
            return;
          }

          steps.eq(max).fadeIn(opt.duration);
        });
      } else if (opt.transition == 'slide') {
        steps.slideUp(opt.duration, function() {
          if (--stepsCount > 0) {
            return;
          }

          steps.eq(max).slideDown(opt.duration);
        });
      } else {
        steps.hide(opt.duration).eq(max).show(opt.duration);
      }

      that[0].heads.removeClass('stepy-active').eq(max).addClass('stepy-active');

      if (that.is('form')) {
        var $fields = undefined;

        if (max == index) {
          $fields = steps.eq(max).find(':input:enabled:visible');
        } else {
          $fields = steps.eq(max).find('.error').select().focus();
        }

        $fields.first().select().focus();
      }

      if (opt.select) {
        opt.select.call(this, max + 1);
      }

      return that;
    },

    validate: function(index) {
      var that = $(this);

      if (!that.is('form')) {
        return true;
      }

      var
        self      = this,
        step      = that.children('fieldset').eq(index),
        isValid   = true,
        $title    = $('#' + that.attr('id') + '-header').children().eq(index),
        $validate = that.validate();

      $(step.find(':input:enabled').get().reverse()).each(function() {
        var fieldIsValid = $validate.element($(this));

        if (fieldIsValid === undefined) {
          fieldIsValid = true;
        }

        isValid &= fieldIsValid;

        if (isValid) {
          if (self.opt.errorImage) {
            $title.removeClass('stepy-error');
          }
        } else {
          if (self.opt.errorImage) {
            $title.addClass('stepy-error');
          }

          $validate.focusInvalid();
        }
      });

      return isValid;
    }
  };

  $.fn.stepy = function(method) {
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error('Method ' + method + ' does not exist!');
    }
  };

  $.fn.stepy.defaults = {
    back:         undefined,
    backLabel:    '< Back',
    block:        false,
    description:  true,
    duration:     undefined,
    enter:        true,
    errorImage:   false,
    finish:       undefined,
    finishButton: true,
    ignore:       '',
    legend:       true,
    next:         undefined,
    nextLabel:    'Next >',
    select:       undefined,
    titleClick:   false,
    titleTarget:  undefined,
    transition:   undefined,
    validate:     false
  };

})(jQuery);
<commit_msg>missing comma<commit_after>/*!
 * jQuery Stepy - A Wizard Plugin
 *
 * The MIT License
 *
 * @author:  Washington Botelho
 * @doc:     wbotelhos.com/stepy
 * @version: 1.1.0
 *
 */

;(function($) {
  'use strict';

  var methods = {
    init: function(settings) {
      return this.each(function() {
        methods.destroy.call(this);

        this.opt = $.extend({}, $.fn.stepy.defaults, settings);

        var
          self = this,
          that = $(this),
          id   = that.attr('id');

        if (id === undefined || id === '') {
          var id = methods._hash.call(self);

          that.attr('id', id);
        }

        // Remove Validator...
        if (self.opt.validate) {
          jQuery.validator.setDefaults({ ignore: self.opt.ignore });

          that.append('
');
        }

        self.header = methods._header.call(self);
        self.steps  = that.children('fieldset');

        self.steps.each(function(index) {
          methods._createHead.call(self, this, index);
          methods._createButtons.call(self, this, index);
        });

        self.heads = self.header.children('li');

        self.heads.first().addClass('stepy-active');

        if (self.opt.finishButton) {
          methods._bindFinish.call(self);
        }

        if (self.opt.titleClick) {
          self.heads.click(function() {
            var
              array   = self.heads.filter('.stepy-active').attr('id').split('-'), // TODO: try keep the number in an attribute.
              current = parseInt(array[array.length - 1], 10),
              clicked = $(this).index();

            if (clicked > current) {
              if (self.opt.next && !methods._execute.call(that, self.opt.next, clicked)) {
                return false;
              }
            } else if (clicked < current) {
              if (self.opt.back && !methods._execute.call(that, self.opt.back, clicked)) {
                return false;
              }
            }

            if (clicked != current) {
              methods.step.call(self, (clicked) + 1);
            }
          });
        } else {
          self.heads.css('cursor', 'default');
        }

        if (self.opt.enter) {
          methods._bindEnter.call(self);
        }

        self.steps.first().find(':input:visible:enabled').first().select().focus();

        that.data({ 'settings': this.opt, 'stepy': true });
      });
    },

    _bindEnter: function() {
      var self = this;

      self.steps.delegate('input[type="text"], input[type="password"]', 'keypress', function(evt) {
        var key = (evt.keyCode ? evt.keyCode : evt.which);

        if (key == 13) {
          evt.preventDefault();

          var buttons = $(this).closest('fieldset').find('.stepy-navigator');

          if (buttons.length) {
            var next = buttons.children('.button-next');

            if (next.length) {
              next.click();
            } else if (self.finish) {
              self.finish.click();
            }
          }
        }
      });
    },

    _bindFinish: function() {
      var
        self   = this,
        that   = $(this),
        finish = that.children('input[type="submit"]');

      self.finish = (finish.length === 1) ? finish : that.children('.stepy-finish');

      if (self.finish.length) {
        var isForm   = that.is('form'),
            onSubmit = undefined;

        if (isForm && self.opt.finish) {
          onSubmit = that.attr('onsubmit');

          that.attr('onsubmit', 'return false;');
        }

        self.finish.on('click.stepy', function(evt) {
          if (self.opt.finish && !methods._execute.call(that, self.opt.finish, self.steps.length - 1)) {
            evt.preventDefault();
          } else if (isForm) {
            if (onSubmit) {
              that.attr('onsubmit', onSubmit);
            } else {
              that.removeAttr('onsubmit');
            }

            var isSubmit = self.finish.attr('type') === 'submit';

            if (!isSubmit && (!self.opt.validate || methods.validate.call(that, self.steps.length - 1))) {
              that.submit();
            }
          }
        });

        self.steps.last().children('.stepy-navigator').append(self.finish);
      } else {
        $.error('Submit button or element with class "stepy-finish" missing!');
      }
    },

    _createBackButton: function(nav, index) {
      var
        self       = this,
        that       = $(this),
        attributes = { href: '#', 'class': 'button-back', html: self.opt.backLabel };

      $('', attributes).on('click.stepy', function(e) {
        e.preventDefault();

        if (!self.opt.back || methods._execute.call(self, self.opt.back, index - 1)) {
          methods.step.call(self, (index - 1) + 1);
        }
      }).appendTo(nav);
    },

    _createButtons: function(step, index) {
      var nav = methods._navigator.call(this).appendTo(step);

      if (index === 0) {
        if (this.steps.length > 1) {
          methods._createNextButton.call(this, nav, index);
        }
      } else {
        $(step).hide();

        methods._createBackButton.call(this, nav, index);

        if (index < this.steps.length - 1) {
          methods._createNextButton.call(this, nav, index);
        }
      }
    },

    _createHead: function(step, index) {
      var
        step = $(step).attr('id', $(this).attr('id') + '-step-' + index).addClass('stepy-step'),
        head = methods._head.call(this, index);

      head.append(methods._title.call(this, step));

      if (this.opt.description) {
        head.append(methods._description.call(this, step));
      }

      this.header.append(head);
    },

    _createNextButton: function(nav, index) {
      var
        self       = this,
        that       = $(this),
        attributes = { href: '#', 'class': 'button-next', html: self.opt.nextLabel };

      $('', attributes).on('click.stepy', function(e) {
        e.preventDefault();

        if (!self.opt.next || methods._execute.call(that, self.opt.next, index + 1)) {
          methods.step.call(self, (index + 1) + 1);
        }
      }).appendTo(nav);
    },

    _description: function(step) {
      var legend = step.children('legend');

      if (!this.opt.legend) {
        legend.hide();
      }

      if (legend.length) {
        return $('', { html: legend.html() });
      }

      methods._error.call(this, '<legend /> element missing!');
    },

    _error: function(message) {
      $(this).html(message);

      $.error(message);
    },

    _execute: function(callback, index) {
      var isValid = callback.call(this, index + 1);

      return isValid || isValid === undefined;
    },

    _hash: function() {
      this.hash = 'stepy-' + Math.random().toString().substring(2)

      return this.hash;
    },

    _head: function(index) {
      return $('
', { id: $(this).attr('id') + '-head-' + index });
    },

    _header: function() {
      var header = $('
', { id: $(this).attr('id') + '-header', 'class': 'stepy-header' });

      if (this.opt.titleTarget) {
        header.appendTo(this.opt.titleTarget);
      } else {
        header.insertBefore(this);
      }

      return header;
    },

    _navigator: function(index) {
      return $('
');
    },

    _title: function(step) {
      return $('
', { html: step.attr('title') || '--' });
    },

    destroy: function() {
      return $(this).each(function() {
        var that = $(this);

        if (that.data('stepy')) {
          var steps = that.data('stepy', false).children('fieldset').css('display', '');

          that.children('.stepy-errors').remove();
          this.finish.appendTo(steps.last());
          steps.find('p.stepy-navigator').remove();
        }
      });
    },

    step: function(index) {
      var
        self = this,
        that = $(this),
        opt  = that[0].opt;

      index--;

      var steps = that.children('fieldset');

      if (index > steps.length - 1) {
        index = steps.length - 1;
      }

      var max = index;

      if (opt.validate) {
        var isValid = true;

        for (var i = 0; i < index; i++) {
          isValid &= methods.validate.call(this, i);

          if (opt.block && !isValid) {
            max = i;
            break;
          }
        }
      }

      var stepsCount = steps.length;

      if (opt.transition == 'fade') {
        steps.fadeOut(opt.duration, function() {
          if (--stepsCount > 0) {
            return;
          }

          steps.eq(max).fadeIn(opt.duration);
        });
      } else if (opt.transition == 'slide') {
        steps.slideUp(opt.duration, function() {
          if (--stepsCount > 0) {
            return;
          }

          steps.eq(max).slideDown(opt.duration);
        });
      } else {
        steps.hide(opt.duration).eq(max).show(opt.duration);
      }

      that[0].heads.removeClass('stepy-active').eq(max).addClass('stepy-active');

      if (that.is('form')) {
        var $fields = undefined;

        if (max == index) {
          $fields = steps.eq(max).find(':input:enabled:visible');
        } else {
          $fields = steps.eq(max).find('.error').select().focus();
        }

        $fields.first().select().focus();
      }

      if (opt.select) {
        opt.select.call(this, max + 1);
      }

      return that;
    },

    validate: function(index) {
      var that = $(this);

      if (!that.is('form')) {
        return true;
      }

      var
        self      = this,
        step      = that.children('fieldset').eq(index),
        isValid   = true,
        $title    = $('#' + that.attr('id') + '-header').children().eq(index),
        $validate = that.validate();

      $(step.find(':input:enabled').get().reverse()).each(function() {
        var fieldIsValid = $validate.element($(this));

        if (fieldIsValid === undefined) {
          fieldIsValid = true;
        }

        isValid &= fieldIsValid;

        if (isValid) {
          if (self.opt.errorImage) {
            $title.removeClass('stepy-error');
          }
        } else {
          if (self.opt.errorImage) {
            $title.addClass('stepy-error');
          }

          $validate.focusInvalid();
        }
      });

      return isValid;
    }
  };

  $.fn.stepy = function(method) {
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error('Method ' + method + ' does not exist!');
    }
  };

  $.fn.stepy.defaults = {
    back:         undefined,
    backLabel:    '< Back',
    block:        false,
    description:  true,
    duration:     undefined,
    enter:        true,
    errorImage:   false,
    finish:       undefined,
    finishButton: true,
    ignore:       '',
    legend:       true,
    next:         undefined,
    nextLabel:    'Next >',
    select:       undefined,
    titleClick:   false,
    titleTarget:  undefined,
    transition:   undefined,
    validate:     false
  };

})(jQuery);
<|endoftext|>


<commit_before>WatchMe = {
  initial: {
    diameter: 300
  },
  textMaker: {
    hour: function (hour) {
      return (hour == 0 ? 12: hour) + '';
    },
    minute: function (minute) {
      return WatchMe.padLeft(minute, '0', 2);
    },
    second: function (second) {
      return WatchMe.padLeft(second, '0', 2);
    }
  }
};

WatchMe.padLeft = function (x, padCharacter, length) {
  var s = '' + x,
      parts = [];
  for (var i = s.length; i < length; ++i) {
    parts.push(padCharacter);
  }
  parts.push(s);
  return parts.join('');
};

WatchMe.cachedTextMeasurements = {};

WatchMe.measureText = function (text, font, fontSize) {
  var cache = WatchMe.cachedTextMeasurements;
  if (cache[font] !== undefined && cache[font][text] !== undefined) {
    return cache[font][text];
  }
  var canvas = WatchMe.canvas.measure,
      context = WatchMe.context.measure;
  if (context.font != font) {
    context.font = font;
  }
  var width = Math.ceil(context.measureText(text).width);
  if (canvas.width < width) {
    canvas.width = width;
    context.font = font;
  }
  if (canvas.height < 2 * fontSize) {
    canvas.height = 2 * fontSize;
    context.font = font;
  }
  context.clearRect(0, 0, canvas.width, canvas.height);
  var height = canvas.height,
      xFill = 0,
      yFill = height / 2;
  context.fillText(text, xFill, yFill);
  var data = context.getImageData(0, 0, width, height).data,
      xMin, xMax, yMin, yMax;
  for (var x = 0; x < width; ++x) {
    for (var y = 0; y < height; ++y) {
      var i = 4 * (y * width + x);
      if (data[i + 3] == 0) {
        continue;
      }
      if (xMin === undefined) {
        xMin = xMax = x;
        yMin = yMax = y;
      } else {
        xMin = Math.min(xMin, x);
        xMax = Math.max(xMax, x);
        yMin = Math.min(yMin, y);
        yMax = Math.max(yMax, y);
      }
    }
  }
  var x0 = (xMin + xMax) / 2,
      y0 = (yMin + yMax) / 2,
      radiusSquared = 0;
  for (var x = xMin; x <= xMax; ++x) {
    for (var y = yMin; y <= yMax; ++y) {
      var i = 4 * (y * width + x);
      if (data[i + 3] == 0) {
        continue;
      }
      var dx = Math.abs(x - x0) + 1,
          dy = Math.abs(y - y0) + 1;
      radiusSquared = Math.max(radiusSquared, dx * dx + dy * dy);
    }
  }
  var radius = Math.ceil(Math.sqrt(radiusSquared));
  context.fillStyle = '#ccc';
  context.beginPath();
  context.arc(x0, y0, radius, 0, 2 * Math.PI);
  context.fill();
  context.fillStyle = '#000';
  context.fillText(text, 0, height / 2);
  if (cache[font] === undefined) {
    cache[font] = {};
  }
  var measurement = cache[font][text] = {
    xMin: xMin, xMax: xMax, yMin: yMin, yMax: yMax,
    radius: radius,
    fillCenter: {
      x: x0 - xFill,
      y: y0 - yFill
    }
  };
  return measurement;
};

WatchMe.update = function () {
  var date = new Date(),
      hour = date.getHours() % 12,
      minute = date.getMinutes(),
      second = date.getSeconds(),
      millisecond = date.getMilliseconds();

  // Draw background graphics.
  var context = WatchMe.context.watch,
      radius = WatchMe.radius,
      center = { x: radius, y: radius };
  context.clearRect(0, 0, 2 * radius, 2 * radius);
  context.beginPath();
  context.fillStyle = '#aaa';
  context.arc(center.x, center.y, 0.015 * radius, 0, 2 * Math.PI);
  context.fill();

  var gap = 0.01 * radius,
      hourRadius = 0.21 * radius,
      hourDistance = radius - hourRadius,
      minuteRadius = 0.18 * radius,
      minuteDistance = hourDistance - gap - hourRadius - minuteRadius,
      secondRadius = 0.085 * radius,
      secondDistance = minuteDistance - gap - minuteRadius - secondRadius;
  /*
  var secondRadius = 0.20 * radius,
      secondDistance = radius - secondRadius,
      minuteRadius = 0.20 * radius,
      minuteDistance = secondDistance - secondRadius - minuteRadius,
      hourRadius = 0.20 * radius,
      hourDistance = 0;
  */

  var paintArc = function (value, textMaker, hertz, distance, radius,
        color, discColor) {
    var angle = -Math.PI / 2 + value * 2 * Math.PI / hertz,
        text = textMaker(value);
    // Value position.
    var x = center.x + Math.cos(angle) * distance,
        y = center.y + Math.sin(angle) * distance;
    // Value text.
    var fontSize = 1.33 * radius,
        font = fontSize + 'px sans-serif';
    context.font = font;
    var m = WatchMe.measureText(text, font, fontSize);
    if (discColor) {
      context.fillStyle = discColor;
      context.beginPath();
      context.arc(x, y, radius, 0, 2 * Math.PI);
      context.fill();
    }
    context.fillStyle = color;
    context.fillText(text, x - m.fillCenter.x, y - m.fillCenter.y);
  };
  for (var h = 0; h < 12; ++h) {
    if (h == hour) {
      paintArc(h, WatchMe.textMaker.hour, 12,
          hourDistance, hourRadius, '#fff', '#444');
    } else {
      paintArc(h, WatchMe.textMaker.hour, 12, hourDistance, hourRadius, '#aaa');
    }
  }
  paintArc(minute, WatchMe.textMaker.minute, 60,
      minuteDistance, minuteRadius, '#fff', '#666');
  paintArc(second, WatchMe.textMaker.second, 60,
      secondDistance, secondRadius, '#fff', '#888');

  if (WatchMe.stopped) {
    return;
  }
  window.requestAnimationFrame(WatchMe.update);
};

WatchMe.load = function () {
  WatchMe.display = {
    timeCheck: document.getElementById('timeCheck')
  };
  WatchMe.canvas = {
    watch: document.createElement('canvas'),
    measure: document.createElement('canvas')
  };
  var canvas = WatchMe.canvas.watch,
      diameter = WatchMe.diameter = WatchMe.initial.diameter,
      radius = WatchMe.radius = diameter / 2;
  document.getElementById('watchContainer').appendChild(canvas);
  canvas.width = diameter;
  canvas.height = diameter;
  WatchMe.context = {
    watch: canvas.getContext('2d'),
    measure: WatchMe.canvas.measure.getContext('2d')
  };
  document.getElementById('stopButton').onmousedown = function () {
    WatchMe.stopped = true;
  };
  window.requestAnimationFrame(WatchMe.update);
};

window.onload = WatchMe.load;
<commit_msg>Separate function for bubble clock<commit_after>WatchMe = {
  initial: {
    diameter: 300
  },
  textMaker: {
    hour: function (hour) {
      return (hour == 0 ? 12: hour) + '';
    },
    minute: function (minute) {
      return WatchMe.padLeft(minute, '0', 2);
    },
    second: function (second) {
      return WatchMe.padLeft(second, '0', 2);
    }
  }
};

WatchMe.padLeft = function (x, padCharacter, length) {
  var s = '' + x,
      parts = [];
  for (var i = s.length; i < length; ++i) {
    parts.push(padCharacter);
  }
  parts.push(s);
  return parts.join('');
};

WatchMe.cachedTextMeasurements = {};

WatchMe.measureText = function (text, font, fontSize) {
  var cache = WatchMe.cachedTextMeasurements;
  if (cache[font] !== undefined && cache[font][text] !== undefined) {
    return cache[font][text];
  }
  var canvas = WatchMe.canvas.measure,
      context = WatchMe.context.measure;
  if (context.font != font) {
    context.font = font;
  }
  var width = Math.ceil(context.measureText(text).width);
  if (canvas.width < width) {
    canvas.width = width;
    context.font = font;
  }
  if (canvas.height < 2 * fontSize) {
    canvas.height = 2 * fontSize;
    context.font = font;
  }
  context.clearRect(0, 0, canvas.width, canvas.height);
  var height = canvas.height,
      xFill = 0,
      yFill = height / 2;
  context.fillText(text, xFill, yFill);
  var data = context.getImageData(0, 0, width, height).data,
      xMin, xMax, yMin, yMax;
  for (var x = 0; x < width; ++x) {
    for (var y = 0; y < height; ++y) {
      var i = 4 * (y * width + x);
      if (data[i + 3] == 0) {
        continue;
      }
      if (xMin === undefined) {
        xMin = xMax = x;
        yMin = yMax = y;
      } else {
        xMin = Math.min(xMin, x);
        xMax = Math.max(xMax, x);
        yMin = Math.min(yMin, y);
        yMax = Math.max(yMax, y);
      }
    }
  }
  var x0 = (xMin + xMax) / 2,
      y0 = (yMin + yMax) / 2,
      radiusSquared = 0;
  for (var x = xMin; x <= xMax; ++x) {
    for (var y = yMin; y <= yMax; ++y) {
      var i = 4 * (y * width + x);
      if (data[i + 3] == 0) {
        continue;
      }
      var dx = Math.abs(x - x0) + 1,
          dy = Math.abs(y - y0) + 1;
      radiusSquared = Math.max(radiusSquared, dx * dx + dy * dy);
    }
  }
  var radius = Math.ceil(Math.sqrt(radiusSquared));
  context.fillStyle = '#ccc';
  context.beginPath();
  context.arc(x0, y0, radius, 0, 2 * Math.PI);
  context.fill();
  context.fillStyle = '#000';
  context.fillText(text, 0, height / 2);
  if (cache[font] === undefined) {
    cache[font] = {};
  }
  var measurement = cache[font][text] = {
    xMin: xMin, xMax: xMax, yMin: yMin, yMax: yMax,
    radius: radius,
    fillCenter: {
      x: x0 - xFill,
      y: y0 - yFill
    }
  };
  return measurement;
};

WatchMe.bubbleClock = {};

WatchMe.bubbleClock.update = function (hour, minute, second) {
  // Draw background graphics.
  var context = WatchMe.bubbleClock.context,
      radius = WatchMe.radius,
      center = { x: radius, y: radius };
  context.clearRect(0, 0, 2 * radius, 2 * radius);
  context.beginPath();
  context.fillStyle = '#aaa';
  context.arc(center.x, center.y, 0.015 * radius, 0, 2 * Math.PI);
  context.fill();

  var gap = 0.01 * radius,
      hourRadius = 0.21 * radius,
      hourDistance = radius - hourRadius,
      minuteRadius = 0.18 * radius,
      minuteDistance = hourDistance - gap - hourRadius - minuteRadius,
      secondRadius = 0.085 * radius,
      secondDistance = minuteDistance - gap - minuteRadius - secondRadius;

  var paintArc = function (value, textMaker, hertz, distance, radius,
        color, discColor) {
    var angle = -Math.PI / 2 + value * 2 * Math.PI / hertz,
        text = textMaker(value);
    // Value position.
    var x = center.x + Math.cos(angle) * distance,
        y = center.y + Math.sin(angle) * distance;
    // Value text.
    var fontSize = 1.33 * radius,
        font = fontSize + 'px sans-serif';
    context.font = font;
    var m = WatchMe.measureText(text, font, fontSize);
    if (discColor) {
      context.fillStyle = discColor;
      context.beginPath();
      context.arc(x, y, radius, 0, 2 * Math.PI);
      context.fill();
    }
    context.fillStyle = color;
    context.fillText(text, x - m.fillCenter.x, y - m.fillCenter.y);
  };
  for (var h = 0; h < 12; ++h) {
    if (h == hour) {
      paintArc(h, WatchMe.textMaker.hour, 12,
          hourDistance, hourRadius, '#fff', '#444');
    } else {
      paintArc(h, WatchMe.textMaker.hour, 12, hourDistance, hourRadius, '#aaa');
    }
  }
  paintArc(minute, WatchMe.textMaker.minute, 60,
      minuteDistance, minuteRadius, '#fff', '#666');
  paintArc(second, WatchMe.textMaker.second, 60,
      secondDistance, secondRadius, '#fff', '#888');
};

WatchMe.update = function () {
  var date = new Date(),
      hour = date.getHours() % 12,
      minute = date.getMinutes(),
      second = date.getSeconds();

  WatchMe.bubbleClock.update(hour, minute, second);

  if (WatchMe.stopped) {
    return;
  }
  window.requestAnimationFrame(WatchMe.update);
};

WatchMe.load = function () {
  WatchMe.display = {
    timeCheck: document.getElementById('timeCheck')
  };
  WatchMe.canvas = {
    watch: document.createElement('canvas'),
    measure: document.createElement('canvas')
  };
  var canvas = WatchMe.canvas.watch,
      diameter = WatchMe.diameter = WatchMe.initial.diameter,
      radius = WatchMe.radius = diameter / 2;
  document.getElementById('watchContainer').appendChild(canvas);
  canvas.width = diameter;
  canvas.height = diameter;
  WatchMe.context = {
    measure: WatchMe.canvas.measure.getContext('2d')
  };
  WatchMe.bubbleClock.context = canvas.getContext('2d');

  document.getElementById('stopButton').onmousedown = function () {
    WatchMe.stopped = true;
  };
  window.requestAnimationFrame(WatchMe.update);
};

window.onload = WatchMe.load;
<|endoftext|>


<commit_before>/**
 * Code in this file will attempt to optimize generated code so it's more compact
 * and executes faster, better, etc.
 */
var jsp = require("../../uglify-js/uglify-js").parser,
	pro = require("../../uglify-js/uglify-js").uglify,
	_ = require('../../lib/alloy/underscore')._,
	util = require('util'),
	colors = require('colors'),
	logger = require('../../common/logger.js'),
	U = require('../../utils'),
	platformDefines,
	platformName, platformOsName
;

var JSON_NULL = JSON.parse('null');
var EQUALITY_SIGNS = {
	'==': 1,
	'===': 1,
	'!=':1,
	'!==':1
};

function getVariableStringValue(a)
{
	var e = a;
	var p = '';
	while(e[0]==='dot' || e[0]==='name' || e[0]==='string' || e[0]==='sub')
	{
		if (e[0]==='sub') // sub is like foo['bar'] which we turn to foo.bar
		{
			p = e[2][1] + '.' + p;
		}
		else
		{
			p = (e[0] == 'dot' ? e[2] : e[1]) + '.' + p;
		}
		e = e[1];
	}
	return p.substring(0,p.length-1);
}

function isEqualityOperation(v) {
	return (v in EQUALITY_SIGNS);
}

function isEqualOp(v) {
	return (v === '===' || v === '==');
}

function removeCode()
{
	return ['block'];  // this is effectively an empty code block
}

function falseVar(name)
{
	return ['var', [ [ name, [ 'num', 0 ] ] ] ];  // this is effectively "false"
}

var VAR_IGNORES = {
	num:1,
	string:1,
	name:1,
	object:1,
	new:1
}

function processVarEntry()
{
	var rhs = this[1][0];
	if (rhs.length === 1)
	{
		// this is a variable declaration with no assignment
		return this;
	}
	if (rhs[1][0] in VAR_IGNORES)
	{
		return this;
	}
	if (rhs[1][0] == 'dot')
	{
		var varname = getVariableStringValue(rhs[1]);
		if (varname == 'Ti.Platform.name' || varname == 'Titanium.Platform.name')
		{
			return ["var",[[rhs[0],["string",platformName]]]]
		}
		if ((varname == 'Ti.Platform.osname' || varname == 'Titanium.Platform.osname') &&
			platformDefines.OS_ANDROID && platformName === 'android')
		{
			return ["var",[[rhs[0],["string","android"]]]]
		}
		if ((varname == 'Ti.Platform.osname' || varname == 'Titanium.Platform.osname') &&
			platformDefines.OS_MOBILEWEB && platformName === 'mobileweb')
		{
			return ["var",[[rhs[0],["string","mobileweb"]]]]
		}
	}
	var isConditionalAssignment;
	try
	{
		isConditionalAssignment = this[1][0][1][0]=='conditional';
	}
	catch(E)
	{
		console.log(this[1])
		console.log(JSON.stringify(this));
		console.log(E.stack);
	}
	var hasSimpleAssignment = !isConditionalAssignment && this[1][0][1][0]!='binary';
	if (hasSimpleAssignment)
	{
		return this;
	}
	if (isConditionalAssignment)
	{
		var entry = this[1][0][1][1];
		if (entry[0]=='name') // skip if normal conditional
		{
			return this;
		}
		// console.log(entry)
		var ifTrue = this[1][0][1][2];
		var ifFalse = this[1][0][1][3];
		var result = processIf.call([[],entry]);
		if (result === null)
		{
			return this;
		}
		if (result[0] == 'block')
		{
			return ['var', [ [ this[1][0][0], ifFalse ] ] ];
		}
		else if (result[0] === 'num')
		{
			return ['var', [ [ this[1][0][0], result[1] ? ifTrue : ifFalse ] ] ];
		}
	}
	var result = processIf.call(this[1][0]);
	if (result===null)
	{
		return this;
	}
	if (result[0]=='block' && result.length == 1)
	{
		// this is a deadcode removal indicator, return false
		return falseVar(this[1][0][0]);
	}
	else
	{
		// return the result as the value of the variable
		return ['var', [ [ this[1][0][0], result ] ] ];
	}
}

function processVar()
{
	var entries = this[1];
	for (var c=0;c<entries.length;c++)
	{
		try
		{
			if (entries[c][1]!==null)
			{
				var result = processVarEntry.call([this[0], [entries[c]]])[1][0];
				entries[c] = result;
			}
		}
		catch(E)
		{
			console.log('error trying to parse => '+JSON.stringify(this));
			console.log('error at this line => '+JSON.stringify(entries[c]));
			return this;
		}
	}
	return this;
}

function processObject() {
	var translate = getVariableStringValue(this);
	if (_.contains(['Ti.Platform.name','Titanium.Platform.name'], translate) && platformName) {
		return ['string',platformName];
	} else if (_.contains(['Ti.Platform.osname','Titanium.Platform.osname'], translate) && platformOsName) {
		return ['string',platformOsName];
	}
	return null;
}

function processIf()
{
	// if [0]
	// binary [1],
	// iflogic [2],
	// elselogic [3]
	var op = this[1][1];
	if (this[1][0] === 'binary' && isEqualityOperation(op))
	{
		var lhs = this[1][2];
		var rhs = this[1][3];

		// right hand must be a string
		if (rhs[0] !== 'string') {
			return null;
		}

		var varName = getVariableStringValue(lhs);
		var value = getVariableStringValue(rhs);

		if ((varName === 'Titanium.Platform.osname' || varName === 'Ti.Platform.osname') && (value === 'iphone' || value === 'ipad'))
		{
			// TODO: make compile time "universal" distinction btw iphone and ipad - https://jira.appcelerator.org/browse/ALOY-223
			return null;
		}

		if (varName === 'Titanium.Platform.name' || varName === 'Ti.Platform.name' || (varName === 'Ti.Platform.osname' && value === 'android'))
		{
			if ((isEqualOp(op) && value === platformName) || (!isEqualOp(op) && value!== platformName))
			{
				if (this[2])
				{
					return this[2][1][0];
				}
				return ['num',1]; // this is effectively "true"
			}
			else
			{
				var elseLogic = this[3];
				if (elseLogic)
				{
					return this[3][1][0];
				}
				else
				{
					return removeCode();
				}
			}
		}
	}
	return null;
}

// strips null and undefined values out of Alloy styles
exports.optimizeStyle = function(styleList) {
	for (var style in styleList) {
		for (var key in styleList[style]) {
			var v = styleList[style][key];
			if (v == JSON_NULL || typeof(v) === 'undefined' || typeof(v) === 'null') {
				delete styleList[style][key];
			}
		}
	}
}

// main function for optimizing runtime Titanium Javascript code
function optimize(ast, defines, fn) {
	try {
		platformDefines = defines;

		// determine platform name from defines
		if (platformDefines.OS_IOS) {
			platformName = 'iPhone OS';
			platformOsName = null;
		} else if (platformDefines.OS_ANDROID) {
			platformOsName = platformName = 'android';
		} else if (platformDefines.OS_MOBILEWEB) {
			platformOsName = platformName = 'mobileweb';
		} else {
			platformName = platformOsName = null;
		}

		// walk the AST looking for ifs and vars
		var w = pro.ast_walker();
		return w.with_walkers({
				"dot": processObject,
				"sub": processObject,
				//"if" : processIf,
				//"var" :processVar
		}, function() {
			return w.walk(ast);
		});
	} catch (e) {
		logger.error('Error compiling source (' + fn + '). ' + e + '\n' + e.stack);
		return ast;
	}
}

exports.optimize = optimize;

<commit_msg>removed refactored out logic<commit_after>/**
 * Code in this file will attempt to optimize generated code so it's more compact
 * and executes faster, better, etc.
 */
var jsp = require("../../uglify-js/uglify-js").parser,
	pro = require("../../uglify-js/uglify-js").uglify,
	_ = require('../../lib/alloy/underscore')._,
	util = require('util'),
	colors = require('colors'),
	logger = require('../../common/logger.js'),
	U = require('../../utils'),
	platformDefines,
	platformName,
	platformOsName;

var JSON_NULL = JSON.parse('null');

function getVariableStringValue(a)
{
	var e = a;
	var p = '';
	while(e[0]==='dot' || e[0]==='name' || e[0]==='string' || e[0]==='sub')
	{
		if (e[0]==='sub') // sub is like foo['bar'] which we turn to foo.bar
		{
			p = e[2][1] + '.' + p;
		}
		else
		{
			p = (e[0] == 'dot' ? e[2] : e[1]) + '.' + p;
		}
		e = e[1];
	}
	return p.substring(0,p.length-1);
}

// Replace the Ti.Platform variables with strings, when possible. We don't need to do
// anything else. uglifyjs will take care of optimization for us by eliminating dead
// code based on string to string comparisons in the ast_squeeze() step.
function processObject() {
	var translate = getVariableStringValue(this);
	if (_.contains(['Ti.Platform.name','Titanium.Platform.name'], translate) && platformName) {
		return ['string',platformName];
	} else if (_.contains(['Ti.Platform.osname','Titanium.Platform.osname'], translate) && platformOsName) {
		return ['string',platformOsName];
	}
	return null;
}

// strips null and undefined values out of Alloy styles
exports.optimizeStyle = function(styleList) {
	for (var style in styleList) {
		for (var key in styleList[style]) {
			var v = styleList[style][key];
			if (v == JSON_NULL || typeof(v) === 'undefined' || typeof(v) === 'null') {
				delete styleList[style][key];
			}
		}
	}
}

// main function for optimizing runtime Titanium Javascript code
function optimize(ast, defines, fn) {
	try {
		platformDefines = defines;

		// determine platform name from defines
		if (platformDefines.OS_IOS) {
			platformName = 'iPhone OS';
			platformOsName = null;
		} else if (platformDefines.OS_ANDROID) {
			platformOsName = platformName = 'android';
		} else if (platformDefines.OS_MOBILEWEB) {
			platformOsName = platformName = 'mobileweb';
		} else {
			platformName = platformOsName = null;
		}

		// walk the AST looking for ifs and vars
		var w = pro.ast_walker();
		return w.with_walkers({
				"dot": processObject,
				"sub": processObject
		}, function() {
			return w.walk(ast);
		});
	} catch (e) {
		logger.error('Error compiling source (' + fn + '). ' + e + '\n' + e.stack);
		return ast;
	}
}

exports.optimize = optimize;

<|endoftext|>


<commit_before>var fixesNumberRegex =
        /fixes:? #[\d]*/i
  , fixesUrlRegex =
        /fixes:? https?:\/\/github.com\/([\da-z\.-]+)\/([\da-z\.-]+)\/issues\/\d{1,10}/i
  , log = require('../utils/logger').logger
  , NAME = 'Fixes Issue Validator'
  ;

function hasFixLinkToIssue(text) {
    if (! text) return false;
    return !! (text.match(fixesNumberRegex) || text.match(fixesUrlRegex));
}

function validator(sha, githubUser, repoClient, callback) {
    var searchString = sha + '+state:open'
      , response = {
          state: 'failure'
        , description: 'This PR must be linked to an issue.'
        , target_url: 'https://github.com/numenta/nupic/wiki/Development-Process'
      };
    log.info('Validating that PR fixes an issue');
    // If this PR was created by this server using the ci account, we'll
    // automatically approve it.
    if (githubUser == 'numenta-ci') {
        response.state = 'success';
        response.description = 'This PR was created by nupic.tools.'
        return callback(null, response);
    }
    repoClient.searchIssues(searchString, function(err, prs) {
        var pr, fixMatch;
        if (err) {
            return callback(err);
        }

        if (prs.total_count ==0) {
            // No PR for this commit, so what's the point?
            response.description = 'No PR for commit.';
            return callback(null, response);
        }

        if (prs.total_count > 1) {
            // What to do?
            log.warn('Found a SHA linked to more than one PR!');
            console.log(prs.items);
        }

        pr = prs.items[0];
        fixMatch = hasFixLinkToIssue(pr.body);
        if (fixMatch) {
            response.state = 'success';
            response.description = 'PR is properly linked to an issue';
        }
        callback(null, response);
    });
}

module.exports.validate = validator;
module.exports.name = NAME;
<commit_msg>Preventing PR authors from tricking fixes-issue validator by linking PR to itself.<commit_after>var fixesNumberRegex =
        /fixes:? #[\d]*/i
  , fixesUrlRegex =
        /fixes:? https?:\/\/github.com\/([\da-z\.-]+)\/([\da-z\.-]+)\/issues\/\d{1,10}/i
  , log = require('../utils/logger').logger
  , NAME = 'Fixes Issue Validator'
  ;

function hasFixLinkToIssue(prNumber, text) {
    var numberMatch, urlMatch;
    if (! text) return false;
    numberMatch = text.match(fixesNumberRegex);
    console.log(numberMatch);
    urlMatch = text.match(fixesUrlRegex);
    console.log(urlMatch);
    // Make sure those sneaky contributors aren't linking to the PR itself.
    if (numberMatch && numberMatch[0].indexOf(prNumber) > -1) {
        numberMatch = false;
    }
    if (urlMatch && urlMatch[0].indexOf(prNumber) > -1) {
        urlMatch = false;
    }
    return (numberMatch || urlMatch);
}

function validator(sha, githubUser, repoClient, callback) {
    var searchString = sha + '+state:open'
      , response = {
          state: 'failure'
        , description: 'This PR must be linked to an issue.'
        , target_url: 'https://github.com/numenta/nupic/wiki/Development-Process'
      };
    log.info('Validating that PR fixes an issue');
    // If this PR was created by this server using the ci account, we'll
    // automatically approve it.
    if (githubUser == 'numenta-ci') {
        response.state = 'success';
        response.description = 'This PR was created by nupic.tools.'
        return callback(null, response);
    }
    repoClient.searchIssues(searchString, function(err, prs) {
        var pr, fixMatch;
        if (err) {
            return callback(err);
        }

        if (prs.total_count ==0) {
            // No PR for this commit, so what's the point?
            response.description = 'No PR for commit.';
            return callback(null, response);
        }

        if (prs.total_count > 1) {
            // What to do?
            log.warn('Found a SHA linked to more than one PR!');
            console.log(prs.items);
        }

        pr = prs.items[0];
        fixMatch = hasFixLinkToIssue(pr.number, pr.body);
        if (fixMatch) {
            response.state = 'success';
            response.description = 'PR is properly linked to an issue';
        }
        callback(null, response);
    });
}

module.exports.validate = validator;
module.exports.name = NAME;
<|endoftext|>


<commit_before>define('views/generic-form', [
        '/third-party/ladda-bootstrap/dist/ladda.min.js',
        '/third-party/bootstrap-datepicker/js/bootstrap-datepicker.js',
        '/third-party/backbone-forms/distribution/adapters/backbone.bootstrap-modal.js',
        '/third-party/bs-fancyfile/js/bootstrap-fancyfile.min.js',
        '/third-party/ckeditor/ckeditor.js',
        '/third-party/twitter-bootstrap-typeahead/js/bootstrap-typeahead.js',

        '/backbone-forms/editors/list.js',
        '/backbone-forms/editors/file.js',
        '/backbone-forms/editors/image.js',
        '/backbone-forms/editors/object-id.js',
        '/backbone-forms/editors/ckeditor.js',
        '/backbone-forms/editors/datepicker.js',

        '/third-party/backbone-forms/distribution/templates/bootstrap3.js',
    ], function (Ladda) {

    return Backbone.View.extend({

        events: {
            'click .submit': 'submit',
            'click .remove': 'remove',
        },

        initialize: function (options) {
            var instance = this;

            instance.collectionName = options.collectionName;
            instance.objectId = options.objectId;

            instance.setElement($('#form-controls').get(0));

            require([
                'model/' + instance.collectionName,
                'form/' + instance.collectionName,
                'json!/config/' + instance.collectionName + '.json',
                'json!/api/' + instance.collectionName + '/' + (instance.objectId||'default'),
                ], function (Model, Form, config, modelData) {

                instance.config = config;
                instance.model = new Model(modelData);
                instance.form = new Form({
                    model: instance.model,
                    fieldsets: instance.config.fieldsets,
                    schema: Form.prototype.schema // force the schema against the model one
                });

                $('#collection-form').html(instance.form.render().$el);
                instance.renderFormControls();
                if (instance.objectId) {
                    instance.renderRevisionsControls();
                }

                instance.applyRevisionsPatch();

            });

            if (instance.$el.data('readonly')) {
                $('.submit, .remove', instance.$el).attr('disabled', 'disabled');
            }
        },

        render: function () {
        },

        renderFormControls: function () {
            var instance = this;
            var controlsHtml = '';
            if (instance.objectId && $('[data-permission-d]').size()) {
                controlsHtml +='<button class="btn btn-danger btn-lg remove ladda-button" data-style="expand-right">Delete</button>';
            }
            if ($('[data-permission-u], [data-permission-c]').size()) {
                controlsHtml += '<button class="btn btn-primary btn-lg submit ladda-button" data-style="expand-right">'
                    + (instance.objectId ? 'Save' : 'Create') + '</button>';
            }
            if (!instance.model.isNew()) {
                controlsHtml += 'Preview';
            }
            instance.$el.html(controlsHtml);
            instance.laddaSubmit = Ladda.create(instance.$('.submit').get(0));
            instance.laddaRemove = Ladda.create(instance.$('.remove').get(0));
        },

        renderRevisionsControls: function () {
            var instance = this;
            $('[data-collection-tostringfield]').html(instance.model.toString());
            $('[data-created]').html(humaneDate(instance.model.get(instance.config.createdField.key)));
            $('[data-updated]').html(humaneDate(instance.model.get(instance.config.updatedField.key)));

            // TODO convert revisionsModel into a collection and handle it with async events
            require([
                'views/generic-form-revisions',
                'json!/api/' + instance.collectionName + '/' + instance.objectId + '/revisions?t=' + Math.random()
                ], function (GenericFormRevisionsView, revisionsModel) {

                instance.revisionsView = new GenericFormRevisionsView({
                    model: instance.model,
                    revisionsModel: revisionsModel
                });
                instance.revisionsView.render();
            });
        },

        submit: function (event) {
            var instance = this;
            var err;
            if (!(err = instance.form.commit())) {
                instance.laddaSubmit.start();
                console.log('model submitted', instance.form.model.toJSON());
                var isNew = instance.model.isNew();
                instance.model.save({}, {
                    success: function () {
                        instance.laddaSubmit.stop();
                        alertify.success('success!');
                        if (isNew) {
                            document.location.href = '/edit/' + instance.collectionName + '/' + instance.model.id;
                        } else {
                            // TODO refresh collection
                            instance.revisionsView && instance.revisionsView.render(); // repaint view
                            $('[data-updated]').html(humaneDate(instance.model.get(instance.config.updatedField.key)));
                        }
                    },
                    error: function () {
                        instance.laddaSubmit.stop();
                        alertify.error('an error has ocurred! :S');
                    }
                });
            } else {
                instance.laddaSubmit.stop();
                console.log('model err', err);
                alertify.error('validation failed, look at the console for details.');
            }
        },

        remove: function (event) {
            var instance = this;
            instance.laddaRemove.start();
            alertify.confirm('Are you sure you want to delete this '+ instance.collectionName, function (ok) {
                instance.laddaRemove.stop();
                if (ok) {
                    instance.model.destroy({
                        success: function () {
                            document.location.href = '/search/' + instance.collectionName;
                        }
                    });
                }
            });
        },

        /* adds compatibility to form refreshing on model change */
        applyRevisionsPatch: function () {
            var instance = this;
            _(instance.config.schema).each(function (schema, prop) {
                instance.model.on('change:' + prop, function(model, val) {
                    var obj = {};
                    if (instance.config.schema[prop].type === 'Date') {
                        val = new Date(val);
                    }
                    obj[prop] = val;
                    instance.form.setValue(obj);
                    instance.notifyRevisionChanges(model, prop);
                });
            });
        },

        notifyRevisionChanges: function (changingModel, prop) {
            var instance = this,
                fieldName = instance.config.schema[prop].title,
                fieldType = instance.config.schema[prop].type,
                valFrom = changingModel.previous(prop),
                valTo = changingModel.get(prop);

            if ('List' === fieldType) {
                valFrom = valFrom.length + ' elements';
                valTo = valTo.length + ' elements';
            }

            if ('Datepicker' === fieldType) {
                valFrom = (new Date(valFrom)).toLocaleDateString();
                valTo = (new Date(valTo)).toLocaleDateString();
            }

            if ('Date' === fieldType) {
                valFrom = (new Date(valFrom)).toTimeString();
                valTo = (new Date(valTo)).toTimeString();
            }

            if ('File' === fieldType || 'Image' === fieldType) {
                valFrom = _.isObject(valFrom) ? valFrom._id : valFrom;
                valTo = _.isObject(valTo) ? valTo._id : valTo;
            }

            if (valFrom !== valTo) {
                alertify.success('' + fieldName + '
 ' + valFrom + '  ' + valTo + '');
            }

        }
    });

});
<commit_msg>revisions list update<commit_after>define('views/generic-form', [
        '/third-party/ladda-bootstrap/dist/ladda.min.js',
        '/third-party/bootstrap-datepicker/js/bootstrap-datepicker.js',
        '/third-party/backbone-forms/distribution/adapters/backbone.bootstrap-modal.js',
        '/third-party/bs-fancyfile/js/bootstrap-fancyfile.min.js',
        '/third-party/ckeditor/ckeditor.js',
        '/third-party/twitter-bootstrap-typeahead/js/bootstrap-typeahead.js',

        '/backbone-forms/editors/list.js',
        '/backbone-forms/editors/file.js',
        '/backbone-forms/editors/image.js',
        '/backbone-forms/editors/object-id.js',
        '/backbone-forms/editors/ckeditor.js',
        '/backbone-forms/editors/datepicker.js',

        '/third-party/backbone-forms/distribution/templates/bootstrap3.js',
    ], function (Ladda) {

    return Backbone.View.extend({

        events: {
            'click .submit': 'submit',
            'click .remove': 'remove',
        },

        initialize: function (options) {
            var instance = this;

            instance.collectionName = options.collectionName;
            instance.objectId = options.objectId;

            instance.setElement($('#form-controls').get(0));

            require([
                'model/' + instance.collectionName,
                'form/' + instance.collectionName,
                'json!/config/' + instance.collectionName + '.json',
                'json!/api/' + instance.collectionName + '/' + (instance.objectId||'default'),
                ], function (Model, Form, config, modelData) {

                instance.config = config;
                instance.model = new Model(modelData);
                instance.form = new Form({
                    model: instance.model,
                    fieldsets: instance.config.fieldsets,
                    schema: Form.prototype.schema // force the schema against the model one
                });

                $('#collection-form').html(instance.form.render().$el);
                instance.renderFormControls();
                if (instance.objectId) {
                    instance.renderRevisionsControls();
                }

                instance.applyRevisionsPatch();

            });

            if (instance.$el.data('readonly')) {
                $('.submit, .remove', instance.$el).attr('disabled', 'disabled');
            }
        },

        render: function () {
        },

        renderFormControls: function () {
            var instance = this;
            var controlsHtml = '';
            if (instance.objectId && $('[data-permission-d]').size()) {
                controlsHtml +='<button class="btn btn-danger btn-lg remove ladda-button" data-style="expand-right">Delete</button>';
            }
            if ($('[data-permission-u], [data-permission-c]').size()) {
                controlsHtml += '<button class="btn btn-primary btn-lg submit ladda-button" data-style="expand-right">'
                    + (instance.objectId ? 'Save' : 'Create') + '</button>';
            }
            if (!instance.model.isNew()) {
                controlsHtml += 'Preview';
            }
            instance.$el.html(controlsHtml);
            instance.laddaSubmit = Ladda.create(instance.$('.submit').get(0));
            instance.laddaRemove = Ladda.create(instance.$('.remove').get(0));
        },

        renderRevisionsControls: function () {
            var instance = this;
            $('[data-collection-tostringfield]').html(instance.model.toString());
            $('[data-created]').html(humaneDate(instance.model.get(instance.config.createdField.key)));
            $('[data-updated]').html(humaneDate(instance.model.get(instance.config.updatedField.key)));

            // TODO convert revisionsModel into a collection and handle it with async events
            require([
                'views/generic-form-revisions',
                'json!/api/' + instance.collectionName + '/' + instance.objectId + '/revisions?t=' + Math.random()
                ], function (GenericFormRevisionsView, revisionsModel) {

                instance.revisionsView = new GenericFormRevisionsView({
                    model: instance.model,
                    revisionsModel: revisionsModel
                });
                instance.revisionsView.render();
            });
        },

        submit: function (event) {
            var instance = this;
            var err;
            if (!(err = instance.form.commit())) {
                instance.laddaSubmit.start();
                console.log('model submitted', instance.form.model.toJSON());
                var isNew = instance.model.isNew();
                instance.model.save({}, {
                    success: function () {
                        instance.laddaSubmit.stop();
                        alertify.success('success!');
                        if (isNew) {
                            document.location.href = '/edit/' + instance.collectionName + '/' + instance.model.id;
                        } else {
                            if (instance.revisionsView) {
                                require([
                                    'json!/api/' + instance.collectionName + '/' + instance.objectId + '/revisions?t=' + Math.random()
                                    ], function (revisionsModel) {
                                    instance.revisionsView.revisionsModel = revisionsModel;
                                    instance.revisionsView.render(); // repaint view
                                });
                            }
                            $('[data-updated]').html(humaneDate(instance.model.get(instance.config.updatedField.key)));
                        }
                    },
                    error: function () {
                        instance.laddaSubmit.stop();
                        alertify.error('an error has ocurred! :S');
                    }
                });
            } else {
                instance.laddaSubmit.stop();
                console.log('model err', err);
                alertify.error('validation failed, look at the console for details.');
            }
        },

        remove: function (event) {
            var instance = this;
            instance.laddaRemove.start();
            alertify.confirm('Are you sure you want to delete this '+ instance.collectionName, function (ok) {
                instance.laddaRemove.stop();
                if (ok) {
                    instance.model.destroy({
                        success: function () {
                            document.location.href = '/search/' + instance.collectionName;
                        }
                    });
                }
            });
        },

        /* adds compatibility to form refreshing on model change */
        applyRevisionsPatch: function () {
            var instance = this;
            _(instance.config.schema).each(function (schema, prop) {
                instance.model.on('change:' + prop, function(model, val) {
                    var obj = {};
                    if (instance.config.schema[prop].type === 'Date') {
                        val = new Date(val);
                    }
                    obj[prop] = val;
                    instance.form.setValue(obj);
                    instance.notifyRevisionChanges(model, prop);
                });
            });
        },

        notifyRevisionChanges: function (changingModel, prop) {
            var instance = this,
                fieldName = instance.config.schema[prop].title,
                fieldType = instance.config.schema[prop].type,
                valFrom = changingModel.previous(prop),
                valTo = changingModel.get(prop);

            if ('List' === fieldType) {
                valFrom = valFrom.length + ' elements';
                valTo = valTo.length + ' elements';
            }

            if ('Datepicker' === fieldType) {
                valFrom = (new Date(valFrom)).toLocaleDateString();
                valTo = (new Date(valTo)).toLocaleDateString();
            }

            if ('Date' === fieldType) {
                valFrom = (new Date(valFrom)).toTimeString();
                valTo = (new Date(valTo)).toTimeString();
            }

            if ('File' === fieldType || 'Image' === fieldType) {
                valFrom = _.isObject(valFrom) ? valFrom._id : valFrom;
                valTo = _.isObject(valTo) ? valTo._id : valTo;
            }

            if (valFrom !== valTo) {
                alertify.success('' + fieldName + '
 ' + valFrom + '  ' + valTo + '');
            }

        }
    });

});
<|endoftext|>


<commit_before>'use strict';

var knex = require('knex');
var async = require('async');
var _ = require('lodash');

function KnexDBBackend(db){
  this.db = db;
}

var bucketNumbers = {
  'meta': 0,
  'resources': 1,
  'parents': 2,
  'users': 3,
  'permissions': 4
};

KnexDBBackend.prototype = {

  begin: function() {
    return {promise: this.db.raw('savepoint service_transaction')};
  },

  add: function(transaction, bucket, key, values) {
    var _this = this;
    transaction.promise = transaction.promise.then(function() {
      _this.db('acl').first('id', 'key', 'value')
        .where({bucket: bucket, key: key})
        .then(function(found) {
          var data = (found !== undefined) ? JSON.parse(found) : {};
          if (found !== undefined) {
            _this.db('acl').where('id', '=', found.id).update({values: _.union(values, data)});
          } else {
            _this.db('acl').insert({bucket: bucket, key: key, values: _.union(values, data)})
          }
        });
      });
  },

  clean: function(callback) {
    var _this = this;
    _this.db.truncate('acl')
      .then(function() {
        return callback(null);
      }).catch(function(err) {
        return callback(err);
      });
  },

  end: function(transaction, callback){
    var _this = this;
    transaction.promise.then(function() {
      _this.db.raw('release savepoint service_transaction');
      callback(null);
    }).catch(function(err) {
      _this.db.raw('rollback to service_transaction').then(function() {
        _this.db.raw('release savepoint service_transaction')
      });
      callback(err);
    });
  },

  get: function(bucket, key, callback) {
    if (bucket.indexOf('allows') != -1) {
      key = bucket;
      bucket = bucketNumbers['permissions'];
    }
    this.db.first('key', 'value')
      .from('acl')
      .where({'bucket': bucket, 'key': key})
      .then(function(value) {
        console.log("Got value", value);
        callback(null, value);
      }).catch(function(err) {
        console.log("Got err", err);
        callback(err, null);
      });
  },

  union: function() {
    console.log("Error: not yet implemented");
  },

  setup: function(callback) {
    var _this = this;
    _this.db.schema.hasTable('acl').then(function(exists) {
      if (!exists) {
        return _this.db.schema.createTable('acl', function(table) {
          table.increments('id');
          table.integer('bucket').notNullable();
          table.string('key', 24).notNullable();
          table.text('values', 'longtext').notNullable();
          table.unique(['bucket', 'key']);
        });
      }
    }).then(function() {
      return callback(null);
    }).catch(function(err) {
      return callback(err);
    });
  },

  teardown: function(callback) {
    this.db.schema.dropTable('acl')
      .then(function() {
        return callback(null);
      }).catch(function(err) {
        return callback(err);
    });
  }
}

exports = module.exports = KnexDBBackend;<commit_msg>Defensive errors for now<commit_after>'use strict';

var knex = require('knex');
var async = require('async');
var _ = require('lodash');

function KnexDBBackend(db){
  this.db = db;
}

var bucketNumbers = {
  'meta': 0,
  'resources': 1,
  'parents': 2,
  'users': 3,
  'permissions': 4
};

KnexDBBackend.prototype = {

  begin: function() {
    return {promise: this.db.raw('savepoint service_transaction')};
  },

  add: function(transaction, bucket, key, values) {
    var _this = this;
    transaction.promise = transaction.promise.then(function() {
      _this.db('acl').first('id', 'key', 'value')
        .where({bucket: bucket, key: key})
        .then(function(found) {
          var data = (found !== undefined) ? JSON.parse(found) : {};
          if (found !== undefined) {
            _this.db('acl').where('id', '=', found.id).update({values: _.union(values, data)});
          } else {
            _this.db('acl').insert({bucket: bucket, key: key, values: _.union(values, data)})
          }
        });
      });
  },

  del: function(transaction, bucket, keys) {
    console.log("del: not yet implemented", bucket, keys);
  },

  remove: function(transaction, bucket, key, values) {
    console.log("remove: not yet implemented", bucket, keys);
  },

  clean: function(callback) {
    var _this = this;
    _this.db.truncate('acl')
      .then(function() {
        return callback(null);
      }).catch(function(err) {
        return callback(err);
      });
  },

  end: function(transaction, callback){
    var _this = this;
    transaction.promise.then(function() {
      _this.db.raw('release savepoint service_transaction');
      callback(null);
    }).catch(function(err) {
      _this.db.raw('rollback to service_transaction').then(function() {
        _this.db.raw('release savepoint service_transaction')
      });
      callback(err);
    });
  },

  get: function(bucket, key, callback) {
    if (bucket.indexOf('allows') != -1) {
      key = bucket;
      bucket = bucketNumbers['permissions'];
    }
    this.db.first('key', 'value')
      .from('acl')
      .where({'bucket': bucket, 'key': key})
      .then(function(value) {
        console.log("Got value", value);
        callback(null, value);
      }).catch(function(err) {
        console.log("Got err", err);
        callback(err, null);
      });
  },

  union: function() {
    console.log("Error: union not yet implemented");
  },

  setup: function(callback) {
    var _this = this;
    _this.db.schema.hasTable('acl').then(function(exists) {
      if (!exists) {
        return _this.db.schema.createTable('acl', function(table) {
          table.increments('id');
          table.integer('bucket').notNullable();
          table.string('key', 24).notNullable();
          table.text('values', 'longtext').notNullable();
          table.unique(['bucket', 'key']);
        });
      }
    }).then(function() {
      return callback(null);
    }).catch(function(err) {
      return callback(err);
    });
  },

  teardown: function(callback) {
    this.db.schema.dropTable('acl')
      .then(function() {
        return callback(null);
      }).catch(function(err) {
        return callback(err);
    });
  }
}

exports = module.exports = KnexDBBackend;<|endoftext|>


<commit_before>/*
 * express-lingua
 * A i18n middleware for the Express.js framework.
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2011, André König (andre.koenig -[at]- gmail [*dot*] com)
 *
 */

//
//
// summary:
//     A class associating language tags with quality values
//
// description:
//     A language tag identifies a language as described at
//     <http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.10>
//     (e.g. 'en-us'). A quality value (qvalue) determines the
//     relative degree of preference for a language tag . Tags and
//     qvalues are present in the HTTP Accept-Language header
//     (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4)
//     (e.g. 'Accept-Language: en-gb,en-us;q=0.7,en;q=0.3')
//
module.exports = function() {

    function LanguageTags() {
        this.tagQvalues = {}; // associates 'q' values with language tags
    }

    //
    //
    // summary:
    //     Associate a tag with a qvalue
    //
    // description:
    //     More than one tag can be assigned to the same qvalue.
    //
    LanguageTags.prototype.addTag = function(tag, qvalue) {
        try {
            this.tagQvalues[qvalue].push(tag);
        } catch (e) {
            if (!(e instanceof TypeError)) {
                throw e;
            }
            this.tagQvalues[qvalue] = [tag];
        }
    };

    //
    //
    // summary:
    //     Associate multiple tags with a qvalue
    //
    // description:
    //     A convenience method to save calling LanguageTags.addTag() multiple
    //     times.
    //
    LanguageTags.prototype.addTags = function(tags, qvalue) {
        try {
            this.tagQvalues[qvalue].push.apply(this.tagQvalues[qvalue], tag);
        } catch (e) {
            if (!(e instanceof TypeError)) {
                throw e;
            }
            this.tagQvalues[qvalue] = tags;
        }
    };

    //
    //
    // summary:
    //     Get a list of all tags
    //
    // description:
    //     The list of tags is ordered by the associated tag qvalue in
    //     descending order.
    //
    LanguageTags.prototype.getTags = function() {
        // get the reverse ordered list of qvalues e.g. -> [1, 0.8, 0.5, 0.3]
        var qvalues = [];
        var qvalue;
        for (qvalue in this.tagQvalues) {
            if (this.tagQvalues.hasOwnProperty(qvalue)) {
                qvalues.push(qvalue);
            }
        }
        qvalues = qvalues.sort().reverse();

        // add the tags to the tag list, ordered by qvalue
        var tags = [];
        var self = this;
        qvalues.forEach(function(qvalue) {
            tags.push.apply(tags, self.tagQvalues[qvalue]);
        });

        return tags;
    };

    return LanguageTags;
};<commit_msg>Fixed problem with the constructor in the languagetags.<commit_after>/*
 * express-lingua
 * A i18n middleware for the Express.js framework.
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2011, André König (andre.koenig -[at]- gmail [*dot*] com)
 *
 */

//
//
// summary:
//     A class associating language tags with quality values
//
// description:
//     A language tag identifies a language as described at
//     <http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.10>
//     (e.g. 'en-us'). A quality value (qvalue) determines the
//     relative degree of preference for a language tag . Tags and
//     qvalues are present in the HTTP Accept-Language header
//     (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4)
//     (e.g. 'Accept-Language: en-gb,en-us;q=0.7,en;q=0.3')
//
module.exports = function() {

    var LanguageTags = function() {
        this.tagQvalues = {}; // associates 'q' values with language tags
    }

    //
    //
    // summary:
    //     Associate a tag with a qvalue
    //
    // description:
    //     More than one tag can be assigned to the same qvalue.
    //
    LanguageTags.prototype.addTag = function(tag, qvalue) {
        try {
            this.tagQvalues[qvalue].push(tag);
        } catch (e) {
            if (!(e instanceof TypeError)) {
                throw e;
            }
            this.tagQvalues[qvalue] = [tag];
        }
    };

    //
    //
    // summary:
    //     Associate multiple tags with a qvalue
    //
    // description:
    //     A convenience method to save calling LanguageTags.addTag() multiple
    //     times.
    //
    LanguageTags.prototype.addTags = function(tags, qvalue) {
        try {
            this.tagQvalues[qvalue].push.apply(this.tagQvalues[qvalue], tag);
        } catch (e) {
            if (!(e instanceof TypeError)) {
                throw e;
            }
            this.tagQvalues[qvalue] = tags;
        }
    };

    //
    //
    // summary:
    //     Get a list of all tags
    //
    // description:
    //     The list of tags is ordered by the associated tag qvalue in
    //     descending order.
    //
    LanguageTags.prototype.getTags = function() {
        // get the reverse ordered list of qvalues e.g. -> [1, 0.8, 0.5, 0.3]
        var qvalues = [];
        var qvalue;
        for (qvalue in this.tagQvalues) {
            if (this.tagQvalues.hasOwnProperty(qvalue)) {
                qvalues.push(qvalue);
            }
        }
        qvalues = qvalues.sort().reverse();

        // add the tags to the tag list, ordered by qvalue
        var tags = [];
        var self = this;
        qvalues.forEach(function(qvalue) {
            tags.push.apply(tags, self.tagQvalues[qvalue]);
        });

        return tags;
    };

    return LanguageTags;
}();<|endoftext|>


<commit_before>(function($){
	if (window.wikiLabels) {
		throw "wikiLabels is already defined!  Exiting.";
	}
	window.wikiLabels = {
		config: {
			serverRoot: "//ores.wmflabs.org/labels",
			prefix: "wikilabels-",
			messages: {
				en: {
					'date-format': "%Y-%m-%d",
					'Review': 'Review',
					'Workset': 'Workset',
					'Save': 'Save',
					'request workset': 'request workset',
					'connect to server': 'connect to server',
					'Campaigns': 'Campaigns',
					'Workset complete!': 'Workset complete!',
					'Submit label': 'Submit label',
					'Request new workset': 'Request new workset',
					'Diff for revision $1': 'Diff for revision $1',
					'No difference': 'No difference', // between revisions
					'review': 'review', // 'review' a workset
					'open': 'open', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' not completed.  Submit anyway?',
					'fullscreen': 'fullscreen'
				},
				pt: {
					'date-format': "%d-%m-%Y",
					'Review': 'Revisar',
					'Workset': 'Grupo',
					'Save': 'Salvar',
					'request workset': 'solicitar um grupo de tarefas',
					'connect to server': 'conectar ao servidor',
					'Campaigns': 'Campanhas',
					'Workset complete!': 'Conjunto de trabalho concluído!',
					'Submit label': 'Submeter o rótulo',
					'Request new workset': 'Solicitar um novo grupo de tarefas',
					'Diff for revision $1': 'Diferenças para a revisão $1',
					'No difference': 'Nenhuma diferença', // between revisions
					'review': 'revisar', // 'review' a workset
					'open': 'abrir', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' não foi concluído. Submeter mesmo assim?',
					'fullscreen': 'tela cheia'
				},
				tr: {
					'date-format': "%Y-%m-%d",
					'Review': 'İncele',
					'Workset': 'İş kümesi',
					'Save': 'Kaydet',
					'request workset': 'iş kümesi iste',
					'connect to server': 'sunucuya bağlan',
					'Campaigns': 'Girişimler',
					'Workset complete!': 'İş kümesi tamamlandı!',
					'Submit label': 'Etiketi sun',
					'Request new workset': 'Yeni iş kümesi iste',
					'Diff for revision $1': '$1 değisikliği için diff',
					'No difference': 'Fark yoktur', // between revisions
					'review': 'incele', // 'review' a workset
					'open': 'açık', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' tamamlanmadı. Genede sunulsun mu?',
					'fullscreen': 'tam ekran'
				},
				az: {

				},
				fa: {
					'date-format': "%Y-%m-%d",
					'Review': 'بازبینی',
					'Workset': 'مجموعه کاری',
					'Save': 'ذخیره',
					'request workset': 'درخواست یک مجموعه',
					'connect to server': 'اتصال به سرور',
					'Campaigns': 'کمپین‌ها',
					'Workset complete!': 'مجموعه کامل شد!',
					'Submit label': 'برچسب را بفرست',
					'Request new workset': 'درخواست یک مجموعه جدید',
					'Diff for revision $1': 'تغییرات برای ویرایش $1',
					'No difference': 'بدون تغییر', // between revisions
					'review': 'بازبینی', // 'review' a workset
					'open': 'باز', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' باز است. آیا مطمئنید؟',
					'fullscreen': 'تمام صفحه'
				},

				fr: {
					'date-format': "%d-%m-%Y",
					'Review': 'Relecture',
					'Workset': 'Ensemble de données',
					'Save': 'Sauvegarder',
					'request workset': 'Demander l\'ensemble de données',
					'connect to server': 'Connecter au serveur',
					'Campaigns': 'Campagnes',
					'Workset complete!': 'Ensemble de données terminé !',
					'Submit label': 'Soumettre l\'étiquette',
					'Request new workset': 'Demander un nouvel ensemble de données',
					'Diff for revision $1': 'Différence pour la révision $1',
					'No difference': 'Aucune différence', // between revisions
					'review': 'Relecture', // 'review' a workset
					'open': 'Ouvrir', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' incomplet.  Soumettre quand même ?',
					'fullscreen': 'Plein écran'
				},
				es: {
					'date-format': "%d-%m-%Y",
					'Review': 'Revisar',
					'Workset':'Grupo',
					'Save': 'Guardar',
					'request workset': 'Solicitar grupo de tareas',
					'connect to server': 'Conectar al servidor',
					'Campaigns': 'Campañas',
					'Workset complete!': '¡Grupo de tareas finalizado!',
					'Submit label': 'Entrar etiqueta',
					'Request new workset': 'Solicitar nuevo grupo de tareas',
					'Diff for revision $1': 'Revisar diferencia $1',
					'No difference': 'No hay diferencia', // between revisions
					'review': 'revisar', // 'review' a workset
					'open': 'abrir', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' incompleto.  ¿Entrar de todas formas?',
					'fullscreen': 'Pantalla completa'
				},
				uk: {
					'date-format': "%Y-%m-%d",
					'Review': 'Перевірка',
					'Workset': 'Робочий набір',
					'Save': 'Зберегти',
					'request workset': 'запитати робочий набір',
					'connect to server': 'під\'єднатись до сервера',
					'Campaigns': 'Кампанії',
					'Workset complete!': 'Робочий набір готовий!',
					'Submit label': 'Надіслати мітку',
					'Request new workset': 'Запитати новий робочий набір',
					'Diff for revision $1': 'Різниця для версії $1',
					'No difference': 'Немає різниці', // between revisions
					'review': 'перевірити', // 'review' a workset
					'open': 'відкрити', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' не готовий.  Усе одно надіслати?',
					'fullscreen': 'повний екран'
				},
				nl: {
					'date-format': "%d-%m-%Y",
					'Review': 'Beoordelen',
					'Workset': 'Werkset',
					'Save': 'Opslaan',
					'request workset': 'werkset opvragen',
					'connect to server': 'verbinden met server',
					'Campaigns': 'Campagnes',
					'Workset complete!': 'Werkset voltooid!',
					'Submit label': 'Label verzenden',
					'Request new workset': 'Nieuwe werkset opvragen',
					'Diff for revision $1': 'Verschil voor bewerking $1',
					'No difference': 'Geen verschil', // between revisions
					'review': 'beoordelen', // 'review' a workset
					'open': 'openen', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' niet voltooid.  Toch verzenden?',
					'fullscreen': 'fullscreen'
				}
			}
		}
	};
})(jQuery);
<commit_msg>add translation for Indonesian<commit_after>(function($){
	if (window.wikiLabels) {
		throw "wikiLabels is already defined!  Exiting.";
	}
	window.wikiLabels = {
		config: {
			serverRoot: "//ores.wmflabs.org/labels",
			prefix: "wikilabels-",
			messages: {
				en: {
					'date-format': "%Y-%m-%d",
					'Review': 'Review',
					'Workset': 'Workset',
					'Save': 'Save',
					'request workset': 'request workset',
					'connect to server': 'connect to server',
					'Campaigns': 'Campaigns',
					'Workset complete!': 'Workset complete!',
					'Submit label': 'Submit label',
					'Request new workset': 'Request new workset',
					'Diff for revision $1': 'Diff for revision $1',
					'No difference': 'No difference', // between revisions
					'review': 'review', // 'review' a workset
					'open': 'open', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' not completed.  Submit anyway?',
					'fullscreen': 'fullscreen'
				},
				pt: {
					'date-format': "%d-%m-%Y",
					'Review': 'Revisar',
					'Workset': 'Grupo',
					'Save': 'Salvar',
					'request workset': 'solicitar um grupo de tarefas',
					'connect to server': 'conectar ao servidor',
					'Campaigns': 'Campanhas',
					'Workset complete!': 'Conjunto de trabalho concluído!',
					'Submit label': 'Submeter o rótulo',
					'Request new workset': 'Solicitar um novo grupo de tarefas',
					'Diff for revision $1': 'Diferenças para a revisão $1',
					'No difference': 'Nenhuma diferença', // between revisions
					'review': 'revisar', // 'review' a workset
					'open': 'abrir', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' não foi concluído. Submeter mesmo assim?',
					'fullscreen': 'tela cheia'
				},
				tr: {
					'date-format': "%Y-%m-%d",
					'Review': 'İncele',
					'Workset': 'İş kümesi',
					'Save': 'Kaydet',
					'request workset': 'iş kümesi iste',
					'connect to server': 'sunucuya bağlan',
					'Campaigns': 'Girişimler',
					'Workset complete!': 'İş kümesi tamamlandı!',
					'Submit label': 'Etiketi sun',
					'Request new workset': 'Yeni iş kümesi iste',
					'Diff for revision $1': '$1 değisikliği için diff',
					'No difference': 'Fark yoktur', // between revisions
					'review': 'incele', // 'review' a workset
					'open': 'açık', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' tamamlanmadı. Genede sunulsun mu?',
					'fullscreen': 'tam ekran'
				},
				az: {

				},
				fa: {
					'date-format': "%Y-%m-%d",
					'Review': 'بازبینی',
					'Workset': 'مجموعه کاری',
					'Save': 'ذخیره',
					'request workset': 'درخواست یک مجموعه',
					'connect to server': 'اتصال به سرور',
					'Campaigns': 'کمپین‌ها',
					'Workset complete!': 'مجموعه کامل شد!',
					'Submit label': 'برچسب را بفرست',
					'Request new workset': 'درخواست یک مجموعه جدید',
					'Diff for revision $1': 'تغییرات برای ویرایش $1',
					'No difference': 'بدون تغییر', // between revisions
					'review': 'بازبینی', // 'review' a workset
					'open': 'باز', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' باز است. آیا مطمئنید؟',
					'fullscreen': 'تمام صفحه'
				},

				fr: {
					'date-format': "%d-%m-%Y",
					'Review': 'Relecture',
					'Workset': 'Ensemble de données',
					'Save': 'Sauvegarder',
					'request workset': 'Demander l\'ensemble de données',
					'connect to server': 'Connecter au serveur',
					'Campaigns': 'Campagnes',
					'Workset complete!': 'Ensemble de données terminé !',
					'Submit label': 'Soumettre l\'étiquette',
					'Request new workset': 'Demander un nouvel ensemble de données',
					'Diff for revision $1': 'Différence pour la révision $1',
					'No difference': 'Aucune différence', // between revisions
					'review': 'Relecture', // 'review' a workset
					'open': 'Ouvrir', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' incomplet.  Soumettre quand même ?',
					'fullscreen': 'Plein écran'
				},
				es: {
					'date-format': "%d-%m-%Y",
					'Review': 'Revisar',
					'Workset':'Grupo',
					'Save': 'Guardar',
					'request workset': 'Solicitar grupo de tareas',
					'connect to server': 'Conectar al servidor',
					'Campaigns': 'Campañas',
					'Workset complete!': '¡Grupo de tareas finalizado!',
					'Submit label': 'Entrar etiqueta',
					'Request new workset': 'Solicitar nuevo grupo de tareas',
					'Diff for revision $1': 'Revisar diferencia $1',
					'No difference': 'No hay diferencia', // between revisions
					'review': 'revisar', // 'review' a workset
					'open': 'abrir', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' incompleto.  ¿Entrar de todas formas?',
					'fullscreen': 'Pantalla completa'
				},
				uk: {
					'date-format': "%Y-%m-%d",
					'Review': 'Перевірка',
					'Workset': 'Робочий набір',
					'Save': 'Зберегти',
					'request workset': 'запитати робочий набір',
					'connect to server': 'під\'єднатись до сервера',
					'Campaigns': 'Кампанії',
					'Workset complete!': 'Робочий набір готовий!',
					'Submit label': 'Надіслати мітку',
					'Request new workset': 'Запитати новий робочий набір',
					'Diff for revision $1': 'Різниця для версії $1',
					'No difference': 'Немає різниці', // between revisions
					'review': 'перевірити', // 'review' a workset
					'open': 'відкрити', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' не готовий.  Усе одно надіслати?',
					'fullscreen': 'повний екран'
				},
				nl: {
					'date-format': "%d-%m-%Y",
					'Review': 'Beoordelen',
					'Workset': 'Werkset',
					'Save': 'Opslaan',
					'request workset': 'werkset opvragen',
					'connect to server': 'verbinden met server',
					'Campaigns': 'Campagnes',
					'Workset complete!': 'Werkset voltooid!',
					'Submit label': 'Label verzenden',
					'Request new workset': 'Nieuwe werkset opvragen',
					'Diff for revision $1': 'Verschil voor bewerking $1',
					'No difference': 'Geen verschil', // between revisions
					'review': 'beoordelen', // 'review' a workset
					'open': 'openen', // 'open' a workset
					'\'$1\' not completed.  Submit anyway?': '\'$1\' niet voltooid.  Toch verzenden?',
					'fullscreen': 'fullscreen'
				},
				id: {
						'date-format': "%d-%m-%Y",
						'Review': 'Tinjau',
						'Workset': 'Pekerjaan',
						'Save': 'Simpan',
						'request workset': 'minta pekerjaan',
						'connect to server': 'sambung ke server',
						'Campaigns': 'Kampanye',
						'Workset complete!': 'Pekerjaan selesai!',
						'Submit label': 'Kirim label',
						'Request new workset': 'Minta pekerjaan baru',
						'Diff for revision $1': 'Beda untuk revisi $1',
						'No difference': 'Tidak ada perbedaan', // between revisions
						'review': 'tinjau', // 'review' a workset
						'open': 'buka', // 'open' a workset
						'\'$1\' not completed.  Submit anyway?': '\'$1\' belum selesai. Lanjut mengirimkan?',
						'fullscreen': 'layar penuh'
					},
			}
		}
	};
})(jQuery);
<|endoftext|>


<commit_before>const tabs = require('sdk/tabs');
const qs = require('sdk/querystring');
const prefs = require('sdk/simple-prefs').prefs;
const store = require('sdk/simple-storage').storage;
const getVideoId = require('get-video-id');

const isAudio = require('./is-audio');
const windowUtils = require('./window-utils');
const getRandomId = require('./get-random-id');
const youtubeHelpers = require('./youtube-helpers');
const sendMetricsData = require('./send-metrics-data');
const getLocaleStrings = require('./get-locale-strings');

module.exports = launchVideo;

// Pass in a video URL as opts.src or pass in a video URL lookup function as opts.getUrlFn
function launchVideo(opts) {
  // UpdateWindow might create a new panel, so do the remaining launch work
  // asynchronously.
  windowUtils.updateWindow();
  windowUtils.whenReady(() => {
    const getUrlFn = opts.getUrlFn;
    const action = opts.action;

    delete opts.getUrlFn;
    delete opts.action;

    windowUtils.show();
    // send some initial data to open the loading view
    // before we fetch the media source
    windowUtils.send('set-video', opts = Object.assign({
      id: getRandomId(),
      width: prefs.width,
      height: prefs.height,
      videoId: getVideoId(opts.url) ? getVideoId(opts.url).id : '',
      strings: getLocaleStrings(opts.domain, (isAudio(opts.url))),
      tabId: tabs.activeTab.id,
      launchUrl: opts.url,
      currentTime: 0,
      playing: action === 'play',
      keyShortcutsEnabled: prefs['keyShortcutsEnabled'],
      confirm: false,
      confirmContent: '{}'
    }, opts));

    // YouTube playlist handling
    if (opts.domain === 'youtube.com' && !!~opts.url.indexOf('list')) {
      if (!!~opts.url.indexOf('watch?v')) {
        const parsed = qs.parse(opts.url.substr(opts.url.indexOf('?') + 1));
        youtubeHelpers.getPlaylistMeta({
          videoId: parsed.v,
          playlistId: parsed.list,
        }, (meta) => {
          opts.confirmContent = meta;
          opts.confirmContent.action = action;
          opts.confirmContent = JSON.stringify(opts.confirmContent);
          sendMetricsData({
            object: 'playlist',
            method: `launch:video:${action}`,
            domain: opts.domain
          });
          windowUtils.send('set-video', Object.assign(opts, {
            confirm: true,
            error: false,
            queue: JSON.stringify(store.queue),
            history: JSON.stringify(store.history)
          }));
        });
      } else {
        // only playlist handling
        const parsed = qs.parse(opts.url.substr(opts.url.indexOf('?') + 1));
        youtubeHelpers.getPlaylist({playlistId: parsed.list}, playlist => {
          if (action === 'play') {
            store.queue = playlist.concat(store.queue);
          } else store.queue = store.queue.concat(playlist);

          const response = {
            trackAdded: (action === 'add-to-queue') && (store.queue.length > 1),
            error: false,
            queue: JSON.stringify(store.queue),
            history: JSON.stringify(store.history)
          };

          sendMetricsData({
            object: 'playlist',
            method: `launch:${action}`,
            domain: opts.domain
          });

          if (action === 'play') response.playing = true;
          windowUtils.send('set-video', response);
        });
      }
    } else {
      // fetch the media source and set it
      getUrlFn(opts, function(item) {
        if (item.err) console.error('LaunchVideo failed to get the streamUrl: ', item.err); // eslint-disable-line no-console

        if (isAudio(item.url)) item.player = 'audio';

        if (action === 'play') store.queue.unshift(item);
        else store.queue.push(item);

        const videoOptions = {
          trackAdded: (action === 'add-to-queue') && (store.queue.length > 1),
          error: item.err ? item.err : false,
          queue: JSON.stringify(store.queue),
          history: JSON.stringify(store.history)
        };

        if (action === 'play') videoOptions.playing = true;
        windowUtils.send('set-video', videoOptions);
      });
    }
  });
}
<commit_msg>Fix regression, pause when adding to queue (#789)<commit_after>const tabs = require('sdk/tabs');
const qs = require('sdk/querystring');
const prefs = require('sdk/simple-prefs').prefs;
const store = require('sdk/simple-storage').storage;
const getVideoId = require('get-video-id');

const isAudio = require('./is-audio');
const windowUtils = require('./window-utils');
const getRandomId = require('./get-random-id');
const youtubeHelpers = require('./youtube-helpers');
const sendMetricsData = require('./send-metrics-data');
const getLocaleStrings = require('./get-locale-strings');

module.exports = launchVideo;

// Pass in a video URL as opts.src or pass in a video URL lookup function as opts.getUrlFn
function launchVideo(opts) {
  // UpdateWindow might create a new panel, so do the remaining launch work
  // asynchronously.
  windowUtils.updateWindow();
  windowUtils.whenReady(() => {
    const getUrlFn = opts.getUrlFn;
    const action = opts.action;

    delete opts.getUrlFn;
    delete opts.action;

    if (action === 'play') opts.action = true;

    windowUtils.show();
    // send some initial data to open the loading view
    // before we fetch the media source
    windowUtils.send('set-video', opts = Object.assign({
      id: getRandomId(),
      width: prefs.width,
      height: prefs.height,
      videoId: getVideoId(opts.url) ? getVideoId(opts.url).id : '',
      strings: getLocaleStrings(opts.domain, (isAudio(opts.url))),
      tabId: tabs.activeTab.id,
      launchUrl: opts.url,
      currentTime: 0,
      keyShortcutsEnabled: prefs['keyShortcutsEnabled'],
      confirm: false,
      confirmContent: '{}'
    }, opts));

    // YouTube playlist handling
    if (opts.domain === 'youtube.com' && !!~opts.url.indexOf('list')) {
      if (!!~opts.url.indexOf('watch?v')) {
        const parsed = qs.parse(opts.url.substr(opts.url.indexOf('?') + 1));
        youtubeHelpers.getPlaylistMeta({
          videoId: parsed.v,
          playlistId: parsed.list,
        }, (meta) => {
          opts.confirmContent = meta;
          opts.confirmContent.action = action;
          opts.confirmContent = JSON.stringify(opts.confirmContent);
          sendMetricsData({
            object: 'playlist',
            method: `launch:video:${action}`,
            domain: opts.domain
          });
          windowUtils.send('set-video', Object.assign(opts, {
            confirm: true,
            error: false,
            queue: JSON.stringify(store.queue),
            history: JSON.stringify(store.history)
          }));
        });
      } else {
        // only playlist handling
        const parsed = qs.parse(opts.url.substr(opts.url.indexOf('?') + 1));
        youtubeHelpers.getPlaylist({playlistId: parsed.list}, playlist => {
          if (action === 'play') {
            store.queue = playlist.concat(store.queue);
          } else store.queue = store.queue.concat(playlist);

          const response = {
            trackAdded: (action === 'add-to-queue') && (store.queue.length > 1),
            error: false,
            queue: JSON.stringify(store.queue),
            history: JSON.stringify(store.history)
          };

          sendMetricsData({
            object: 'playlist',
            method: `launch:${action}`,
            domain: opts.domain
          });

          if (action === 'play') response.playing = true;
          windowUtils.send('set-video', response);
        });
      }
    } else {
      // fetch the media source and set it
      getUrlFn(opts, function(item) {
        if (item.err) console.error('LaunchVideo failed to get the streamUrl: ', item.err); // eslint-disable-line no-console

        if (isAudio(item.url)) item.player = 'audio';

        if (action === 'play') store.queue.unshift(item);
        else store.queue.push(item);

        const videoOptions = {
          trackAdded: (action === 'add-to-queue') && (store.queue.length > 1),
          error: item.err ? item.err : false,
          queue: JSON.stringify(store.queue),
          history: JSON.stringify(store.history)
        };

        if (action === 'play') videoOptions.playing = true;
        windowUtils.send('set-video', videoOptions);
      });
    }
  });
}
<|endoftext|>