<commit_before>/**
 * @class
 * @classdesc: webpack2 快速开发网站项目模板入口
 * @extends
 * @example:
 * @author: maksim email:maksim.lin@foxmail.com
 * @copyright: Ds是累积平时项目工作的经验代码库，不属于职位任务与项目的内容。里面代码大部分理念来至曾经flash 前端时代，尽力减小类之间耦合，通过webpack按需request使用。Ds库里内容多来至网络与参考其他开源代码库。Ds库也开源开放，随意使用在所属的职位任务与项目中。
 * @constructor
 **/
_time = new Date().getTime();
//网址主模块
window.SiteModel = {
    ShowProgress: ShowProgress,//设置加载进度方法
    HitLoadPanel: HitLoadPanel,//隐藏加载进度方法 [如需要使用这个函数进行设置隐藏加载进度条，Dom默认直接hide(),Createjs的loading 直接删除父级对象]
    Debug:false,//是否debug  会根据端口号进行判断
    SiteResizeModel:null,//也可以通过这里获取自适应模块
    LoadPanel:null,//加载界面 [Dom的loading 请在InitLoadPanel函数内进行实现   Createjs的loading，正常来说不需要修改，如果需要修改InitCreateJsLoadPanel函数内修改实现]
    CJSModel:null,//createjs项目模块  [设置IsCJSSiteModel=true 时候才会创建]
    AudioAutoPlayLister:null,//声音自动播放加载与控制器类对象
    //对整个网站框架进行ReSize方法执行
    ReSize:function(){
      SiteModel.SiteResizeModel.ReSize();
    },
    //==============以上参数不做修改，会根据下列配置进行生成===================
    ScreenType:'v',//网站自适应方式
    Screen:'#screen',//网站自适应容器
    HasCreateJs:false,//网站是否需要是否是用createjs    [设置开发网站的类型,true会使用vendors2.js false使用vendors1.js]
    IsCJSSiteModel:false,//是否是用createjs方式网站    [需要设置HasCreateJs 等于true]
    IsCJSLoadPanel:false,//是否用createjs的loading  [设置使用什么方式做loading]
    //声音自动播放加载与控制器类对象参数，不需要可以设置成null。
    AudioAutoPlayListerData:{
    //加载声音列表  list=null list=undefined list.length<=0没有这个列表不会执行
    list:[],//项格式 {src:'./media/BGM.mp3',id:'BGM',loop:true}
    //默认播放声音背景
    id:'BGM',
    //这个BMG 绑定的控制的按钮
    button:'#BGMBtn'
  },
};
/**
 * 加载单页面应用的代码
 */
function LoadSinglePageApplicationJS(){
  require.ensure(
      ['app/AppMain.js'],
      function() {
          ShowProgress(20);
          _SinglePageApplication = require('app/AppMain.js');
          SiteModel.SinglePageApplication = _SinglePageApplication;
          SiteModel.SinglePageApplication.Init();
      },
      'AppMain'//单页面应用打包的js名称
  );
}
/**
 *  初始化Dom loading界面
 */
function InitLoadPanel(){
  //开始初始化Domloading
  SiteModel.LoadPanel=$('#siteLoadPanel');
  //加载这单页面应用
  LoadSinglePageApplicationJS();
}
/**
 * 设置加载进度方法
 * @param {[Number]} progress [loading的百分比 0-100]
 */
function ShowProgress(progress){
  //获取load界面
  var _loadPanel=SiteModel.LoadPanel;

  //判断是Dom方式的loading
  if((_loadPanel instanceof HTMLElement)||(_loadPanel.length>=1&&_loadPanel[0] instanceof HTMLElement)){
    //【Dom Loading 请在这里实现】
    $('#siteLoadPanel .progress').css({width:(progress+1)+'%'});
    $('#siteLoadPanel .label').html((progress+1)+'%');
  }
  //判断是createjs类型loading
  else if(createjs!==undefined&&_loadPanel instanceof createjs.DisplayObject){
    if(progress>=99)progress=99;
    if(_loadPanel instanceof createjs.MovieClip)_loadPanel.gotoAndStop(progress);
    if(_loadPanel.label)_loadPanel.label.text=progress<10?'0'+progress+'%':progress+'%';
  }
}
/**
 * 隐藏进度条方法
 */
function HitLoadPanel(){
  var _loadPanel=SiteModel.LoadPanel;
  if(!_loadPanel)return;
  //判断是Dom方式的loading
  if((_loadPanel instanceof HTMLElement)||(_loadPanel.length>=1&&_loadPanel[0] instanceof HTMLElement)){
    $(_loadPanel).hide();
  }
  else if(createjs!==undefined&&_loadPanel instanceof createjs.DisplayObject){
    if(_loadPanel.parent)_loadPanel.parent.removeChild(_loadPanel);
  }
}
/*=================以下部分基本通用可以不需要修改===================*/
//进行判断是否进行debug的判断
if (location.href.indexOf(':8001') != -1) SiteModel.Debug = true;
//屏蔽滑动页面
document.addEventListener('touchmove', function(e) {e.preventDefault();}, false);
/**
 * 构建createjs模块
 */
function InitCJSModel(){
  //构建createjs模块
  SiteModel.CJSModel = ccjs.CCJSModel.Create({
      appendTo:$('#cjsBox')[0],
      width: 640,
      height: 1040,
      fps: 30
  });
}
/**
 *  初始化CreateJs loading界面
 */
function InitCreateJsLoadPanel(){
  //loading加载配置
  var _loadObj = {
      basePath: './assets/',
      //js路径
      jsUrl: 'loading.js',
      jsNS: 'loadlib',
      imgNS: 'loadimages',
      //加载完成后调用的方法
      complete: onComplete,
      //加载进行调用的方法
      // progress: onProgress,
      //加载方式 初始化LoadQueue的crossOrigin参数
      loadType: true,
  };
  //loading加载完成后的方法处理
  function onComplete(e) {
    console.log('LoadPanel加载完成');
    //创建加载界面
    SiteModel.LoadPanel=new loadlib.LoadPanel();
    //添加到场景
    SiteModel.CJSModel.Root.addChild(SiteModel.LoadPanel);
    SiteModel.LoadPanel.gotoAndStop(0);
    SiteResizeModel.ReSize();
    ShowProgress(10);
    //加载这单页面应用
    LoadSinglePageApplicationJS();
  }
  //开始加载loading的资源
  ccjs.LoadCJSAssets(_loadObj);
}

/**
 * 初始化网站自适应模块
 */
function InitSiteResizeModel(){
  //网站自适应模块
  window.SiteResizeModel = new Ds.SiteMoblieResizeModel({
    screen:SiteModel.Screen,
    screenType:SiteModel.ScreenType,
  });
  SiteModel.SiteResizeModel=SiteResizeModel;
  //进行提示浮动层显示
  if(SiteResizeModel.ScreenType!='auto')SiteResizeModel.InitOrientationTip();
  //监听场景自适应
  SiteResizeModel.on('resize', ReSize);
  //开始进行初始化场景自适应
  SiteResizeModel.InitResize();
  //解决loading页面缩放问题
  $(SiteModel.Screen).show();
}
/**
 * 自适应
 */
function ReSize(){
  //var _Width, _Height, _PageScale, _ActualH, _Horizontal = false,_IsInputState = false,_ScreenWidth, _DensityDpi;
  if(SiteResizeModel.ScreenType=='auto'){

  }
}

/**
 * 加载基础库的
 */
function LoadBaseJS() {
    require.ensure(
        [
          'jquery',
          'eventdispatcher',
          'log',
          'ds/gemo/QuickTrack',
          'ds/media/MobileAudioAutoPlayLister',
          'sitemoblieresizemodel',
        ],
        function() {
            require([
              'jquery',
              'eventdispatcher',
              'log',
              'ds/gemo/QuickTrack',
              'ds/media/MobileAudioAutoPlayLister',
              'sitemoblieresizemodel',
            ],function(){
              console.log('LoadBaseJS:', new Date().getTime() - _time);
              if(SiteModel.AudioAutoPlayListerData){
                InitAudioAutoPlayLister();
              }
              InitSiteResizeModel();
              if(SiteModel.HasCreateJs)LoadCJSFrameWorkJS();
              else LoadFrameWorkJS();
            });

        },
        'base'
    );
}
/**
 * 初始化默认背景声音播放
 */
function InitAudioAutoPlayLister(){
  SiteModel.AudioAutoPlayLister=new Ds.media.MobileAudioAutoPlayLister();
  SiteModel.AudioAutoPlayLister.InitLoadAndSetBGM(SiteModel.AudioAutoPlayListerData);
}
/**
 * 加载项目需要支持的第三方库
 */
function LoadCJSFrameWorkJS(){
  require.ensure(
      [
          'createjs',//需要create
          'dscreatejs',//需要create 扩展
          'jstween',//需要运动引擎
          'touchjs',//需要touch事件
      ],
      function() {
          require([
              'createjs',
              'dscreatejs',
              'jstween',
              'touchjs',
          ],function(){
            console.log('LoadCJSFrameWorkJS:', new Date().getTime() - _time);
            //是否CJS类型网站
            if(SiteModel.IsCJSSiteModel) InitCJSModel();
            //使用什么模式的加载loading
            if(SiteModel.IsCJSLoadPanel)InitCreateJsLoadPanel();
            else InitLoadPanel();
          });

      },
      'vendors2'
  );
}
/**
 * 加载项目需要支持的第三方库
 */
function LoadFrameWorkJS(){
  require.ensure(
      [
          'jstween',//需要运动引擎
          'touchjs',//需要touch事件
      ],
      function() {
          require([
              'jstween',
              'touchjs',
          ],function(){
          	console.log('LoadFrameWorkJS:', new Date().getTime() - _time);
          	InitLoadPanel();
          });

      },
      'vendors1'
  );
}
//开始加载代码
LoadBaseJS();
<commit_msg>避免不需要create时候报错<commit_after>/**
 * @class
 * @classdesc: webpack2 快速开发网站项目模板入口
 * @extends
 * @example:
 * @author: maksim email:maksim.lin@foxmail.com
 * @copyright: Ds是累积平时项目工作的经验代码库，不属于职位任务与项目的内容。里面代码大部分理念来至曾经flash 前端时代，尽力减小类之间耦合，通过webpack按需request使用。Ds库里内容多来至网络与参考其他开源代码库。Ds库也开源开放，随意使用在所属的职位任务与项目中。
 * @constructor
 **/
