<commit_before>function setTitle(component,q) {
	var tpl = new Ext.Template([
		'
{t}
',
	]);
	tpl.compile();
	html = tpl.apply( {t: q.get('text') } );
	component.getTitle().setHtml(html);
}

function setQuestion(c, q) {
	c.removeAll();
	var response = buildQuestion(q);
	c.add(Ext.decode(response).data);
}

function getNextQuestion(newO, direction) {
	// direction = 0 for direct, -1 for prev, 1 for next
	var s = Ext.getStore('Questions');
	// wrap around for now; go to welcome / summary
	if ( newO < 0 ) {
		// summary
		newO = s.getCount() - 1;
	} else if ( newO > s.getCount() - 1) {
		// start (clear/etc)
		newO = 0;
	}
	var q = s.getAt(newO);
	// skip?
	log(q.get('skip'));
	if ( q.get('skip') != null ) {
		q = skipQuestions(q, direction);
	}
	//
	return q;
}

function skipQuestions(q, direction) {
	log('skipQuestion direction: ' + direction + ' q: ' + q.get('skip').split(',')[0] );
	var skipItems = q.get('skip').split(',');
	skipItems.forEach(logArrayElements);
	skipItems.forEach(function(element) {
		if ( newQ = skipQuestionsItem(q, element, direction) ) {
			log('skipped ' + q.get('id'));
			log('newQ ' + newQ.get('id'));
		}
	});
	return newQ;
}
function skipQuestionsItem(q, element, direction) {
	var item = element.split('.');
	// if this question id
	log( item[0] );
	// has this answer
	log( item[1] );
	// skip this question id
	log( 'skipped q ' + q.get('id') );
	log( 'skipped o ' + q.get('ordinal') );
	// make sure the skipped q has a response of null
	// saveResponse()
	//  getNextQuestion(newO, direction)
	var newQ = getNextQuestion(q.get('ordinal') + direction, direction);
	return newQ;
}

function buildQuestion(q) {
	//fixme switch on question types here
	var tpl = new Ext.XTemplate(
		'{ success: true, data: [ ' ,
			// fields
			'{ xtype: "hiddenfield", name: "q", suborgetsdropped: "{name}"}, ' ,
			'{ xtype: "hiddenfield", name: "ordinal", suborgetsdropped: "{name}"}, ' ,
			// options fieldset
			'{ xtype: "fieldset", items: [ ',
				'<tpl for="options">',
				'<tpl if="this.isGroup(text)">',
					"{ xtype: 'label', name:'{name}', style: 'padding: 0.2em;background: #eee;font-weight:bold;font-size: 1.2em;width: 30% !important;', cls:'x-form-labelDISAPPEARS', html:'{[this.formatGroup(values.text)]}',}, ",
				'<tpl elseif="text != "TEXT_OTHER"">',
				'{ ' ,
					'<tpl if="parent.type == "SC"">',
					'xtype: "radiofield", ' ,
					'</tpl>',
					'<tpl if="parent.type == "SC-SL"">',
					'xtype: "radiofield", ' ,
					'</tpl>',
					'<tpl if="parent.type == "MC"">',
					'xtype: "checkboxfield", ' ,
					'</tpl>',
					'name : "options", ' ,
					'label: "{text}", ' ,
					'value: "{value}", ' ,
					'labelWidth: "66%",	 ' ,
					'labelWrap: true,	 ' ,
					'labelAlign: "left",	 ' ,
					'style: "font-size: 1.2em;", ',
					'<tpl if="parent.type == "SC-SL"">',
					'listeners: { ',
						'check: function(button) { ',
							'Ext.get("{parent.name}").setHtml("' ,
								"
",
									'<tpl switch="value">',
										'<tpl case="0">',
											"",
										'<tpl case="1">',
											"",
										'<tpl case="2">',
											"",
										'<tpl default>',
											'',
									'</tpl>',
								"
" ,
							'"); ',
						'}',
					'}, ' ,
					'</tpl>',
				'}, ' ,
				'</tpl>',
				'</tpl>',
				// TEXT_OTHER
				'<tpl for="options">',
					'<tpl if="text == "TEXT_OTHER"">',
						"{ xtype: 'textfield', id:'{name}', name: 'other', ",
							'style: "font-size: 1.2em;", ',
							"label:'Other',}, ",
					'</tpl>',
				'</tpl>',
			'], }, ' ,
			// stoplight
			'<tpl if="type == "SC-SL"">',
			"{ html: '",
			'

',
			'
',
				'',
			'
',
			'

',
			"'}, ",
			'</tpl>',
			// category
			"{ html: '",
			'
',
				'{category}',
			'
',
			"'}, ",
			// info
			"{ html: '",
			'
',
				'{info}',
			'
',
			"'}, ",
		'] }',
	    {
        // XTemplate configuration:
        disableFormats: true,
        isGroup: function(text){
           return text.substring(0, 6) == "GROUP:";
        },
        formatGroup: function(text){
           return text.substring(6, text.length);
        },
    }
	);
	tpl.compile();
	var html = tpl.apply({name:Date.now(), info:q.get('info'), category:q.get('category'),options:q.get('options'), required:q.get('required'), type:q.get('type')});
	//log(html);
	return html;
}

<commit_msg>skip logic working; need to look up actual responses<commit_after>function setTitle(component,q) {
	var tpl = new Ext.Template([
		'
{t}
',
	]);
	tpl.compile();
	html = tpl.apply( {t: q.get('text') } );
	component.getTitle().setHtml(html);
}

function setQuestion(c, q) {
	c.removeAll();
	var response = buildQuestion(q);
	c.add(Ext.decode(response).data);
}

function getNextQuestion(newO, direction) {
	// direction = 0 for direct, -1 for prev, 1 for next
	var s = Ext.getStore('Questions');
	// wrap around for now; go to welcome / summary
	if ( newO < 0 ) {
		// summary
		newO = s.getCount() - 1;
	} else if ( newO > s.getCount() - 1) {
		// start (clear/etc)
		newO = 0;
	}
	var q = s.getAt(newO);
	// skip?
	log(q.get('skip'));
	if ( q.get('skip') != null ) {
		q = skipQuestions(q, direction);
	}
	//
	return q;
}

function skipQuestions(q, direction) {
	log('skipQuestion direction: ' + direction + ' q: ' + q.get('skip').split(',')[0] );
	var skipItems = q.get('skip').split(',');
	skipItems.forEach(logArrayElements);
	newQ = q;
	skipItems.forEach(function(element) {
		if ( newQ = skipQuestionsItem(newQ, element, direction) ) {
			log('newQ ' + newQ.get('id'));
		}
	});
	return newQ;
}

function skipQuestionsItem(q, element, direction) {
	var item = element.split('.');
	// need this q var to update
	if ( isResponseEqualSkip(q,item[0], item[1]) ) {
		log('skipped ' + q.get('id'));
		// save empty response for skipped q
		q = getNextQuestion(q.get('ordinal') + direction, direction);
	}
	return q;
}

function isResponseEqualSkip(q,skipQ, skipR) {
	log('skipQ ' + skipQ );
	log('skipR ' + skipR );
	// skip this question id
	log( 'skip it? q ' + q.get('id') );
	log( 'skip it? o ' + q.get('ordinal') );
	// make sure the skipped q has a response of null
	// saveResponse()
	//  getNextQuestion(newO, direction)
	return (
		(skipQ == 62 && skipR == 1)
			);
}

function buildQuestion(q) {
	//fixme switch on question types here
	var tpl = new Ext.XTemplate(
		'{ success: true, data: [ ' ,
			// fields
			'{ xtype: "hiddenfield", name: "q", suborgetsdropped: "{name}"}, ' ,
			'{ xtype: "hiddenfield", name: "ordinal", suborgetsdropped: "{name}"}, ' ,
			// options fieldset
			'{ xtype: "fieldset", items: [ ',
				'<tpl for="options">',
				'<tpl if="this.isGroup(text)">',
					"{ xtype: 'label', name:'{name}', style: 'padding: 0.2em;background: #eee;font-weight:bold;font-size: 1.2em;width: 30% !important;', cls:'x-form-labelDISAPPEARS', html:'{[this.formatGroup(values.text)]}',}, ",
				'<tpl elseif="text != "TEXT_OTHER"">',
				'{ ' ,
					'<tpl if="parent.type == "SC"">',
					'xtype: "radiofield", ' ,
					'</tpl>',
					'<tpl if="parent.type == "SC-SL"">',
					'xtype: "radiofield", ' ,
					'</tpl>',
					'<tpl if="parent.type == "MC"">',
					'xtype: "checkboxfield", ' ,
					'</tpl>',
					'name : "options", ' ,
					'label: "{text}", ' ,
					'value: "{value}", ' ,
					'labelWidth: "66%",	 ' ,
					'labelWrap: true,	 ' ,
					'labelAlign: "left",	 ' ,
					'style: "font-size: 1.2em;", ',
					'<tpl if="parent.type == "SC-SL"">',
					'listeners: { ',
						'check: function(button) { ',
							'Ext.get("{parent.name}").setHtml("' ,
								"
",
									'<tpl switch="value">',
										'<tpl case="0">',
											"",
										'<tpl case="1">',
											"",
										'<tpl case="2">',
											"",
										'<tpl default>',
											'',
									'</tpl>',
								"
" ,
							'"); ',
						'}',
					'}, ' ,
					'</tpl>',
				'}, ' ,
				'</tpl>',
				'</tpl>',
				// TEXT_OTHER
				'<tpl for="options">',
					'<tpl if="text == "TEXT_OTHER"">',
						"{ xtype: 'textfield', id:'{name}', name: 'other', ",
							'style: "font-size: 1.2em;", ',
							"label:'Other',}, ",
					'</tpl>',
				'</tpl>',
			'], }, ' ,
			// stoplight
			'<tpl if="type == "SC-SL"">',
			"{ html: '",
			'

',
			'
',
				'',
			'
',
			'

',
			"'}, ",
			'</tpl>',
			// category
			"{ html: '",
			'
',
				'{category}',
			'
',
			"'}, ",
			// info
			"{ html: '",
			'
',
				'{info}',
			'
',
			"'}, ",
		'] }',
	    {
        // XTemplate configuration:
        disableFormats: true,
        isGroup: function(text){
           return text.substring(0, 6) == "GROUP:";
        },
        formatGroup: function(text){
           return text.substring(6, text.length);
        },
    }
	);
	tpl.compile();
	var html = tpl.apply({name:Date.now(), info:q.get('info'), category:q.get('category'),options:q.get('options'), required:q.get('required'), type:q.get('type')});
	//log(html);
	return html;
}

<|endoftext|>


