<commit_before>#!/usr/bin/env node
var fs = require('fs')
var GitHubSlugger = require('github-slugger')
var markybars = require('./lib/markybars.js')
var path = require('path')
var pullOrClone = require('./lib/pull-or-clone.js')
var join = path.join
var sh = require('shelljs')
var resolve = require('path').resolve

var awesomePath = join('tmp/awesome-standard')
var buildPath = 'build'
var demoPath = join('tmp/standard-demo')
var mdPath = join('tmp/markdown')
var stdPath = join('tmp/standard')
var stdDocsPath = join('tmp/standard/docs')
var page = join('layout/page.html')
var demoPage = join('layout/demo.html')

var partials = {
  'toc': join('layout/partials/toc.html')
}

var slugger = new GitHubSlugger()

if (!sh.which('git')) {
  sh.echo('Sorry, this script requires git')
  sh.exit(1)
}

pullOrClone('https://github.com/feross/standard', stdPath)
pullOrClone('https://github.com/feross/awesome-standard', awesomePath)
pullOrClone('https://github.com/flet/standard-demo', demoPath)

sh.rm('-rf', buildPath)
sh.rm('-rf', mdPath)

sh.mkdir(buildPath)
sh.mkdir(mdPath)

sh.cp('-f', join('markdown/*.md'), mdPath)
sh.cp('-f', join(stdPath, '*.md'), mdPath)
sh.cp('-f', join(stdDocsPath, '*.md'), mdPath)
sh.cp('-f', join(awesomePath, 'README.md'), join(mdPath, 'awesome.md'))

var genPage = markybars.compile(page, partials)
var genDemo = markybars.compile(demoPage, partials)

var files = sh.ls(mdPath)
files.forEach(function (file) {
  var fileData = fs.readFileSync(join(mdPath, file), 'utf8')
  var name = path.parse(file).name
  var gen = name === 'demo' ? genDemo : genPage

  var htmlData = gen({data: fileData})
  var fileName = slugger.slug(name) + '.html'

  fs.writeFileSync(join(buildPath, fileName), htmlData, 'utf8')
})