_time = new Date().getTime();
//网址主模块
window.SiteModel = {
    ShowProgress: ShowProgress,//设置加载进度方法
    HitLoadPanel: HitLoadPanel,//隐藏加载进度方法 [如需要使用这个函数进行设置隐藏加载进度条，Dom默认直接hide(),Createjs的loading 直接删除父级对象]
    Debug:false,//是否debug  会根据端口号进行判断
    SiteResizeModel:null,//也可以通过这里获取自适应模块
    LoadPanel:null,//加载界面 [Dom的loading 请在InitLoadPanel函数内进行实现   Createjs的loading，正常来说不需要修改，如果需要修改InitCreateJsLoadPanel函数内修改实现]
    CJSModel:null,//createjs项目模块  [设置IsCJSSiteModel=true 时候才会创建]
    AudioAutoPlayLister:null,//声音自动播放加载与控制器类对象
    //对整个网站框架进行ReSize方法执行
    ReSize:function(){
      SiteModel.SiteResizeModel.ReSize();
    },
    //==============以上参数不做修改，会根据下列配置进行生成===================
    ScreenType:'v',//网站自适应方式
    Screen:'#screen',//网站自适应容器
    HasCreateJs:false,//网站是否需要是否是用createjs    [设置开发网站的类型,true会使用vendors2.js false使用vendors1.js]
    IsCJSSiteModel:false,//是否是用createjs方式网站    [需要设置HasCreateJs 等于true]
    IsCJSLoadPanel:false,//是否用createjs的loading  [设置使用什么方式做loading]
    //声音自动播放加载与控制器类对象参数，不需要可以设置成null。
    AudioAutoPlayListerData:{
    //加载声音列表  list=null list=undefined list.length<=0没有这个列表不会执行
    list:[],//项格式 {src:'./media/BGM.mp3',id:'BGM',loop:true}
    //默认播放声音背景
    id:'BGM',
    //这个BMG 绑定的控制的按钮
    button:'#BGMBtn'
  },
};
/**
 * 加载单页面应用的代码
 */
function LoadSinglePageApplicationJS(){
  require.ensure(
      ['app/AppMain.js'],
      function() {
          ShowProgress(20);
          _SinglePageApplication = require('app/AppMain.js');
          SiteModel.SinglePageApplication = _SinglePageApplication;
          SiteModel.SinglePageApplication.Init();
      },
      'AppMain'//单页面应用打包的js名称
  );
}
/**
 *  初始化Dom loading界面
 */
function InitLoadPanel(){
  //开始初始化Domloading
  SiteModel.LoadPanel=$('#siteLoadPanel');
  //加载这单页面应用
  LoadSinglePageApplicationJS();
}
/**
 * 设置加载进度方法
 * @param {[Number]} progress [loading的百分比 0-100]
 */
function ShowProgress(progress){
  //获取load界面
  var _loadPanel=SiteModel.LoadPanel;

  //判断是Dom方式的loading
  if((_loadPanel instanceof HTMLElement)||(_loadPanel.length>=1&&_loadPanel[0] instanceof HTMLElement)){
    //【Dom Loading 请在这里实现】
    $('#siteLoadPanel .progress').css({width:(progress+1)+'%'});
    $('#siteLoadPanel .label').html((progress+1)+'%');
  }
  //判断是createjs类型loading
  else if(window['createjs']!==undefined&&_loadPanel instanceof createjs.DisplayObject){
    if(progress>=99)progress=99;
    if(_loadPanel instanceof createjs.MovieClip)_loadPanel.gotoAndStop(progress);
    if(_loadPanel.label)_loadPanel.label.text=progress<10?'0'+progress+'%':progress+'%';
  }
}
/**
 * 隐藏进度条方法
 */
function HitLoadPanel(){
  var _loadPanel=SiteModel.LoadPanel;
  if(!_loadPanel)return;
  //判断是Dom方式的loading
  if((_loadPanel instanceof HTMLElement)||(_loadPanel.length>=1&&_loadPanel[0] instanceof HTMLElement)){
    $(_loadPanel).hide();
  }
  else if(window['createjs']!==undefined&&_loadPanel instanceof createjs.DisplayObject){
    if(_loadPanel.parent)_loadPanel.parent.removeChild(_loadPanel);
  }
}
/*=================以下部分基本通用可以不需要修改===================*/
//进行判断是否进行debug的判断
if (location.href.indexOf(':8001') != -1) SiteModel.Debug = true;
//屏蔽滑动页面
document.addEventListener('touchmove', function(e) {e.preventDefault();}, false);
/**
 * 构建createjs模块
 */
function InitCJSModel(){
  //构建createjs模块
  SiteModel.CJSModel = ccjs.CCJSModel.Create({
      appendTo:$('#cjsBox')[0],
      width: 640,
      height: 1040,
      fps: 30
  });
}
/**
 *  初始化CreateJs loading界面
 */
function InitCreateJsLoadPanel(){
  //loading加载配置
  var _loadObj = {
      basePath: './assets/',
      //js路径
      jsUrl: 'loading.js',
      jsNS: 'loadlib',
      imgNS: 'loadimages',
      //加载完成后调用的方法
      complete: onComplete,
      //加载进行调用的方法
      // progress: onProgress,
      //加载方式 初始化LoadQueue的crossOrigin参数
      loadType: true,
  };
  //loading加载完成后的方法处理
  function onComplete(e) {
    console.log('LoadPanel加载完成');
    //创建加载界面
    SiteModel.LoadPanel=new loadlib.LoadPanel();
    //添加到场景
    SiteModel.CJSModel.Root.addChild(SiteModel.LoadPanel);
    SiteModel.LoadPanel.gotoAndStop(0);
    SiteResizeModel.ReSize();
    ShowProgress(10);
    //加载这单页面应用
    LoadSinglePageApplicationJS();
  }
  //开始加载loading的资源
  ccjs.LoadCJSAssets(_loadObj);
}

/**
 * 初始化网站自适应模块
 */
function InitSiteResizeModel(){
  //网站自适应模块
  window.SiteResizeModel = new Ds.SiteMoblieResizeModel({
    screen:SiteModel.Screen,
    screenType:SiteModel.ScreenType,
  });
  SiteModel.SiteResizeModel=SiteResizeModel;
  //进行提示浮动层显示
  if(SiteResizeModel.ScreenType!='auto')SiteResizeModel.InitOrientationTip();
  //监听场景自适应
  SiteResizeModel.on('resize', ReSize);
  //开始进行初始化场景自适应
  SiteResizeModel.InitResize();
  //解决loading页面缩放问题
  $(SiteModel.Screen).show();
}
/**
 * 自适应
 */
function ReSize(){
  //var _Width, _Height, _PageScale, _ActualH, _Horizontal = false,_IsInputState = false,_ScreenWidth, _DensityDpi;
  if(SiteResizeModel.ScreenType=='auto'){

  }
}

/**
 * 加载基础库的
 */
function LoadBaseJS() {
    require.ensure(
        [
          'jquery',
          'eventdispatcher',
          'log',
          'ds/gemo/QuickTrack',
          'ds/media/MobileAudioAutoPlayLister',
          'sitemoblieresizemodel',
        ],
        function() {
            require([
              'jquery',
              'eventdispatcher',
              'log',
              'ds/gemo/QuickTrack',
              'ds/media/MobileAudioAutoPlayLister',
              'sitemoblieresizemodel',
            ],function(){
              console.log('LoadBaseJS:', new Date().getTime() - _time);
              if(SiteModel.AudioAutoPlayListerData){
                InitAudioAutoPlayLister();
              }
              InitSiteResizeModel();
              if(SiteModel.HasCreateJs)LoadCJSFrameWorkJS();
              else LoadFrameWorkJS();
            });

        },
        'base'
    );
}
/**
 * 初始化默认背景声音播放
 */
function InitAudioAutoPlayLister(){
  SiteModel.AudioAutoPlayLister=new Ds.media.MobileAudioAutoPlayLister();
  SiteModel.AudioAutoPlayLister.InitLoadAndSetBGM(SiteModel.AudioAutoPlayListerData);
}
/**
 * 加载项目需要支持的第三方库
 */
function LoadCJSFrameWorkJS(){
  require.ensure(
      [
          'createjs',//需要create
          'dscreatejs',//需要create 扩展
          'jstween',//需要运动引擎
          'touchjs',//需要touch事件
      ],
      function() {
          require([
              'createjs',
              'dscreatejs',
              'jstween',
              'touchjs',
          ],function(){
            console.log('LoadCJSFrameWorkJS:', new Date().getTime() - _time);
            //是否CJS类型网站
            if(SiteModel.IsCJSSiteModel) InitCJSModel();
            //使用什么模式的加载loading
            if(SiteModel.IsCJSLoadPanel)InitCreateJsLoadPanel();
            else InitLoadPanel();
          });

      },
      'vendors2'
  );
}
/**
 * 加载项目需要支持的第三方库
 */
function LoadFrameWorkJS(){
  require.ensure(
      [
          'jstween',//需要运动引擎
          'touchjs',//需要touch事件
      ],
      function() {
          require([
              'jstween',
              'touchjs',
          ],function(){
            console.log('LoadFrameWorkJS:', new Date().getTime() - _time);
            InitLoadPanel();
          });

      },
      'vendors1'
  );
}
//开始加载代码
LoadBaseJS();
<|endoftext|>