<commit_before>define([
  "backbone-plugins",
  "helpers"
], function(Backbone, Helpers) {

  var Settings = Backbone.NestedModel.extend({
    localStorage: new Backbone.LocalStorage('komanda.settings'),
    store : 'settings',

    defaults: {
      themes: {
        base: "komanda-base.css",
        current: "komanda-dark",
        list: {
          "komanda-dark": {
            name: "Komanda Dark",
            css: "themes/komanda-dark/komanda-dark.css"
          },
          "octa": {
            name: "Octa",
            css: "themes/octa/octa.css"
          },
          "pitch-black": {
            name: "Pitch Black",
            css: "themes/pitch-black/pitch-black.css"
          }
        }
      },
      notifications: {
        highlight: true,
        pm: true,
        status: true,
        badge: true
      },
      embed: {
        all: false,
        gist: false,
        jsfiddle: false,
        images: true
      },
      display: {
        timestamp: 'MM/DD/YY hh:mm:ss'
      }
    },

    modelEvents: {
      "sync": "save"
    },

    initialize: function() {
      this.bind('change', function(a, b) {
        // Komanda.settings.set('themes', a.attributes.themes);
        // Komanda.settings.save(null);

        if (a.changed.hasOwnProperty(('themes'))) Helpers.loadTheme(a.attributes);
      });
    }
  });

  return Settings;
});
<commit_msg>change komanda-dark name<commit_after>define([
  "backbone-plugins",
  "helpers"
], function(Backbone, Helpers) {

  var Settings = Backbone.NestedModel.extend({
    localStorage: new Backbone.LocalStorage('komanda.settings'),
    store : 'settings',

    defaults: {
      themes: {
        base: "komanda-base.css",
        current: "komanda-dark",
        list: {
          "komanda-dark": {
            name: "Komanda",
            css: "themes/komanda-dark/komanda-dark.css"
          },
          "octa": {
            name: "Octa",
            css: "themes/octa/octa.css"
          },
          "pitch-black": {
            name: "Pitch Black",
            css: "themes/pitch-black/pitch-black.css"
          }
        }
      },
      notifications: {
        highlight: true,
        pm: true,
        status: true,
        badge: true
      },
      embed: {
        all: false,
        gist: false,
        jsfiddle: false,
        images: true
      },
      display: {
        timestamp: 'MM/DD/YY hh:mm:ss'
      }
    },

    modelEvents: {
      "sync": "save"
    },

    initialize: function() {
      this.bind('change', function(a, b) {
        // Komanda.settings.set('themes', a.attributes.themes);
        // Komanda.settings.save(null);

        if (a.changed.hasOwnProperty(('themes'))) Helpers.loadTheme(a.attributes);
      });
    }
  });

  return Settings;
});
<|endoftext|>


<commit_before>var assert = require('chai').assert;
var dbConnection = require('../test-data/testConnection');
var dbMigrate = require('../lib/dbMigrate');
var basicMigrations = require('../test-data/simpleForwardMigrations');
var dbInfo = require('../lib/dbInfo');
var _ = require('lodash');

var $npm = {
  debug: require('debug')('db-migration:test:dbMigrate'),
  sinon: require('sinon')
};

describe('dbMigrate', function () {

  beforeEach(function() {
    // Where we left off here is how to spy on this correctly.
    //  I'm thinking of going through another project. See how they do it.
    // this.restore = { //doesn't work
    //   tx: dbConnection.tx,
    //   one: dbConnection.one
    // }; //save refs

    //dbConnection.tx = $npm.sinon.spy(dbConnection.tx);
    //dbConnection.one = $npm.sinon.spy(dbConnection.one);
    $npm.sinon.spy(dbConnection, 'tx');
    assert.equal(dbConnection.tx.callCount, 0);
    //
    //

    return dbConnection
      .none('drop table if exists example;')
      .then(function() {
        console.log('beforeEach :: dropped example');
        return dbInfo(dbConnection);
      }).catch(function(er){
        console.log('afterEach:catch', er);
      });
  });

  afterEach(function() {
    return dbConnection
      .none('drop table if exists example;')
      .then(function() {
        console.log('afterEach :: dropped example');
      })
      .catch(function(er){
        console.log('afterEach:catch', er);
      });
  });

  it('basic migration', function() {
    var result = dbMigrate(dbConnection, basicMigrations);
    return result.then(function(batchResult){
      console.log('[unit test then] batchResult', batchResult);
      console.log('                 *** SUCESS **');
      assert.isTrue(batchResult.overallResult);
      assert.isTrue(batchResult["1.0.0"].result);
      assert.isTrue(batchResult["1.0.1"].result);
      assert.isTrue(batchResult["1.0.2"].result);
    });
  });

  it('track deployed DB version in DB', function() {
    var result = dbMigrate(dbConnection, basicMigrations); //3 versions.
    return result.then(function(batchResult) {
      return dbConnection
        .one("SELECT value from pg_migration_dbinfo where key = 'db_version';")
        .then(function(result) {
          assert.equal(result.value, '1.0.2');
        });
    });
  });

  it('Performs incremental DB deployments', function() {
    var result = dbMigrate(dbConnection, basicMigrations); //to 1.0.2
    return result
      .then(function(batchResult) {
        assert.isTrue(batchResult.overallResult);
        return batchResult;
      })
      .then(function(batchResult) {
        var clonedMigrations = _.cloneDeep(basicMigrations);
        clonedMigrations['1.0.3'] = {
          tables: ["CREATE TABLE secondtable( id INTEGER SERIAL PRIMARY KEY NOT NULL, name VARCHAR(500), something1 INTEGER, something2 NUMERIC );"],
          data: [],
          indexes: ["CREATE UNIQUE INDEX 'secondTable_something1_uindex' ON secondtable (something1);"]
        };

        var result2 = dbMigrate(dbConnection, clonedMigrations);
        return result2
          .then(function(result) {
            assert.isTrue(result.overallResult);
            return result;
          })
          .then(function(results) {
            return dbConnection
              .one("SELECT value from pg_migration_dbinfo where key = 'db_version';")
              .then(function(result) {
                assert.equal(result.value, '1.0.3');
              });
          })
      });
  });
});<commit_msg>Leverage the spy; use call counts to check that the target function was called only as many times as needed for the latest version.<commit_after>var assert = require('chai').assert;
var dbConnection = require('../test-data/testConnection');
var dbMigrate = require('../lib/dbMigrate');
var basicMigrations = require('../test-data/simpleForwardMigrations');
var dbInfo = require('../lib/dbInfo');
var _ = require('lodash');

var $npm = {
  debug: require('debug')('db-migration:test:dbMigrate'),
  sinon: require('sinon')
};

describe('dbMigrate', function () {

  beforeEach(function() {
    // Where we left off here is how to spy on this correctly.
    //  I'm thinking of going through another project. See how they do it.
    // this.restore = { //doesn't work
    //   tx: dbConnection.tx,
    //   one: dbConnection.one
    // }; //save refs

    //dbConnection.tx = $npm.sinon.spy(dbConnection.tx);
    //dbConnection.one = $npm.sinon.spy(dbConnection.one);
    $npm.sinon.spy(dbConnection, 'tx');
    assert.equal(dbConnection.tx.callCount, 0);
    //
    //

    return dbConnection
      .none('drop table if exists example;')
      .then(function() {
        console.log('beforeEach :: dropped example');
        return dbInfo(dbConnection);
      }).catch(function(er){
        console.log('afterEach:catch', er);
      });
  });

  afterEach(function() {
    return dbConnection
      .none('drop table if exists example;')
      .then(function() {
        console.log('afterEach :: dropped example');
      })
      .catch(function(er){
        console.log('afterEach:catch', er);
      });
  });

  it('basic migration', function() {
    var result = dbMigrate(dbConnection, basicMigrations);
    return result.then(function(batchResult){
      console.log('[unit test then] batchResult', batchResult);
      console.log('                 *** SUCESS **');
      assert.isTrue(batchResult.overallResult);
      assert.isTrue(batchResult["1.0.0"].result);
      assert.isTrue(batchResult["1.0.1"].result);
      assert.isTrue(batchResult["1.0.2"].result);
    });
  });

  it('track deployed DB version in DB', function() {
    var result = dbMigrate(dbConnection, basicMigrations); //3 versions.
    return result.then(function(batchResult) {
      return dbConnection
        .one("SELECT value from pg_migration_dbinfo where key = 'db_version';")
        .then(function(result) {
          assert.equal(result.value, '1.0.2');
        });
    });
  });

  it('Performs incremental DB deployments', function() {
    var result = dbMigrate(dbConnection, basicMigrations); //to 1.0.2
    return result
      .then(function(batchResult) {
        assert.isTrue(batchResult.overallResult);
        return batchResult;
      })
      .then(function(batchResult) {

        assert.equal(3, dbConnection.tx.callCount);
        dbConnection.tx.reset(); //reset the spy.

        var clonedMigrations = _.cloneDeep(basicMigrations);
        clonedMigrations['1.0.3'] = {
          tables: ["CREATE TABLE secondtable( id INTEGER SERIAL PRIMARY KEY NOT NULL, name VARCHAR(500), something1 INTEGER, something2 NUMERIC );"],
          data: [],
          indexes: ["CREATE UNIQUE INDEX 'secondTable_something1_uindex' ON secondtable (something1);"]
        };

        var result2 = dbMigrate(dbConnection, clonedMigrations);
        return result2
          .then(function(result) {
            assert.isTrue(result.overallResult);

            assert.equal(1, dbConnection.tx.callCount);
            dbConnection.tx.reset(); //reset the spy.

            return result;
          })
          .then(function(results) {
            return dbConnection
              .one("SELECT value from pg_migration_dbinfo where key = 'db_version';")
              .then(function(result) {
                assert.equal(result.value, '1.0.3');
              });
          })
      });
  });
});<|endoftext|>


<commit_before>/** EVENTS
 ****************************************************************************/

function deleteVideoButtonClicked(li) {
    var playlistElem = $('.playlistElem.selected'),
        playlist = playlistElem.data('model');

    playlist.deleteVideo(li.index());
    playlistManager.save();
    playlistElem.click(); // reload playlist
}

function playlistMouseDown(event) {
	$('#left-menu li').removeClass('selected');
	$(this).addClass('selected');
}

function loadPlaylist(playlistId, videoId) {
    $.getJSON('/api/playlists/' + playlistId, function(data) {
        var playlist = new Playlist(data.title, data.videos, data.remoteId, data.owner, data.isPrivate);
        loadPlaylistView(playlist, videoId);
    });
}

function savePlaylistButtonClicked(event) {
    var playlistBar = $(this).parent();
    var playlist = playlistBar.data('playlist');
    playlistManager.addPlaylist(playlist.copy()); // create copy without connection to remote
    playlistBar.replaceWith(createPlaylistBar(playlist));
    constructPlaylistsMenu();
}

function syncPlaylistButtonClicked(event) {
    var playlistBar = $(this).parent();
    var playlist = playlistBar.data('playlist');
    playlist.sync(function() {
        playlistBar.replaceWith(createPlaylistBar(playlist));
        history.pushState(null, null, playlist.getUrl());
        constructPlaylistsMenu();
    });
}