// replace all RULES.md instances in links with rules.html
sh.sed('-i', /RULES\.md/g, 'rules.html', join(buildPath, 'readme.html'))
sh.sed('-i', /\".*docs\/webstorm\.md\"/g, '\"webstorm.html\"', join(buildPath, 'readme.html'))

// rename files to be internet friendly
sh.mv('-f', join(buildPath, 'readme.html'), join(buildPath, 'index.html'))

// once everything is built, copy it to root
sh.rm('../*.html')
sh.cp('-R', buildPath + '/', resolve(__dirname, '..'))

// copy standard-demo bundle.js to root
sh.cp('-f', join(demoPath, 'bundle.js'), resolve(__dirname, '..', 'standard-demo.js'))
<commit_msg>remove unneeded escape sequence<commit_after>#!/usr/bin/env node
var fs = require('fs')
var GitHubSlugger = require('github-slugger')
var markybars = require('./lib/markybars.js')
var path = require('path')
var pullOrClone = require('./lib/pull-or-clone.js')
var join = path.join
var sh = require('shelljs')
var resolve = require('path').resolve

var awesomePath = join('tmp/awesome-standard')
var buildPath = 'build'
var demoPath = join('tmp/standard-demo')
var mdPath = join('tmp/markdown')
var stdPath = join('tmp/standard')
var stdDocsPath = join('tmp/standard/docs')
var page = join('layout/page.html')
var demoPage = join('layout/demo.html')

var partials = {
  'toc': join('layout/partials/toc.html')
}

var slugger = new GitHubSlugger()

if (!sh.which('git')) {
  sh.echo('Sorry, this script requires git')
  sh.exit(1)
}

pullOrClone('https://github.com/feross/standard', stdPath)
pullOrClone('https://github.com/feross/awesome-standard', awesomePath)
pullOrClone('https://github.com/flet/standard-demo', demoPath)

sh.rm('-rf', buildPath)
sh.rm('-rf', mdPath)

sh.mkdir(buildPath)
sh.mkdir(mdPath)

sh.cp('-f', join('markdown/*.md'), mdPath)
sh.cp('-f', join(stdPath, '*.md'), mdPath)
sh.cp('-f', join(stdDocsPath, '*.md'), mdPath)
sh.cp('-f', join(awesomePath, 'README.md'), join(mdPath, 'awesome.md'))

var genPage = markybars.compile(page, partials)
var genDemo = markybars.compile(demoPage, partials)

var files = sh.ls(mdPath)
files.forEach(function (file) {
  var fileData = fs.readFileSync(join(mdPath, file), 'utf8')
  var name = path.parse(file).name
  var gen = name === 'demo' ? genDemo : genPage

  var htmlData = gen({data: fileData})
  var fileName = slugger.slug(name) + '.html'

  fs.writeFileSync(join(buildPath, fileName), htmlData, 'utf8')
})

// replace all RULES.md instances in links with rules.html
sh.sed('-i', /RULES\.md/g, 'rules.html', join(buildPath, 'readme.html'))
sh.sed('-i', /".*docs\/webstorm\.md"/g, '"webstorm.html"', join(buildPath, 'readme.html'))

// rename files to be internet friendly
sh.mv('-f', join(buildPath, 'readme.html'), join(buildPath, 'index.html'))

// once everything is built, copy it to root
sh.rm('../*.html')
sh.cp('-R', buildPath + '/', resolve(__dirname, '..'))

// copy standard-demo bundle.js to root
sh.cp('-f', join(demoPath, 'bundle.js'), resolve(__dirname, '..', 'standard-demo.js'))
<|endoftext|>


<commit_before>/*!
 * require-once - http://github.com/robloach/require-once
 * @license MIT
 *   http://opensource.org/licenses/MIT
 */

/**
 * Universal Module Definition: http://github.com/umdjs/umd
 *
 * Find out how we should load the packages.
 */
(function (root, factory) {
  /* global define */
  if (typeof define === 'function' && define.amd) {
    /**
     * AMD
     */
    define(function (require) {
      // Use AMD's require() wrapper.
      root.requireOne = factory(require)
      return root.requireOne
    })
  } else if (typeof exports === 'object') {
    /**
     * CommonJS
     */
    module.exports = factory(require)
  } else {
    /**
     * Global scope
     */
    root.requireOne = factory(function (packageName) {
      if (root[packageName]) {
        return root[packageName]
      }
      throw new Error('Package ' + packageName + 'not found')
    })
  }
}(this, function (requireFunction) {
  /**
   * Iterate through each package, returning the first loadable one.
   *
   * @param {(...string|string[])} packages - An array or argument list of
   *   strings representing which packages to load.
   *
   * @returns The first available package. Throws an error otherwise.
   *
   * @throws Throws an Error when none of the packages could be loaded.
   *
   * @global
   */
  return function requireFromArray (packages) {
    // Retrieve the list of package names.
    var packagesNames = Array.isArray(packages) ? packages : arguments
    for (var i in packagesNames) {
      try {
        return requireFunction(packagesNames[i])
      } catch (e) {
        // Do nothing, but continue on to the next package.
        continue
      }
    }
    throw new Error('Could not found one of the expected packages: ' + JSON.stringify(packages))
  }
}))
<commit_msg>Use 'in' for global array check<commit_after>/*!
 * require-once - http://github.com/robloach/require-once
 * @license MIT
 *   http://opensource.org/licenses/MIT
 */

/**
 * Universal Module Definition: http://github.com/umdjs/umd
 *
 * Find out how we should load the packages.
 */
(function (root, factory) {
  /* global define */
  if (typeof define === 'function' && define.amd) {
    /**
     * AMD
     */
    define(function (require) {
      // Use AMD's require() wrapper.
      root.requireOne = factory(require)
      return root.requireOne
    })
  } else if (typeof exports === 'object') {
    /**
     * CommonJS
     */
    module.exports = factory(require)
  } else {
    /**
     * Global scope
     */
    root.requireOne = factory(function (packageName) {
      if (packageName in root) {
        return root[packageName]
      }
      throw new Error('Package ' + packageName + 'not found')
    })
  }
}(this, function (requireFunction) {
  /**
   * Iterate through each package, returning the first loadable one.
   *
   * @param {(...string|string[])} packages - An array or argument list of
   *   strings representing which packages to load.
   *
   * @returns The first available package. Throws an error otherwise.
   *
   * @throws Throws an Error when none of the packages could be loaded.
   *
   * @global
   */
  return function requireFromArray (packages) {
    // Retrieve the list of package names.
    var packagesNames = Array.isArray(packages) ? packages : arguments
    for (var i in packagesNames) {
      try {
        return requireFunction(packagesNames[i])
      } catch (e) {
        // Do nothing, but continue on to the next package.
        continue
      }
    }
    throw new Error('Could not found one of the expected packages: ' + JSON.stringify(packages))
  }
}))
<|endoftext|>


<commit_before>/*
 * mobile checkboxradio unit tests
 */
(function($){
	module( 'jquery.mobile.forms.checkboxradio.js' );

	test( "widget can be disabled and enabled", function(){
		var input = $( "#checkbox-1" ),
			button = input.parent().find( ".ui-btn" );

		input.checkboxradio( "disable" );
		input.checkboxradio( "enable" );
		ok( !input.attr( "disabled" ), "start input as enabled" );
		ok( !input.parent().hasClass( "ui-disabled" ), "no disabled styles" );
		ok( !input.attr( "checked" ), "not checked before click" );
		button.trigger( "click" );
		ok( input.attr( "checked" ), "checked after click" );
		ok( button.hasClass( "ui-checkbox-on" ), "active styles after click" );
		button.trigger( "click" );

		input.checkboxradio( "disable" );
		ok( input.attr( "disabled" ), "input disabled" );
		ok( input.parent().hasClass( "ui-disabled" ), "disabled styles" );
		ok( !input.attr( "checked" ), "not checked before click" );
		button.trigger( "click" );
		ok( !input.attr( "checked" ), "not checked after click" );
		ok( !button.hasClass( "ui-checkbox-on" ), "no active styles after click" );
	});

	test( "clicking a checkbox within a controlgroup does not affect checkboxes with the same name in the same controlgroup", function(){
		var input1 = $("#checkbox-31");
		var button1 = input1.parent().find(".ui-btn");
		var input2 = $("#checkbox-32");
		var button2 = input2.parent().find(".ui-btn");

		ok(!input1.attr("checked"), "input1 not checked before click");
		ok(!input2.attr("checked"), "input2 not checked before click");

		button1.trigger("click");
		ok(input1.attr("checked"), "input1 checked after click on input1");
		ok(!input2.attr("checked"), "input2 not checked after click on input1");

		button2.trigger("click");
		ok(input1.attr("checked"), "input1 not changed after click on input2");
		ok(input2.attr("checked"), "input2 checked after click on input2");
	});

	asyncTest( "change events fired on checkbox for both check and uncheck", function(){
		var $checkbox = $( "#checkbox-2" ),
			$checkboxLabel = $checkbox.parent().find( ".ui-btn" );

		$checkbox.unbind( "change" );

		expect( 1 );

		$checkbox.one('change', function(){
			ok( true, "change fired on click to check the box" );
		});

		$checkboxLabel.trigger( "click" );

		//test above will be triggered twice, and the start here once
		$checkbox.one('change', function(){
			start();
		});

		$checkboxLabel.trigger( "click" );
	});

	asyncTest( "radio button labels should update the active button class to last clicked and clear checked", function(){
		var $radioBtns = $( '#radio-active-btn-test input' ),
			singleActiveAndChecked = function(){
				same( $( "#radio-active-btn-test .ui-radio-on" ).length, 1, "there should be only one active button" );
				// Use the .checked property, not the checked attribute which is not dynamic
				var numChecked = 0;
				$( "#radio-active-btn-test input" ).each(function(i, e) {
					if( e.checked ) {
						numChecked++;
					}
				});
				same( numChecked, 1, "there should be only one checked" );
			};

		$.testHelper.sequence([
			function(){
				$radioBtns.last().siblings( 'label' ).click();
			},

			function(){
				ok( $radioBtns.last().prop( 'checked' ), "last input is checked" );
				ok( $radioBtns.last().siblings( 'label' ).hasClass( 'ui-radio-on' ),
					"last input label is an active button" );

				ok( !$radioBtns.first().prop( 'checked' ), "first input label is not active" );
				ok( !$radioBtns.first().siblings( 'label' ).hasClass( 'ui-radio-on' ),
					"first input label is not active" );

				singleActiveAndChecked();

				$radioBtns.first().siblings( 'label' ).click();
			},

			function(){
				ok( $radioBtns.first().prop( 'checked' ));
				ok( $radioBtns.first().siblings( 'label' ).hasClass( 'ui-radio-on' ),
					"first input label is an active button" );

				ok( !$radioBtns.last().prop( 'checked' ));
				ok( !$radioBtns.last().siblings( 'label' ).hasClass( 'ui-radio-on' ),
					"last input label is not active" );

				singleActiveAndChecked();

				start();
			}
		], 500);

	});

	test( "checkboxradio controls will create when inside a container that receives a 'create' event", function(){
		ok( !$("#enhancetest").appendTo(".ui-page-active").find(".ui-checkbox").length, "did not have enhancements applied" );
		ok( $("#enhancetest").trigger("create").find(".ui-checkbox").length, "enhancements applied" );
	});

	$.mobile.page.prototype.options.keepNative = "input.should-be-native";

	// not testing the positive case here since's it's obviously tested elsewhere
	test( "checkboxradio elements in the keepNative set shouldn't be enhanced", function() {
		ok( !$("input.should-be-native").parent().is("div.ui-checkbox") );
	});

	test( "Elements with â€œdata-mini='true'â€� should have â€œui-miniâ€� class attached to enhanced element.", function(){
		var full = document.getElementById("radio-full"),
			$fulllbl = $('[for="radio-full"]'),
			mini = document.getElementById("radio-mini"),
			$minilbl = $('[for="radio-mini"]'),
			minictrl = $("#mini-control");

		ok( !full.getAttribute('data-nstest-mini') && !$fulllbl.hasClass('ui-mini'), "Original element does not have data attribute, enhanced version does not recieve .ui-mini.");
		ok( mini.getAttribute('data-nstest-mini'), "Original element has data attribute, enhanced version recieves .ui-mini." );
	});

	asyncTest( "clicking the label triggers a click on the element", function() {
		var clicked = false;

		expect( 1 );

		$( "#checkbox-click-triggered" ).one('click', function() {
			clicked = true;
		});

		$.testHelper.sequence([
			function() {
				$( "[for='checkbox-click-triggered']" ).click();
			},

			function() {
				ok(clicked, "click was fired on input");
				start();
			}
		], 2000);
	});

	asyncTest( "clicking the label triggers a change on the element", function() {
		var changed = false;

		expect( 1 );

		$( "#checkbox-change-triggered" ).one('change', function() {
			changed = true;
		});

		$.testHelper.sequence([
			function() {
				$( "[for='checkbox-change-triggered']" ).click();
			},

			function() {
				ok(changed, "change was fired on input");
				start();
			}
		], 2000);
	});

	test( "theme should be inherited", function() {
		var $inherited = $( "#checkbox-inherit-theme" ),
		    $explicit = $( "#checkbox-explicit-theme" );

		ok( $inherited.siblings("label").hasClass( "ui-btn-up-a" ), "should inherit from page" );
		ok( $explicit.siblings("label").hasClass( "ui-btn-up-b" ), "should not inherit" );
	});

	asyncTest( "form submission should include radio button values", function() {
		var $form = $( "#radio-form" ), $input = $form.find("input").first();

		$.testHelper.pageSequence([
			function() {
				$input.click();
				$form.submit();
			},

			function( timeout ){
				ok( location.search.indexOf("radio1=1") >= 0, "the radio was checked" );

				// if the changepage in the previous function failed don't go back
				if( !timeout ){
					window.history.back();
				}
			},

			function(){
				start();
			}
		]);
	});

	asyncTest( "form submission should include checkbox button values", function() {
		var $form = $( "#check-form" ), $inputs = $form.find("input");

		$.testHelper.pageSequence([
			function() {
				$inputs.click();
				$form.submit();
			},

			function( timeout ){
				ok( location.search.indexOf("checkbox-form=on") >= 0, "the first checkbox was checked" );
				ok( location.search.indexOf("checkbox-form-2=on") >= 0, "the second checkbox was checked" );
				// if the changepage in the previous function failed don't go back
				if( !timeout ){
					window.history.back();
				}
			},

			function(){
				start();
			}
		]);
	});

	test( "no label raises an exception", function() {
		expect( 1 );

		try {
			$( "#checkbox-exception" ).checkboxradio();
		} catch (e) {
			ok( e.toString().indexOf( "[checkboxradio]" ) >= 0, "checkboxradio exception raised" );
		}
	});

  test( "nested label checkbox still renders", function() {
    var $checkbox = $( "#checkbox-nested-label" );

    try {
      $checkbox.checkboxradio();
    } catch (e) {
      ok( false, "checkboxradio exception raised: " + e.toString());
    }

    ok( $checkbox.parent().hasClass("ui-checkbox"), "enhancement has occured");
  });

  test( "nested label (no [for]) checkbox still renders", function() {
    var $checkbox = $( "#checkbox-nested-label-no-for" );

    try {
      $checkbox.checkboxradio();
    } catch (e) {
      ok( false, "checkboxradio exception raised: " + e.toString());
    }

    ok( $checkbox.parent().hasClass("ui-checkbox"), "enhancement has occured");
  });

	test( "Icon positioning", function() {
		var bottomicon = $("[for='bottomicon']")
			topicon = $("[for='topicon']");

		ok( bottomicon.hasClass("ui-btn-icon-bottom"), "Icon position set on label adds the appropriate class." );
		ok( topicon.hasClass("ui-btn-icon-top"), "Icon position set on input adds the appropriate class to the label." );
	});
})(jQuery);
<commit_msg>fixed quote characters in test description so that they don't need weird encoding (editing this file in Eclipse on Windows seems to have broken them)<commit_after>/*
 * mobile checkboxradio unit tests
 */
(function($){
	module( 'jquery.mobile.forms.checkboxradio.js' );

	test( "widget can be disabled and enabled", function(){
		var input = $( "#checkbox-1" ),
			button = input.parent().find( ".ui-btn" );

		input.checkboxradio( "disable" );
		input.checkboxradio( "enable" );
		ok( !input.attr( "disabled" ), "start input as enabled" );
		ok( !input.parent().hasClass( "ui-disabled" ), "no disabled styles" );
		ok( !input.attr( "checked" ), "not checked before click" );
		button.trigger( "click" );
		ok( input.attr( "checked" ), "checked after click" );
		ok( button.hasClass( "ui-checkbox-on" ), "active styles after click" );
		button.trigger( "click" );

		input.checkboxradio( "disable" );
		ok( input.attr( "disabled" ), "input disabled" );
		ok( input.parent().hasClass( "ui-disabled" ), "disabled styles" );
		ok( !input.attr( "checked" ), "not checked before click" );
		button.trigger( "click" );
		ok( !input.attr( "checked" ), "not checked after click" );
		ok( !button.hasClass( "ui-checkbox-on" ), "no active styles after click" );
	});

	test( "clicking a checkbox within a controlgroup does not affect checkboxes with the same name in the same controlgroup", function(){
		var input1 = $("#checkbox-31");
		var button1 = input1.parent().find(".ui-btn");
		var input2 = $("#checkbox-32");
		var button2 = input2.parent().find(".ui-btn");

		ok(!input1.attr("checked"), "input1 not checked before click");
		ok(!input2.attr("checked"), "input2 not checked before click");

		button1.trigger("click");
		ok(input1.attr("checked"), "input1 checked after click on input1");
		ok(!input2.attr("checked"), "input2 not checked after click on input1");

		button2.trigger("click");
		ok(input1.attr("checked"), "input1 not changed after click on input2");
		ok(input2.attr("checked"), "input2 checked after click on input2");
	});

	asyncTest( "change events fired on checkbox for both check and uncheck", function(){
		var $checkbox = $( "#checkbox-2" ),
			$checkboxLabel = $checkbox.parent().find( ".ui-btn" );

		$checkbox.unbind( "change" );

		expect( 1 );

		$checkbox.one('change', function(){
			ok( true, "change fired on click to check the box" );
		});

		$checkboxLabel.trigger( "click" );

		//test above will be triggered twice, and the start here once
		$checkbox.one('change', function(){
			start();
		});

		$checkboxLabel.trigger( "click" );
	});

	asyncTest( "radio button labels should update the active button class to last clicked and clear checked", function(){
		var $radioBtns = $( '#radio-active-btn-test input' ),
			singleActiveAndChecked = function(){
				same( $( "#radio-active-btn-test .ui-radio-on" ).length, 1, "there should be only one active button" );
				// Use the .checked property, not the checked attribute which is not dynamic
				var numChecked = 0;
				$( "#radio-active-btn-test input" ).each(function(i, e) {
					if( e.checked ) {
						numChecked++;
					}
				});
				same( numChecked, 1, "there should be only one checked" );
			};

		$.testHelper.sequence([
			function(){
				$radioBtns.last().siblings( 'label' ).click();
			},

			function(){
				ok( $radioBtns.last().prop( 'checked' ), "last input is checked" );
				ok( $radioBtns.last().siblings( 'label' ).hasClass( 'ui-radio-on' ),
					"last input label is an active button" );

				ok( !$radioBtns.first().prop( 'checked' ), "first input label is not active" );
				ok( !$radioBtns.first().siblings( 'label' ).hasClass( 'ui-radio-on' ),
					"first input label is not active" );

				singleActiveAndChecked();

				$radioBtns.first().siblings( 'label' ).click();
			},

			function(){
				ok( $radioBtns.first().prop( 'checked' ));
				ok( $radioBtns.first().siblings( 'label' ).hasClass( 'ui-radio-on' ),
					"first input label is an active button" );

				ok( !$radioBtns.last().prop( 'checked' ));
				ok( !$radioBtns.last().siblings( 'label' ).hasClass( 'ui-radio-on' ),
					"last input label is not active" );

				singleActiveAndChecked();

				start();
			}
		], 500);

	});

	test( "checkboxradio controls will create when inside a container that receives a 'create' event", function(){
		ok( !$("#enhancetest").appendTo(".ui-page-active").find(".ui-checkbox").length, "did not have enhancements applied" );
		ok( $("#enhancetest").trigger("create").find(".ui-checkbox").length, "enhancements applied" );
	});

	$.mobile.page.prototype.options.keepNative = "input.should-be-native";

	// not testing the positive case here since's it's obviously tested elsewhere
	test( "checkboxradio elements in the keepNative set shouldn't be enhanced", function() {
		ok( !$("input.should-be-native").parent().is("div.ui-checkbox") );
	});

	test( "Elements with \u201cdata-mini='true'\u201d should have \u201cui-mini\u201d class attached to enhanced element.", function(){
		var full = document.getElementById("radio-full"),
			$fulllbl = $('[for="radio-full"]'),
			mini = document.getElementById("radio-mini"),
			$minilbl = $('[for="radio-mini"]'),
			minictrl = $("#mini-control");

		ok( !full.getAttribute('data-nstest-mini') && !$fulllbl.hasClass('ui-mini'), "Original element does not have data attribute, enhanced version does not recieve .ui-mini.");
		ok( mini.getAttribute('data-nstest-mini'), "Original element has data attribute, enhanced version recieves .ui-mini." );
	});

	asyncTest( "clicking the label triggers a click on the element", function() {
		var clicked = false;

		expect( 1 );

		$( "#checkbox-click-triggered" ).one('click', function() {
			clicked = true;
		});

		$.testHelper.sequence([
			function() {
				$( "[for='checkbox-click-triggered']" ).click();
			},

			function() {
				ok(clicked, "click was fired on input");
				start();
			}
		], 2000);
	});

	asyncTest( "clicking the label triggers a change on the element", function() {
		var changed = false;

		expect( 1 );

		$( "#checkbox-change-triggered" ).one('change', function() {
			changed = true;
		});

		$.testHelper.sequence([
			function() {
				$( "[for='checkbox-change-triggered']" ).click();
			},

			function() {
				ok(changed, "change was fired on input");
				start();
			}
		], 2000);
	});

	test( "theme should be inherited", function() {
		var $inherited = $( "#checkbox-inherit-theme" ),
		    $explicit = $( "#checkbox-explicit-theme" );

		ok( $inherited.siblings("label").hasClass( "ui-btn-up-a" ), "should inherit from page" );
		ok( $explicit.siblings("label").hasClass( "ui-btn-up-b" ), "should not inherit" );
	});

	asyncTest( "form submission should include radio button values", function() {
		var $form = $( "#radio-form" ), $input = $form.find("input").first();

		$.testHelper.pageSequence([
			function() {
				$input.click();
				$form.submit();
			},

			function( timeout ){
				ok( location.search.indexOf("radio1=1") >= 0, "the radio was checked" );

				// if the changepage in the previous function failed don't go back
				if( !timeout ){
					window.history.back();
				}
			},

			function(){
				start();
			}
		]);
	});

	asyncTest( "form submission should include checkbox button values", function() {
		var $form = $( "#check-form" ), $inputs = $form.find("input");

		$.testHelper.pageSequence([
			function() {
				$inputs.click();
				$form.submit();
			},

			function( timeout ){
				ok( location.search.indexOf("checkbox-form=on") >= 0, "the first checkbox was checked" );
				ok( location.search.indexOf("checkbox-form-2=on") >= 0, "the second checkbox was checked" );
				// if the changepage in the previous function failed don't go back
				if( !timeout ){
					window.history.back();
				}
			},

			function(){
				start();
			}
		]);
	});

	test( "no label raises an exception", function() {
		expect( 1 );

		try {
			$( "#checkbox-exception" ).checkboxradio();
		} catch (e) {
			ok( e.toString().indexOf( "[checkboxradio]" ) >= 0, "checkboxradio exception raised" );
		}
	});

  test( "nested label checkbox still renders", function() {
    var $checkbox = $( "#checkbox-nested-label" );

    try {
      $checkbox.checkboxradio();
    } catch (e) {
      ok( false, "checkboxradio exception raised: " + e.toString());
    }

    ok( $checkbox.parent().hasClass("ui-checkbox"), "enhancement has occured");
  });

  test( "nested label (no [for]) checkbox still renders", function() {
    var $checkbox = $( "#checkbox-nested-label-no-for" );

    try {
      $checkbox.checkboxradio();
    } catch (e) {
      ok( false, "checkboxradio exception raised: " + e.toString());
    }

    ok( $checkbox.parent().hasClass("ui-checkbox"), "enhancement has occured");
  });

	test( "Icon positioning", function() {
		var bottomicon = $("[for='bottomicon']")
			topicon = $("[for='topicon']");

		ok( bottomicon.hasClass("ui-btn-icon-bottom"), "Icon position set on label adds the appropriate class." );
		ok( topicon.hasClass("ui-btn-icon-top"), "Icon position set on input adds the appropriate class to the label." );
	});
})(jQuery);
<|endoftext|>


<commit_before>@describe "resolver and generator" {
    it "should do default resolves" {

		var shapes = Resolver()("my.shapes");
		var tools = Resolver()("my.tools");

		Resolver().set("my.tools.X",5);
		Resolver.default.namespace.my.tools.X should == 5;
		shapes should === Resolver.default.namespace.my.shapes;
		tools should === Resolver.default.namespace.my.tools;

		Resolver.default.namespace.my should != undefined;
	}
	it "should override default resolver" {
		Resolver("default").override({});
		Resolver.default.namespace.my should === undefined;

		Resolver()("my")
		Resolver.default.namespace.my should != undefined;
	}
	it "should provide resolver reference" {
		var my = Resolver().reference("my");
		my.get() should != undefined;

		var num = Resolver().reference("num");
		num.set(5);
		num.get() should == 5;

    }
}

@describe "generator" {
	it "should do default generation" {
		Generator() should instanceof Object;
	}

	it "should register base and variant constructors" {

		var NumberType = Generator(Resolver("essential")("Type"),"Number");

		var shapes = {};

		function Shape() {}
		Shape.arguments = [ ];

		function Rectangle(width,height) {

		}
		Rectangle.bases = [Shape];
		Rectangle.arguments = [ NumberType({name:"width",preset:true}), NumberType({name:"height",preset:true}) ]; //TODO NumberType({name:"width"}) optional: , default:  seed:
		Rectangle.prototype.earlyFunc = function() {};

		shapes.Shape = Generator(Shape);
		shapes.Rectangle = Generator(Rectangle);

		Rectangle.prototype.getWidth = function() {
			return this.width;
		};

		typeof shapes.Shape.info.options should == 'object'
		shapes.Rectangle.bases should == Rectangle.bases;
		shapes.Rectangle.arguments should == Rectangle.arguments

		var s = shapes.Shape();
		var r55 = shapes.Rectangle(5,5);
		r55 should be_instanceof(Rectangle);
		r55 should be_instanceof(shapes.Rectangle);
		r55 should be_instanceof(Shape);
		r55 should be_instanceof(shapes.Shape);

		shapes.Rectangle.prototype.getWidth should == Rectangle.prototype.getWidth
		typeof shapes.Rectangle.prototype.earlyFunc should == 'function'
		r55.width should == 5;
		r55.getWidth() should == 5;

		shapes.Shape.mixin({
			sides: 0
		});

		shapes.Rectangle.mixin({
			sides: 2,
			getRatio: function() { return this.width / this.height; }
		});

		Shape.prototype.sides should == 0;
		s.sides should == 0;
		Rectangle.prototype.sides should == 2;
		r55.sides should == 2;

		function Circle(diameter) {

		}
		Circle.prototype.earlyFunc = function() {};

		shapes.Circle = Generator(Circle,Shape,{
			arguments : [ NumberType({name:"diameter",preset:true}) ] //TODO NumberType({name:"width"}) optional: , default:  seed:
		});

		Circle.prototype.getWidth = function() {
			return this.diameter;
		};

		shapes.Circle.bases.length should == 1;
		shapes.Circle.bases[0] should == Shape;
		shapes.Circle.info.options.arguments.length should == 1;
		typeof shapes.Circle.info.options.arguments[0] should == 'object';
		Circle.prototype.sides should == 0;

		var c9 = shapes.Circle(9);
		c9 should be_instanceof(Circle);
		c9 should be_instanceof(shapes.Circle);
		c9 should be_instanceof(Shape);
		c9 should be_instanceof(shapes.Shape);
		c9.diameter should == 9;
		c9.getWidth() should == 9;
	}

	it "should make a simple type generator" {
		var Simple = Generator(function(v) { return v; }, { alloc: false });

		var s8 = Simple(8);
		s8 should == 8;
	}

	it "should generate same instance for singleton" {

		Generator(SingleBase).setSingleton();

		var instance = Generator(SingleBase)()
		//	assertTrue(instance.initCalled);

		Generator(SingleBase)() should == instance;
	}
}

<commit_msg>touch<commit_after>@describe "resolver and generator" {
    it "should do default resolves" {

		var shapes = Resolver()("my.shapes");
		var tools = Resolver()("my.tools");

		Resolver().set("my.tools.X",5);
		Resolver.default.namespace.my.tools.X should == 5;
		shapes should === Resolver.default.namespace.my.shapes;
		tools should === Resolver.default.namespace.my.tools;

		Resolver.default.namespace.my should != undefined;
	}
	it "should override default resolver" {
		Resolver("default").override({});
		Resolver.default.namespace.my should === undefined;

		Resolver()("my")
		Resolver.default.namespace.my should != undefined;
	}
	it "should provide resolver reference" {
		var my = Resolver().reference("my");
		my.get() should != undefined;

		var num = Resolver().reference("num");
		num.set(5);
		num.get() should == 5;

    }
}

@describe "generator" {
	it "should do default generation" {
		Generator() should instanceof Object;
	}

	it "should register base and variant constructors" {

		var NumberType = Generator(Resolver("essential")("Type"),"Number");

		var shapes = {};

		function Shape() {}
		Shape.arguments = [ ];

		function Rectangle(width,height) {

		}
		Rectangle.bases = [Shape];
		Rectangle.arguments = [ NumberType({name:"width",preset:true}), NumberType({name:"height",preset:true}) ]; //TODO NumberType({name:"width"}) optional: , default:  seed:
		Rectangle.prototype.earlyFunc = function() {};

		shapes.Shape = Generator(Shape);
		shapes.Rectangle = Generator(Rectangle);

		Rectangle.prototype.getWidth = function() {
			return this.width;
		};

		typeof shapes.Shape.info.options should == 'object'
		shapes.Rectangle.bases should == Rectangle.bases;
		shapes.Rectangle.arguments should == Rectangle.arguments

		var s = shapes.Shape();
		var r55 = shapes.Rectangle(5,5);
		r55 should be_instanceof(Rectangle);
		r55 should be_instanceof(shapes.Rectangle);
		r55 should be_instanceof(Shape);
		r55 should be_instanceof(shapes.Shape);

		shapes.Rectangle.prototype.getWidth should == Rectangle.prototype.getWidth
		typeof shapes.Rectangle.prototype.earlyFunc should == 'function'
		r55.width should == 5;
		r55.getWidth() should == 5;

		shapes.Shape.mixin({
			sides: 0
		});

		shapes.Rectangle.mixin({
			sides: 2,
			getRatio: function() { return this.width / this.height; }
		});

		Shape.prototype.sides should == 0;
		s.sides should == 0;
		Rectangle.prototype.sides should == 2;
		r55.sides should == 2;

		function Circle(diameter) {

		}
		Circle.prototype.earlyFunc = function() {};

		shapes.Circle = Generator(Circle,Shape,{
			arguments : [ NumberType({name:"diameter",preset:true}) ] //TODO NumberType({name:"width"}) optional: , default:  seed:
		});

		Circle.prototype.getWidth = function() {
			return this.diameter;
		};

		shapes.Circle.bases.length should == 1;
		shapes.Circle.bases[0] should == Shape;
		shapes.Circle.info.options.arguments.length should == 1;
		typeof shapes.Circle.info.options.arguments[0] should == 'object';
		Circle.prototype.sides should == 0;

		var c9 = shapes.Circle(9);
		c9 should be_instanceof(Circle);
		c9 should be_instanceof(shapes.Circle);
		c9 should be_instanceof(Shape);
		c9 should be_instanceof(shapes.Shape);
		c9.diameter should == 9;
		c9.getWidth() should == 9;
	}

	it "should make a simple type generator" {
		var Simple = Generator(function(v) { return v; }, { alloc: false });

		var s8 = Simple(8);
		s8 should == 8;
	}

	it "should generate same instance for singleton" {

		Generator(SingleBase).setSingleton();

		var instance = Generator(SingleBase)()
		//	assertTrue(instance.initCalled);

		Generator(SingleBase)() should == instance;
	}
}

<|endoftext|>


<commit_before>(function() {
    'use strict';

    angular.module('chaise.record')

    .controller('RecordController', ['$window', '$rootScope', 'AlertsService', function RecordController($window, $rootScope, AlertsService) {
        var vm = this;

        vm.alerts = AlertsService.alerts;
        vm.modifyRecord = chaiseConfig.editRecord === false ? false : true;
        vm.showEmptyRelatedTables = false;

        vm.createRecord = function() {
            var newRef = $rootScope.reference.contextualize.entryCreate;
            var appURL = newRef.appLink;
            if (!appURL) {
                AlertsService.addAlert({type: 'error', message: "Application Error: app linking undefined for " + newRef.compactPath});
            }
            else {
                $window.location.href = appURL;
            }
        };

        vm.editRecord = function() {
            var newRef = $rootScope.reference.contextualize.entryEdit;
            var appURL = newRef.appLink;
            if (!appURL) {
                AlertsService.addAlert({type: 'error', message: "Application Error: app linking undefined for " + newRef.compactPath});
            }
            else {
                $window.location.href = appURL;
            }
        };

        vm.permalink = function getPermalink() {
            if (!$rootScope.reference) {
                return $window.location.href;
            }
            return $rootScope.context.mainURI;
        };

        vm.toRecordSet = function(ref) {
            var appURL = ref.appLink;
            if (!appURL) {
                return AlertsService.addAlert({type: 'error', message: "Application Error: app linking undefined for " + ref.compactPath});
            }
            return $window.location.href = appURL;
        };

        vm.showRelatedTable = function(i) {
            if ($rootScope.tableModels && $rootScope.tableModels[i-1] && $rootScope.tableModels[i]) {
                var isFirstOrHasLoaded = i === 0 || $rootScope.tableModels[i-1].hasLoaded;
                if (vm.showEmptyRelatedTables) {
                    return isFirstOrHasLoaded;
                }
                return isFirstOrHasLoaded && $rootScope.tableModels[i].rowValues.length > 0;
            }
        };
    }]);
})();
<commit_msg>Fix bug where first related table would not appear (#668)<commit_after>(function() {
    'use strict';

    angular.module('chaise.record')

    .controller('RecordController', ['$window', '$rootScope', 'AlertsService', function RecordController($window, $rootScope, AlertsService) {
        var vm = this;

        vm.alerts = AlertsService.alerts;
        vm.modifyRecord = chaiseConfig.editRecord === false ? false : true;
        vm.showEmptyRelatedTables = false;

        vm.createRecord = function() {
            var newRef = $rootScope.reference.contextualize.entryCreate;
            var appURL = newRef.appLink;
            if (!appURL) {
                AlertsService.addAlert({type: 'error', message: "Application Error: app linking undefined for " + newRef.compactPath});
            }
            else {
                $window.location.href = appURL;
            }
        };

        vm.editRecord = function() {
            var newRef = $rootScope.reference.contextualize.entryEdit;
            var appURL = newRef.appLink;
            if (!appURL) {
                AlertsService.addAlert({type: 'error', message: "Application Error: app linking undefined for " + newRef.compactPath});
            }
            else {
                $window.location.href = appURL;
            }
        };

        vm.permalink = function getPermalink() {
            if (!$rootScope.reference) {
                return $window.location.href;
            }
            return $rootScope.context.mainURI;
        };

        vm.toRecordSet = function(ref) {
            var appURL = ref.appLink;
            if (!appURL) {
                return AlertsService.addAlert({type: 'error', message: "Application Error: app linking undefined for " + ref.compactPath});
            }
            return $window.location.href = appURL;
        };

        vm.showRelatedTable = function(i) {
            var isFirst = false, prevTableHasLoaded = false;
            if ($rootScope.tableModels && $rootScope.tableModels[i]) {
                if (i === 0) {
                    isFirst = true;
                } else if ($rootScope.tableModels[i-1]) {
                    prevTableHasLoaded = $rootScope.tableModels[i-1].hasLoaded;
                }

                if (vm.showEmptyRelatedTables) {
                    return isFirst || prevTableHasLoaded;
                }
                return (isFirst || prevTableHasLoaded) && $rootScope.tableModels[i].rowValues.length > 0;
            }
        };
    }]);
})();
<|endoftext|>