<commit_before>/**
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function() {
'use strict';

var observedTags = {
  animate: true,
  animateMotion: true,
  animateTransform: true,
  mpath: true,
  set: true
};

var observedAttributes = {
  accumulate: true,
  additive: true,
  attributeName: true,
  attributeType: true, // For animate and set elements: CSS | XML | auto
  begin: true,
  by: true,
  calcMode: true,
  dur: true,
  end: true,
  fill: true,
  from: true,
  keyPoints: true,
  keyTimes: true,
  max: true,
  min: true,
  onbegin: true,
  onend: true,
  onrepeat: true,
  path: true,
  repeatCount: true,
  repeatDur: true,
  restart: true,
  rotate: true,
  to: true,
  type: true, // animatetransform: translate | scale | rotate | skewX | skewY
  values: true,
  'xlink:href': true
};

// Control debug logging.
var verbose = false;

var animationRecords = {};

// Implements http://www.w3.org/TR/SVG/animate.html#ClockValueSyntax
// Converts value to milliseconds.
function parseClockValue(value) {
  var result;
  if (value === 'indefinite') {
    result = Infinity;
  } else if (value.indexOf(':') === -1) {
    // We have a Timecount value
    result = parseFloat(value);
    if (value.indexOf('h') !== -1) {
      result *= 3600000;
    } else if (value.indexOf('min') !== -1) {
      result *= 60000;
    } else if (value.indexOf('ms') === -1) { // The default unit is seconds
      result *= 1000;
    } // else milliseconds
  } else {
    var components = value.split(':');
    result = parseInt(components[0]) * 60;
    if (components.length === 2) {
      // Partial clock value with minutes : seconds [.fraction]
      result += parseFloat(components[1]);
    } else {
      // Full clock value with hours : minutes : seconds [.fraction]
      result += parseInt(components[1]);
      result *= 60;
      result += parseFloat(components[2]);
    }
    result *= 1000;
  }
  return result;
}

function createTimingInput(animationRecord) {
  var timingInput = {};

  if (animationRecord.dur) {
    timingInput.duration = parseClockValue(animationRecord.dur);
  } else {
    // Absent duration means infinite duration.
    timingInput.duration = Infinity;
  }

  if (animationRecord.repeatCount) {
    timingInput.iterations = parseFloat(animationRecord.repeatCount);
  }

  // http://www.w3.org/TR/smil/smil-timing.html#adef-fill
  // http://www.w3.org/TR/smil/smil-timing.html#adef-fillDefault
  if (animationRecord.fill === 'freeze' ||
      animationRecord.fill === 'hold' ||
      animationRecord.fill === 'transition' ||
      (animationRecord.fill !== 'remove' &&
       !animationRecord.dur &&
       !animationRecord.end &&
       !animationRecord.repeatCount &&
       !animationRecord.repeatDir)) {
    timingInput.fill = 'forwards';

    // FIXME: support animationRecord.fill === 'fillDefault',
    // where we must inspect the inherited fillDefault attribute.
  }

  return timingInput;
}

function createEffectOptions(animationRecord) {
  var options = {};

  // 'sum' adds to the underlying value of the attribute and other lower
  // priority animations.
  // http://www.w3.org/TR/smil/smil-animation.html#adef-additive
  if (animationRecord.additive && animationRecord.additive === 'sum') {
    options.composite = 'accumulate';
  } else {
    // default behavior is options.composite = 'replace';
  }

  // http://www.w3.org/TR/smil/smil-animation.html#adef-accumulate
  if (animationRecord.accumulate &&
      animationRecord.accumulate === 'sum') {
    options.iterationComposite = 'accumulate';
  } else {
    // default behavior is options.iterationComposite = 'replace';
  }

  return options;
}

function createAnimation(animationRecord) {
  animationRecord.timingInput = createTimingInput(animationRecord);
  animationRecord.options = createEffectOptions(animationRecord);

  // FIXME: Implement animateMotion and mpath, i.e. motion path animation.
  if (animationRecord.nodeName === 'animateMotion' ||
      animationRecord.nodeName === 'mpath') {
    // not yet implemented
    return;
  }

  var attributeName = animationRecord.attributeName;
  if (animationRecord.nodeName === 'animateTransform') {
    attributeName = 'transform';
  }

  if (!attributeName) {
    return;
  }

  var keyframes = null;
  if ((animationRecord.nodeName === 'animate' ||
       animationRecord.nodeName === 'animateTransform')) {
    // FIXME: Support more ways of specifying keyframes, e.g. by, or only to.
    // FIXME: Support ways of specifying timing function.

    var processValue;
    if (animationRecord.nodeName === 'animate') {
      processValue = function(value) { return value; };
    } else {
      // animationRecord.nodeName === 'animateTransform'
      var transformType;
      if (animationRecord.type === 'scale' ||
          animationRecord.type === 'rotate' ||
          animationRecord.type === 'skewX' ||
          animationRecord.type === 'skewY') {
        transformType = animationRecord.type;
      } else {
        transformType = 'translate'; // default if type is not specified
      }

      processValue = function(value) {
          return transformType + '(' + value + ')';
      };
    }

    if (animationRecord.values) {
      var valueList = animationRecord.values.split(';');
      keyframes = [];
      for (var valueIndex = 0; valueIndex < valueList.length; ++valueIndex) {
        var keyframe = {};
        keyframe[attributeName] = processValue(valueList[valueIndex].trim());
        keyframes.push(keyframe);
      }

      // FIXME: check keyTimes - if present, must have the same number of
      // entries as values.
    } else if (animationRecord.from && animationRecord.to) {
      keyframes = [
        {offset: 0},
        {offset: 1}
      ];
      keyframes[0][attributeName] = processValue(animationRecord.from);
      keyframes[1][attributeName] = processValue(animationRecord.to);
    }
  } else if (animationRecord.nodeName === 'set' && animationRecord.to) {
    keyframes = [
      {offset: 0},
      {offset: 1}
    ];
    keyframes[0][attributeName] = animationRecord.to;
    keyframes[1][attributeName] = animationRecord.to;
  }

  if (verbose) {
    console.log('keyframes  = ' + JSON.stringify(keyframes));
    console.log('options  = ' + JSON.stringify(animationRecord.options));
    console.log('timingInput  = ' + JSON.stringify(
        animationRecord.timingInput));
  }

  var animation = null;
  if (keyframes) {
    animationRecord.keyframes = keyframes;
    animationRecord.keyframeEffect =
        new KeyframeEffect(keyframes, animationRecord.options);
    if (animationRecord.target) {
      animation = new Animation(animationRecord.target,
                                animationRecord.keyframeEffect,
                                animationRecord.timingInput);
      animationRecord.animation = animation;
    }
  }

  // FIXME: Respect begin and end attributes.
  if (animation) {
    animationRecord.player = document.timeline.play(animation);
  }
}

function createAnimationRecord(element) {
  var animationRecord = {
    element: element,
    nodeName: element.nodeName,
    parentNode: element.parentNode
  };

  var attributes = element.attributes;
  for (var index = 0; index < attributes.length; ++index) {
    var attributeName = attributes[index].name;
    if (attributeName in observedAttributes) {
      animationRecord[attributeName] = attributes[index].value;
    }
  }

  var targetName = animationRecord['xlink:href'];
  if (targetName && targetName.indexOf('#') === 0) {
    animationRecord.target =
        document.getElementById(targetName.substring(1));
  } else {
    animationRecord.target = element.parentNode;
  }

  animationRecords[element] = animationRecord;

  createAnimation(animationRecord);
}

function walkSVG(node) {
  if (node.nodeName in observedTags) {
    createAnimationRecord(node);
  }
  var child = node.firstChild;
  while (child) {
    walkSVG(child);
    child = child.nextSibling;
  }
}

window.onload = function() {

  // We would like to use document.querySelectorAll(tag) for each tag in
  // observedTags, but can't yet due to
  // querySelectorAll unable to find SVG camelCase elements in HTML
  // https://code.google.com/p/chromium/issues/detail?id=237435

  var svgFragmentList = document.querySelectorAll('svg');
  for (var index = 0; index < svgFragmentList.length; ++index) {
    walkSVG(svgFragmentList[index]);
  }
};

})();
<commit_msg>Simple animateMotion path support<commit_after>/**
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function() {
'use strict';

var observedTags = {
  animate: true,
  animateMotion: true,
  animateTransform: true,
  mpath: true,
  set: true
};

var observedAttributes = {
  accumulate: true,
  additive: true,
  attributeName: true,
  attributeType: true, // For animate and set elements: CSS | XML | auto
  begin: true,
  by: true,
  calcMode: true,
  dur: true,
  end: true,
  fill: true,
  from: true,
  keyPoints: true,
  keyTimes: true,
  max: true,
  min: true,
  onbegin: true,
  onend: true,
  onrepeat: true,
  path: true,
  repeatCount: true,
  repeatDur: true,
  restart: true,
  rotate: true,
  to: true,
  type: true, // animatetransform: translate | scale | rotate | skewX | skewY
  values: true,
  'xlink:href': true
};

// Control debug logging.
var verbose = false;

var animationRecords = {};

// Implements http://www.w3.org/TR/SVG/animate.html#ClockValueSyntax
// Converts value to milliseconds.
function parseClockValue(value) {
  var result;
  if (value === 'indefinite') {
    result = Infinity;
  } else if (value.indexOf(':') === -1) {
    // We have a Timecount value
    result = parseFloat(value);
    if (value.indexOf('h') !== -1) {
      result *= 3600000;
    } else if (value.indexOf('min') !== -1) {
      result *= 60000;
    } else if (value.indexOf('ms') === -1) { // The default unit is seconds
      result *= 1000;
    } // else milliseconds
  } else {
    var components = value.split(':');
    result = parseInt(components[0]) * 60;
    if (components.length === 2) {
      // Partial clock value with minutes : seconds [.fraction]
      result += parseFloat(components[1]);
    } else {
      // Full clock value with hours : minutes : seconds [.fraction]
      result += parseInt(components[1]);
      result *= 60;
      result += parseFloat(components[2]);
    }
    result *= 1000;
  }
  return result;
}

function createTimingInput(animationRecord) {
  var timingInput = {};

  if (animationRecord.dur) {
    timingInput.duration = parseClockValue(animationRecord.dur);
  } else {
    // Absent duration means infinite duration.
    timingInput.duration = Infinity;
  }

  if (animationRecord.repeatCount) {
    if (animationRecord.repeatCount === 'indefinite') {
      timingInput.iterations = Infinity;
    } else {
      timingInput.iterations = parseFloat(animationRecord.repeatCount);
    }
  }

  // http://www.w3.org/TR/smil/smil-timing.html#adef-fill
  // http://www.w3.org/TR/smil/smil-timing.html#adef-fillDefault
  if (animationRecord.fill === 'freeze' ||
      animationRecord.fill === 'hold' ||
      animationRecord.fill === 'transition' ||
      (animationRecord.fill !== 'remove' &&
       !animationRecord.dur &&
       !animationRecord.end &&
       !animationRecord.repeatCount &&
       !animationRecord.repeatDir)) {
    timingInput.fill = 'forwards';

    // FIXME: support animationRecord.fill === 'fillDefault',
    // where we must inspect the inherited fillDefault attribute.
  }

  return timingInput;
}

function createEffectOptions(animationRecord) {
  var options = {};

  // 'sum' adds to the underlying value of the attribute and other lower
  // priority animations.
  // http://www.w3.org/TR/smil/smil-animation.html#adef-additive
  if (animationRecord.additive && animationRecord.additive === 'sum') {
    options.composite = 'accumulate';
  } else {
    // default behavior is options.composite = 'replace';
  }

  // http://www.w3.org/TR/smil/smil-animation.html#adef-accumulate
  if (animationRecord.accumulate &&
      animationRecord.accumulate === 'sum') {
    options.iterationComposite = 'accumulate';
  } else {
    // default behavior is options.iterationComposite = 'replace';
  }

  return options;
}

function createAnimation(animationRecord) {
  if (animationRecord.target) {
    var animation = new Animation(animationRecord.target,
                                  animationRecord.effect,
                                  animationRecord.timingInput);
    animationRecord.animation = animation;

    // FIXME: Respect begin and end attributes.
    animationRecord.player = document.timeline.play(animation);
  }
}

function createKeyframeAnimation(animationRecord) {

  var attributeName = animationRecord.attributeName;
  if (animationRecord.nodeName === 'animateTransform') {
    attributeName = 'transform';
  }

  if (!attributeName) {
    return;
  }

  var keyframes = null;
  if ((animationRecord.nodeName === 'animate' ||
       animationRecord.nodeName === 'animateTransform')) {
    // FIXME: Support more ways of specifying keyframes, e.g. by, or only to.
    // FIXME: Support ways of specifying timing function.

    var processValue;
    if (animationRecord.nodeName === 'animate') {
      processValue = function(value) { return value; };
    } else {
      // animationRecord.nodeName === 'animateTransform'
      var transformType;
      if (animationRecord.type === 'scale' ||
          animationRecord.type === 'rotate' ||
          animationRecord.type === 'skewX' ||
          animationRecord.type === 'skewY') {
        transformType = animationRecord.type;
      } else {
        transformType = 'translate'; // default if type is not specified
      }

      processValue = function(value) {
          return transformType + '(' + value + ')';
      };
    }

    if (animationRecord.values) {
      var valueList = animationRecord.values.split(';');
      keyframes = [];
      for (var valueIndex = 0; valueIndex < valueList.length; ++valueIndex) {
        var keyframe = {};
        keyframe[attributeName] = processValue(valueList[valueIndex].trim());
        keyframes.push(keyframe);
      }

      // FIXME: check keyTimes - if present, must have the same number of
      // entries as values.
    } else if (animationRecord.from && animationRecord.to) {
      keyframes = [
        {offset: 0},
        {offset: 1}
      ];
      keyframes[0][attributeName] = processValue(animationRecord.from);
      keyframes[1][attributeName] = processValue(animationRecord.to);
    }
  } else if (animationRecord.nodeName === 'set' && animationRecord.to) {
    keyframes = [
      {offset: 0},
      {offset: 1}
    ];
    keyframes[0][attributeName] = animationRecord.to;
    keyframes[1][attributeName] = animationRecord.to;
  }

  if (verbose) {
    console.log('keyframes  = ' + JSON.stringify(keyframes));
    console.log('options  = ' + JSON.stringify(animationRecord.options));
    console.log('timingInput  = ' + JSON.stringify(
        animationRecord.timingInput));
  }

  if (keyframes) {
    animationRecord.keyframes = keyframes;
    animationRecord.effect =
        new KeyframeEffect(keyframes, animationRecord.options);
    createAnimation(animationRecord);
  }
}

function createMotionPathAnimation(animationRecord) {
  var resolvedPath;
  if (animationRecord.mpathRecord) {
    var pathRef = animationRecord.mpathRecord['xlink:href'];
    if (pathRef && pathRef.indexOf('#') === 0) {
      animationRecord.pathNode = document.getElementById(pathRef.substring(1));
      if (animationRecord.pathNode) {
        resolvedPath = animationRecord.pathNode.getAttribute('d');
      }
    }
  } else {
    resolvedPath = animationRecord.path;
  }

  if (verbose) {
    console.log('resolvedPath = ' + resolvedPath);
  }

  if (resolvedPath) {
    animationRecord.resolvedPath = resolvedPath;
    animationRecord.effect =
        new MotionPathEffect(resolvedPath, animationRecord.options);
    createAnimation(animationRecord);
  }
}

function createAnimationRecord(element) {
  var animationRecord = {
    element: element,
    nodeName: element.nodeName,
    parentNode: element.parentNode
  };

  var attributes = element.attributes;
  for (var index = 0; index < attributes.length; ++index) {
    var attributeName = attributes[index].name;
    if (attributeName in observedAttributes) {
      animationRecord[attributeName] = attributes[index].value;
    }
  }

  var targetRef = animationRecord['xlink:href'];
  if (targetRef && targetRef.indexOf('#') === 0) {
    animationRecord.target =
        document.getElementById(targetRef.substring(1));
  } else {
    animationRecord.target = element.parentNode;
  }

  animationRecord.timingInput = createTimingInput(animationRecord);
  animationRecord.options = createEffectOptions(animationRecord);

  animationRecords[element] = animationRecord;

  if (animationRecord.nodeName === 'mpath') {
    animationRecords[element.parentNode].mpathRecord = animationRecord;
  } else if (animationRecord.nodeName !== 'animateMotion') {
    createKeyframeAnimation(animationRecord);
  }
  // else we have animateMotion, and wait in case we have an mpath child
}

function walkSVG(node) {
  if (node.nodeName in observedTags) {
    createAnimationRecord(node);
  }
  var child = node.firstChild;
  while (child) {
    walkSVG(child);
    child = child.nextSibling;
  }

  if (node.nodeName === 'animateMotion') {
    createMotionPathAnimation(animationRecords[node]);
  }
}

window.onload = function() {

  // We would like to use document.querySelectorAll(tag) for each tag in
  // observedTags, but can't yet due to
  // querySelectorAll unable to find SVG camelCase elements in HTML
  // https://code.google.com/p/chromium/issues/detail?id=237435

  var svgFragmentList = document.querySelectorAll('svg');
  for (var index = 0; index < svgFragmentList.length; ++index) {
    walkSVG(svgFragmentList[index]);
  }
};

})();
<|endoftext|>


<commit_before>var assert        = require("assert");
var request       = require("request");
var _             = require("lodash");
var addressparser = require("addressparser");
var pkg           = require("../package.json");

//
// Constants
//
var STATUS_OK = 200;

//
// Helper
//
var responseErrorTpl = _.template("${message} (${code}, ${statusCode})");

function checkOptions(options) {
    var apiKey = options.apiKey;
    var apiUrl = options.apiUrl;

    assert(apiKey && _.isString(apiKey), "apiKey: must be a non-empty string");
    assert(apiUrl && _.isString(apiUrl), "apiUrl: must be a non-empty string");
}

function addAddress(obj, address) {
    obj[address.address] = address.name || "";
    return obj;
}

function flattenGroups(addresses) {
    var flattened = [];

    function traverse(obj) {
        if (obj.group) {
            obj.group.forEach(traverse);
        } else {
            flattened.push(obj);
        }
    }

    addresses.forEach(traverse);

    return flattened;
}

function transformAddresses(addresses) {
    return flattenGroups(addressparser(addresses)).reduce(function (obj, address) {
        return addAddress(obj, address);
    }, {});
}

function transformFromAddresses(addresses) {
    var fromAddress = flattenGroups(addressparser(addresses))[0];

    return [fromAddress.address, fromAddress.name];
}

function isErrorResponse(response) {
    if (response.statusCode !== STATUS_OK) {
        return true;
    }

    return false;
}

function responseError(response, body) {
    return new Error(responseErrorTpl({
        message:    body.message || "server error",
        code:       body.code || "-",
        statusCode: response.statusCode
    }));
}

function makeInfo(data) {
    return {
        messageId: data["message-id"] || ""
    };
}

//
// Transport class
//
function SendinBlueTransport(options) {
    checkOptions(options);

    this.options = options;
    this.name    = "SendinBlue";
    this.version = pkg.version;
}

SendinBlueTransport.prototype.send = function (mail, callback) {
    request({
        uri: this.sendUrl(),
        method: "POST",
        headers: {
            "api-key": this.options.apiKey
        },
        json: true,
        body: this.transformData(mail.data)
    }, function (err, response, body) {
        if (err) {
            return callback(err);
        }

        if (isErrorResponse(response)) {
            return callback(responseError(response, body));
        }

        callback(null, makeInfo(body.data));
    });
};

SendinBlueTransport.prototype.sendUrl = function () {
    return this.options.apiUrl + "/email";
};

SendinBlueTransport.prototype.transformData = function (data) {
    return {
        from:    transformFromAddresses(data.from),
        to:      transformAddresses(data.to),
        cc:      transformAddresses(data.cc),
        bcc:     transformAddresses(data.bcc),
        replyto: transformFromAddresses(data.replyTo),
        subject: data.subject,
        text:    data.text,
        html:    data.html
    };
};

module.exports = function (options) {
    return new SendinBlueTransport(options);
};
<commit_msg>Build api end point in constructor<commit_after>var assert        = require("assert");
var request       = require("request");
var _             = require("lodash");
var addressparser = require("addressparser");
var pkg           = require("../package.json");

//
// Constants
//
var STATUS_OK = 200;

//
// Helper
//
var responseErrorTpl = _.template("${message} (${code}, ${statusCode})");

function checkOptions(options) {
    var apiKey = options.apiKey;
    var apiUrl = options.apiUrl;

    assert(apiKey && _.isString(apiKey), "apiKey: must be a non-empty string");
    assert(apiUrl && _.isString(apiUrl), "apiUrl: must be a non-empty string");
}

function addAddress(obj, address) {
    obj[address.address] = address.name || "";
    return obj;
}

function flattenGroups(addresses) {
    var flattened = [];

    function traverse(obj) {
        if (obj.group) {
            obj.group.forEach(traverse);
        } else {
            flattened.push(obj);
        }
    }

    addresses.forEach(traverse);

    return flattened;
}

function transformAddresses(addresses) {
    return flattenGroups(addressparser(addresses)).reduce(function (obj, address) {
        return addAddress(obj, address);
    }, {});
}

function transformFromAddresses(addresses) {
    var fromAddress = flattenGroups(addressparser(addresses))[0];

    return [fromAddress.address, fromAddress.name];
}

function isErrorResponse(response) {
    if (response.statusCode !== STATUS_OK) {
        return true;
    }

    return false;
}

function responseError(response, body) {
    return new Error(responseErrorTpl({
        message:    body.message || "server error",
        code:       body.code || "-",
        statusCode: response.statusCode
    }));
}

function makeInfo(data) {
    return {
        messageId: data["message-id"] || ""
    };
}

//
// Transport class
//
function SendinBlueTransport(options) {
    checkOptions(options);

    this.apiKey = options.apiKey;
    this.apiEndPoint = options.apiUrl + "/email";

    this.name    = "SendinBlue";
    this.version = pkg.version;
}

SendinBlueTransport.prototype.send = function (mail, callback) {
    request({
        uri: this.apiEndPoint,
        method: "POST",
        headers: {
            "api-key": this.apiKey
        },
        json: true,
        body: this.transformData(mail.data)
    }, function (err, response, body) {
        if (err) {
            return callback(err);
        }

        if (isErrorResponse(response)) {
            return callback(responseError(response, body));
        }

        callback(null, makeInfo(body.data));
    });
};

SendinBlueTransport.prototype.transformData = function (data) {
    return {
        from:    transformFromAddresses(data.from),
        to:      transformAddresses(data.to),
        cc:      transformAddresses(data.cc),
        bcc:     transformAddresses(data.bcc),
        replyto: transformFromAddresses(data.replyTo),
        subject: data.subject,
        text:    data.text,
        html:    data.html
    };
};

module.exports = function (options) {
    return new SendinBlueTransport(options);
};
<|endoftext|>


<commit_before>(function() {
    var fitopts = {min: 6, max: 1000};

    var Gauge = function(json) {
      view.View.call(this, json);
      this.query = json.query;
      this.title = json.title;
      this.clickFocusable = true;
      this.el.addClass('gauge');
      this.el.append(
        '
' +
          '
?
' +
          '

' +
          '
'
      );

      this.box = this.el.find('.box');
      this.el.find('h2').text(this.title);

      if (this.query) {
        var reflowed = false;
        var me = this;
        var value = this.el.find('.value');
        this.sub = subs.subscribe(this.query, function(e) {
          me.box.attr('class', 'box state ' + e.state);
          value.text(format.float(e.metric));
          value.attr('title', e.description);

          // The first time, do a full-height reflow.
          if (reflowed) {
            value.quickfit(fitopts);
          } else {
            me.reflow();
            reflowed = true;
          }
        });
      }
    }

    view.inherit(view.View, Gauge);
    view.Gauge = Gauge;
    view.types.Gauge = Gauge;

    Gauge.prototype.json = function() {
      return $.extend(view.View.prototype.json.call(this), {
        type: 'Gauge',
        title: this.title,
        query: this.query
      });
    }

    var editTemplate = _.template(
        "Title" +
        "<input type='text' name='title' value='{{title}}' />
" +
        "Query" +
        '<textarea type="text" name="query" class="query">{{query}}</textarea>'    );

    Gauge.prototype.editForm = function() {
      return editTemplate(this);
    }

    Gauge.prototype.reflow = function() {
      // Size metric
      var value = this.el.find('.value');
      value.quickfit({min: 6, max: 1000, font_height_scale: 1});

      // Size title
      var title = this.el.find('h2');
      title.quickfit(fitopts);
    }

    Gauge.prototype.delete = function() {
      if (this.sub) {
        subs.unsubscribe(this.sub);
      }
      view.View.prototype.delete.call(this);
    }
})();
<commit_msg>update Gauge control to optionally format metrics using thousands separators<commit_after>(function() {
    var fitopts = {min: 6, max: 1000};

    var Gauge = function(json) {
      view.View.call(this, json);
      this.query = json.query;
      this.title = json.title;
      this.commaSeperateThousands = json.commaSeperateThousands;
      this.clickFocusable = true;
      this.el.addClass('gauge');
      this.el.append(
        '
' +
          '
?
' +
          '

' +
          '
'
      );

      this.box = this.el.find('.box');
      this.el.find('h2').text(this.title);

      if (this.query) {
        var reflowed = false;
        var me = this;
        var value = this.el.find('.value');
        this.sub = subs.subscribe(this.query, function(e) {
          me.box.attr('class', 'box state ' + e.state);
          value.text(format.float(e.metric, 2, me.commaSeperateThousands));
          value.attr('title', e.description);

          // The first time, do a full-height reflow.
          if (reflowed) {
            value.quickfit(fitopts);
          } else {
            me.reflow();
            reflowed = true;
          }
        });
      }
    }

    view.inherit(view.View, Gauge);
    view.Gauge = Gauge;
    view.types.Gauge = Gauge;

    Gauge.prototype.json = function() {
      return $.extend(view.View.prototype.json.call(this), {
        type: 'Gauge',
        title: this.title,
        query: this.query,
        commaSeperateThousands: this.commaSeperateThousands
      });
    }

    var editTemplate = _.template(
        "Title" +
        "<input type='text' name='title' value='{{title}}' />
" +
        "Query" +
        '<textarea type="text" name="query" class="query">{{query}}</textarea>' +
        "Comma Seperate Thousands" +
        "<input type='checkbox' name='commaSeperateThousands' {% if(commaSeperateThousands)  { %} checked='checked' {% } %} />" );

    Gauge.prototype.editForm = function() {
      return editTemplate(this);
    }

    Gauge.prototype.reflow = function() {
      // Size metric
      var value = this.el.find('.value');
      value.quickfit({min: 6, max: 1000, font_height_scale: 1});

      // Size title
      var title = this.el.find('h2');
      title.quickfit(fitopts);
    }

    Gauge.prototype.delete = function() {
      if (this.sub) {
        subs.unsubscribe(this.sub);
      }
      view.View.prototype.delete.call(this);
    }
})();
<|endoftext|>


<commit_before>'use strict';

const INLINE_ELEMENTS = [
  'a',
  'abbr',
  'acronym',
  'b',
  'bdo',
  'big',
  'br',
  'button',
  'cite',
  'code',
  'dfn',
  'em',
  'i',
  'img',
  'input',
  'kbd',
  'label',
  'map',
  'object',
  'q',
  'samp',
  'script',
  'select',
  'small',
  'span',
  'strong',
  'sub',
  'sup',
  'textarea',
  'tt',
  'var'
];

module.exports = {
  meta: {
    docs: {
      description: 'Ensures inline tags are not rendered without spaces between them',
      category: 'Stylistic Issues',
      recommended: false
    },
    fixable: false,
    schema: [
      {
        type: 'object',
        properties: {},
        default: {},
        additionalProperties: false
      }
    ]
  },
  create: function (context) {
    const elementName = node => (
      node.openingElement &&
      node.openingElement.name &&
      node.openingElement.name.type === 'JSXIdentifier' &&
      node.openingElement.name.name
    );

    const isInlineElement = node => (
      node.type === 'JSXElement' &&
      INLINE_ELEMENTS.indexOf(elementName(node)) !== -1
    );

    const TEXT_FOLLOWING_ELEMENT_PATTERN = /^\s*\n\s*\S/;
    const TEXT_PRECEDING_ELEMENT_PATTERN = /\S\s*\n\s*$/;

    return {
      JSXElement: function(node) {
        let lastChild = null;
        let child = null;
        (node.children.concat([null])).forEach(nextChild => {
          if (
            (lastChild || nextChild) &&
            (!lastChild || isInlineElement(lastChild)) &&
            (child && child.type === 'Literal') &&
            (!nextChild || isInlineElement(nextChild)) &&
            true
          ) {
            if (lastChild && child.value.match(TEXT_FOLLOWING_ELEMENT_PATTERN)) {
              context.report({
                node: child,
                loc: child.loc,
                message: `Ambiguous spacing after previous element ${elementName(lastChild)}`
              });
            } else if (nextChild && child.value.match(TEXT_PRECEDING_ELEMENT_PATTERN)) {
              context.report({
                node: child,
                loc: child.loc,
                message: `Ambiguous spacing before next element ${elementName(nextChild)}`
              });
            }
          }
          lastChild = child;
          child = nextChild;
        });
      }
    };
  }
};
<commit_msg>Review comments<commit_after>'use strict';

// This list is taken from https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
const INLINE_ELEMENTS = new Set([
  'a',
  'abbr',
  'acronym',
  'b',
  'bdo',
  'big',
  'br',
  'button',
  'cite',
  'code',
  'dfn',
  'em',
  'i',
  'img',
  'input',
  'kbd',
  'label',
  'map',
  'object',
  'q',
  'samp',
  'script',
  'select',
  'small',
  'span',
  'strong',
  'sub',
  'sup',
  'textarea',
  'tt',
  'var'
]);

module.exports = {
  meta: {
    docs: {
      description: 'Ensures inline tags are not rendered without spaces between them',
      category: 'Stylistic Issues',
      recommended: false
    },
    fixable: false,
    schema: [
      {
        type: 'object',
        properties: {},
        default: {},
        additionalProperties: false
      }
    ]
  },
  create: function (context) {
    const elementName = node => (
      node.openingElement &&
      node.openingElement.name &&
      node.openingElement.name.type === 'JSXIdentifier' &&
      node.openingElement.name.name
    );

    const isInlineElement = node => (
      node.type === 'JSXElement' &&
      INLINE_ELEMENTS.has(elementName(node))
    );

    const TEXT_FOLLOWING_ELEMENT_PATTERN = /^\s*\n\s*\S/;
    const TEXT_PRECEDING_ELEMENT_PATTERN = /\S\s*\n\s*$/;

    return {
      JSXElement: function(node) {
        let lastChild = null;
        let child = null;
        (node.children.concat([null])).forEach(nextChild => {
          if (
            (lastChild || nextChild) &&
            (!lastChild || isInlineElement(lastChild)) &&
            (child && child.type === 'Literal') &&
            (!nextChild || isInlineElement(nextChild)) &&
            true
          ) {
            if (lastChild && child.value.match(TEXT_FOLLOWING_ELEMENT_PATTERN)) {
              context.report({
                node: child,
                loc: child.loc,
                message: `Ambiguous spacing after previous element ${elementName(lastChild)}`
              });
            } else if (nextChild && child.value.match(TEXT_PRECEDING_ELEMENT_PATTERN)) {
              context.report({
                node: child,
                loc: child.loc,
                message: `Ambiguous spacing before next element ${elementName(nextChild)}`
              });
            }
          }
          lastChild = child;
          child = nextChild;
        });
      }
    };
  }
};
<|endoftext|>


<commit_before>/**
 * @depend ../../sinon.js
 * @depend event.js
 */