function createPlaylistBar(playlist) {
    var div = $('

').data('playlist', playlist);

    $('').text(playlist.title).appendTo(div);

    if (playlist.owner) {
        if (playlist.owner.id != my_user_id) {
            var owner = $('').text('by: ');
            $('').text(playlist.owner.name).appendTo(owner);
            owner.appendTo(div);

            // Add save button if not already saved
            if (!(playlist.remoteId in playlistManager.getPlaylistsMap())) {
                $('<input type="button" class="save"></button>')
                    .val('Copy playlist')
                    .click(savePlaylistButtonClicked)
                    .appendTo(div);
            }

        }
        //$('<input type="button" class="share"></button>').val('Share').appendTo(div);
    } else if (logged_in) {
        $('<input type="button" class="sync"></button>')
            .val('Sync')
            .click(syncPlaylistButtonClicked)
            .appendTo(div);
    }

    return div;
}

function loadPlaylistView(playlist, videoId) {
	$('#results-container ol').hide();
    $('#playlistbar').replaceWith(createPlaylistBar(playlist)).show();
    $('#playlist').html('');

    $.each(playlist.videos, function(i, item) {
        var li = createResultsItem(item.title, item.videoId);
        li.data('additionalMenuButtons').push({
            title: 'Delete',
            li: li,
            callback: deleteVideoButtonClicked
        });
        li.addClass('droppable');
        li.addClass('draggable');
        li.addClass('reorderable');
        li.appendTo('#playlist');
    });

	$('#playlist').show();
}

/**
 * Mark the playlistElem in the #left-menu as selected, then
 * fill #playlist with the contained videos.
 */
function playlistClicked(event) {
    var playlist = $(this).data('model');

    if (playlist.remoteId) {
        history.pushState(null, null, playlist.getUrl());
    } else {
        history.pushState(null, null, '/');
    }

	$('#playlist').data('owner', $(this));

    loadPlaylistView(playlist);
}

function shuffleButtonClicked(event) {
    if ($(this).hasClass('shuffle-on')) {
        setShuffle(false, $(this).parent());
        Player.addSiblingsToPlayorder($('#results-container li.playing, #results-container li.paused'), false);
    } else {
        setShuffle(true, $(this).parent());
        Player.addSiblingsToPlayorder($('#results-container li.playing, #results-container li.paused'), true);
    }
    event.stopPropagation();
}

/** MISC
 ****************************************************************************/

function setShuffle(enabled, playlistElem) {
	var playlist = playlistElem.data('model');
	playlist.shuffle = enabled;
	playlistManager.save();
	if (enabled) {
		$(playlistElem).find('.shuffle-off').addClass('shuffle-on');
		$(playlistElem).find('.shuffle-off').removeClass('shuffle-off');
	} else {
		$(playlistElem).find('.shuffle-on').addClass('shuffle-off');
		$(playlistElem).find('.shuffle-on').removeClass('shuffle-on');
	}
}

/** CLASS PLAYLIST
 ****************************************************************************/

function Playlist(title, videos, remoteId, owner, isPrivate, shuffle) {
    this.title = title;
    this.videos = videos;
    this.remoteId = remoteId || null;
    this.isPrivate = isPrivate || false;
    this.shuffle = shuffle;
    this.owner = owner;
    this.synced = true; // not part of JSON structure
    this.syncing = false; // not part of JSON structure

    this.getUrl = function() {
        return '/users/' + this.owner.id + '/playlists/' + this.remoteId;
    };

    this.copy = function() {
        return new Playlist(this.title, this.videos);
    };

    this.rename = function(newTitle) {
        var title = $.trim(newTitle);
        if (title.length > 0 && title.length < 50) {
            this.title = newTitle;
        }
        this.synced = false;
    };

    this.unsync = function(callback) {
        $.ajax({
            type: 'DELETE',
            url: '/api/playlists/' + this.remoteId,
            success: function() {
                if (callback) {
                    callback();
                }
            }
        });

        this.remoteId = null;
        this.owner = null;
    };

    this.createNewPlaylistOnRemote = function(callback) {
        var self = this,
            params = {
                'json': JSON.stringify(this.toJSON())
            };

        this.syncing = true;

        $.post('/api/playlists', params, function(data, textStatus) {
            self.syncing = false;
            if (textStatus === 'success') {
                self.remoteId = data.remoteId;
                self.owner = data.owner;
                self.synced = true;
            } else {
                alert('Failed to create new playlist ' + self.title);
            }
            if (callback) {
                callback();
            }
        });
    };

    this.updatePlaylistOnRemote = function(callback) {
        var self = this,
            params = {
                'json': JSON.stringify(this.toJSON())
            };

        this.syncing = true;

        $.post('/api/playlists/' + this.remoteId, params, function(data, textStatus) {
            self.syncing = false;
            if (textStatus === 'success') {
                self.synced = true;
            } else {
                alert('Failed to update playlist ' + self.title);
            }
            if (callback) {
                callback();
            }
        });
    };

    this.sync = function(callback) {
        if (this.remoteId && this.synced) {
            callback();
        } else if (this.remoteId) {
            this.updatePlaylistOnRemote(callback);
        } else {
            this.createNewPlaylistOnRemote(callback);
        }
    };

    this.addVideo = function(title, videoId) {
        if (this.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        if (typeof title !== 'string') {
            throw "title param must be string";
        }
        if (typeof videoId !== 'string') {
            throw "videoId param must be string";
        }

        this.videos.push({
            videoId: videoId,
            title: title,
        });

        this.synced = false;
    };

    this.moveVideo = function(sourceIndex, destIndex) {
        if (this.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        var tmp;

        if (destIndex > sourceIndex) {
            destIndex -= 1;
        }

        tmp = this.videos.splice(sourceIndex, 1)[0];
        this.videos.splice(destIndex, 0, tmp);

        this.synced = false;
    };

    this.deleteVideo = function(index) {
        if (this.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        this.videos.splice(index, 1);
        this.synced = false;
    };

    this.toJSON = function() {
        return {
            title: this.title,
            videos: this.videos,
            remoteId: this.remoteId,
            owner: this.owner,
            isPrivate: this.isPrivate,
			shuffle: this.shuffle
        };
    };

    this.createListElem = function() {
        var li = $('
')
            .addClass("playlistElem")
            .addClass('droppable')
            .data('model', this)
            .bind('contextmenu', showPlaylistContextMenu)
            .mousedown(playlistMouseDown)
            .click(playlistClicked);

        $('').text(this.title).appendTo(li);

        if (this.remoteId) {
            li.addClass('remote');
        } else {
            li.addClass('local')
        }

        if (this.isPrivate) {
            li.addClass('private');
        }

        var shuffleButton = $('<button/>').click(shuffleButtonClicked);

        if (this.shuffle) {
            shuffleButton.addClass('shuffle-on');
        } else {
            shuffleButton.addClass('shuffle-off');
        }

        shuffleButton.appendTo(li);

        return li;
    };
};
<commit_msg>Fix bug where video could not be deleted<commit_after>/** EVENTS
 ****************************************************************************/

function deleteVideoButtonClicked(li) {
    var playlist = $('#playlistbar').data('playlist');

    playlist.deleteVideo(li.index());
    playlistManager.save();

    loadPlaylistView(playlist);
}

function playlistMouseDown(event) {
	$('#left-menu li').removeClass('selected');
	$(this).addClass('selected');
}

function loadPlaylist(playlistId, videoId) {
    $.getJSON('/api/playlists/' + playlistId, function(data) {
        var playlist = new Playlist(data.title, data.videos, data.remoteId, data.owner, data.isPrivate);
        loadPlaylistView(playlist, videoId);
    });
}

function savePlaylistButtonClicked(event) {
    var playlistBar = $(this).parent();
    var playlist = playlistBar.data('playlist');
    playlistManager.addPlaylist(playlist.copy()); // create copy without connection to remote
    playlistBar.replaceWith(createPlaylistBar(playlist));
    constructPlaylistsMenu();
}

function syncPlaylistButtonClicked(event) {
    var playlistBar = $(this).parent();
    var playlist = playlistBar.data('playlist');
    playlist.sync(function() {
        playlistBar.replaceWith(createPlaylistBar(playlist));
        history.pushState(null, null, playlist.getUrl());
        constructPlaylistsMenu();
    });
}

function createPlaylistBar(playlist) {
    var div = $('

').data('playlist', playlist);

    $('').text(playlist.title).appendTo(div);

    if (playlist.owner) {
        if (playlist.owner.id != my_user_id) {
            var owner = $('').text('by: ');
            $('').text(playlist.owner.name).appendTo(owner);
            owner.appendTo(div);

            // Add save button if not already saved
            if (!(playlist.remoteId in playlistManager.getPlaylistsMap())) {
                $('<input type="button" class="save"></button>')
                    .val('Copy playlist')
                    .click(savePlaylistButtonClicked)
                    .appendTo(div);
            }

        }
        //$('<input type="button" class="share"></button>').val('Share').appendTo(div);
    } else if (logged_in) {
        $('<input type="button" class="sync"></button>')
            .val('Sync')
            .click(syncPlaylistButtonClicked)
            .appendTo(div);
    }

    return div;
}

function loadPlaylistView(playlist, videoId) {
	$('#results-container ol').hide();
    $('#playlistbar').replaceWith(createPlaylistBar(playlist)).show();
    $('#playlist').html('');

    $.each(playlist.videos, function(i, item) {
        var li = createResultsItem(item.title, item.videoId);
        li.data('additionalMenuButtons').push({
            title: 'Delete',
            li: li,
            callback: deleteVideoButtonClicked
        });
        li.addClass('droppable');
        li.addClass('draggable');
        li.addClass('reorderable');
        li.appendTo('#playlist');
    });

	$('#playlist').show();
}

/**
 * Mark the playlistElem in the #left-menu as selected, then
 * fill #playlist with the contained videos.
 */
function playlistClicked(event) {
    var playlist = $(this).data('model');

    if (playlist.remoteId) {
        history.pushState(null, null, playlist.getUrl());
    } else {
        history.pushState(null, null, '/');
    }

	$('#playlist').data('owner', $(this));

    loadPlaylistView(playlist);
}

function shuffleButtonClicked(event) {
    if ($(this).hasClass('shuffle-on')) {
        setShuffle(false, $(this).parent());
        Player.addSiblingsToPlayorder($('#results-container li.playing, #results-container li.paused'), false);
    } else {
        setShuffle(true, $(this).parent());
        Player.addSiblingsToPlayorder($('#results-container li.playing, #results-container li.paused'), true);
    }
    event.stopPropagation();
}

/** MISC
 ****************************************************************************/

function setShuffle(enabled, playlistElem) {
	var playlist = playlistElem.data('model');
	playlist.shuffle = enabled;
	playlistManager.save();
	if (enabled) {
		$(playlistElem).find('.shuffle-off').addClass('shuffle-on');
		$(playlistElem).find('.shuffle-off').removeClass('shuffle-off');
	} else {
		$(playlistElem).find('.shuffle-on').addClass('shuffle-off');
		$(playlistElem).find('.shuffle-on').removeClass('shuffle-on');
	}
}

/** CLASS PLAYLIST
 ****************************************************************************/

function Playlist(title, videos, remoteId, owner, isPrivate, shuffle) {
    this.title = title;
    this.videos = videos;
    this.remoteId = remoteId || null;
    this.isPrivate = isPrivate || false;
    this.shuffle = shuffle;
    this.owner = owner;
    this.synced = true; // not part of JSON structure
    this.syncing = false; // not part of JSON structure

    this.getUrl = function() {
        return '/users/' + this.owner.id + '/playlists/' + this.remoteId;
    };

    this.copy = function() {
        return new Playlist(this.title, this.videos);
    };

    this.rename = function(newTitle) {
        var title = $.trim(newTitle);
        if (title.length > 0 && title.length < 50) {
            this.title = newTitle;
        }
        this.synced = false;
    };

    this.unsync = function(callback) {
        $.ajax({
            type: 'DELETE',
            url: '/api/playlists/' + this.remoteId,
            success: function() {
                if (callback) {
                    callback();
                }
            }
        });

        this.remoteId = null;
        this.owner = null;
    };

    this.createNewPlaylistOnRemote = function(callback) {
        var self = this,
            params = {
                'json': JSON.stringify(this.toJSON())
            };

        this.syncing = true;

        $.post('/api/playlists', params, function(data, textStatus) {
            self.syncing = false;
            if (textStatus === 'success') {
                self.remoteId = data.remoteId;
                self.owner = data.owner;
                self.synced = true;
            } else {
                alert('Failed to create new playlist ' + self.title);
            }
            if (callback) {
                callback();
            }
        });
    };

    this.updatePlaylistOnRemote = function(callback) {
        var self = this,
            params = {
                'json': JSON.stringify(this.toJSON())
            };

        this.syncing = true;

        $.post('/api/playlists/' + this.remoteId, params, function(data, textStatus) {
            self.syncing = false;
            if (textStatus === 'success') {
                self.synced = true;
            } else {
                alert('Failed to update playlist ' + self.title);
            }
            if (callback) {
                callback();
            }
        });
    };

    this.sync = function(callback) {
        if (this.remoteId && this.synced) {
            callback();
        } else if (this.remoteId) {
            this.updatePlaylistOnRemote(callback);
        } else {
            this.createNewPlaylistOnRemote(callback);
        }
    };

    this.addVideo = function(title, videoId) {
        if (this.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        if (typeof title !== 'string') {
            throw "title param must be string";
        }
        if (typeof videoId !== 'string') {
            throw "videoId param must be string";
        }

        this.videos.push({
            videoId: videoId,
            title: title,
        });

        this.synced = false;
    };

    this.moveVideo = function(sourceIndex, destIndex) {
        if (this.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        var tmp;

        if (destIndex > sourceIndex) {
            destIndex -= 1;
        }

        tmp = this.videos.splice(sourceIndex, 1)[0];
        this.videos.splice(destIndex, 0, tmp);

        this.synced = false;
    };

    this.deleteVideo = function(index) {
        if (this.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        this.videos.splice(index, 1);
        this.synced = false;
    };

    this.toJSON = function() {
        return {
            title: this.title,
            videos: this.videos,
            remoteId: this.remoteId,
            owner: this.owner,
            isPrivate: this.isPrivate,
			shuffle: this.shuffle
        };
    };

    this.createListElem = function() {
        var li = $('
')
            .addClass("playlistElem")
            .addClass('droppable')
            .data('model', this)
            .bind('contextmenu', showPlaylistContextMenu)
            .mousedown(playlistMouseDown)
            .click(playlistClicked);

        $('').text(this.title).appendTo(li);

        if (this.remoteId) {
            li.addClass('remote');
        } else {
            li.addClass('local')
        }

        if (this.isPrivate) {
            li.addClass('private');
        }

        var shuffleButton = $('<button/>').click(shuffleButtonClicked);

        if (this.shuffle) {
            shuffleButton.addClass('shuffle-on');
        } else {
            shuffleButton.addClass('shuffle-off');
        }

        shuffleButton.appendTo(li);

        return li;
    };
};
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Sources.SourceFormatData = class {
  /**
   * @param {!Workspace.UISourceCode} originalSourceCode
   * @param {!Workspace.UISourceCode} formattedSourceCode
   * @param {!Formatter.FormatterSourceMapping} mapping
   */
  constructor(originalSourceCode, formattedSourceCode, mapping) {
    this.originalSourceCode = originalSourceCode;
    this.formattedSourceCode = formattedSourceCode;
    this.mapping = mapping;
  }

  originalPath() {
    return this.originalSourceCode.project().id() + ':' + this.originalSourceCode.url();
  }

  /**
   * @param {!Object} object
   * @return {?Sources.SourceFormatData}
   */
  static _for(object) {
    return object[Sources.SourceFormatData._formatDataSymbol];
  }
};

Sources.SourceFormatData._formatDataSymbol = Symbol('formatData');

Sources.SourceFormatter = class {
  constructor() {
    this._projectId = 'formatter:';
    this._project = new Bindings.ContentProviderBasedProject(
        Workspace.workspace, this._projectId, Workspace.projectTypes.Formatter, 'formatter',
        true /* isServiceProject */);

    /** @type {!Map<!Workspace.UISourceCode, !{promise: !Promise<!Sources.SourceFormatData>, formatData: ?Sources.SourceFormatData}>} */
    this._formattedSourceCodes = new Map();
    this._scriptMapping = new Sources.SourceFormatter.ScriptMapping();
    this._styleMapping = new Sources.SourceFormatter.StyleMapping();
    Workspace.workspace.addEventListener(
        Workspace.Workspace.Events.UISourceCodeRemoved, this._onUISourceCodeRemoved, this);
  }

  /**
   * @param {!Common.Event} event
   */
  _onUISourceCodeRemoved(event) {
    const uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
    const cacheEntry = this._formattedSourceCodes.get(uiSourceCode);
    if (cacheEntry && cacheEntry.formatData) {
      this._discardFormatData(cacheEntry.formatData);
    }
    this._formattedSourceCodes.remove(uiSourceCode);
  }

  /**
   * @param {!Workspace.UISourceCode} formattedUISourceCode
   * @return {?Workspace.UISourceCode}
   */
  discardFormattedUISourceCode(formattedUISourceCode) {
    const formatData = Sources.SourceFormatData._for(formattedUISourceCode);
    if (!formatData) {
      return null;
    }
    this._discardFormatData(formatData);
    this._formattedSourceCodes.remove(formatData.originalSourceCode);
    return formatData.originalSourceCode;
  }

  /**
   * @param {!Sources.SourceFormatData} formatData
   */
  _discardFormatData(formatData) {
    delete formatData.formattedSourceCode[Sources.SourceFormatData._formatDataSymbol];
    this._scriptMapping._setSourceMappingEnabled(formatData, false);
    this._styleMapping._setSourceMappingEnabled(formatData, false);
    this._project.removeFile(formatData.formattedSourceCode.url());
  }

  /**
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @return {boolean}
   */
  hasFormatted(uiSourceCode) {
    return this._formattedSourceCodes.has(uiSourceCode);
  }

  /**
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @return {!Promise<!Sources.SourceFormatData>}
   */
  async format(uiSourceCode) {
    const cacheEntry = this._formattedSourceCodes.get(uiSourceCode);
    if (cacheEntry) {
      return cacheEntry.promise;
    }

    let fulfillFormatPromise;
    const resultPromise = new Promise(fulfill => {
      fulfillFormatPromise = fulfill;
    });
    this._formattedSourceCodes.set(uiSourceCode, {promise: resultPromise, formatData: null});
    const {content} = await uiSourceCode.requestContent();
    // ------------ ASYNC ------------
    Formatter.Formatter.format(
        uiSourceCode.contentType(), uiSourceCode.mimeType(), content || '', formatDone.bind(this));
    return resultPromise;

    /**
     * @this Sources.SourceFormatter
     * @param {string} formattedContent
     * @param {!Formatter.FormatterSourceMapping} formatterMapping
     */
    function formatDone(formattedContent, formatterMapping) {
      const cacheEntry = this._formattedSourceCodes.get(uiSourceCode);
      if (!cacheEntry || cacheEntry.promise !== resultPromise) {
        return;
      }
      let formattedURL;
      let count = 0;
      let suffix = '';
      do {
        formattedURL = `${uiSourceCode.url()}:formatted${suffix}`;
        suffix = `:${count++}`;
      } while (this._project.uiSourceCodeForURL(formattedURL));
      const contentProvider =
          Common.StaticContentProvider.fromString(formattedURL, uiSourceCode.contentType(), formattedContent);
      const formattedUISourceCode =
          this._project.addContentProvider(formattedURL, contentProvider, uiSourceCode.mimeType());
      const formatData = new Sources.SourceFormatData(uiSourceCode, formattedUISourceCode, formatterMapping);
      formattedUISourceCode[Sources.SourceFormatData._formatDataSymbol] = formatData;
      this._scriptMapping._setSourceMappingEnabled(formatData, true);
      this._styleMapping._setSourceMappingEnabled(formatData, true);
      cacheEntry.formatData = formatData;

      for (const decoration of uiSourceCode.allDecorations()) {
        const range = decoration.range();
        const startLocation = formatterMapping.originalToFormatted(range.startLine, range.startColumn);
        const endLocation = formatterMapping.originalToFormatted(range.endLine, range.endColumn);

        formattedUISourceCode.addDecoration(
            new TextUtils.TextRange(startLocation[0], startLocation[1], endLocation[0], endLocation[1]),
            /** @type {string} */ (decoration.type()), decoration.data());
      }

      fulfillFormatPromise(formatData);
    }
  }
};

/**
 * @implements {Bindings.DebuggerSourceMapping}
 */
Sources.SourceFormatter.ScriptMapping = class {
  constructor() {
    Bindings.debuggerWorkspaceBinding.addSourceMapping(this);
  }

  /**
   * @override
   * @param {!SDK.DebuggerModel.Location} rawLocation
   * @return {?Workspace.UILocation}
   */
  rawLocationToUILocation(rawLocation) {
    const script = rawLocation.script();
    const formatData = script && Sources.SourceFormatData._for(script);
    if (!formatData) {
      return null;
    }
    const lineNumber = rawLocation.lineNumber;
    const columnNumber = rawLocation.columnNumber || 0;
    const formattedLocation = formatData.mapping.originalToFormatted(lineNumber, columnNumber);
    return formatData.formattedSourceCode.uiLocation(formattedLocation[0], formattedLocation[1]);
  }

  /**
   * @override
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @param {number} lineNumber
   * @param {number} columnNumber
   * @return {!Array<!SDK.DebuggerModel.Location>}
   */
  uiLocationToRawLocations(uiSourceCode, lineNumber, columnNumber) {
    const formatData = Sources.SourceFormatData._for(uiSourceCode);
    if (!formatData) {
      return [];
    }
    const [originalLine, originalColumn] = formatData.mapping.formattedToOriginal(lineNumber, columnNumber);
    const scripts = this._scriptsForUISourceCode(formatData.originalSourceCode)
                        .filter(script => script.containsLocation(originalLine, originalColumn));
    return scripts.map(script => script.debuggerModel.createRawLocation(script, originalLine, originalColumn));
  }

  /**
   * @param {!Sources.SourceFormatData} formatData
   * @param {boolean} enabled
   */
  _setSourceMappingEnabled(formatData, enabled) {
    const scripts = this._scriptsForUISourceCode(formatData.originalSourceCode);
    if (!scripts.length) {
      return;
    }
    if (enabled) {
      for (const script of scripts) {
        script[Sources.SourceFormatData._formatDataSymbol] = formatData;
      }
    } else {
      for (const script of scripts) {
        delete script[Sources.SourceFormatData._formatDataSymbol];
      }
    }
    for (const script of scripts) {
      Bindings.debuggerWorkspaceBinding.updateLocations(script);
    }
  }

  /**
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @return {!Array<!SDK.Script>}
   */
  _scriptsForUISourceCode(uiSourceCode) {
    if (uiSourceCode.contentType() === Common.resourceTypes.Document) {
      const target = Bindings.NetworkProject.targetForUISourceCode(uiSourceCode);
      const debuggerModel = target && target.model(SDK.DebuggerModel);
      if (debuggerModel) {
        const scripts = debuggerModel.scriptsForSourceURL(uiSourceCode.url())
                            .filter(script => script.isInlineScript() && !script.hasSourceURL);
        return scripts;
      }
    }
    if (uiSourceCode.contentType().isScript()) {
      const rawLocations = Bindings.debuggerWorkspaceBinding.uiLocationToRawLocations(uiSourceCode, 0, 0);
      return rawLocations.map(location => location.script()).filter(script => !!script);
    }
    return [];
  }
};

/**
 * @implements {Bindings.CSSWorkspaceBinding.SourceMapping}
 */
Sources.SourceFormatter.StyleMapping = class {
  constructor() {
    Bindings.cssWorkspaceBinding.addSourceMapping(this);
    this._headersSymbol = Symbol('Sources.SourceFormatter.StyleMapping._headersSymbol');
  }

  /**
   * @override
   * @param {!SDK.CSSLocation} rawLocation
   * @return {?Workspace.UILocation}
   */
  rawLocationToUILocation(rawLocation) {
    const styleHeader = rawLocation.header();
    const formatData = styleHeader && Sources.SourceFormatData._for(styleHeader);
    if (!formatData) {
      return null;
    }
    const formattedLocation =
        formatData.mapping.originalToFormatted(rawLocation.lineNumber, rawLocation.columnNumber || 0);
    return formatData.formattedSourceCode.uiLocation(formattedLocation[0], formattedLocation[1]);
  }

  /**
   * @override
   * @param {!Workspace.UILocation} uiLocation
   * @return {!Array<!SDK.CSSLocation>}
   */
  uiLocationToRawLocations(uiLocation) {
    const formatData = Sources.SourceFormatData._for(uiLocation.uiSourceCode);
    if (!formatData) {
      return [];
    }
    const [originalLine, originalColumn] =
        formatData.mapping.formattedToOriginal(uiLocation.lineNumber, uiLocation.columnNumber);
    const headers = formatData.originalSourceCode[this._headersSymbol].filter(
        header => header.containsLocation(originalLine, originalColumn));
    return headers.map(header => new SDK.CSSLocation(header, originalLine, originalColumn));
  }

  /**
   * @param {!Sources.SourceFormatData} formatData
   * @param {boolean} enable
   */
  _setSourceMappingEnabled(formatData, enable) {
    const original = formatData.originalSourceCode;
    const headers = this._headersForUISourceCode(original);
    if (enable) {
      original[this._headersSymbol] = headers;
      headers.forEach(header => header[Sources.SourceFormatData._formatDataSymbol] = formatData);
    } else {
      original[this._headersSymbol] = null;
      headers.forEach(header => delete header[Sources.SourceFormatData._formatDataSymbol]);
    }
    headers.forEach(header => Bindings.cssWorkspaceBinding.updateLocations(header));
  }

  /**
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @return {!Array<!SDK.CSSStyleSheetHeader>}
   */
  _headersForUISourceCode(uiSourceCode) {
    if (uiSourceCode.contentType() === Common.resourceTypes.Document) {
      const target = Bindings.NetworkProject.targetForUISourceCode(uiSourceCode);
      const cssModel = target && target.model(SDK.CSSModel);
      if (cssModel) {
        return cssModel.headersForSourceURL(uiSourceCode.url())
            .filter(header => header.isInline && !header.hasSourceURL);
      }
    } else if (uiSourceCode.contentType().isStyleSheet()) {
      const rawLocations = Bindings.cssWorkspaceBinding.uiLocationToRawLocations(uiSourceCode.uiLocation(0, 0));
      return rawLocations.map(rawLocation => rawLocation.header()).filter(header => !!header);
    }
    return [];
  }
};

Sources.sourceFormatter = new Sources.SourceFormatter();
<commit_msg>[sources] Fix raw<->UI location mapping for formatted inline scripts.<commit_after>// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Sources.SourceFormatData = class {
  /**
   * @param {!Workspace.UISourceCode} originalSourceCode
   * @param {!Workspace.UISourceCode} formattedSourceCode
   * @param {!Formatter.FormatterSourceMapping} mapping
   */
  constructor(originalSourceCode, formattedSourceCode, mapping) {
    this.originalSourceCode = originalSourceCode;
    this.formattedSourceCode = formattedSourceCode;
    this.mapping = mapping;
  }

  originalPath() {
    return this.originalSourceCode.project().id() + ':' + this.originalSourceCode.url();
  }

  /**
   * @param {!Object} object
   * @return {?Sources.SourceFormatData}
   */
  static _for(object) {
    return object[Sources.SourceFormatData._formatDataSymbol];
  }
};

Sources.SourceFormatData._formatDataSymbol = Symbol('formatData');

Sources.SourceFormatter = class {
  constructor() {
    this._projectId = 'formatter:';
    this._project = new Bindings.ContentProviderBasedProject(
        Workspace.workspace, this._projectId, Workspace.projectTypes.Formatter, 'formatter',
        true /* isServiceProject */);

    /** @type {!Map<!Workspace.UISourceCode, !{promise: !Promise<!Sources.SourceFormatData>, formatData: ?Sources.SourceFormatData}>} */
    this._formattedSourceCodes = new Map();
    this._scriptMapping = new Sources.SourceFormatter.ScriptMapping();
    this._styleMapping = new Sources.SourceFormatter.StyleMapping();
    Workspace.workspace.addEventListener(
        Workspace.Workspace.Events.UISourceCodeRemoved, this._onUISourceCodeRemoved, this);
  }

  /**
   * @param {!Common.Event} event
   */
  _onUISourceCodeRemoved(event) {
    const uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
    const cacheEntry = this._formattedSourceCodes.get(uiSourceCode);
    if (cacheEntry && cacheEntry.formatData) {
      this._discardFormatData(cacheEntry.formatData);
    }
    this._formattedSourceCodes.remove(uiSourceCode);
  }

  /**
   * @param {!Workspace.UISourceCode} formattedUISourceCode
   * @return {?Workspace.UISourceCode}
   */
  discardFormattedUISourceCode(formattedUISourceCode) {
    const formatData = Sources.SourceFormatData._for(formattedUISourceCode);
    if (!formatData) {
      return null;
    }
    this._discardFormatData(formatData);
    this._formattedSourceCodes.remove(formatData.originalSourceCode);
    return formatData.originalSourceCode;
  }

  /**
   * @param {!Sources.SourceFormatData} formatData
   */
  _discardFormatData(formatData) {
    delete formatData.formattedSourceCode[Sources.SourceFormatData._formatDataSymbol];
    this._scriptMapping._setSourceMappingEnabled(formatData, false);
    this._styleMapping._setSourceMappingEnabled(formatData, false);
    this._project.removeFile(formatData.formattedSourceCode.url());
  }

  /**
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @return {boolean}
   */
  hasFormatted(uiSourceCode) {
    return this._formattedSourceCodes.has(uiSourceCode);
  }

  /**
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @return {!Promise<!Sources.SourceFormatData>}
   */
  async format(uiSourceCode) {
    const cacheEntry = this._formattedSourceCodes.get(uiSourceCode);
    if (cacheEntry) {
      return cacheEntry.promise;
    }

    let fulfillFormatPromise;
    const resultPromise = new Promise(fulfill => {
      fulfillFormatPromise = fulfill;
    });
    this._formattedSourceCodes.set(uiSourceCode, {promise: resultPromise, formatData: null});
    const {content} = await uiSourceCode.requestContent();
    // ------------ ASYNC ------------
    Formatter.Formatter.format(
        uiSourceCode.contentType(), uiSourceCode.mimeType(), content || '', formatDone.bind(this));
    return resultPromise;

    /**
     * @this Sources.SourceFormatter
     * @param {string} formattedContent
     * @param {!Formatter.FormatterSourceMapping} formatterMapping
     */
    function formatDone(formattedContent, formatterMapping) {
      const cacheEntry = this._formattedSourceCodes.get(uiSourceCode);
      if (!cacheEntry || cacheEntry.promise !== resultPromise) {
        return;
      }
      let formattedURL;
      let count = 0;
      let suffix = '';
      do {
        formattedURL = `${uiSourceCode.url()}:formatted${suffix}`;
        suffix = `:${count++}`;
      } while (this._project.uiSourceCodeForURL(formattedURL));
      const contentProvider =
          Common.StaticContentProvider.fromString(formattedURL, uiSourceCode.contentType(), formattedContent);
      const formattedUISourceCode =
          this._project.addContentProvider(formattedURL, contentProvider, uiSourceCode.mimeType());
      const formatData = new Sources.SourceFormatData(uiSourceCode, formattedUISourceCode, formatterMapping);
      formattedUISourceCode[Sources.SourceFormatData._formatDataSymbol] = formatData;
      this._scriptMapping._setSourceMappingEnabled(formatData, true);
      this._styleMapping._setSourceMappingEnabled(formatData, true);
      cacheEntry.formatData = formatData;

      for (const decoration of uiSourceCode.allDecorations()) {
        const range = decoration.range();
        const startLocation = formatterMapping.originalToFormatted(range.startLine, range.startColumn);
        const endLocation = formatterMapping.originalToFormatted(range.endLine, range.endColumn);

        formattedUISourceCode.addDecoration(
            new TextUtils.TextRange(startLocation[0], startLocation[1], endLocation[0], endLocation[1]),
            /** @type {string} */ (decoration.type()), decoration.data());
      }

      fulfillFormatPromise(formatData);
    }
  }
};

/**
 * @implements {Bindings.DebuggerSourceMapping}
 */
Sources.SourceFormatter.ScriptMapping = class {
  constructor() {
    Bindings.debuggerWorkspaceBinding.addSourceMapping(this);
  }

  /**
   * @override
   * @param {!SDK.DebuggerModel.Location} rawLocation
   * @return {?Workspace.UILocation}
   */
  rawLocationToUILocation(rawLocation) {
    const script = rawLocation.script();
    const formatData = script && Sources.SourceFormatData._for(script);
    if (!formatData) {
      return null;
    }
    const lineNumber = rawLocation.lineNumber - script.lineOffset;
    const columnNumber = (rawLocation.columnNumber || 0) - (lineNumber === 0 ? script.columnOffset : 0);
    const formattedLocation = formatData.mapping.originalToFormatted(lineNumber, columnNumber);
    return formatData.formattedSourceCode.uiLocation(formattedLocation[0], formattedLocation[1]);
  }

  /**
   * @override
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @param {number} lineNumber
   * @param {number} columnNumber
   * @return {!Array<!SDK.DebuggerModel.Location>}
   */
  uiLocationToRawLocations(uiSourceCode, lineNumber, columnNumber) {
    const formatData = Sources.SourceFormatData._for(uiSourceCode);
    if (!formatData) {
      return [];
    }
    const [originalLine, originalColumn] = formatData.mapping.formattedToOriginal(lineNumber, columnNumber);
    const scripts = this._scriptsForUISourceCode(formatData.originalSourceCode).filter(script => {
      const [scriptLine, scriptColumn] = originalToScript(script);
      return script.containsLocation(scriptLine, scriptColumn);
    });
    return scripts.map(script => {
      const [scriptLine, scriptColumn] = originalToScript(script);
      return script.debuggerModel.createRawLocation(script, scriptLine, scriptColumn);
    });

    function originalToScript(script) {
      const scriptLine = originalLine + script.lineOffset;
      const scriptColumn = originalColumn + (originalLine === 0 ? script.columnOffset : 0);
      return [scriptLine, scriptColumn];
    }
  }

  /**
   * @param {!Sources.SourceFormatData} formatData
   * @param {boolean} enabled
   */
  _setSourceMappingEnabled(formatData, enabled) {
    const scripts = this._scriptsForUISourceCode(formatData.originalSourceCode);
    if (!scripts.length) {
      return;
    }
    if (enabled) {
      for (const script of scripts) {
        script[Sources.SourceFormatData._formatDataSymbol] = formatData;
      }
    } else {
      for (const script of scripts) {
        delete script[Sources.SourceFormatData._formatDataSymbol];
      }
    }
    for (const script of scripts) {
      Bindings.debuggerWorkspaceBinding.updateLocations(script);
    }
  }

  /**
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @return {!Array<!SDK.Script>}
   */
  _scriptsForUISourceCode(uiSourceCode) {
    if (uiSourceCode.contentType() === Common.resourceTypes.Document) {
      const target = Bindings.NetworkProject.targetForUISourceCode(uiSourceCode);
      const debuggerModel = target && target.model(SDK.DebuggerModel);
      if (debuggerModel) {
        const scripts = debuggerModel.scriptsForSourceURL(uiSourceCode.url())
                            .filter(script => script.isInlineScript() && !script.hasSourceURL);
        return scripts;
      }
    }
    if (uiSourceCode.contentType().isScript()) {
      const rawLocations = Bindings.debuggerWorkspaceBinding.uiLocationToRawLocations(uiSourceCode, 0, 0);
      return rawLocations.map(location => location.script()).filter(script => !!script);
    }
    return [];
  }
};

/**
 * @implements {Bindings.CSSWorkspaceBinding.SourceMapping}
 */
Sources.SourceFormatter.StyleMapping = class {
  constructor() {
    Bindings.cssWorkspaceBinding.addSourceMapping(this);
    this._headersSymbol = Symbol('Sources.SourceFormatter.StyleMapping._headersSymbol');
  }

  /**
   * @override
   * @param {!SDK.CSSLocation} rawLocation
   * @return {?Workspace.UILocation}
   */
  rawLocationToUILocation(rawLocation) {
    const styleHeader = rawLocation.header();
    const formatData = styleHeader && Sources.SourceFormatData._for(styleHeader);
    if (!formatData) {
      return null;
    }
    const formattedLocation =
        formatData.mapping.originalToFormatted(rawLocation.lineNumber, rawLocation.columnNumber || 0);
    return formatData.formattedSourceCode.uiLocation(formattedLocation[0], formattedLocation[1]);
  }

  /**
   * @override
   * @param {!Workspace.UILocation} uiLocation
   * @return {!Array<!SDK.CSSLocation>}
   */
  uiLocationToRawLocations(uiLocation) {
    const formatData = Sources.SourceFormatData._for(uiLocation.uiSourceCode);
    if (!formatData) {
      return [];
    }
    const [originalLine, originalColumn] =
        formatData.mapping.formattedToOriginal(uiLocation.lineNumber, uiLocation.columnNumber);
    const headers = formatData.originalSourceCode[this._headersSymbol].filter(
        header => header.containsLocation(originalLine, originalColumn));
    return headers.map(header => new SDK.CSSLocation(header, originalLine, originalColumn));
  }

  /**
   * @param {!Sources.SourceFormatData} formatData
   * @param {boolean} enable
   */
  _setSourceMappingEnabled(formatData, enable) {
    const original = formatData.originalSourceCode;
    const headers = this._headersForUISourceCode(original);
    if (enable) {
      original[this._headersSymbol] = headers;
      headers.forEach(header => header[Sources.SourceFormatData._formatDataSymbol] = formatData);
    } else {
      original[this._headersSymbol] = null;
      headers.forEach(header => delete header[Sources.SourceFormatData._formatDataSymbol]);
    }
    headers.forEach(header => Bindings.cssWorkspaceBinding.updateLocations(header));
  }

  /**
   * @param {!Workspace.UISourceCode} uiSourceCode
   * @return {!Array<!SDK.CSSStyleSheetHeader>}
   */
  _headersForUISourceCode(uiSourceCode) {
    if (uiSourceCode.contentType() === Common.resourceTypes.Document) {
      const target = Bindings.NetworkProject.targetForUISourceCode(uiSourceCode);
      const cssModel = target && target.model(SDK.CSSModel);
      if (cssModel) {
        return cssModel.headersForSourceURL(uiSourceCode.url())
            .filter(header => header.isInline && !header.hasSourceURL);
      }
    } else if (uiSourceCode.contentType().isStyleSheet()) {
      const rawLocations = Bindings.cssWorkspaceBinding.uiLocationToRawLocations(uiSourceCode.uiLocation(0, 0));
      return rawLocations.map(rawLocation => rawLocation.header()).filter(header => !!header);
    }
    return [];
  }
};

Sources.sourceFormatter = new Sources.SourceFormatter();
<|endoftext|>


<commit_before>define(['./module'], function (controllers) {
    'use strict';
    controllers.controller('mapLoadCtrl', ['$scope','$http', '$rootScope','UserService', '$routeParams','$route','$location','todayTime', function ($scope, $http, $rootScope, UserService,  $routeParams, $route,$location, todayTime) {
        $scope.isAdministrator = UserService.isAdministrator;
                $rootScope.$broadcast('Update',"");

        var tiles   = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            minZoom: 2,
            attribution: '© OpenStreetMap contributors'
        });
        var geoJson = L.geoJson (ukraineBorders, {
            style: {
                opacity:     0,
                fillOpacity: 0
            }
        });
        var latlng  = L.latLng(50.00, 32.00);
        var map     = L.map('map-content', {
            center: latlng,
            zoom: 7,
            layers:[tiles, geoJson] //disabling geoJson because of blocking ukraine-zone on the map
        });
        $rootScope.geoJson = geoJson; //forwarding geoJson object to $rooTscope
        var markers = L.markerClusterGroup();
        $scope.data = {};
        var markerIcon;

        $rootScope.getProblemsAndPlaceMarkers = function(){
            $http({ method: 'GET', url: '/api/problems' }).success(function (data) {
                $scope.data = data;
                placeMarkers($scope.data);
            });
        };
        $scope.getProblemsAndPlaceMarkers();

        navigator.geolocation.getCurrentPosition(getUserPosition);

        function getUserPosition(position) {
            var mapCenter = [
                position.coords.latitude,
                position.coords.longitude
            ];
            map.setView(mapCenter, 10);
        }

        function onMarkerClick(marker){
            if($scope.isAdministrator()) {
                window.location.href="#/map";
                window.location.href = "#/problem/editProblem/" + this._id;
            } else{
                window.location.href="#/map";
                window.location.href="#/problem/showProblem/"+ this._id;
            }

            $rootScope.$broadcast('Update',"_problem");
            map.panTo(marker.latlng);
        };

        function placeMarkers(data) {
            markers.clearLayers();
            var newData = userSelectionFilterMarkers(data);
            angular.forEach(newData, function (location) {
                markerIcon = L.icon({
                    iconUrl : 'images/markers/'+location['ProblemTypes_Id']+ '.png',
                    iconAnchor: [25,79]
                });

                var marker = L.marker([location.Latitude, location.Longtitude], {icon: markerIcon});
                marker.on('click', onMarkerClick);
                marker._id = location['Id'];
                markers.addLayer(marker);
            });
            map.addLayer(markers);
        };

        function userSelectionFilterMarkers(data) {
            var tempData = [];
            for (var i = 0; i < data.length; i++) {
                var location = data[i];
                var problemTypeSelected = isSelected($scope.problemTypes, location.ProblemTypes_Id);
                var problemStatusSelected = isSelected($scope.problemStatuses, location.Status);
                if (problemTypeSelected && problemStatusSelected){
                    tempData.push(location);
                }
            };
            var newData = dateRange(tempData);
            return newData;
        };

        function isSelected(filtersArray, ProblemTypes_Id) {
            for (var i = 0; i < filtersArray.length; i++) {
                if (filtersArray[i].id == ProblemTypes_Id) {
                    return filtersArray[i].selected;
                }
            };
        };

        function dateRange (data) {
            var dateFrom = Date.parse(todayTime.formDataDt);
            var dateTill = Date.parse(todayTime.formDataDtSecond);
            var tempData = [];
            for (var i = 0; i < data.length; i++) {
                var location = data[i];
                var locationDate = Date.parse(location.Date);
                if (dateFrom < locationDate && locationDate < dateTill) {
                    tempData.push(location);
                };
            };
            var newData = tempData;
            return newData;
        }

        $scope.problemTypes = [
            {name: 'Проблеми лісів',            id: 1, selected: true},
            {name: 'Сміттєзвалища',             id: 2, selected: true},
            {name: 'Незаконна забудова',        id: 3, selected: true},
            {name: 'Проблеми водойм',           id: 4, selected: true},
            {name: 'Загрози біорізноманіттю',   id: 5, selected: true},
            {name: 'Браконьєрство',             id: 6, selected: true},
            {name: 'Інші проблеми',             id: 7, selected: true}
        ];

        $scope.problemStatuses = [
            {name: 'Нова',     id: 0, selected: true},
            {name: 'Вирішена', id: 1, selected: true}
        ];

        $scope.placeUserProblemsChecker;
        $scope.toggleSelection = function () {
            if($scope.placeUserProblemsChecker)
                placeMarkers($scope.dataUserProblems);
            else
                placeMarkers($scope.data);
        };

    }]);
});
<commit_msg>Update map-load.js<commit_after>define(['./module'], function (controllers) {
    'use strict';
    controllers.controller('mapLoadCtrl', ['$scope','$http', '$rootScope','UserService', '$routeParams','$route','$location','todayTime', function ($scope, $http, $rootScope, UserService,  $routeParams, $route,$location, todayTime) {
        $scope.isAdministrator = UserService.isAdministrator;
                $rootScope.$broadcast('Update',"");

        var tiles   = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            minZoom: 2,
            detectRetina: true,
            attribution: '© OpenStreetMap contributors'
        });
        var geoJson = L.geoJson (ukraineBorders, {
            style: {
                opacity:     0,
                fillOpacity: 0
            }
        });
        var latlng  = L.latLng(50.00, 32.00);
        var map     = L.map('map-content', {
            center: latlng,
            zoom: 7,
            layers:[tiles, geoJson] //disabling geoJson because of blocking ukraine-zone on the map
        });
        $rootScope.geoJson = geoJson; //forwarding geoJson object to $rooTscope
        var markers = L.markerClusterGroup();
        $scope.data = {};
        var markerIcon;

        $rootScope.getProblemsAndPlaceMarkers = function(){
            $http({ method: 'GET', url: '/api/problems' }).success(function (data) {
                $scope.data = data;
                placeMarkers($scope.data);
            });
        };
        $scope.getProblemsAndPlaceMarkers();

        navigator.geolocation.getCurrentPosition(getUserPosition);

        function getUserPosition(position) {
            var mapCenter = [
                position.coords.latitude,
                position.coords.longitude
            ];
            map.setView(mapCenter, 10);
        }

        function onMarkerClick(marker){
            if($scope.isAdministrator()) {
                window.location.href="#/map";
                window.location.href = "#/problem/editProblem/" + this._id;
            } else{
                window.location.href="#/map";
                window.location.href="#/problem/showProblem/"+ this._id;
            }

            $rootScope.$broadcast('Update',"_problem");
            map.panTo(marker.latlng);
        };

        function placeMarkers(data) {
            markers.clearLayers();
            var newData = userSelectionFilterMarkers(data);
            angular.forEach(newData, function (location) {
                markerIcon = L.icon({
                    iconUrl : 'images/markers/'+location['ProblemTypes_Id']+ '.png',
                    iconAnchor: [25,79]
                });

                var marker = L.marker([location.Latitude, location.Longtitude], {icon: markerIcon});
                marker.on('click', onMarkerClick);
                marker._id = location['Id'];
                markers.addLayer(marker);
            });
            map.addLayer(markers);
        };

        function userSelectionFilterMarkers(data) {
            var tempData = [];
            for (var i = 0; i < data.length; i++) {
                var location = data[i];
                var problemTypeSelected = isSelected($scope.problemTypes, location.ProblemTypes_Id);
                var problemStatusSelected = isSelected($scope.problemStatuses, location.Status);
                if (problemTypeSelected && problemStatusSelected){
                    tempData.push(location);
                }
            };
            var newData = dateRange(tempData);
            return newData;
        };

        function isSelected(filtersArray, ProblemTypes_Id) {
            for (var i = 0; i < filtersArray.length; i++) {
                if (filtersArray[i].id == ProblemTypes_Id) {
                    return filtersArray[i].selected;
                }
            };
        };

        function dateRange (data) {
            var dateFrom = Date.parse(todayTime.formDataDt);
            var dateTill = Date.parse(todayTime.formDataDtSecond);
            var tempData = [];
            for (var i = 0; i < data.length; i++) {
                var location = data[i];
                var locationDate = Date.parse(location.Date);
                if (dateFrom < locationDate && locationDate < dateTill) {
                    tempData.push(location);
                };
            };
            var newData = tempData;
            return newData;
        }

        $scope.problemTypes = [
            {name: 'Проблеми лісів',            id: 1, selected: true},
            {name: 'Сміттєзвалища',             id: 2, selected: true},
            {name: 'Незаконна забудова',        id: 3, selected: true},
            {name: 'Проблеми водойм',           id: 4, selected: true},
            {name: 'Загрози біорізноманіттю',   id: 5, selected: true},
            {name: 'Браконьєрство',             id: 6, selected: true},
            {name: 'Інші проблеми',             id: 7, selected: true}
        ];

        $scope.problemStatuses = [
            {name: 'Нова',     id: 0, selected: true},
            {name: 'Вирішена', id: 1, selected: true}
        ];

        $scope.placeUserProblemsChecker;
        $scope.toggleSelection = function () {
            if($scope.placeUserProblemsChecker)
                placeMarkers($scope.dataUserProblems);
            else
                placeMarkers($scope.data);
        };

    }]);
});
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert'),
  Frequency = require('../lib/frequency'),
  moment = require('moment');

Frequency.fn.odd = require('number-kind').odd;
Frequency.fn.even = require('number-kind').even;
Frequency.fn.leap = require('leap-year');

describe('Frequency', function () {
  describe('#()', function () {
    var f;
    it('should take date string notation', function () {
      f = new Frequency('FT9H');
      assert.equal(f.getValue('h'), 9);

      f = new Frequency('F6D/W');
      assert.equal(f.getValue('D', 'W'), 6);
    });

    it('should take date and time string notation', function () {
      f = new Frequency('F3D/WT10H0M0S');
      assert.equal(f.getValue('D', 'week'), 3);
      assert.equal(f.getValue('h'), 10);
      assert.equal(f.getValue('minute'), 0);
      assert.equal(f.getValue('s'), 0);
    });

    it('should detect invalid string notation', function () {
      assert.throws(function () {
        new Frequency('F9H');
      });

      assert.throws(function () {
        new Frequency('FT6D');
      });
    });

    it('should take set of rules', function () {
      f = new Frequency({h: {fix: 9}});
      assert.equal(f.getValue('h'), 9);
    });
  });

  describe('#getValue()', function () {
    it('should return values set with on', function () {
      var f = new Frequency();

      f.on('hour', 10).on('minute', 30);
      assert.equal(f.getValue('hour'), 10);
      assert.equal(f.getValue('m', 'h'), 30);

      f.on('day', 3, 'week');
      assert.equal(f.getValue('day', 'week'), 3);

      f.on('week', {fn: 'odd', scope: 'E'});
      assert.equal(f.getValue('week', 'epoch'), 'odd');
    });
  });

  describe('#next()', function () {
    it('should return a Date instance', function () {
      assert.equal(typeof (new Frequency()).next(new Date(2013, 8, 2)).getTime, 'function');
    });

    it('should handle date', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2);

      assert.deepEqual(f.next(start).toString(), new Date(2013, 8, 2).toString());

      f.on('hour', 10); // each day at 10:00:00
      assert.deepEqual(f.next(start).toString(), new Date(2013, 8, 2, 10).toString());

      f.on('hour', 0); // each day at 00:00:00
      assert.deepEqual(f.next(start).toString(), new Date(2013, 8, 2).toString());
    });

    it('should handle date and time', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2, 11, 10, 20);

      assert.equal(f.next(start).toString(), new Date(2013, 8, 2, 11, 10, 20).toString());

      f.on('hour', 10); // each day at 10:00:00
      assert.equal(f.next(start).toString(), new Date(2013, 8, 3, 10).toString());

      f.on('hour', 0); // each day at 00:00:00
      assert.equal(f.next(start).toString(), new Date(2013, 8, 3).toString());
    });

    it('should return date if it matches', function () {
      var f = new Frequency();

      f.on('hour', 10).on('minute', 0).on('second', 0); // each day at 10:00:00
      assert.equal(f.next(new Date(2013, 8, 2, 10)).toString(), (new Date(2013, 8, 2, 10)).toString());
    });

    it('should handle different rules', function () {
      var f = new Frequency(),
        start = new Date(2013, 6, 2);

      f.on('month', 8); // each August 1st at 00:00:00
      assert.equal(f.next(start).toString(), new Date(2013, 7, 1).toString());
    });

    it('should increase parent of fix', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2);

      f.on('month', 3); // each March 1st at 00:00:00
      assert.equal(f.next(start).toString(), new Date(2014, 2, 1).toString());

      f.on('month', 3).on('minute', 30); // each March 1st every 30 minutes
      assert.equal(f.next(start).toString(), new Date(2014, 2, 1, 0, 30).toString());
    });

    it('should handle DST', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2);

      f.on('month', 11); // each November 1st at 00:00:00 (across DST)
      assert.equal(f.next(start).toString(), new Date(2013, 10, 1).toString());
    });

    it('should handle different scope', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2, 11, 10, 20);

      f.on('hour', 10).on('day', 3, 'week'); // each Wednesday at 10:00:00
      assert.deepEqual(f.next(start).toString(), new Date(2013, 8, 4, 10).toString());
    });

    it('should work with string notation', function () {
      var f = new Frequency('F1D/WT15H45M');
      assert.deepEqual(f.next(new Date(2014, 2, 10)), new Date(2014, 2, 10, 15, 45));
      assert.deepEqual(f.next(new Date(2014, 2, 10, 15, 45, 1)), new Date(2014, 2, 10, 15, 45, 1));
      assert.deepEqual(f.next(new Date(2014, 2, 10, 15, 46)), new Date(2014, 2, 17, 15, 45));

      f = new Frequency('FT15H45M');
      assert.deepEqual(f.next(new Date(2014, 2, 10)), new Date(2014, 2, 10, 15, 45));
    });

    it('should work with string notation containing defaults', function () {
      var f = new Frequency('F1D/WT15H45M0S');
      assert.deepEqual(f.next(new Date(2014, 2, 4)), new Date(2014, 2, 10, 15, 45));
    });

    it('should apply functions to units', function () {
      var f = new Frequency('F(odd)W/E1D/WT15H45M0S'); // Mondays of odd weeks at 15:45:00
      assert.deepEqual(f.next(new Date(2015, 3, 29)), new Date(2015, 4, 4, 15, 45));
      assert.deepEqual(f.next(new Date(2014, 7, 11)), new Date(2014, 7, 11, 15, 45));

      f = new Frequency('F(even)W/ET9H30M0S'); // Every day of even weeks at 9:30:00
      assert.deepEqual(f.next(new Date(2015, 4, 4)), new Date(2015, 4, 11, 9, 30));

      Frequency.fn.weekend = function (weekday) {
          return weekday === 6 || weekday === 7;
        };
      f = new Frequency('F(weekend)D/WT12H0M0S'); // Weekends at 12:00:00
      assert.deepEqual(f.next(new Date(2014, 7, 20)), new Date(2014, 7, 23, 12));

      Frequency.fn.inSummer = function (month) {
          return month === 7 || month === 8;
        };
      f = new Frequency('F(inSummer)M1DT0H0M0S'); // First day of "summer" months at midnight
      var date = new Date(2014, 0, 15);
      date = f.next(date);
      assert.deepEqual(date, new Date(2014, 6, 1, 0, 0, 0));
      date = f.next(date.setDate(2));
      assert.deepEqual(date, new Date(2014, 7, 1, 0, 0, 0));
      date = f.next(date.setDate(2));
      assert.deepEqual(date, new Date(2015, 6, 1, 0, 0, 0));
    });
  });

  describe('#between()', function () {
    var arr, arrm;

    before(function () {
      // plain javascript
      var f = new Frequency(),
        start = new Date(2013, 8, 2),
        end = new Date(2013, 8, 9);

      f.on('hour', 10).on('minute', 0).on('second', 0); // each day at 10:00:00
      arr = f.between(start, end);

      // with moment
      var fm = new Frequency(),
        startm = moment(new Date(2013, 8, 2)),
        endm = moment(new Date(2013, 8, 9));

      fm.on('hour', 10).on('minute', 0).on('second', 0); // each day at 10:00:00
      arrm = fm.between(startm, endm);
    });

    it('should return an array of dates', function () {
      assert.equal(arr.length, 7);
      assert.equal(arrm.length, 7);
    });

    it('should have the first item match the frequency', function () {
      assert.deepEqual(arr[0], new Date(2013, 8, 2, 10));
      assert.deepEqual(arrm[0], new Date(2013, 8, 2, 10));
    });

    it('should have the last item match the frequency', function () {
      assert.deepEqual(arr[6], new Date(2013, 8, 8, 10));
      assert.deepEqual(arrm[6], new Date(2013, 8, 8, 10));
    });

    it('should return using string notation', function () {
      var f = new Frequency('F1D/WT15H45M0S');
      var dates = f.between(new Date(2014, 2, 10), new Date(2014, 2, 17));
      assert.equal(dates.length, 1);
    });

    it('should return nothing using string notation', function () {
      var f = new Frequency('F1D/WT15H45M0S');
      var dates = f.between(new Date(2014, 2, 4), new Date(2014, 2, 10));
      assert.equal(dates.length, 0);
    });
  });

  describe('#compare()', function () {
    it('should detect before', function () {
      var f = new Frequency('F1D/W');
      assert.ok(f.compare(new Frequency('F2D/W')) === -1);
    });

    it('should detect after', function () {
      var f = new Frequency('F2D/W');
      assert.ok(f.compare(new Frequency('F1D/W')) === 1);
    });

    it('should detect equal', function () {
      var f = new Frequency('F1D/W');
      assert.ok(f.compare(new Frequency('F1D/W')) === 0);
    });
  });

  describe('#toString()', function () {
    it('should output the same string passed to the constructor', function () {
      assert.equal((new Frequency('FT15H45M')).toString(), 'FT15H45M');
      assert.equal((new Frequency('F1D/WT15H45M')).toString(), 'F1D/WT15H45M');
      assert.equal((new Frequency('F1D/WT15H45M0S')).toString(), 'F1D/WT15H45M0S');

      assert.equal((new Frequency('F(leap)Y1D/WT15H45M0S')).toString(), 'F(leap)Y1D/WT15H45M0S');
      assert.equal((new Frequency('F(odd)W/E1D/WT15H45M0S')).toString(), 'F(odd)W/E1D/WT15H45M0S');
    });

    it('should output rules set with on() to string notation', function () {
      var f = new Frequency();

      f.on('month', 2).on('hour', 10);
      assert.equal(f.toString(), 'F2MT10H');
    });

    it('should output scope set with on() to string notation', function () {
      var f = new Frequency();

      f.on('day', 2, 'week').on('hour', 10);
      assert.equal(f.toString(), 'F2D/WT10H');
    });

    it('should respect default unit order', function () {
      var f = new Frequency({second: {fix: 0}});

      f.on('minute', 0).on('hour', 10);
      assert.equal(f.toString(), 'FT10H0M0S');
    });
  });
});
<commit_msg>add failing tests<commit_after>'use strict';