<commit_before>describe('Timepicker feature', function() {
  'use strict';

  var $input1,
    $input2,
    $input3,
    $timepicker1,
    $timepicker2,
    $timepicker3,
    tp1,
    tp2,
    tp3;

  beforeEach(function () {
    loadFixtures('timepicker.html');

    $input1 = $('#timepicker1');
    $timepicker1 = $input1.timepicker();
    tp1 = $timepicker1.data('timepicker');

    $input2 = $('#timepicker2');
    $timepicker2 = $input2.timepicker({
      template: 'modal',
      showSeconds: true,
      minuteStep: 30,
      secondStep: 30,
      defaultTime: false
    });
    tp2 = $timepicker2.data('timepicker');

    $input3 = $('#timepicker3');
    $timepicker3 = $input3.timepicker({
      showMeridian: false,
      showSeconds: true
    });
    tp3 = $timepicker3.data('timepicker');
  });

  afterEach(function () {
    if ($input1.data('timepicker') !== undefined) {
      $input1.data('timepicker').remove();
    }
    if ($input2.data('timepicker') !== undefined) {
      $input2.data('timepicker').remove();
    }
    if ($input3.data('timepicker') !== undefined) {
      $input3.data('timepicker').remove();
    }
    $input1.remove();
    $input2.remove();
    $input3.remove();
  });

  it('should be available on the jquery object', function() {
    expect($.fn.timepicker).toBeDefined();
  });

  it('should be chainable', function() {
    expect($timepicker1).toBe($input1);
  });

  it('should have sensible defaults', function() {
    expect(tp1.defaultTime).toBeTruthy();
    expect(tp1.minuteStep).toBe(15);
    expect(tp1.secondStep).toBe(15);
    expect(tp1.disableFocus).toBe(false);
    expect(tp1.showSeconds).toBe(false);
    expect(tp1.showInputs).toBe(true);
    expect(tp1.showMeridian).toBe(true);
    expect(tp1.template).toBe('dropdown');
    expect(tp1.modalBackdrop).toBe(false);
    expect(tp1.modalBackdrop).toBe(false);
    expect(tp1.isOpen).toBe(false);
  });

  it('should allow user to configure defaults', function() {
    expect(tp2.template).toBe('modal');
    expect(tp2.minuteStep).toBe(30);
  });

  it('should have current time by default', function() {
    var dTime = new Date(),
      hour = dTime.getHours(),
      minute = Math.floor(dTime.getMinutes() / 15) * 15;

    expect(tp3.hour).toBe(hour);
    expect(tp3.minute).toBe(minute);
  });

  it('should not override time with current time if value is already set', function() {
    $('body').append('
<input id="timepicker4Input" type="text" value="12:15 AM" />
');
    var $input4 = $('#timepicker4Input').timepicker(),
      tp4 = $input4.data('timepicker');

    expect($input4.val()).toBe('12:15 AM');

    tp4.remove();
    $('#timepicker4').remove();
  });

  it('should have no value if defaultTime is set to false', function() {
    expect($input2.val()).toBe('');
  });

  it('should update the element and widget with the setValues method', function() {
    tp2.setValues('09:15:20 AM');

    expect(tp2.hour).toBe(9);
    expect(tp2.minute).toBe(15);
    expect(tp2.second).toBe(20);
    expect(tp2.meridian).toBe('AM');
    expect($input2.val()).toBe('09:15:20 AM');
    expect(tp2.$widget.find('.bootstrap-timepicker-hour').val()).toBe('09');
    expect(tp2.$widget.find('.bootstrap-timepicker-minute').val()).toBe('15');
    expect(tp2.$widget.find('.bootstrap-timepicker-second').val()).toBe('20');
    expect(tp2.$widget.find('.bootstrap-timepicker-meridian').val()).toBe('AM');
  });

  it('should be able to format time values into a string', function() {
    expect(tp2.formatTime(3, 15, 45, 'PM')).toBe('03:15:45 PM');
  });

  it('should be able get & set the pickers time', function() {
    tp3.setTime('23:15:20');
    expect(tp3.getTime()).toBe('23:15:20');
  });

  it('should update picker on blur', function() {
    $input1.val('10:25 AM');
    expect(tp1.getTime()).not.toBe('10:25 AM');
    $input1.trigger('blur');
    expect(tp1.getTime()).toBe('10:25 AM');
  });

  it('should update element with updateElement method', function() {
    tp1.hour = 10;
    tp1.minute = 30;
    tp1.meridian = 'PM';
    expect($input1.val()).not.toBe('10:30 PM');
    tp1.updateElement();
    expect($input1.val()).toBe('10:30 PM');
  });

  it('should update widget with updateWidget method', function() {
    tp2.hour = 10;
    tp2.minute = 30;
    tp2.second = 15;

    expect(tp2.$widget.find('.bootstrap-timepicker-hour').val()).not.toBe('10');
    expect(tp2.$widget.find('.bootstrap-timepicker-minute').val()).not.toBe('30');
    expect(tp2.$widget.find('.bootstrap-timepicker-second').val()).not.toBe('15');

    tp2.updateWidget();

    expect(tp2.$widget.find('.bootstrap-timepicker-hour').val()).toBe('10');
    expect(tp2.$widget.find('.bootstrap-timepicker-minute').val()).toBe('30');
    expect(tp2.$widget.find('.bootstrap-timepicker-second').val()).toBe('15');
  });

  it('should update picker with updateFromElementVal method', function() {
    tp1.hour = 12;
    tp1.minute = 12;
    tp1.meridian = 'PM';
    tp1.update();

    $input1.val('10:30 AM');

    expect(tp1.$widget.find('.bootstrap-timepicker-hour').val()).not.toBe('10');
    expect(tp1.$widget.find('.bootstrap-timepicker-minute').val()).not.toBe('30');
    expect(tp1.$widget.find('.bootstrap-timepicker-meridian').val()).not.toBe('AM');
    expect(tp1.hour).not.toBe(10);
    expect(tp1.minute).not.toBe(30);
    expect(tp1.meridian).not.toBe('AM');

    tp1.updateFromElementVal();

    expect(tp1.$widget.find('.bootstrap-timepicker-hour').val()).toBe('10');
    expect(tp1.$widget.find('.bootstrap-timepicker-minute').val()).toBe('30');
    expect(tp1.$widget.find('.bootstrap-timepicker-meridian').val()).toBe('AM');
    expect(tp1.hour).toBe(10);
    expect(tp1.minute).toBe(30);
    expect(tp1.meridian).toBe('AM');
  });

  it('should update picker with updateFromWidgetInputs method', function() {
    tp1.hour = 12;
    tp1.minute = 12;
    tp1.meridian = 'PM';
    tp1.update();

    tp1.$widget.find('.bootstrap-timepicker-hour').val(10);
    tp1.$widget.find('.bootstrap-timepicker-minute').val(30);
    tp1.$widget.find('.bootstrap-timepicker-meridian').val('AM');

    expect(tp1.hour).not.toBe(10);
    expect(tp1.minute).not.toBe(30);
    expect(tp1.meridian).not.toBe('AM');
    expect($input1.val()).not.toBe('10:30 AM');

    tp1.updateFromWidgetInputs();

    expect(tp1.hour).toBe(10);
    expect(tp1.minute).toBe(30);
    expect(tp1.meridian).toBe('AM');
    expect($input1.val()).toBe('10:30 AM');
  });

  it('should increment hours with incrementHour method', function() {
    tp1.hour = 9;
    tp1.incrementHour();
    expect(tp1.hour).toBe(10);
  });

  it('should decrement hours with decrementHour method', function() {
    tp1.hour = 9;
    tp1.decrementHour();
    expect(tp1.hour).toBe(8);
  });

  it('should toggle meridian if hour goes past 12', function() {
    $input1.val('11:00 AM');
    tp1.updateFromElementVal();
    tp1.incrementHour();

    expect(tp1.hour).toBe(12);
    expect(tp1.minute).toBe(0);
    expect(tp1.meridian).toBe('PM');
  });

  it('should toggle meridian if hour goes below 1', function() {
    $input1.val('11:00 AM');
    tp1.updateFromElementVal();
    tp1.incrementHour();

    expect(tp1.hour).toBe(12);
    expect(tp1.minute).toBe(0);
    expect(tp1.meridian).toBe('PM');
  });

  it('should set hour to 1 if hour increments on 12 for 12h clock', function() {
    $input1.val('11:15 PM');
    tp1.updateFromElementVal();
    tp1.incrementHour();
    tp1.incrementHour();

    expect(tp1.getTime()).toBe('01:15 AM');
  });

  it('should set hour to 0 if hour increments on 23 for 24h clock', function() {
    $input3.val('22:15:30');
    tp3.updateFromElementVal();
    tp3.incrementHour();
    tp3.incrementHour();

    expect(tp3.hour).toBe(0);
    expect(tp3.minute).toBe(15);
    expect(tp3.second).toBe(30);
  });

  it('should increment minutes with incrementMinute method', function() {
    tp1.minute = 10;
    tp1.incrementMinute();

    expect(tp1.minute).toBe(15);

    tp2.minute = 0;
    tp2.incrementMinute();

    expect(tp2.minute).toBe(30);
  });

  it('should decrement minutes with decrementMinute method', function() {
    tp1.hour = 11;
    tp1.minute = 0;
    tp1.decrementMinute();

    expect(tp1.hour).toBe(10);
    expect(tp1.minute).toBe(45);

    tp2.hour = 11;
    tp2.minute = 0;
    tp2.decrementMinute();

    expect(tp2.hour).toBe(10);
    expect(tp2.minute).toBe(30);
  });

  it('should increment hour if minutes increment past 59', function() {
    $input1.val('11:55 AM');
    tp1.updateFromElementVal();
    tp1.incrementMinute();
    tp1.update();

    expect(tp1.getTime()).toBe('12:00 PM');
  });

  it('should toggle meridian with toggleMeridian method', function() {
    tp1.meridian = 'PM';
    tp1.toggleMeridian();

    expect(tp1.meridian).toBe('AM');
  });

  it('should increment seconds with incrementSecond method', function() {
    tp1.second = 0;
    tp1.incrementSecond();

    expect(tp1.second).toBe(15);

    tp2.second = 0;
    tp2.incrementSecond();

    expect(tp2.second).toBe(30);
  });

  it('should decrement seconds with decrementSecond method', function() {
    tp2.hour = 11;
    tp2.minute = 0;
    tp2.second = 0;
    tp2.decrementSecond();

    expect(tp2.minute).toBe(59);
    expect(tp2.second).toBe(30);
  });

  it('should increment minute by 1 if seconds increment past 59', function() {
    $input2.val('11:55:30 AM');
    tp2.updateFromElementVal();
    tp2.incrementSecond();
    tp2.update();

    expect(tp2.getTime()).toBe('11:56:00 AM');
  });

  it('should not have any remaining events if remove is called', function() {
    var hideEvents = 0;

    $input1.on('hide.timepicker', function() {
      hideEvents++;
    });

    $input1.parents('div').find('.add-on').trigger('click');
    $('body').trigger('mousedown');

    expect(hideEvents).toBe(1);

    tp1.remove();
    tp2.remove();
    tp3.remove();

    $('body').trigger('click');
    expect(hideEvents).toBe(1);
  });

  it('should not have the widget in the DOM if remove method is called', function() {
    expect($('body')).toContain('.bootstrap-timepicker-widget');
    tp1.remove();
    tp2.remove();
    tp3.remove();
    expect($('body')).not.toContain('.bootstrap-timepicker-widget');
  });

  it('should be able to set time from a script', function() {
    $input1.timepicker('setTime', '12:35 PM');
    tp1.update();
    expect(tp1.getTime()).toBe('12:35 PM');
  });
});
<commit_msg>add spec to cover showWidget<commit_after>describe('Timepicker feature', function() {
  'use strict';

  var $input1,
    $input2,
    $input3,
    $timepicker1,
    $timepicker2,
    $timepicker3,
    tp1,
    tp2,
    tp3;

  beforeEach(function () {
    loadFixtures('timepicker.html');

    $input1 = $('#timepicker1');
    $timepicker1 = $input1.timepicker();
    tp1 = $timepicker1.data('timepicker');

    $input2 = $('#timepicker2');
    $timepicker2 = $input2.timepicker({
      template: 'modal',
      showSeconds: true,
      minuteStep: 30,
      secondStep: 30,
      defaultTime: false
    });
    tp2 = $timepicker2.data('timepicker');

    $input3 = $('#timepicker3');
    $timepicker3 = $input3.timepicker({
      showMeridian: false,
      showSeconds: true
    });
    tp3 = $timepicker3.data('timepicker');
  });

  afterEach(function () {
    if ($input1.data('timepicker') !== undefined) {
      $input1.data('timepicker').remove();
    }
    if ($input2.data('timepicker') !== undefined) {
      $input2.data('timepicker').remove();
    }
    if ($input3.data('timepicker') !== undefined) {
      $input3.data('timepicker').remove();
    }
    $input1.remove();
    $input2.remove();
    $input3.remove();
  });

  it('should be available on the jquery object', function() {
    expect($.fn.timepicker).toBeDefined();
  });

  it('should be chainable', function() {
    expect($timepicker1).toBe($input1);
  });

  it('should have sensible defaults', function() {
    expect(tp1.defaultTime).toBeTruthy();
    expect(tp1.minuteStep).toBe(15);
    expect(tp1.secondStep).toBe(15);
    expect(tp1.disableFocus).toBe(false);
    expect(tp1.showSeconds).toBe(false);
    expect(tp1.showInputs).toBe(true);
    expect(tp1.showMeridian).toBe(true);
    expect(tp1.template).toBe('dropdown');
    expect(tp1.modalBackdrop).toBe(false);
    expect(tp1.modalBackdrop).toBe(false);
    expect(tp1.isOpen).toBe(false);
  });

  it('should allow user to configure defaults', function() {
    expect(tp2.template).toBe('modal');
    expect(tp2.minuteStep).toBe(30);
  });

  it('should have current time by default', function() {
    var dTime = new Date(),
      hour = dTime.getHours(),
      minute = Math.floor(dTime.getMinutes() / 15) * 15;

    expect(tp3.hour).toBe(hour);
    expect(tp3.minute).toBe(minute);
  });

  it('should not override time with current time if value is already set', function() {
    $('body').append('
<input id="timepicker4Input" type="text" value="12:15 AM" />
');
    var $input4 = $('#timepicker4Input').timepicker(),
      tp4 = $input4.data('timepicker');

    expect($input4.val()).toBe('12:15 AM');

    tp4.remove();
    $('#timepicker4').remove();
  });

  it('should have no value if defaultTime is set to false', function() {
    expect($input2.val()).toBe('');
  });

  it('should update the element and widget with the setValues method', function() {
    tp2.setValues('09:15:20 AM');

    expect(tp2.hour).toBe(9);
    expect(tp2.minute).toBe(15);
    expect(tp2.second).toBe(20);
    expect(tp2.meridian).toBe('AM');
    expect($input2.val()).toBe('09:15:20 AM');
    expect(tp2.$widget.find('.bootstrap-timepicker-hour').val()).toBe('09');
    expect(tp2.$widget.find('.bootstrap-timepicker-minute').val()).toBe('15');
    expect(tp2.$widget.find('.bootstrap-timepicker-second').val()).toBe('20');
    expect(tp2.$widget.find('.bootstrap-timepicker-meridian').val()).toBe('AM');
  });

  it('should be able to format time values into a string', function() {
    expect(tp2.formatTime(3, 15, 45, 'PM')).toBe('03:15:45 PM');
  });

  it('should be able get & set the pickers time', function() {
    tp3.setTime('23:15:20');
    expect(tp3.getTime()).toBe('23:15:20');
  });

  it('should update picker on blur', function() {
    $input1.val('10:25 AM');
    expect(tp1.getTime()).not.toBe('10:25 AM');
    $input1.trigger('blur');
    expect(tp1.getTime()).toBe('10:25 AM');
  });

  it('should update element with updateElement method', function() {
    tp1.hour = 10;
    tp1.minute = 30;
    tp1.meridian = 'PM';
    expect($input1.val()).not.toBe('10:30 PM');
    tp1.updateElement();
    expect($input1.val()).toBe('10:30 PM');
  });

  it('should update widget with updateWidget method', function() {
    tp2.hour = 10;
    tp2.minute = 30;
    tp2.second = 15;

    expect(tp2.$widget.find('.bootstrap-timepicker-hour').val()).not.toBe('10');
    expect(tp2.$widget.find('.bootstrap-timepicker-minute').val()).not.toBe('30');
    expect(tp2.$widget.find('.bootstrap-timepicker-second').val()).not.toBe('15');

    tp2.updateWidget();

    expect(tp2.$widget.find('.bootstrap-timepicker-hour').val()).toBe('10');
    expect(tp2.$widget.find('.bootstrap-timepicker-minute').val()).toBe('30');
    expect(tp2.$widget.find('.bootstrap-timepicker-second').val()).toBe('15');
  });

  it('should update picker with updateFromElementVal method', function() {
    tp1.hour = 12;
    tp1.minute = 12;
    tp1.meridian = 'PM';
    tp1.update();

    $input1.val('10:30 AM');

    expect(tp1.$widget.find('.bootstrap-timepicker-hour').val()).not.toBe('10');
    expect(tp1.$widget.find('.bootstrap-timepicker-minute').val()).not.toBe('30');
    expect(tp1.$widget.find('.bootstrap-timepicker-meridian').val()).not.toBe('AM');
    expect(tp1.hour).not.toBe(10);
    expect(tp1.minute).not.toBe(30);
    expect(tp1.meridian).not.toBe('AM');

    tp1.updateFromElementVal();

    expect(tp1.$widget.find('.bootstrap-timepicker-hour').val()).toBe('10');
    expect(tp1.$widget.find('.bootstrap-timepicker-minute').val()).toBe('30');
    expect(tp1.$widget.find('.bootstrap-timepicker-meridian').val()).toBe('AM');
    expect(tp1.hour).toBe(10);
    expect(tp1.minute).toBe(30);
    expect(tp1.meridian).toBe('AM');
  });

  it('should update picker with updateFromWidgetInputs method', function() {
    tp1.hour = 12;
    tp1.minute = 12;
    tp1.meridian = 'PM';
    tp1.update();

    tp1.$widget.find('.bootstrap-timepicker-hour').val(10);
    tp1.$widget.find('.bootstrap-timepicker-minute').val(30);
    tp1.$widget.find('.bootstrap-timepicker-meridian').val('AM');

    expect(tp1.hour).not.toBe(10);
    expect(tp1.minute).not.toBe(30);
    expect(tp1.meridian).not.toBe('AM');
    expect($input1.val()).not.toBe('10:30 AM');

    tp1.updateFromWidgetInputs();

    expect(tp1.hour).toBe(10);
    expect(tp1.minute).toBe(30);
    expect(tp1.meridian).toBe('AM');
    expect($input1.val()).toBe('10:30 AM');
  });

  it('should increment hours with incrementHour method', function() {
    tp1.hour = 9;
    tp1.incrementHour();
    expect(tp1.hour).toBe(10);
  });

  it('should decrement hours with decrementHour method', function() {
    tp1.hour = 9;
    tp1.decrementHour();
    expect(tp1.hour).toBe(8);
  });

  it('should toggle meridian if hour goes past 12', function() {
    $input1.val('11:00 AM');
    tp1.updateFromElementVal();
    tp1.incrementHour();

    expect(tp1.hour).toBe(12);
    expect(tp1.minute).toBe(0);
    expect(tp1.meridian).toBe('PM');
  });

  it('should toggle meridian if hour goes below 1', function() {
    $input1.val('11:00 AM');
    tp1.updateFromElementVal();
    tp1.incrementHour();

    expect(tp1.hour).toBe(12);
    expect(tp1.minute).toBe(0);
    expect(tp1.meridian).toBe('PM');
  });

  it('should set hour to 1 if hour increments on 12 for 12h clock', function() {
    $input1.val('11:15 PM');
    tp1.updateFromElementVal();
    tp1.incrementHour();
    tp1.incrementHour();

    expect(tp1.getTime()).toBe('01:15 AM');
  });

  it('should set hour to 0 if hour increments on 23 for 24h clock', function() {
    $input3.val('22:15:30');
    tp3.updateFromElementVal();
    tp3.incrementHour();
    tp3.incrementHour();

    expect(tp3.hour).toBe(0);
    expect(tp3.minute).toBe(15);
    expect(tp3.second).toBe(30);
  });

  it('should increment minutes with incrementMinute method', function() {
    tp1.minute = 10;
    tp1.incrementMinute();

    expect(tp1.minute).toBe(15);

    tp2.minute = 0;
    tp2.incrementMinute();

    expect(tp2.minute).toBe(30);
  });

  it('should decrement minutes with decrementMinute method', function() {
    tp1.hour = 11;
    tp1.minute = 0;
    tp1.decrementMinute();

    expect(tp1.hour).toBe(10);
    expect(tp1.minute).toBe(45);

    tp2.hour = 11;
    tp2.minute = 0;
    tp2.decrementMinute();

    expect(tp2.hour).toBe(10);
    expect(tp2.minute).toBe(30);
  });

  it('should increment hour if minutes increment past 59', function() {
    $input1.val('11:55 AM');
    tp1.updateFromElementVal();
    tp1.incrementMinute();
    tp1.update();

    expect(tp1.getTime()).toBe('12:00 PM');
  });

  it('should toggle meridian with toggleMeridian method', function() {
    tp1.meridian = 'PM';
    tp1.toggleMeridian();

    expect(tp1.meridian).toBe('AM');
  });

  it('should increment seconds with incrementSecond method', function() {
    tp1.second = 0;
    tp1.incrementSecond();

    expect(tp1.second).toBe(15);

    tp2.second = 0;
    tp2.incrementSecond();

    expect(tp2.second).toBe(30);
  });

  it('should decrement seconds with decrementSecond method', function() {
    tp2.hour = 11;
    tp2.minute = 0;
    tp2.second = 0;
    tp2.decrementSecond();

    expect(tp2.minute).toBe(59);
    expect(tp2.second).toBe(30);
  });

  it('should increment minute by 1 if seconds increment past 59', function() {
    $input2.val('11:55:30 AM');
    tp2.updateFromElementVal();
    tp2.incrementSecond();
    tp2.update();

    expect(tp2.getTime()).toBe('11:56:00 AM');
  });

  it('should not have any remaining events if remove is called', function() {
    var hideEvents = 0;

    $input1.on('hide.timepicker', function() {
      hideEvents++;
    });

    $input1.parents('div').find('.add-on').trigger('click');
    $('body').trigger('mousedown');

    expect(hideEvents).toBe(1);

    tp1.remove();
    tp2.remove();
    tp3.remove();

    $('body').trigger('click');
    expect(hideEvents).toBe(1);
  });

  it('should not have the widget in the DOM if remove method is called', function() {
    expect($('body')).toContain('.bootstrap-timepicker-widget');
    tp1.remove();
    tp2.remove();
    tp3.remove();
    expect($('body')).not.toContain('.bootstrap-timepicker-widget');
  });

  it('should be able to set time from a script', function() {
    $input1.timepicker('setTime', '12:35 PM');
    tp1.update();
    expect(tp1.getTime()).toBe('12:35 PM');
  });

  it('should be able to opened from script', function() {
    expect(tp1.isOpen).toBe(false);
    $input1.timepicker('showWidget');
    expect(tp1.isOpen).toBe(true);
  });
});
<|endoftext|>


<commit_before>/*global JsonML, jQuery, window */
/*
	JsonFx_UI.js
	DOM utilities

	Created: 2006-11-11-1759
	Modified: 2009-11-07-1038

	Copyright (c)2006-2009 Stephen M. McKamey
	Distributed under an open-source license: http://jsonfx.net/license
*/

/* namespace JsonFx.UI */
var JsonFx;
if ("undefined" === typeof JsonFx) {
	JsonFx = {};
}
if ("undefined" === typeof JsonFx.UI) {
	JsonFx.UI = {};
}

/* dependency checks --------------------------------------------*/

if ("undefined" === typeof JsonML) {
	throw new Error("JsonFx.UI requires JsonML");
}
if ("undefined" === typeof JsonFx.Bindings) {
	throw new Error("JsonFx.UI requires JsonFx.Bindings");
}

/* DOM utilities ------------------------------------------------*/

/*bool*/ JsonFx.UI.cancelEvent = function(/*Event*/ evt) {
	evt = evt || window.event;
	if (evt) {
		if (evt.stopPropagation) {
			evt.stopPropagation();
			evt.preventDefault();
		} else {
			try {
				evt.cancelBubble = true;
				evt.returnValue = false;
			} catch (ex) {
				// IE6
			}
		}
	}
	return false;
};

/*void*/ JsonFx.UI.addHandler = function(/*DOM*/ target, /*string*/ name, /*function*/ handler) {
	if ("string" === typeof handler) {
		/*jslint evil:true */
		handler = new Function(handler);
		/*jslint evil:false */
	}

	if ("function" !== typeof handler) {
		return;
	}

	if ("undefined" !== typeof jQuery) {
		jQuery(target).bind(name, handler);
	} else if (target.addEventListener) {
		// DOM Level 2 model for binding events
		target.addEventListener(name, handler, false);
	} else if (target.attachEvent) {
		// IE model for binding events
		target.attachEvent("on"+name, handler);
	} else {
		// DOM Level 0 model for binding events
		var old = target["on"+name];
		target["on"+name] = ("function" !== typeof old) ? handler :
			function(/*Event*/ e) { return (old.call(this, e) !== false) && (handler.call(this, e) !== false); };
	}
};

/*void*/ JsonFx.UI.removeHandler = function(/*DOM*/ target, /*string*/ name, /*function*/ handler) {
	if ("function" !== typeof handler) {
		// DOM Level 0 model for binding events
		target["on"+name] = null;
		return;
	}

	if ("undefined" !== typeof jQuery) {
		jQuery(target).unbind(name, handler);
	} else if (target.addEventListener) {
		// DOM Level 2 model for binding events
		target.removeEventListener(name, handler, false);
	} else if (target.attachEvent) {
		// IE model for binding events
		target.detachEvent("on"+name, handler);
	} else {
		// DOM Level 0 model for binding events
		target["on"+name] = null;
	}
};

/*bool*/ JsonFx.UI.clear = function(/*DOM*/ elem) {
	if (!elem) {
		return;
	}

	// unbind to prevent memory leaks
	JsonFx.Bindings.unbind(elem);

	while (elem.lastChild) {
		elem.removeChild(elem.lastChild);
	}
};

/*bool*/ JsonFx.UI.hasClass = function(/*DOM*/ elem, /*string*/ cssClass) {
	if (!elem || !elem.className || !cssClass) {
		return false;
	}

	var css = elem.className.split(' ');
	for (var i=0; i < css.length; i++) {
		if (css[i] === cssClass) {
			return true;
		}
	}

	return false;
};

/*void*/ JsonFx.UI.addClass = function(/*DOM*/ elem, /*string*/ cssClass) {
	if (!elem || !cssClass) {
		return;
	}

	elem.className += ' '+cssClass;
};

/*void*/ JsonFx.UI.removeClass = function(/*DOM*/ elem, /*string*/ cssClass) {
	if (!elem || !cssClass) {
		return;
	}

	var css = elem.className.split(' ');
	for (var i=0; i < css.length; i++) {
		if (!css[i] || css[i] === cssClass) {
			css.splice(i, 1);
			i--;
		}
	}

	elem.className = css.join(" ");
};

/*DOM*/ JsonFx.UI.findParent = function(/*DOM*/ elem, /*string*/ cssClass, /*bool*/ skipRoot) {
	if (!cssClass) {
		return null;
	}

	if (skipRoot) {
		elem = elem.parentNode;
	}

	// search up the ancestors
	while (elem) {
		if (JsonFx.UI.hasClass(elem, cssClass)) {
			return elem;
		}

		elem = elem.parentNode;
	}
	return null;
};

/*DOM*/ JsonFx.UI.findChild = function(/*DOM*/ elem, /*string*/ cssClass, /*bool*/ skipRoot) {
	if (!cssClass) {
		return null;
	}

	// breadth-first search of all children
	var i, queue = [];

	if (skipRoot) {
		if (elem && elem.childNodes) {
			for (i=0; i<elem.childNodes.length; i++) {
				queue.push(elem.childNodes[i]);
			}
		}
	} else {
		queue.push(elem);
	}

	while (queue.length) {
		elem = queue.shift();
		if (JsonFx.UI.hasClass(elem, cssClass)) {
			return elem;
		}
		if (elem && elem.childNodes) {
			for (i=0; i<elem.childNodes.length; i++) {
				queue.push(elem.childNodes[i]);
			}
		}
	}
	return null;
};

/*DOM*/ JsonFx.UI.findPrev = function(/*DOM*/ elem, /*string*/ cssClass, /*bool*/ skipRoot) {
	if (!cssClass) {
		return null;
	}

	if (skipRoot) {
		elem = elem.previousSibling;
	}

	// search up siblings in order
	while (elem) {
		if (JsonFx.UI.hasClass(elem, cssClass)) {
			return elem;
		}
		elem = elem.previousSibling;
	}
	return null;
};

/*DOM*/ JsonFx.UI.findNext = function(/*DOM*/ elem, /*string*/ cssClass, /*bool*/ skipRoot) {
	if (!cssClass) {
		return null;
	}

	if (skipRoot) {
		elem = elem.nextSibling;
	}

	// search down siblings in order
	while (elem) {
		if (JsonFx.UI.hasClass(elem, cssClass)) {
			return elem;
		}
		elem = elem.nextSibling;
	}
	return null;
};

/* JsonML utilities ---------------------------------------------*/

/* deprecated */
/*DOM*/ JsonFx.UI.bind = function(/*JBST*/ jbst, /*JSON*/ data, /*int*/ index, /*int*/ count) {
	return JsonML.BST(jbst).bind(data, index, count);
};
<commit_msg>- making dependency between JsonFx_UI.js and JsonFx_Bindings.js optional<commit_after>/*global JsonML, jQuery, window */
/*
	JsonFx_UI.js
	DOM utilities

	Created: 2006-11-11-1759
	Modified: 2009-11-07-1038

	Copyright (c)2006-2009 Stephen M. McKamey
	Distributed under an open-source license: http://jsonfx.net/license
*/

/* namespace JsonFx.UI */
var JsonFx;
if ("undefined" === typeof JsonFx) {
	JsonFx = {};
}
if ("undefined" === typeof JsonFx.UI) {
	JsonFx.UI = {};
}

/* dependency checks --------------------------------------------*/

if ("undefined" === typeof JsonML) {
	throw new Error("JsonFx.UI requires JsonML");
}

/* DOM utilities ------------------------------------------------*/

/*bool*/ JsonFx.UI.cancelEvent = function(/*Event*/ evt) {
	evt = evt || window.event;
	if (evt) {
		if (evt.stopPropagation) {
			evt.stopPropagation();
			evt.preventDefault();
		} else {
			try {
				evt.cancelBubble = true;
				evt.returnValue = false;
			} catch (ex) {
				// IE6
			}
		}
	}
	return false;
};

/*void*/ JsonFx.UI.addHandler = function(/*DOM*/ target, /*string*/ name, /*function*/ handler) {
	if ("string" === typeof handler) {
		/*jslint evil:true */
		handler = new Function(handler);
		/*jslint evil:false */
	}

	if ("function" !== typeof handler) {
		return;
	}

	if ("undefined" !== typeof jQuery) {
		jQuery(target).bind(name, handler);
	} else if (target.addEventListener) {
		// DOM Level 2 model for binding events
		target.addEventListener(name, handler, false);
	} else if (target.attachEvent) {
		// IE model for binding events
		target.attachEvent("on"+name, handler);
	} else {
		// DOM Level 0 model for binding events
		var old = target["on"+name];
		target["on"+name] = ("function" !== typeof old) ? handler :
			function(/*Event*/ e) { return (old.call(this, e) !== false) && (handler.call(this, e) !== false); };
	}
};

/*void*/ JsonFx.UI.removeHandler = function(/*DOM*/ target, /*string*/ name, /*function*/ handler) {
	if ("function" !== typeof handler) {
		// DOM Level 0 model for binding events
		target["on"+name] = null;
		return;
	}

	if ("undefined" !== typeof jQuery) {
		jQuery(target).unbind(name, handler);
	} else if (target.addEventListener) {
		// DOM Level 2 model for binding events
		target.removeEventListener(name, handler, false);
	} else if (target.attachEvent) {
		// IE model for binding events
		target.detachEvent("on"+name, handler);
	} else {
		// DOM Level 0 model for binding events
		target["on"+name] = null;
	}
};

/*bool*/ JsonFx.UI.clear = function(/*DOM*/ elem) {
	if (!elem) {
		return;
	}

	// unbind to prevent memory leaks
	if ("undefined" !== typeof JsonFx.Bindings) {
		JsonFx.Bindings.unbind(elem);
	}

	while (elem.lastChild) {
		elem.removeChild(elem.lastChild);
	}
};

/*bool*/ JsonFx.UI.hasClass = function(/*DOM*/ elem, /*string*/ cssClass) {
	if (!elem || !elem.className || !cssClass) {
		return false;
	}

	var css = elem.className.split(' ');
	for (var i=0; i < css.length; i++) {
		if (css[i] === cssClass) {
			return true;
		}
	}

	return false;
};

/*void*/ JsonFx.UI.addClass = function(/*DOM*/ elem, /*string*/ cssClass) {
	if (!elem || !cssClass) {
		return;
	}

	elem.className += ' '+cssClass;
};

/*void*/ JsonFx.UI.removeClass = function(/*DOM*/ elem, /*string*/ cssClass) {
	if (!elem || !cssClass) {
		return;
	}

	var css = elem.className.split(' ');
	for (var i=0; i < css.length; i++) {
		if (!css[i] || css[i] === cssClass) {
			css.splice(i, 1);
			i--;
		}
	}

	elem.className = css.join(" ");
};

/*DOM*/ JsonFx.UI.findParent = function(/*DOM*/ elem, /*string*/ cssClass, /*bool*/ skipRoot) {
	if (!cssClass) {
		return null;
	}

	if (skipRoot) {
		elem = elem.parentNode;
	}

	// search up the ancestors
	while (elem) {
		if (JsonFx.UI.hasClass(elem, cssClass)) {
			return elem;
		}

		elem = elem.parentNode;
	}
	return null;
};

/*DOM*/ JsonFx.UI.findChild = function(/*DOM*/ elem, /*string*/ cssClass, /*bool*/ skipRoot) {
	if (!cssClass) {
		return null;
	}

	// breadth-first search of all children
	var i, queue = [];

	if (skipRoot) {
		if (elem && elem.childNodes) {
			for (i=0; i<elem.childNodes.length; i++) {
				queue.push(elem.childNodes[i]);
			}
		}
	} else {
		queue.push(elem);
	}

	while (queue.length) {
		elem = queue.shift();
		if (JsonFx.UI.hasClass(elem, cssClass)) {
			return elem;
		}
		if (elem && elem.childNodes) {
			for (i=0; i<elem.childNodes.length; i++) {
				queue.push(elem.childNodes[i]);
			}
		}
	}
	return null;
};

/*DOM*/ JsonFx.UI.findPrev = function(/*DOM*/ elem, /*string*/ cssClass, /*bool*/ skipRoot) {
	if (!cssClass) {
		return null;
	}

	if (skipRoot) {
		elem = elem.previousSibling;
	}

	// search up siblings in order
	while (elem) {
		if (JsonFx.UI.hasClass(elem, cssClass)) {
			return elem;
		}
		elem = elem.previousSibling;
	}
	return null;
};

/*DOM*/ JsonFx.UI.findNext = function(/*DOM*/ elem, /*string*/ cssClass, /*bool*/ skipRoot) {
	if (!cssClass) {
		return null;
	}

	if (skipRoot) {
		elem = elem.nextSibling;
	}

	// search down siblings in order
	while (elem) {
		if (JsonFx.UI.hasClass(elem, cssClass)) {
			return elem;
		}
		elem = elem.nextSibling;
	}
	return null;
};

/* JsonML utilities ---------------------------------------------*/

/* deprecated */
/*DOM*/ JsonFx.UI.bind = function(/*JBST*/ jbst, /*JSON*/ data, /*int*/ index, /*int*/ count) {
	return JsonML.BST(jbst).bind(data, index, count);
};
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

define([
    "firebug/lib/object",
    "firebug/firebug",
    "firebug/lib/xpcom",
    "firebug/lib/events",
    "firebug/lib/url",
    "firebug/lib/css",
    "firebug/chrome/window",
    "firebug/lib/xml",
    "firebug/lib/options",
    "firebug/lib/array",
    "firebug/editor/editorSelector"
],
function(Obj, Firebug, Xpcom, Events, Url, Css, Win, Xml, Options, Arr, EditorSelector) {

// ********************************************************************************************* //
// Constants

const Cc = Components.classes;
const Ci = Components.interfaces;

const reSplitCSS = /(url\("?[^"\)]+"?\)?)|(rgba?\([^)]*\)?)|(hsla?\([^)]*\)?)|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,4})?)|"([^"]*)"?|'([^']*)'?|([^,\s\/!\(\)]+)|(!(.*)?)/;
const reURL = /url\("?([^"\)]+)?"?\)/;
const reRepeat = /no-repeat|repeat-x|repeat-y|repeat/;

// ********************************************************************************************* //
// CSS Module

Firebug.CSSModule = Obj.extend(Firebug.Module, Firebug.EditorSelector,
{
    dispatchName: "cssModule",

    freeEdit: function(styleSheet, value)
    {
        if (FBTrace.DBG_CSS)
            FBTrace.sysout("CSSModule.freeEdit", arguments);

        if (!styleSheet.editStyleSheet)
        {
            var ownerNode = getStyleSheetOwnerNode(styleSheet);
            styleSheet.disabled = true;

            var url = Xpcom.CCSV("@mozilla.org/network/standard-url;1", Ci.nsIURL);
            url.spec = styleSheet.href;

            var editStyleSheet = ownerNode.ownerDocument.createElementNS(
                "http://www.w3.org/1999/xhtml",
                "style");

            Firebug.setIgnored(editStyleSheet);

            editStyleSheet.setAttribute("type", "text/css");
            editStyleSheet.setAttributeNS(
                "http://www.w3.org/XML/1998/namespace",
                "base",
                url.directory);

            if (ownerNode.hasAttribute("media"))
                editStyleSheet.setAttribute("media", ownerNode.getAttribute("media"));

            // Insert the edited stylesheet directly after the old one to ensure the styles
            // cascade properly.
            ownerNode.parentNode.insertBefore(editStyleSheet, ownerNode.nextSibling);

            styleSheet.editStyleSheet = editStyleSheet;
        }

        styleSheet.editStyleSheet.innerHTML = value;

        if (FBTrace.DBG_CSS)
            FBTrace.sysout("css.saveEdit styleSheet.href:" + styleSheet.href +
                " got innerHTML:" + value);

        Events.dispatch(this.fbListeners, "onCSSFreeEdit", [styleSheet, value]);
    },

    insertRule: function(styleSheet, cssText, ruleIndex)
    {
        if (FBTrace.DBG_CSS)
            FBTrace.sysout("Insert: " + ruleIndex + " " + cssText);

        var insertIndex = styleSheet.insertRule(cssText, ruleIndex);

        Events.dispatch(this.fbListeners, "onCSSInsertRule", [styleSheet, cssText, ruleIndex]);

        return insertIndex;
    },

    deleteRule: function(src, ruleIndex)
    {
        var inlineStyle = (src instanceof window.Element);
        if (FBTrace.DBG_CSS)
        {
            if (inlineStyle)
            {
                FBTrace.sysout("deleteRule: element.style", src);
            }
            else
            {
                FBTrace.sysout("deleteRule: " + ruleIndex + " " + src.cssRules.length,
                    src.cssRules);
            }
        }

        var rule = (inlineStyle ? src : src.cssRules[ruleIndex]);
        var afterParams = [src, rule.style.cssText];
        afterParams.push(inlineStyle ? "" : rule.selectorText);

        Events.dispatch(this.fbListeners, "onCSSDeleteRule", [src, ruleIndex]);

        if (src instanceof window.Element)
            src.removeAttribute("style");
        else
            src.deleteRule(ruleIndex);

        Events.dispatch(this.fbListeners, "onAfterCSSDeleteRule", afterParams);
    },

    setProperty: function(rule, propName, propValue, propPriority)
    {
        var style = rule.style || rule;

        // Record the original CSS text for the inline case so we can reconstruct at a later
        // point for diffing purposes
        var baseText = style.cssText;

        var prevValue = style.getPropertyValue(propName);
        var prevPriority = style.getPropertyPriority(propName);

        // XXXjoe Gecko bug workaround: Just changing priority doesn't have any effect
        // unless we remove the property first
        style.removeProperty(propName);

        style.setProperty(propName, propValue, propPriority);

        if (propName)
        {
            Events.dispatch(this.fbListeners, "onCSSSetProperty", [style, propName, propValue,
                propPriority, prevValue, prevPriority, rule, baseText]);
        }
    },

    removeProperty: function(rule, propName, parent)
    {
        var style = rule.style || rule;

        // Record the original CSS text for the inline case so we can reconstruct at a later
        // point for diffing purposes
        var baseText = style.cssText;

        var prevValue = style.getPropertyValue(propName);
        var prevPriority = style.getPropertyPriority(propName);

        style.removeProperty(propName);

        if (propName)
            Events.dispatch(this.fbListeners, "onCSSRemoveProperty", [style, propName, prevValue,
                prevPriority, rule, baseText]);
    },

    /**
     * Method for atomic property removal, such as through the context menu.
     */
    deleteProperty: function(rule, propName, context)
    {
        Events.dispatch(this.fbListeners, "onBeginFirebugChange", [rule, context]);
        Firebug.CSSModule.removeProperty(rule, propName);
        Events.dispatch(this.fbListeners, "onEndFirebugChange", [rule, context]);
    },

    disableProperty: function(disable, rule, propName, parsedValue, map, context)
    {
        Events.dispatch(this.fbListeners, "onBeginFirebugChange", [rule, context]);

        if (disable)
        {
            Firebug.CSSModule.removeProperty(rule, propName);

            map.push({"name": propName, "value": parsedValue.value,
                "important": parsedValue.priority});
        }
        else
        {
            Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority);

            var index = findPropByName(map, propName);
            map.splice(index, 1);
        }

        Events.dispatch(this.fbListeners, "onEndFirebugChange", [rule, context]);
    },

    /**
     * Get a document's temporary stylesheet for storage of user-provided rules.
     * If it doesn't exist yet, create it.
     */
    getDefaultStyleSheet: function(doc)
    {
        // Cache the temporary sheet on an expando of the document.
        var sheet = doc.fbDefaultSheet;
        if (!sheet)
        {
            sheet = Css.appendStylesheet(doc, "chrome://firebug/default-stylesheet.css").sheet;
            sheet.defaultStylesheet = true;
            doc.fbDefaultSheet = sheet;
        }
        return sheet;
    },

    parseCSSValue: function(value, offset)
    {
        var start = 0;
        var m;
        while (true)
        {
            m = reSplitCSS.exec(value);
            if (m && m.index+m[0].length < offset)
            {
                value = value.substr(m.index+m[0].length);
                start += m.index+m[0].length;
                offset -= m.index+m[0].length;
            }
            else
                break;
        }

        if (!m)
            return;

        var type;
        if (m[1])
            type = "url";
        else if (m[2] || m[4])
            type = "rgb";
        else if (m[3])
            type = "hsl";
        else if (m[5])
            type = "int";

        var cssValue = {value: m[0], start: start+m.index, end: start+m.index+m[0].length, type: type};

        if (!type)
        {
            if (m[10] && m[10].indexOf("gradient") != -1)
            {
                var arg = value.substr(m[0].length).match(/\((?:(?:[^\(\)]*)|(?:\(.*?\)))+\)/);
                if (!arg)
                  return;

                cssValue.value += arg[0];
                cssValue.type = "gradient";
            }
            else if (Css.isColorKeyword(cssValue.value))
            {
                cssValue.type = "colorKeyword";
            }
        }

        return cssValue;
    },

    parseCSSFontFamilyValue: function(value, offset, propName)
    {
        var skipped = 0;
        if (propName === "font")
        {
            var rePreFont = new RegExp(
                "^.*" + // anything, then
                "(" +
                    "\\d+(\\.\\d+)?([a-z]*|%)|" + // a number (with possible unit)
                    "(x{1,2}-)?(small|large)|medium|larger|smaller" + // or an named size description
                ") "
            );
            var m = rePreFont.exec(value);
            if (!m || offset < m[0].length)
                return this.parseCSSValue(value, offset);
            skipped = m[0].length;
            value = value.substr(skipped);
            offset -= skipped;
        }

        var matches = /^(.*?)(\s*!.*)?$/.exec(value);
        var fonts = matches[1].split(",");

        var totalLength = 0;
        for (var i = 0; i < fonts.length; ++i)
        {
            totalLength += fonts[i].length;
            if (offset <= totalLength)
            {
                // Give back the value and location of this font, whitespace-trimmed.
                var font = fonts[i].replace(/^\s+/, "");
                var end = totalLength;
                var start = end - font.length;
                return {
                    value: font,
                    start: start + skipped,
                    end: end + skipped,
                    type: "fontFamily"
                };
            }

            // include ","
            ++totalLength;
        }

        // Parse !important.
        var ret = this.parseCSSValue(value, offset);
        if (ret)
        {
            ret.start += skipped;
            ret.end += skipped;
        }
        return ret;
    },

    parseURLValue: function(value)
    {
        var m = reURL.exec(value);
        return m ? m[1] : "";
    },

    parseRepeatValue: function(value)
    {
        var m = reRepeat.exec(value);
        return m ? m[0] : "";
    },

    getPropertyInfo: function(computedStyle, propName)
    {
        var propInfo = {
            property: propName,
            value: computedStyle.getPropertyValue(propName),
            matchedSelectors: [],
            matchedRuleCount: 0
        };

        return propInfo;
    },

    getColorDisplayOptionMenuItems: function()
    {
        return [
            "-",
            {
                label: "computed.option.label.Colors_As_Hex",
                tooltiptext: "computed.option.tip.Colors_As_Hex",
                type: "radio",
                name: "colorDisplay",
                id: "colorDisplayHex",
                command: function() {
                    return Options.set("colorDisplay", "hex");
                },
                checked: Options.get("colorDisplay") == "hex"
            },
            {
                label: "computed.option.label.Colors_As_RGB",
                tooltiptext: "computed.option.tip.Colors_As_RGB",
                type: "radio",
                name: "colorDisplay",
                id: "colorDisplayRGB",
                command: function() {
                    return Options.set("colorDisplay", "rgb");
                },
                checked: Options.get("colorDisplay") == "rgb"
            },
            {
                label: "computed.option.label.Colors_As_HSL",
                tooltiptext: "computed.option.tip.Colors_As_HSL",
                type: "radio",
                name: "colorDisplay",
                id: "colorDisplayHSL",
                command: function() {
                    return Options.set("colorDisplay", "hsl");
                },
                checked: Options.get("colorDisplay") == "hsl"
            }
        ];
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Module functions

    initialize: function()
    {
        this.editors = {};
        this.registerEditor("Live",
        {
            startEditing: function(stylesheet, context, panel)
            {
                panel.startLiveEditing(stylesheet, context);
            },
            stopEditing: function()
            {
                Firebug.Editor.stopEditing();
            }
        });

        this.registerEditor("Source",
        {
            startEditing: function(stylesheet, context, panel)
            {
                panel.startSourceEditing(stylesheet, context);
            },
            stopEditing: function()
            {
                Firebug.Editor.stopEditing();
            }
        });
    },

    initContext: function(context)
    {
        context.dirtyListener = new Firebug.CSSDirtyListener(context);
        this.addListener(context.dirtyListener);
    },

    destroyContext: function(context)
    {
        this.removeListener(context.dirtyListener);
    }
});

// ********************************************************************************************* //
// Helpers

function getStyleSheetOwnerNode(sheet)
{
    for (; sheet && !sheet.ownerNode; sheet = sheet.parentStyleSheet);

    return sheet.ownerNode;
}

function findPropByName(props, name)
{
    for (var i = 0; i < props.length; ++i)
    {
        if (props[i].name == name)
            return i;
    }
}

// ********************************************************************************************* //
// Registration

Firebug.registerModule(Firebug.CSSModule);

return Firebug.CSSModule;

// ********************************************************************************************* //
});
<commit_msg>Chaning order of implemented methods (initialization and module stuff should be at the begining)<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/lib/object",
    "firebug/firebug",
    "firebug/lib/xpcom",
    "firebug/lib/events",
    "firebug/lib/url",
    "firebug/lib/css",
    "firebug/chrome/window",
    "firebug/lib/xml",
    "firebug/lib/options",
    "firebug/lib/array",
    "firebug/editor/editorSelector"
],
function(Obj, Firebug, Xpcom, Events, Url, Css, Win, Xml, Options, Arr, EditorSelector) {

// ********************************************************************************************* //
// Constants

const Cc = Components.classes;
const Ci = Components.interfaces;

const reSplitCSS = /(url\("?[^"\)]+"?\)?)|(rgba?\([^)]*\)?)|(hsla?\([^)]*\)?)|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,4})?)|"([^"]*)"?|'([^']*)'?|([^,\s\/!\(\)]+)|(!(.*)?)/;
const reURL = /url\("?([^"\)]+)?"?\)/;
const reRepeat = /no-repeat|repeat-x|repeat-y|repeat/;