/*jslint eqeqeq: false, onevar: false*/
/*global sinon, module, require, XDomainRequest*/
/**
 * Fake XDomainRequest object
 */
"use strict";

if (typeof sinon == "undefined") {
    this.sinon = {};
}
sinon.xdr = { XDomainRequest: this.XDomainRequest };

// wrapper for global
(function (global) {
    var xdr = sinon.xdr;
    xdr.GlobalXDomainRequest = global.XDomainRequest;
    xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
    xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest :  false;

    function FakeXDomainRequest() {
        this.readyState = FakeXDomainRequest.UNSENT;
        this.requestBody = null;
        this.status = 0;

        if (typeof FakeXDomainRequest.onCreate == "function") {
            FakeXDomainRequest.onCreate(this);
        }
    }

    function verifyState(xdr) {
        if (xdr.readyState !== FakeXDomainRequest.OPENED) {
            throw new Error("INVALID_STATE_ERR");
        }

        if (xdr.sendFlag) {
            throw new Error("INVALID_STATE_ERR");
        }
    }

    function verifyRequestSent(xdr) {
        if (xdr.readyState == FakeXDomainRequest.DONE) {
            throw new Error("Request done");
        }
    }

    function verifyResponseBodyType(body) {
        if (typeof body != "string") {
            var error = new Error("Attempted to respond to fake XDomainRequest with " +
                                 body + ", which is not a string.");
            error.name = "InvalidBodyException";
            throw error;
        }
    }

    sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
        open: function open(method, url) {
            this.method = method;
            this.url = url;

            this.responseText = null;
            this.sendFlag = false;

            this.readyStateChange(FakeXDomainRequest.OPENED);
        },

        readyStateChange: function readyStateChange(state) {
            this.readyState = state;
            var eventName = '';
            switch (this.readyState) {
                case FakeXDomainRequest.UNSENT:
                    break;
                case FakeXDomainRequest.OPENED:
                    break;
                case FakeXDomainRequest.LOADING:
                    if (this.sendFlag){
                        //raise the progress event
                        eventName = 'onprogress';
                    }
                    break;
                case FakeXDomainRequest.DONE:
                    if (this.errorFlag || (this.status < 200 || this.status > 299)) {
                        eventName = 'onerror';
                    }
                    else if (this.isTimeout){
                        eventName = 'ontimeout'
                    }
                    else {
                        eventName = 'onload'
                    }
                    break;
            }

            // raising event (if defined)
            if (eventName) {
                if (typeof this[eventName] == "function") {
                    try {
                        this[eventName]();
                    } catch (e) {
                        sinon.logError("Fake XHR " + eventName + " handler", e);
                    }
                }
            }
        },

        send: function send(data) {
            verifyState(this);

            if (!/^(get|head)$/i.test(this.method)) {
                this.requestBody = data;
            }

            this.errorFlag = false;
            this.sendFlag = true;
            this.readyStateChange(FakeXDomainRequest.OPENED);

            if (typeof this.onSend == "function") {
                this.onSend(this);
            }
        },

        abort: function abort() {
            this.aborted = true;
            this.responseText = null;
            this.errorFlag = true;

            if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
                this.readyStateChange(sinon.FakeXDomainRequest.DONE);
                this.sendFlag = false;
            }
        },
        setResponseBody: function setResponseBody(body) {
            verifyRequestSent(this);
            verifyResponseBodyType(body);

            var chunkSize = this.chunkSize || 10;
            var index = 0;
            this.responseText = "";

            do {
                this.readyStateChange(FakeXDomainRequest.LOADING);
                this.responseText += body.substring(index, index + chunkSize);
                index += chunkSize;
            } while (index < body.length);

            this.readyStateChange(FakeXDomainRequest.DONE);
        },

        respond: function respond(status, contentType, body) {
            // content-type ignored, since XDomainRequest does not carry this
			// we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
			// test integration across browsers
            this.status = typeof status == "number" ? status : 200;
            this.setResponseBody(body || "");
        },
        simulatetimeout: function(){
		    this.status = 0;
            this.isTimeout = true;
            this.setResponseBody("");
        }
    });

    sinon.extend(FakeXDomainRequest, {
        UNSENT: 0,
        OPENED: 1,
        LOADING: 3,
        DONE: 4
    });

    sinon.useFakeXDomainRequest = function () {
        sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
            if (xdr.supportsXDR) {
                global.XDomainRequest = xdr.GlobalXDomainRequest;
            }

            delete sinon.FakeXDomainRequest.restore;

            if (keepOnCreate !== true) {
                delete sinon.FakeXDomainRequest.onCreate;
            }
        };
        if (xdr.supportsXDR) {
            global.XDomainRequest = sinon.FakeXDomainRequest;
        }
        return sinon.FakeXDomainRequest;
    };

    sinon.FakeXDomainRequest = FakeXDomainRequest;
})(this);