var assert = require('assert'),
  Frequency = require('../lib/frequency'),
  moment = require('moment');

Frequency.fn.odd = require('number-kind').odd;
Frequency.fn.even = require('number-kind').even;
Frequency.fn.leap = require('leap-year');

describe('Frequency', function () {
  describe('#()', function () {
    var f;
    it('should take date string notation', function () {
      f = new Frequency('FT9H');
      assert.equal(f.getValue('h'), 9);

      f = new Frequency('F6D/W');
      assert.equal(f.getValue('D', 'W'), 6);
    });

    it('should take date and time string notation', function () {
      f = new Frequency('F3D/WT10H0M0S');
      assert.equal(f.getValue('D', 'week'), 3);
      assert.equal(f.getValue('h'), 10);
      assert.equal(f.getValue('minute'), 0);
      assert.equal(f.getValue('s'), 0);
    });

    it('should detect invalid string notation', function () {
      assert.throws(function () {
        new Frequency('F9H');
      });

      assert.throws(function () {
        new Frequency('FT6D');
      });
    });

    it('should take set of rules', function () {
      f = new Frequency({h: {fix: 9}});
      assert.equal(f.getValue('h'), 9);
    });
  });

  describe('#getValue()', function () {
    it('should return values set with on', function () {
      var f = new Frequency();

      f.on('hour', 10).on('minute', 30);
      assert.equal(f.getValue('hour'), 10);
      assert.equal(f.getValue('m', 'h'), 30);

      f.on('day', 3, 'week');
      assert.equal(f.getValue('day', 'week'), 3);

      f.on('week', {fn: 'odd', scope: 'E'});
      assert.equal(f.getValue('week', 'epoch'), 'odd');
    });
  });

  describe('#next()', function () {
    it('should return a Date instance', function () {
      assert.equal(typeof (new Frequency()).next(new Date(2013, 8, 2)).getTime, 'function');
    });

    it('should handle date', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2);

      assert.deepEqual(f.next(start).toString(), new Date(2013, 8, 2).toString());

      f.on('hour', 10); // each day at 10:00:00
      assert.deepEqual(f.next(start).toString(), new Date(2013, 8, 2, 10).toString());

      f.on('hour', 0); // each day at 00:00:00
      assert.deepEqual(f.next(start).toString(), new Date(2013, 8, 2).toString());
    });

    it('should handle date and time', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2, 11, 10, 20);

      assert.equal(f.next(start).toString(), new Date(2013, 8, 2, 11, 10, 20).toString());

      f.on('hour', 10); // each day at 10:00:00
      assert.equal(f.next(start).toString(), new Date(2013, 8, 3, 10).toString());

      f.on('hour', 0); // each day at 00:00:00
      assert.equal(f.next(start).toString(), new Date(2013, 8, 3).toString());
    });

    it('should return date if it matches', function () {
      var f = new Frequency();

      f.on('hour', 10).on('minute', 0).on('second', 0); // each day at 10:00:00
      assert.equal(f.next(new Date(2013, 8, 2, 10)).toString(), (new Date(2013, 8, 2, 10)).toString());
    });

    it('should handle different rules', function () {
      var f = new Frequency(),
        start = new Date(2013, 6, 2);

      f.on('month', 8); // each August 1st at 00:00:00
      assert.equal(f.next(start).toString(), new Date(2013, 7, 1).toString());
    });

    it('should increase parent of fix', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2);

      f.on('month', 3); // each March 1st at 00:00:00
      assert.equal(f.next(start).toString(), new Date(2014, 2, 1).toString());

      f.on('month', 3).on('minute', 30); // each March 1st every 30 minutes
      assert.equal(f.next(start).toString(), new Date(2014, 2, 1, 0, 30).toString());
    });

    it('should handle DST', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2);

      f.on('month', 11); // each November 1st at 00:00:00 (across DST)
      assert.equal(f.next(start).toString(), new Date(2013, 10, 1).toString());
    });

    it('should handle different scope', function () {
      var f = new Frequency(),
        start = new Date(2013, 8, 2, 11, 10, 20);

      f.on('hour', 10).on('day', 3, 'week'); // each Wednesday at 10:00:00
      assert.deepEqual(f.next(start).toString(), new Date(2013, 8, 4, 10).toString());
    });

    it('should work with string notation', function () {
      var f = new Frequency('F1D/WT15H45M');
      assert.deepEqual(f.next(new Date(2014, 2, 10)), new Date(2014, 2, 10, 15, 45));
      assert.deepEqual(f.next(new Date(2014, 2, 10, 15, 45, 1)), new Date(2014, 2, 10, 15, 45, 1));
      assert.deepEqual(f.next(new Date(2014, 2, 10, 15, 46)), new Date(2014, 2, 17, 15, 45));

      f = new Frequency('FT15H45M');
      assert.deepEqual(f.next(new Date(2014, 2, 10)), new Date(2014, 2, 10, 15, 45));
    });

    it('should work with string notation containing defaults', function () {
      var f = new Frequency('F1D/WT15H45M0S');
      assert.deepEqual(f.next(new Date(2014, 2, 4)), new Date(2014, 2, 10, 15, 45));
    });

    it('should apply functions to units', function () {
      var f = new Frequency('F(odd)W/E1D/WT15H45M0S'); // Mondays of odd weeks at 15:45:00
      assert.deepEqual(
        f.next(new Date(2015, 3, 29)),
        new Date(2015, 4, 4, 15, 45)
      );
      assert.deepEqual(
        f.next(new Date(2014, 7, 11)),
        new Date(2014, 7, 11, 15, 45)
      );

      assert.deepEqual(
        (new Frequency('F(even)W/ET9H30M0S')) // Every day of even weeks at 9:30:00
          .next(new Date(2015, 4, 4)),
        new Date(2015, 4, 11, 9, 30)
      );

      f = new Frequency('F(odd)W/E5D/WT13H0M0S'); // Fridays of odd weeks at 13:00:00
      assert.deepEqual(
        f.next(new Date(2016, 1, 26, 13, 30, 0)),
        new Date(2016, 2, 11, 13, 0, 0)
      );

      assert.deepEqual(
        f.next(new Date(2016, 1, 26, 14, 30, 0)),
        new Date(2016, 2, 11, 13, 0, 0)
      );

      assert.deepEqual(
        (new Frequency('F(even)W/E5D/WT13H0M0S')) // Fridays of even weeks at 13:00:00
          .next(new Date(2016, 2, 4, 13, 30, 0)),
        new Date(2016, 2, 18, 13, 0, 0)
      );

      Frequency.fn.weekend = function (weekday) {
          return weekday === 6 || weekday === 7;
        };
      f = new Frequency('F(weekend)D/WT12H0M0S'); // Weekends at 12:00:00
      assert.deepEqual(f.next(new Date(2014, 7, 20)), new Date(2014, 7, 23, 12));

      Frequency.fn.inSummer = function (month) {
          return month === 7 || month === 8;
        };
      f = new Frequency('F(inSummer)M1DT0H0M0S'); // First day of "summer" months at midnight
      var date = new Date(2014, 0, 15);
      date = f.next(date);
      assert.deepEqual(date, new Date(2014, 6, 1, 0, 0, 0));
      date = f.next(date.setDate(2));
      assert.deepEqual(date, new Date(2014, 7, 1, 0, 0, 0));
      date = f.next(date.setDate(2));
      assert.deepEqual(date, new Date(2015, 6, 1, 0, 0, 0));
    });
  });

  describe('#between()', function () {
    var arr, arrm;

    before(function () {
      // plain javascript
      var f = new Frequency(),
        start = new Date(2013, 8, 2),
        end = new Date(2013, 8, 9);

      f.on('hour', 10).on('minute', 0).on('second', 0); // each day at 10:00:00
      arr = f.between(start, end);

      // with moment
      var fm = new Frequency(),
        startm = moment(new Date(2013, 8, 2)),
        endm = moment(new Date(2013, 8, 9));

      fm.on('hour', 10).on('minute', 0).on('second', 0); // each day at 10:00:00
      arrm = fm.between(startm, endm);
    });

    it('should return an array of dates', function () {
      assert.equal(arr.length, 7);
      assert.equal(arrm.length, 7);
    });

    it('should have the first item match the frequency', function () {
      assert.deepEqual(arr[0], new Date(2013, 8, 2, 10));
      assert.deepEqual(arrm[0], new Date(2013, 8, 2, 10));
    });

    it('should have the last item match the frequency', function () {
      assert.deepEqual(arr[6], new Date(2013, 8, 8, 10));
      assert.deepEqual(arrm[6], new Date(2013, 8, 8, 10));
    });

    it('should return using string notation', function () {
      var f = new Frequency('F1D/WT15H45M0S');
      var dates = f.between(new Date(2014, 2, 10), new Date(2014, 2, 17));
      assert.equal(dates.length, 1);
    });

    it('should return nothing using string notation', function () {
      var f = new Frequency('F1D/WT15H45M0S');
      var dates = f.between(new Date(2014, 2, 4), new Date(2014, 2, 10));
      assert.equal(dates.length, 0);
    });
  });

  describe('#compare()', function () {
    it('should detect before', function () {
      var f = new Frequency('F1D/W');
      assert.ok(f.compare(new Frequency('F2D/W')) === -1);
    });

    it('should detect after', function () {
      var f = new Frequency('F2D/W');
      assert.ok(f.compare(new Frequency('F1D/W')) === 1);
    });

    it('should detect equal', function () {
      var f = new Frequency('F1D/W');
      assert.ok(f.compare(new Frequency('F1D/W')) === 0);
    });
  });

  describe('#toString()', function () {
    it('should output the same string passed to the constructor', function () {
      assert.equal((new Frequency('FT15H45M')).toString(), 'FT15H45M');
      assert.equal((new Frequency('F1D/WT15H45M')).toString(), 'F1D/WT15H45M');
      assert.equal((new Frequency('F1D/WT15H45M0S')).toString(), 'F1D/WT15H45M0S');

      assert.equal((new Frequency('F(leap)Y1D/WT15H45M0S')).toString(), 'F(leap)Y1D/WT15H45M0S');
      assert.equal((new Frequency('F(odd)W/E1D/WT15H45M0S')).toString(), 'F(odd)W/E1D/WT15H45M0S');
    });

    it('should output rules set with on() to string notation', function () {
      var f = new Frequency();

      f.on('month', 2).on('hour', 10);
      assert.equal(f.toString(), 'F2MT10H');
    });

    it('should output scope set with on() to string notation', function () {
      var f = new Frequency();

      f.on('day', 2, 'week').on('hour', 10);
      assert.equal(f.toString(), 'F2D/WT10H');
    });

    it('should respect default unit order', function () {
      var f = new Frequency({second: {fix: 0}});

      f.on('minute', 0).on('hour', 10);
      assert.equal(f.toString(), 'FT10H0M0S');
    });
  });
});
<|endoftext|>