// ********************************************************************************************* //
// CSS Module

Firebug.CSSModule = Obj.extend(Firebug.Module, Firebug.EditorSelector,
{
    dispatchName: "cssModule",

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Module

    initialize: function()
    {
        this.editors = {};
        this.registerEditor("Live",
        {
            startEditing: function(stylesheet, context, panel)
            {
                panel.startLiveEditing(stylesheet, context);
            },
            stopEditing: function()
            {
                Firebug.Editor.stopEditing();
            }
        });

        this.registerEditor("Source",
        {
            startEditing: function(stylesheet, context, panel)
            {
                panel.startSourceEditing(stylesheet, context);
            },
            stopEditing: function()
            {
                Firebug.Editor.stopEditing();
            }
        });
    },

    initContext: function(context)
    {
        context.dirtyListener = new Firebug.CSSDirtyListener(context);
        this.addListener(context.dirtyListener);
    },

    destroyContext: function(context)
    {
        this.removeListener(context.dirtyListener);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

    freeEdit: function(styleSheet, value)
    {
        if (FBTrace.DBG_CSS)
            FBTrace.sysout("CSSModule.freeEdit", arguments);

        if (!styleSheet.editStyleSheet)
        {
            var ownerNode = getStyleSheetOwnerNode(styleSheet);
            styleSheet.disabled = true;

            var url = Xpcom.CCSV("@mozilla.org/network/standard-url;1", Ci.nsIURL);
            url.spec = styleSheet.href;

            var editStyleSheet = ownerNode.ownerDocument.createElementNS(
                "http://www.w3.org/1999/xhtml",
                "style");

            Firebug.setIgnored(editStyleSheet);

            editStyleSheet.setAttribute("type", "text/css");
            editStyleSheet.setAttributeNS(
                "http://www.w3.org/XML/1998/namespace",
                "base",
                url.directory);

            if (ownerNode.hasAttribute("media"))
                editStyleSheet.setAttribute("media", ownerNode.getAttribute("media"));

            // Insert the edited stylesheet directly after the old one to ensure the styles
            // cascade properly.
            ownerNode.parentNode.insertBefore(editStyleSheet, ownerNode.nextSibling);

            styleSheet.editStyleSheet = editStyleSheet;
        }

        styleSheet.editStyleSheet.innerHTML = value;

        if (FBTrace.DBG_CSS)
            FBTrace.sysout("css.saveEdit styleSheet.href:" + styleSheet.href +
                " got innerHTML:" + value);

        Events.dispatch(this.fbListeners, "onCSSFreeEdit", [styleSheet, value]);
    },

    insertRule: function(styleSheet, cssText, ruleIndex)
    {
        if (FBTrace.DBG_CSS)
            FBTrace.sysout("Insert: " + ruleIndex + " " + cssText);

        var insertIndex = styleSheet.insertRule(cssText, ruleIndex);

        Events.dispatch(this.fbListeners, "onCSSInsertRule", [styleSheet, cssText, ruleIndex]);

        return insertIndex;
    },

    deleteRule: function(src, ruleIndex)
    {
        var inlineStyle = (src instanceof window.Element);
        if (FBTrace.DBG_CSS)
        {
            if (inlineStyle)
            {
                FBTrace.sysout("deleteRule: element.style", src);
            }
            else
            {
                FBTrace.sysout("deleteRule: " + ruleIndex + " " + src.cssRules.length,
                    src.cssRules);
            }
        }

        var rule = (inlineStyle ? src : src.cssRules[ruleIndex]);
        var afterParams = [src, rule.style.cssText];
        afterParams.push(inlineStyle ? "" : rule.selectorText);

        Events.dispatch(this.fbListeners, "onCSSDeleteRule", [src, ruleIndex]);

        if (src instanceof window.Element)
            src.removeAttribute("style");
        else
            src.deleteRule(ruleIndex);

        Events.dispatch(this.fbListeners, "onAfterCSSDeleteRule", afterParams);
    },

    setProperty: function(rule, propName, propValue, propPriority)
    {
        var style = rule.style || rule;

        // Record the original CSS text for the inline case so we can reconstruct at a later
        // point for diffing purposes
        var baseText = style.cssText;

        var prevValue = style.getPropertyValue(propName);
        var prevPriority = style.getPropertyPriority(propName);

        // XXXjoe Gecko bug workaround: Just changing priority doesn't have any effect
        // unless we remove the property first
        style.removeProperty(propName);

        style.setProperty(propName, propValue, propPriority);

        if (propName)
        {
            Events.dispatch(this.fbListeners, "onCSSSetProperty", [style, propName, propValue,
                propPriority, prevValue, prevPriority, rule, baseText]);
        }
    },

    removeProperty: function(rule, propName, parent)
    {
        var style = rule.style || rule;

        // Record the original CSS text for the inline case so we can reconstruct at a later
        // point for diffing purposes
        var baseText = style.cssText;

        var prevValue = style.getPropertyValue(propName);
        var prevPriority = style.getPropertyPriority(propName);

        style.removeProperty(propName);

        if (propName)
            Events.dispatch(this.fbListeners, "onCSSRemoveProperty", [style, propName, prevValue,
                prevPriority, rule, baseText]);
    },

    /**
     * Method for atomic property removal, such as through the context menu.
     */
    deleteProperty: function(rule, propName, context)
    {
        Events.dispatch(this.fbListeners, "onBeginFirebugChange", [rule, context]);
        Firebug.CSSModule.removeProperty(rule, propName);
        Events.dispatch(this.fbListeners, "onEndFirebugChange", [rule, context]);
    },

    disableProperty: function(disable, rule, propName, parsedValue, map, context)
    {
        Events.dispatch(this.fbListeners, "onBeginFirebugChange", [rule, context]);

        if (disable)
        {
            Firebug.CSSModule.removeProperty(rule, propName);

            map.push({"name": propName, "value": parsedValue.value,
                "important": parsedValue.priority});
        }
        else
        {
            Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority);

            var index = findPropByName(map, propName);
            map.splice(index, 1);
        }

        Events.dispatch(this.fbListeners, "onEndFirebugChange", [rule, context]);
    },

    /**
     * Get a document's temporary stylesheet for storage of user-provided rules.
     * If it doesn't exist yet, create it.
     */
    getDefaultStyleSheet: function(doc)
    {
        // Cache the temporary sheet on an expando of the document.
        var sheet = doc.fbDefaultSheet;
        if (!sheet)
        {
            sheet = Css.appendStylesheet(doc, "chrome://firebug/default-stylesheet.css").sheet;
            sheet.defaultStylesheet = true;
            doc.fbDefaultSheet = sheet;
        }
        return sheet;
    },

    parseCSSValue: function(value, offset)
    {
        var start = 0;
        var m;
        while (true)
        {
            m = reSplitCSS.exec(value);
            if (m && m.index+m[0].length < offset)
            {
                value = value.substr(m.index+m[0].length);
                start += m.index+m[0].length;
                offset -= m.index+m[0].length;
            }
            else
                break;
        }

        if (!m)
            return;

        var type;
        if (m[1])
            type = "url";
        else if (m[2] || m[4])
            type = "rgb";
        else if (m[3])
            type = "hsl";
        else if (m[5])
            type = "int";

        var cssValue = {value: m[0], start: start+m.index, end: start+m.index+m[0].length, type: type};

        if (!type)
        {
            if (m[10] && m[10].indexOf("gradient") != -1)
            {
                var arg = value.substr(m[0].length).match(/\((?:(?:[^\(\)]*)|(?:\(.*?\)))+\)/);
                if (!arg)
                  return;

                cssValue.value += arg[0];
                cssValue.type = "gradient";
            }
            else if (Css.isColorKeyword(cssValue.value))
            {
                cssValue.type = "colorKeyword";
            }
        }

        return cssValue;
    },

    parseCSSFontFamilyValue: function(value, offset, propName)
    {
        var skipped = 0;
        if (propName === "font")
        {
            var rePreFont = new RegExp(
                "^.*" + // anything, then
                "(" +
                    "\\d+(\\.\\d+)?([a-z]*|%)|" + // a number (with possible unit)
                    "(x{1,2}-)?(small|large)|medium|larger|smaller" + // or an named size description
                ") "
            );
            var m = rePreFont.exec(value);
            if (!m || offset < m[0].length)
                return this.parseCSSValue(value, offset);
            skipped = m[0].length;
            value = value.substr(skipped);
            offset -= skipped;
        }

        var matches = /^(.*?)(\s*!.*)?$/.exec(value);
        var fonts = matches[1].split(",");

        var totalLength = 0;
        for (var i = 0; i < fonts.length; ++i)
        {
            totalLength += fonts[i].length;
            if (offset <= totalLength)
            {
                // Give back the value and location of this font, whitespace-trimmed.
                var font = fonts[i].replace(/^\s+/, "");
                var end = totalLength;
                var start = end - font.length;
                return {
                    value: font,
                    start: start + skipped,
                    end: end + skipped,
                    type: "fontFamily"
                };
            }

            // include ","
            ++totalLength;
        }

        // Parse !important.
        var ret = this.parseCSSValue(value, offset);
        if (ret)
        {
            ret.start += skipped;
            ret.end += skipped;
        }
        return ret;
    },

    parseURLValue: function(value)
    {
        var m = reURL.exec(value);
        return m ? m[1] : "";
    },

    parseRepeatValue: function(value)
    {
        var m = reRepeat.exec(value);
        return m ? m[0] : "";
    },

    getPropertyInfo: function(computedStyle, propName)
    {
        var propInfo = {
            property: propName,
            value: computedStyle.getPropertyValue(propName),
            matchedSelectors: [],
            matchedRuleCount: 0
        };

        return propInfo;
    },

    getColorDisplayOptionMenuItems: function()
    {
        return [
            "-",
            {
                label: "computed.option.label.Colors_As_Hex",
                tooltiptext: "computed.option.tip.Colors_As_Hex",
                type: "radio",
                name: "colorDisplay",
                id: "colorDisplayHex",
                command: function() {
                    return Options.set("colorDisplay", "hex");
                },
                checked: Options.get("colorDisplay") == "hex"
            },
            {
                label: "computed.option.label.Colors_As_RGB",
                tooltiptext: "computed.option.tip.Colors_As_RGB",
                type: "radio",
                name: "colorDisplay",
                id: "colorDisplayRGB",
                command: function() {
                    return Options.set("colorDisplay", "rgb");
                },
                checked: Options.get("colorDisplay") == "rgb"
            },
            {
                label: "computed.option.label.Colors_As_HSL",
                tooltiptext: "computed.option.tip.Colors_As_HSL",
                type: "radio",
                name: "colorDisplay",
                id: "colorDisplayHSL",
                command: function() {
                    return Options.set("colorDisplay", "hsl");
                },
                checked: Options.get("colorDisplay") == "hsl"
            }
        ];
    },
});

// ********************************************************************************************* //
// Helpers

function getStyleSheetOwnerNode(sheet)
{
    for (; sheet && !sheet.ownerNode; sheet = sheet.parentStyleSheet);

    return sheet.ownerNode;
}

function findPropByName(props, name)
{
    for (var i = 0; i < props.length; ++i)
    {
        if (props[i].name == name)
            return i;
    }
}

// ********************************************************************************************* //
// Registration

Firebug.registerModule(Firebug.CSSModule);

return Firebug.CSSModule;

// ********************************************************************************************* //
});
<|endoftext|>