if (typeof module == "object" && typeof require == "function") {
    module.exports = sinon;
}
<commit_msg>Indentation fixes<commit_after>/**
 * @depend ../../sinon.js
 * @depend event.js
 */
/*jslint eqeqeq: false, onevar: false*/
/*global sinon, module, require, XDomainRequest*/
/**
 * Fake XDomainRequest object
 */
"use strict";

if (typeof sinon == "undefined") {
    this.sinon = {};
}
sinon.xdr = { XDomainRequest: this.XDomainRequest };

// wrapper for global
(function (global) {
    var xdr = sinon.xdr;
    xdr.GlobalXDomainRequest = global.XDomainRequest;
    xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
    xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest :  false;

    function FakeXDomainRequest() {
        this.readyState = FakeXDomainRequest.UNSENT;
        this.requestBody = null;
        this.status = 0;

        if (typeof FakeXDomainRequest.onCreate == "function") {
            FakeXDomainRequest.onCreate(this);
        }
    }

    function verifyState(xdr) {
        if (xdr.readyState !== FakeXDomainRequest.OPENED) {
            throw new Error("INVALID_STATE_ERR");
        }

        if (xdr.sendFlag) {
            throw new Error("INVALID_STATE_ERR");
        }
    }

    function verifyRequestSent(xdr) {
        if (xdr.readyState == FakeXDomainRequest.DONE) {
            throw new Error("Request done");
        }
    }

    function verifyResponseBodyType(body) {
        if (typeof body != "string") {
            var error = new Error("Attempted to respond to fake XDomainRequest with " +
                                 body + ", which is not a string.");
            error.name = "InvalidBodyException";
            throw error;
        }
    }

    sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
        open: function open(method, url) {
            this.method = method;
            this.url = url;

            this.responseText = null;
            this.sendFlag = false;

            this.readyStateChange(FakeXDomainRequest.OPENED);
        },

        readyStateChange: function readyStateChange(state) {
            this.readyState = state;
            var eventName = '';
            switch (this.readyState) {
                case FakeXDomainRequest.UNSENT:
                    break;
                case FakeXDomainRequest.OPENED:
                    break;
                case FakeXDomainRequest.LOADING:
                    if (this.sendFlag){
                        //raise the progress event
                        eventName = 'onprogress';
                    }
                    break;
                case FakeXDomainRequest.DONE:
                    if (this.errorFlag || (this.status < 200 || this.status > 299)) {
                        eventName = 'onerror';
                    }
                    else if (this.isTimeout){
                        eventName = 'ontimeout'
                    }
                    else {
                        eventName = 'onload'
                    }
                    break;
            }

            // raising event (if defined)
            if (eventName) {
                if (typeof this[eventName] == "function") {
                    try {
                        this[eventName]();
                    } catch (e) {
                        sinon.logError("Fake XHR " + eventName + " handler", e);
                    }
                }
            }
        },

        send: function send(data) {
            verifyState(this);

            if (!/^(get|head)$/i.test(this.method)) {
                this.requestBody = data;
            }

            this.errorFlag = false;
            this.sendFlag = true;
            this.readyStateChange(FakeXDomainRequest.OPENED);

            if (typeof this.onSend == "function") {
                this.onSend(this);
            }
        },

        abort: function abort() {
            this.aborted = true;
            this.responseText = null;
            this.errorFlag = true;

            if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
                this.readyStateChange(sinon.FakeXDomainRequest.DONE);
                this.sendFlag = false;
            }
        },
        setResponseBody: function setResponseBody(body) {
            verifyRequestSent(this);
            verifyResponseBodyType(body);

            var chunkSize = this.chunkSize || 10;
            var index = 0;
            this.responseText = "";

            do {
                this.readyStateChange(FakeXDomainRequest.LOADING);
                this.responseText += body.substring(index, index + chunkSize);
                index += chunkSize;
            } while (index < body.length);

            this.readyStateChange(FakeXDomainRequest.DONE);
        },

        respond: function respond(status, contentType, body) {
            // content-type ignored, since XDomainRequest does not carry this
            // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
            // test integration across browsers
            this.status = typeof status == "number" ? status : 200;
            this.setResponseBody(body || "");
        },
        simulatetimeout: function(){
            this.status = 0;
            this.isTimeout = true;
            this.setResponseBody("");
        }
    });

    sinon.extend(FakeXDomainRequest, {
        UNSENT: 0,
        OPENED: 1,
        LOADING: 3,
        DONE: 4
    });

    sinon.useFakeXDomainRequest = function () {
        sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
            if (xdr.supportsXDR) {
                global.XDomainRequest = xdr.GlobalXDomainRequest;
            }

            delete sinon.FakeXDomainRequest.restore;

            if (keepOnCreate !== true) {
                delete sinon.FakeXDomainRequest.onCreate;
            }
        };
        if (xdr.supportsXDR) {
            global.XDomainRequest = sinon.FakeXDomainRequest;
        }
        return sinon.FakeXDomainRequest;
    };

    sinon.FakeXDomainRequest = FakeXDomainRequest;
})(this);