<commit_before>/* global $ */
import _ from "lodash";
import "datatables.net-bs";

export default class Table {
  constructor(table) {
    this.table = table;

    // Set options based on data attributes
    this.paginated = !(this.table.dataset.paginated === 'false');
    this.sortColumn = (_.isNil(this.table.dataset.sortColumn) ||
                        _.isNaN(this.table.dataset.sortColumn)) ?
                        1 : this.table.dataset.sortColumn;
    this.sortOrder = this.table.dataset.sortOrder === "asc" ? "asc" : "desc";
    this.lengthChangable = this.table.dataset.lengthChangable === 'true';

    // Just remove the search input from the DOM instead of disabling it
    this.domOptions = "lrtip";
    if (this.table.dataset.searchable === 'true') {
      this.domOptions = "lfrtip";
    }

    this.render();
  }

  render() {
    this.table = $(this.table).DataTable({ // eslint-disable-line new-cap
      //dom: this.domOptions,
      lengthChange: this.lengthChangable,
      info: false,
      paging: this.paginated,
      pagingType: "numbers"
    })
      .order([this.sortColumn, this.sortOrder])
      .draw();
  }
}
<commit_msg>fix jslint<commit_after>/* global $ */
import _ from "lodash";
import "datatables.net-bs";

export default class Table {
  constructor(table) {
    this.table = table;

    // Set options based on data attributes
    this.paginated = !(this.table.dataset.paginated === 'false');
    this.sortColumn = (_.isNil(this.table.dataset.sortColumn) ||
                        _.isNaN(this.table.dataset.sortColumn)) ?
                        1 : this.table.dataset.sortColumn;
    this.sortOrder = this.table.dataset.sortOrder === "asc" ? "asc" : "desc";
    this.lengthChangable = this.table.dataset.lengthChangable === 'true';

    // Just remove the search input from the DOM instead of disabling it
    this.domOptions = "lrtip";
    if (this.table.dataset.searchable === 'true') {
      this.domOptions = "lfrtip";
    }

    this.render();
  }