if (typeof module == "object" && typeof require == "function") {
    module.exports = sinon;
}
<|endoftext|>


<commit_before>/*
 * App submission Tracking Initialization
 * Requirements by Gareth Cull
 * https://bugzilla.mozilla.org/show_bug.cgi?id=957347
 * TODO: Post validator error/success message tracking.
 */

define('tracking_app_submit', [], function() {
    if (!_gaq) {
        return;
    }

    var logTracking = false;

    function log(msg) {
        if (logTracking) {
            console.log(msg);
        }
    }

    // Step 1: Submit an app button is clicked.
    $('#partnership').on('click', '.submit-app .button', function() {
        _gaq.push([
            '_trackEvent',
            'Sumbit an App CTA',
            'click',
            $(this).text()
        ]);

        log('Submit an app button click tracked...');
    });

    function videoEvent(action, id) {
        _gaq.push([
            '_trackEvent',
            'Interactions with Video',
            action,
            id
        ]);

        log('Video ' + action + ' event tracked...');
    }

    // Step 1: Video playback control.
    // Partners page video playback control.
    function initVideoEvents() {
        $('video').each(function() {
            var $this = $(this);
            var id = $this.closest('.video-item').attr('id');

            $this.on('play', function() {
                videoEvent('play', id);
            }).on('pause', function() {
                videoEvent('pause', id);
            }).on('ended', function() {
                videoEvent('finish', id);
            });
        });
    }

    initVideoEvents();

    function socialLinkEvent(label) {
        _gaq.push([
            '_trackEvent',
            'Follow Firefox Apps',
            'click',
            label
        ]);

        log(label + ' social link event tracked...');
    }

    // Partners page: Social links.
    $('.connected').on('click', '.marketplace a', function() {
        socialLinkEvent('Apps Blog');
    }).on('click', '.twitter a', function() {
        socialLinkEvent('Twitter');
    }).on('click', '.youtube a', function() {
        socialLinkEvent('YouTube Channel');
    }).on('click', '.email a', function() {
        socialLinkEvent('Email');
    });

    // Step 1: Packaged app "select a file" button is clicked.
    $('#upload-app').on('click', function() {
        _gaq.push([
            '_trackEvent',
            'Packaged App Validation',
            'click',
            'Select a file'
        ]);

        log('Packaged app select file button tracked...');
    });

    // Step 3: View app listing click.
    $('.edit-addon-nav').on('click', 'li:last-child a', function() {
        _gaq.push([
            '_trackEvent',
            'Open Preview App Page',
            'click',
            'Preview App from Submission Flow Step 3'
        ]);

        log('View listing click tracked...');
    });

    // Edit page: User submitted "requires flash".
    $('#edit-app-technical').on('submit', 'form', function() {
        if ($('#id_flash:checked').length) {
            _gaq.push([
                '_trackEvent',
                'App Requires Flash Support',
                'click',
                'Yes'
            ]);

            log('App requires flash submission tracked...');
        }
    });

    // Step 2: Validate button triggered failed validation.
    $('#upload-webapp-url').on('upload_errors', function(e, r) {
        var numErrors = r.validation.errors;

        _gaq.push([
            '_trackEvent',
            'Hosted App Validation',
            'unsuccessful',
            numErrors + ' validation errors occurred'
        ]);

        log('Failed verify tracked...');
    }).on('upload_success', function(e, r) { // Successful validation.
        var nonErrors = r.validation.warnings + r.validation.notices;

        _gaq.push([
            '_trackEvent',
            'Hosted App Validation',
            'successful',
            nonErrors + ' validation warnings/notices occurred'
        ]);

        log('Successful verify tracked...');
    });

    // Step 2: App form submitted. Track which app types were selected.
    $('#upload-webapp').on('submit', function(e) {
        var selectSel = '#id_free_platforms';
        if ($('#paid-tab-header.active')[0]) {
            selectSel = '#id_paid_platforms';
        }
        var selectedAppTypes = $(selectSel).val();
        if (selectedAppTypes && selectedAppTypes.length) {
            _gaq.push([
                '_setCustomVar',
                14,
                'Selected App Types',
                selectedAppTypes.join(', '),
                1
            ]);
            log('App types selection tracked...');
        } else {
            log('No app types selected');
        }
    });

    // MDN link was clicked. Opens in a new tab so flow is uninterrupted.
    $('.learn-mdn').on('click', 'a', function() {
        _gaq.push([
            '_trackEvent',
            'MDN Exits',
            'click',
            'MDN App Manifests'
        ]);

        log('MDN link tracked...');
    });

    // Step 3: Form submitted. Track which categories were selected.
    // Track whether 'requires flash' was checked.
    // Track whether 'publish my app as soon as...' was unchecked.
    $('#submit-media').on('submit', function() {
        var cats = [];
        $('.addon-categories input:checked').each(function() {
            cats.push($(this).closest('label').text());
        });

        _gaq.push([
            '_setCustomVar',
            15,
            'Dev: App Category Submitted',
            cats.join(', '),
            1
        ]);

        if ($('#id_publish:checked').length === 0) {
            _gaq.push([
                '_trackEvent',
                "Publish my app in the Firefox Marketplace as soon as it's reviewed",
                'uncheck',
                'Opting Out'
            ]);

            log('Publish soon opt-out tracked...');
        }

        if ($('input[name=flash][value=1]:checked').length) {
            _gaq.push([
                '_trackEvent',
                'App Requires Flash Support',
                'click',
                'Yes'
            ]);

            log('App requires flash submission tracked...');
        }

        log('Category choices tracked...');
    });

    // Step 4: Page loaded.
    if ($('#submit-next-steps').length) {
        _gaq.push([
            '_trackEvent',
            'App Successfully Submitted',
            'onload',
            location.href
        ]);

        log('Step 4 page load tracked...');
    }

    // Step 3 page loaded. Track any errors.
    if ($('#submit-details').length) {
        var $errorLists = $('.errorlist:visible');
        var fields = [];

        if ($errorLists.length === 0) {
            return;
        }

        $errorLists.each(function() {
            fields.push($(this).closest('div:not(.error)').attr('id') || 'unknown field');
        });

        _gaq.push([
            '_trackEvent',
            'Details Page Submission Errors from Required Fields',
            'error',
            fields.join(', '),
            $errorLists.length
        ]);
    }
});
<commit_msg>rm dimension15, it's used in fireplace (bug 1139478)<commit_after>/*
 * App submission Tracking Initialization
 * Requirements by Gareth Cull
 * https://bugzilla.mozilla.org/show_bug.cgi?id=957347
 * TODO: Post validator error/success message tracking.
 */