  render() {
    this.table = $(this.table).DataTable({ // eslint-disable-line new-cap
      // dom: this.domOptions,
      lengthChange: this.lengthChangable,
      info: false,
      paging: this.paginated,
      pagingType: "numbers"
    })
      .order([this.sortColumn, this.sortOrder])
      .draw();
  }
}
<|endoftext|>


<commit_before>exports.listeners = {
  playerEnter: function(l10n) {
    return function(player, players) {
      console.log(arguments);
      var rand = getRand();
      if (rand === 3) {
        rand = getRand();
        player.setAttribute('sanity', player.getAttribute('sanity') -
          rand);
        player.sayL10n(l10n, 'DISCOMFORT');
      }
    }
  },
};

function getRand() {
  return Math.floor(Math.random() * 5 + 1);
}<commit_msg>Made more DRY and removed debug stuff.<commit_after>exports.listeners = {
  playerEnter: function(l10n) {
    return function(player, players) {
      if (getRand() === 3) {
        player.setAttribute('sanity', player.getAttribute('sanity') -
          getRand());
        player.sayL10n(l10n, 'DISCOMFORT');
      }
    }
  },
};

function getRand() {
  return Math.floor(Math.random() * 5 + 1);
}<|endoftext|>


<commit_before>define([
    'angular',
    'config'
], function(angular, config) {
    'use strict';

    var module = angular.module('quizApp.main.services', ['ngResource']);

    module.service('Globals', function() {
        return {
            active_quiz: null,
        };
    });
});
<commit_msg>[frontend] main.services: config and ngResource are not used here.<commit_after>define([
    'angular'
], function(angular) {
    'use strict';

    var module = angular.module('quizApp.main.services', []);

    module.service('Globals', function() {
        return {
            active_quiz: null,
        };
    });
});
<|endoftext|>