define('tracking_app_submit', [], function() {
    if (!_gaq) {
        return;
    }

    var logTracking = false;

    function log(msg) {
        if (logTracking) {
            console.log(msg);
        }
    }

    // Step 1: Submit an app button is clicked.
    $('#partnership').on('click', '.submit-app .button', function() {
        _gaq.push([
            '_trackEvent',
            'Sumbit an App CTA',
            'click',
            $(this).text()
        ]);

        log('Submit an app button click tracked...');
    });

    function videoEvent(action, id) {
        _gaq.push([
            '_trackEvent',
            'Interactions with Video',
            action,
            id
        ]);

        log('Video ' + action + ' event tracked...');
    }

    // Step 1: Video playback control.
    // Partners page video playback control.
    function initVideoEvents() {
        $('video').each(function() {
            var $this = $(this);
            var id = $this.closest('.video-item').attr('id');

            $this.on('play', function() {
                videoEvent('play', id);
            }).on('pause', function() {
                videoEvent('pause', id);
            }).on('ended', function() {
                videoEvent('finish', id);
            });
        });
    }

    initVideoEvents();

    function socialLinkEvent(label) {
        _gaq.push([
            '_trackEvent',
            'Follow Firefox Apps',
            'click',
            label
        ]);

        log(label + ' social link event tracked...');
    }

    // Partners page: Social links.
    $('.connected').on('click', '.marketplace a', function() {
        socialLinkEvent('Apps Blog');
    }).on('click', '.twitter a', function() {
        socialLinkEvent('Twitter');
    }).on('click', '.youtube a', function() {
        socialLinkEvent('YouTube Channel');
    }).on('click', '.email a', function() {
        socialLinkEvent('Email');
    });

    // Step 1: Packaged app "select a file" button is clicked.
    $('#upload-app').on('click', function() {
        _gaq.push([
            '_trackEvent',
            'Packaged App Validation',
            'click',
            'Select a file'
        ]);

        log('Packaged app select file button tracked...');
    });

    // Step 3: View app listing click.
    $('.edit-addon-nav').on('click', 'li:last-child a', function() {
        _gaq.push([
            '_trackEvent',
            'Open Preview App Page',
            'click',
            'Preview App from Submission Flow Step 3'
        ]);

        log('View listing click tracked...');
    });

    // Edit page: User submitted "requires flash".
    $('#edit-app-technical').on('submit', 'form', function() {
        if ($('#id_flash:checked').length) {
            _gaq.push([
                '_trackEvent',
                'App Requires Flash Support',
                'click',
                'Yes'
            ]);

            log('App requires flash submission tracked...');
        }
    });

    // Step 2: Validate button triggered failed validation.
    $('#upload-webapp-url').on('upload_errors', function(e, r) {
        var numErrors = r.validation.errors;

        _gaq.push([
            '_trackEvent',
            'Hosted App Validation',
            'unsuccessful',
            numErrors + ' validation errors occurred'
        ]);

        log('Failed verify tracked...');
    }).on('upload_success', function(e, r) { // Successful validation.
        var nonErrors = r.validation.warnings + r.validation.notices;

        _gaq.push([
            '_trackEvent',
            'Hosted App Validation',
            'successful',
            nonErrors + ' validation warnings/notices occurred'
        ]);

        log('Successful verify tracked...');
    });

    // Step 2: App form submitted. Track which app types were selected.
    $('#upload-webapp').on('submit', function(e) {
        var selectSel = '#id_free_platforms';
        if ($('#paid-tab-header.active')[0]) {
            selectSel = '#id_paid_platforms';
        }
        var selectedAppTypes = $(selectSel).val();
        if (selectedAppTypes && selectedAppTypes.length) {
            _gaq.push([
                '_setCustomVar',
                14,
                'Selected App Types',
                selectedAppTypes.join(', '),
                1
            ]);
            log('App types selection tracked...');
        } else {
            log('No app types selected');
        }
    });

    // MDN link was clicked. Opens in a new tab so flow is uninterrupted.
    $('.learn-mdn').on('click', 'a', function() {
        _gaq.push([
            '_trackEvent',
            'MDN Exits',
            'click',
            'MDN App Manifests'
        ]);

        log('MDN link tracked...');
    });

    // Step 3: Form submitted. Track which categories were selected.
    // Track whether 'requires flash' was checked.
    // Track whether 'publish my app as soon as...' was unchecked.
    $('#submit-media').on('submit', function() {
        var cats = [];
        $('.addon-categories input:checked').each(function() {
            cats.push($(this).closest('label').text());
        });

        if ($('#id_publish:checked').length === 0) {
            _gaq.push([
                '_trackEvent',
                "Publish my app in the Firefox Marketplace as soon as it's reviewed",
                'uncheck',
                'Opting Out'
            ]);

            log('Publish soon opt-out tracked...');
        }

        if ($('input[name=flash][value=1]:checked').length) {
            _gaq.push([
                '_trackEvent',
                'App Requires Flash Support',
                'click',
                'Yes'
            ]);

            log('App requires flash submission tracked...');
        }

        log('Category choices tracked...');
    });

    // Step 4: Page loaded.
    if ($('#submit-next-steps').length) {
        _gaq.push([
            '_trackEvent',
            'App Successfully Submitted',
            'onload',
            location.href
        ]);

        log('Step 4 page load tracked...');
    }

    // Step 3 page loaded. Track any errors.
    if ($('#submit-details').length) {
        var $errorLists = $('.errorlist:visible');
        var fields = [];

        if ($errorLists.length === 0) {
            return;
        }

        $errorLists.each(function() {
            fields.push($(this).closest('div:not(.error)').attr('id') || 'unknown field');
        });

        _gaq.push([
            '_trackEvent',
            'Details Page Submission Errors from Required Fields',
            'error',
            fields.join(', '),
            $errorLists.length
        ]);
    }
});
<|endoftext|>


<commit_before>// Universal Subtitles, universalsubtitles.org
//
// Copyright (C) 2011 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('unisubs.editmetadata.Dialog');

/**
 * @constructor
 */
unisubs.editmetadata.Dialog = function(videoSource, serverModel, subtitleState) {
    unisubs.Dialog.call(this, videoSource);
    unisubs.SubTracker.getInstance().start(true);

    this.opener_ = opener;
    this.subtitleState_ = subtitleState;
    this.serverModel_ = serverModel;
    this.captionSet_ = this.serverModel_.getCaptionSet();
    this.captionManager_ = new unisubs.CaptionManager(this.getVideoPlayerInternal(), this.captionSet_);
    this.saved_ = false;
};
goog.inherits(unisubs.editmetadata.Dialog, unisubs.Dialog);

unisubs.editmetadata.Dialog.prototype.createDom = function() {
    unisubs.editmetadata.Dialog.superClass_.createDom.call(this);
    this.metadataPanel_ = new unisubs.editmetadata.EditmetadataPanel(
        this.serverModel_.getCaptionSet(), this.getVideoPlayerInternal(),
        this.serverModel_, this.captionManager_);
    this.getCaptioningAreaInternal().addChild(this.metadataPanel_, true);

    var rightPanel = this.createRightPanel_();

    this.setRightPanelInternal(rightPanel);
    this.getHandler().
        listen(
            rightPanel, unisubs.RightPanel.EventType.DONE,
            this.handleDoneKeyPress_).
        listen(
            rightPanel, unisubs.RightPanel.EventType.SAVEANDEXIT,
            this.handleSaveAndExitKeyPress_);
    goog.dom.classes.add(this.getContentElement(), 'unisubs-modal-widget-translate');
    this.showGuidelines_();

    this.timelineSubtitleSet_ = new unisubs.timeline.SubtitleSet(this.captionSet_, this.getVideoPlayerInternal());
    this.getTimelinePanelInternal().addChild(
        new unisubs.timeline.Timeline(1, this.timelineSubtitleSet_,
                                      this.getVideoPlayerInternal(), true), true);
};

unisubs.editmetadata.Dialog.prototype.showGuidelines_ = function() {
    if (!unisubs.guidelines['review']) {
        return;
    }

    var guidelinesPanel = new unisubs.GuidelinesPanel(unisubs.guidelines['review']);
    this.showTemporaryPanel(guidelinesPanel);
    this.displayingGuidelines_ = true;

    var that = this;
    this.getHandler().listenOnce(guidelinesPanel, unisubs.GuidelinesPanel.CONTINUE, function(e) {
        goog.Timer.callOnce(function() {
            that.displayingGuidelines_ = false;
            that.hideTemporaryPanel();
        });
    });
};

unisubs.editmetadata.Dialog.prototype.createRightPanel_ = function() {
    var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
    var title = "Edit Title & Description Subtitles";
    var helpContents = new unisubs.RightPanel.HelpContents(title, [
        $d('p', {}, "Edit title and description for this video."),
    ]);
    return new unisubs.editmetadata.EditmetadataRightPanel(
        this, this.serverModel_, helpContents, [], false, "Done?", "Submit final Review");
};

unisubs.editmetadata.Dialog.prototype.captionReached_ = function(event) {
    var c = event.caption;
    this.getVideoPlayerInternal().showCaptionText(c ? c.getText() : '');
};

unisubs.editmetadata.Dialog.prototype.enterDocument = function() {
    unisubs.editmetadata.Dialog.superClass_.enterDocument.call(this);
    unisubs.Dialog.translationDialogOpen = false;
    var doc = this.getDomHelper().getDocument();
    this.getHandler().listen(
            this.captionManager_,
            unisubs.CaptionManager.CAPTION,
            this.captionReached_);
};

unisubs.editmetadata.Dialog.prototype.disposeInternal = function() {
    unisubs.editmetadata.Dialog.superClass_.disposeInternal.call(this);
    this.serverModel_.dispose();
    this.timelineSubtitleSet_.dispose();
    this.timelineSubtitleSet_ = null;
};

unisubs.editmetadata.Dialog.prototype.getSubtitleLanguage = function() {
    return this.subtitleState_.LANGUAGE;
};

unisubs.editmetadata.Dialog.prototype.getServerModel = function() {
    return this.serverModel_;
};

unisubs.editmetadata.Dialog.prototype.isWorkSaved = function() {
    return this.saved_ || false;
};

unisubs.editmetadata.Dialog.prototype.saveWorkInternal = function(closeAfterSave) {
    var that = this;
    this.getRightPanelInternal().showLoading(true);
    this.getRightPanelInternal().finish('In Progress');
};

unisubs.editmetadata.Dialog.prototype.onWorkSaved = function(closeAfterSave){
    this.saved_ = true;
    unisubs.widget.ResumeEditingRecord.clear();
    if (this.finishFailDialog_) {
        this.finishFailDialog_.setVisible(false);
        this.finishFailDialog_ = null;
    }
    if (closeAfterSave) {
        this.setVisible(false);
    }
};
<commit_msg>Fixed trailing comma and therefore compiled js on the widget<commit_after>// Universal Subtitles, universalsubtitles.org
//
// Copyright (C) 2011 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('unisubs.editmetadata.Dialog');

/**
 * @constructor
 */
unisubs.editmetadata.Dialog = function(videoSource, serverModel, subtitleState) {
    unisubs.Dialog.call(this, videoSource);
    unisubs.SubTracker.getInstance().start(true);

    this.opener_ = opener;
    this.subtitleState_ = subtitleState;
    this.serverModel_ = serverModel;
    this.captionSet_ = this.serverModel_.getCaptionSet();
    this.captionManager_ = new unisubs.CaptionManager(this.getVideoPlayerInternal(), this.captionSet_);
    this.saved_ = false;
};
goog.inherits(unisubs.editmetadata.Dialog, unisubs.Dialog);

unisubs.editmetadata.Dialog.prototype.createDom = function() {
    unisubs.editmetadata.Dialog.superClass_.createDom.call(this);
    this.metadataPanel_ = new unisubs.editmetadata.EditmetadataPanel(
        this.serverModel_.getCaptionSet(), this.getVideoPlayerInternal(),
        this.serverModel_, this.captionManager_);
    this.getCaptioningAreaInternal().addChild(this.metadataPanel_, true);

    var rightPanel = this.createRightPanel_();

    this.setRightPanelInternal(rightPanel);
    this.getHandler().
        listen(
            rightPanel, unisubs.RightPanel.EventType.DONE,
            this.handleDoneKeyPress_).
        listen(
            rightPanel, unisubs.RightPanel.EventType.SAVEANDEXIT,
            this.handleSaveAndExitKeyPress_);
    goog.dom.classes.add(this.getContentElement(), 'unisubs-modal-widget-translate');
    this.showGuidelines_();

    this.timelineSubtitleSet_ = new unisubs.timeline.SubtitleSet(this.captionSet_, this.getVideoPlayerInternal());
    this.getTimelinePanelInternal().addChild(
        new unisubs.timeline.Timeline(1, this.timelineSubtitleSet_,
                                      this.getVideoPlayerInternal(), true), true);
};

unisubs.editmetadata.Dialog.prototype.showGuidelines_ = function() {
    if (!unisubs.guidelines['review']) {
        return;
    }

    var guidelinesPanel = new unisubs.GuidelinesPanel(unisubs.guidelines['review']);
    this.showTemporaryPanel(guidelinesPanel);
    this.displayingGuidelines_ = true;

    var that = this;
    this.getHandler().listenOnce(guidelinesPanel, unisubs.GuidelinesPanel.CONTINUE, function(e) {
        goog.Timer.callOnce(function() {
            that.displayingGuidelines_ = false;
            that.hideTemporaryPanel();
        });
    });
};

unisubs.editmetadata.Dialog.prototype.createRightPanel_ = function() {
    var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
    var title = "Edit Title & Description Subtitles";
    var helpContents = new unisubs.RightPanel.HelpContents(title, [
        $d('p', {}, "Edit title and description for this video.")
    ]);
    return new unisubs.editmetadata.EditmetadataRightPanel(
        this, this.serverModel_, helpContents, [], false, "Done?", "Submit final Review");
};

unisubs.editmetadata.Dialog.prototype.captionReached_ = function(event) {
    var c = event.caption;
    this.getVideoPlayerInternal().showCaptionText(c ? c.getText() : '');
};

unisubs.editmetadata.Dialog.prototype.enterDocument = function() {
    unisubs.editmetadata.Dialog.superClass_.enterDocument.call(this);
    unisubs.Dialog.translationDialogOpen = false;
    var doc = this.getDomHelper().getDocument();
    this.getHandler().listen(
            this.captionManager_,
            unisubs.CaptionManager.CAPTION,
            this.captionReached_);
};

unisubs.editmetadata.Dialog.prototype.disposeInternal = function() {
    unisubs.editmetadata.Dialog.superClass_.disposeInternal.call(this);
    this.serverModel_.dispose();
    this.timelineSubtitleSet_.dispose();
    this.timelineSubtitleSet_ = null;
};

unisubs.editmetadata.Dialog.prototype.getSubtitleLanguage = function() {
    return this.subtitleState_.LANGUAGE;
};

unisubs.editmetadata.Dialog.prototype.getServerModel = function() {
    return this.serverModel_;
};

unisubs.editmetadata.Dialog.prototype.isWorkSaved = function() {
    return this.saved_ || false;
};

unisubs.editmetadata.Dialog.prototype.saveWorkInternal = function(closeAfterSave) {
    var that = this;
    this.getRightPanelInternal().showLoading(true);
    this.getRightPanelInternal().finish('In Progress');
};

unisubs.editmetadata.Dialog.prototype.onWorkSaved = function(closeAfterSave){
    this.saved_ = true;
    unisubs.widget.ResumeEditingRecord.clear();
    if (this.finishFailDialog_) {
        this.finishFailDialog_.setVisible(false);
        this.finishFailDialog_ = null;
    }
    if (closeAfterSave) {
        this.setVisible(false);
    }
};
<|endoftext|>