<commit_before>const Self = imports.misc.extensionUtils.getCurrentExtension();

// network requests
const Soup = imports.gi.Soup;

const RWG_SETTINGS_SCHEMA_UNSPLASH = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.unsplash';
const RWG_SETTINGS_SCHEMA_WALLHAVEN = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.wallhaven';
const RWG_SETTINGS_SCHEMA_REDDIT = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.reddit';
const RWG_SETTINGS_SCHEMA_GENERIC_JSON = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.genericJSON';

const SettingsModule = Self.imports.settings;
const HistoryModule = Self.imports.history;

const LoggerModule = Self.imports.logger;
const JSONPath = Self.imports.jsonpath.jsonpath;

var BaseAdapter = class {

	constructor() {
		this.logger = new LoggerModule.Logger('RWG3', 'BaseAdapter');
	}

	/**
	 * Retrieves a new url for an image and calls the given callback with an HistoryEntry as parameter.
	 * The history element will be null and the error will be set if an error occurred.
	 *
	 * @param callback(historyElement, error)
	 */
	requestRandomImage(callback) {
		this._error("requestRandomImage not implemented", callback);
	}

	fileName(uri) {
		while (this._isURIEncoded(uri)) {
			uri = decodeURIComponent(uri);
		}

		let base = uri.substring(uri.lastIndexOf('/') + 1);
		if (base.indexOf('?') >= 0) {
			base = base.substr(0, base.indexOf('?'));
		}
		return base;
	}

	_isURIEncoded(uri) {
		uri = uri || '';

		try {
			return uri !== decodeURIComponent(uri);
		} catch (err) {
			this.logger.error(err);
			return false;
		}
	}

	_error(err, callback) {
		let error = {"error": err};
		this.logger.error(JSON.stringify(error));

		if (callback) {
			callback(null, error);
		}
	}

};

var UnsplashAdapter = class extends BaseAdapter {

	constructor() {
		super();

		this.sourceName = 'Unsplash';
		this.sourceUrl = 'https://unsplash.com/';

		// query options
		this.options = {
			'username': '',
			'query': '',
			'collections': [],
			'w': 1920,
			'h': 1080,
			'featured': false
		};

		this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_UNSPLASH);
	}

	requestRandomImage(callback) {
		let session = new Soup.SessionAsync();

		this._readOptionsFromSettings();
		let optionsString = this._generateOptionsString();
		let clientParam = 'client_id=64daf439e9b579dd566620c0b07022706522d87b255d06dd01d5470b7f193b8d';

		let url = 'https://api.unsplash.com/photos/random?' + optionsString + clientParam;
		url = encodeURI(url);

		let message = Soup.Message.new('GET', url);

		if (message === null) {
			this._error("Could not create request.", callback);
			return;
		}

		let utmParameters = 'utm_source=RandomWallpaperGnome3&utm_medium=referral&utm_campaign=api-credit';

		session.queue_message(message, (session, message) => {
			let downloadMessage = null;
			let authorName, authorUrl, imageLinkUrl;

			try {
				let data = JSON.parse(message.response_body.data);

				authorName = data.user.name;
				authorUrl = encodeURI(data.user.links.html);
				imageLinkUrl = encodeURI(data.links.html);

				// check whether the download link contains parameters already
				let junctionSymbol = data.links.download_location.split('?').length > 1 ? '&' : '?';
				let downloadLocation = data.links.download_location + junctionSymbol + clientParam;
				downloadMessage = Soup.Message.new('GET', downloadLocation);
			} catch (e) {
				this._error("Unexpected response. (" + e + ")", callback);
				return;
			}

			if (message === null) {
				this._error("Could not create request.", callback);
				return;
			}

			session.queue_message(downloadMessage, (session, message) => {
				try {
					let downloadData = JSON.parse(message.response_body.data);

					if (callback) {
						let historyEntry = new HistoryModule.HistoryEntry(authorName, this.sourceName, encodeURI(downloadData.url));
						historyEntry.source.sourceUrl = encodeURI(this.sourceUrl + '?' + utmParameters);
						historyEntry.source.authorUrl = encodeURI(authorUrl + '?' + utmParameters);
						historyEntry.source.imageLinkUrl = imageLinkUrl + '?' + utmParameters;
						callback(historyEntry);
					}
				} catch (e) {
					this._error("Unexpected response. (" + e + ")", callback);
					return;
				}
			});
		});
	}

	_generateOptionsString() {
		let options = this.options;
		let optionsString = "";

		for (let key in options) {
			if (options.hasOwnProperty(key)) {
				if (options[key]) {
					optionsString += key + "=" + options[key] + "&";
				}
			}
		}

		return optionsString;
	}

	_readOptionsFromSettings() {
		this.options.query = this._settings.get('unsplash-keyword', 'string');

		this.options.username = this._settings.get('unsplash-username', 'string');
		if (this.options.username && this.options.username[0] === '@') {
			this.options.username = this.options.username.substring(1); // remove @ prefix
		}

		this.options.collections = this._settings.get('unsplash-collections', 'string').split(',').map(
			(elem) => {
				return elem.trim();
			});

		this.options.w = this._settings.get('image-width', 'int');
		this.options.h = this._settings.get('image-height', 'int');

		this.options.featured = this._settings.get('featured-only', 'boolean');
	}
};

var WallhavenAdapter = class extends BaseAdapter {

	constructor() {
		super();

		this.options = {
			'q': '',
			'apikey': '',
			'purity': '110', // SFW, sketchy
			'sorting': 'random',
			'categories': '111', // General, Anime, People
			'resolutions': ['1920x1200', '2560x1440']
		};

		this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_WALLHAVEN);
	}

	requestRandomImage(callback) {
		let session = new Soup.SessionAsync();

		this._readOptionsFromSettings();
		let optionsString = this._generateOptionsString();
		let url = 'https://wallhaven.cc/api/v1/search?' + encodeURI(optionsString);

		let message = Soup.Message.new('GET', url);

		session.queue_message(message, (session, message) => {
			let images = JSON.parse(message.response_body.data).data;

			if (!images || images.length === 0) {
				this._error("No image found. body:"+images, callback);
				return;
			}

			// get a random entry from the array
			let imageUrl = images[Math.floor(Math.random() * images.length)].path;

			let apiKey = this.options["apikey"];
			if(apiKey){
                imageUrl += "?apikey="+apiKey;
            }

            if (callback) {
                let historyEntry = new HistoryModule.HistoryEntry(null, 'Wallhaven', imageUrl);
                historyEntry.source.sourceUrl = 'https://wallhaven.cc/';
                historyEntry.source.imageLinkUrl = url;
                callback(historyEntry);
            }
		});
	}

	_generateOptionsString() {
		let options = this.options;
		let optionsString = "";

		for (let key in options) {
			if (options.hasOwnProperty(key)) {
				if (Array.isArray(options[key])) {
					optionsString += key + "=" + options[key].join() + "&";
				} else {
					if (options[key]) {
						optionsString += key + "=" + options[key] + "&";
					}
				}
			}
		}

		return optionsString;
	}

	_readOptionsFromSettings() {
		this.options.q = this._settings.get('wallhaven-keyword', 'string');
		this.options.apikey = this._settings.get('wallhaven-api-key', 'string');

		this.options.resolutions = this._settings.get('resolutions', 'string').split(',');
		this.options.resolutions = this.options.resolutions.map((elem) => {
			return elem.trim();
		});

		let categories = [];
		categories.push(+this._settings.get('category-general', 'boolean')); // + is implicit conversion to int
		categories.push(+this._settings.get('category-anime', 'boolean'));
		categories.push(+this._settings.get('category-people', 'boolean'));
		this.options.categories = categories.join('');

		let purity = [];
		purity.push(+this._settings.get('allow-sfw', 'boolean'));
		purity.push(+this._settings.get('allow-sketchy', 'boolean'));
		purity.push(+this._settings.get('allow-nsfw', 'boolean'));
		this.options.purity = purity.join('');
	}
};

var RedditAdapter = class extends BaseAdapter {

	constructor() {
		super();

		this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_REDDIT);
	}

	_ampDecode(string) {
		return string.replace(/\&/g, '&');
	}

	requestRandomImage(callback) {
		let session = new Soup.SessionAsync();

		const subreddits = this._settings.get('subreddits', 'string').split(',').map(s => s.trim()).join('+');
		const require_sfw = this._settings.get('allow-sfw', 'boolean');
		const url = encodeURI('https://www.reddit.com/r/' + subreddits + '.json');

		let message = Soup.Message.new('GET', url);

		if (message === null) {
			this._error("Could not create request.", callback);
			return;
		}

		session.queue_message(message, (session, message) => {
			try {
				const submissions = JSON.parse(message.response_body.data).data.children.filter(child => {
					if (child.data.post_hint !== 'image') return false;
					if (require_sfw) return child.data.over_18 === false;
					return true;
				});
				if (submissions.length === 0) {
					this._error("No suitable submissions found!", callback);
					return;
				}
				const random = Math.floor(Math.random() * submissions.length);
				const submission = submissions[random].data;
				const imageDownloadUrl = this._ampDecode(submission.preview.images[0].source.url);

				if (callback) {
					let historyEntry = new HistoryModule.HistoryEntry(null, 'Reddit', imageDownloadUrl);
					historyEntry.source.sourceUrl = 'https://www.reddit.com/' + submission.subreddit_name_prefixed;
					historyEntry.source.imageLinkUrl = 'https://www.reddit.com/' + submission.permalink;
					callback(historyEntry);
				}
			} catch (e) {
				this._error("Could not create request. (" + e + ")", callback);
			}
		});
	}

};

var GenericJsonAdapter = class extends BaseAdapter {

	constructor() {
		super();
		this._jsonPathParser = new JSONPath.JSONPathParser();
		this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_GENERIC_JSON);
	}

	requestRandomImage(callback) {
		let session = new Soup.SessionAsync();

		let url = this._settings.get("generic-json-request-url", "string");
		url = encodeURI(url);

		let message = Soup.Message.new('GET', url);

		if (message === null) {
			this._error("Could not create request.", callback);
			return;
		}

		session.queue_message(message, (session, message) => {
			try {
				let response = JSON.parse(message.response_body.data);
				let JSONPath = this._settings.get("generic-json-response-path", "string");
				let imageDownloadUrl = this._jsonPathParser.access(response, JSONPath);
				imageDownloadUrl = this._settings.get("generic-json-url-prefix", "string") + imageDownloadUrl;

				if (callback) {
					let historyEntry = new HistoryModule.HistoryEntry(null, 'Generic JSON Source', imageDownloadUrl);
					historyEntry.source.sourceUrl = imageDownloadUrl;
					callback(historyEntry);
				}
			} catch (e) {
				this._error("Unexpected response. (" + e + ")", callback);
			}
		});

	}

};
<commit_msg>convert spaces to tabs<commit_after>const Self = imports.misc.extensionUtils.getCurrentExtension();

// network requests
const Soup = imports.gi.Soup;

const RWG_SETTINGS_SCHEMA_UNSPLASH = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.unsplash';
const RWG_SETTINGS_SCHEMA_WALLHAVEN = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.wallhaven';
const RWG_SETTINGS_SCHEMA_REDDIT = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.reddit';
const RWG_SETTINGS_SCHEMA_GENERIC_JSON = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.genericJSON';

const SettingsModule = Self.imports.settings;
const HistoryModule = Self.imports.history;

const LoggerModule = Self.imports.logger;
const JSONPath = Self.imports.jsonpath.jsonpath;

var BaseAdapter = class {

	constructor() {
		this.logger = new LoggerModule.Logger('RWG3', 'BaseAdapter');
	}

	/**
	 * Retrieves a new url for an image and calls the given callback with an HistoryEntry as parameter.
	 * The history element will be null and the error will be set if an error occurred.
	 *
	 * @param callback(historyElement, error)
	 */
	requestRandomImage(callback) {
		this._error("requestRandomImage not implemented", callback);
	}

	fileName(uri) {
		while (this._isURIEncoded(uri)) {
			uri = decodeURIComponent(uri);
		}

		let base = uri.substring(uri.lastIndexOf('/') + 1);
		if (base.indexOf('?') >= 0) {
			base = base.substr(0, base.indexOf('?'));
		}
		return base;
	}

	_isURIEncoded(uri) {
		uri = uri || '';

		try {
			return uri !== decodeURIComponent(uri);
		} catch (err) {
			this.logger.error(err);
			return false;
		}
	}

	_error(err, callback) {
		let error = {"error": err};
		this.logger.error(JSON.stringify(error));

		if (callback) {
			callback(null, error);
		}
	}

};

var UnsplashAdapter = class extends BaseAdapter {

	constructor() {
		super();

		this.sourceName = 'Unsplash';
		this.sourceUrl = 'https://unsplash.com/';

		// query options
		this.options = {
			'username': '',
			'query': '',
			'collections': [],
			'w': 1920,
			'h': 1080,
			'featured': false
		};

		this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_UNSPLASH);
	}

	requestRandomImage(callback) {
		let session = new Soup.SessionAsync();

		this._readOptionsFromSettings();
		let optionsString = this._generateOptionsString();
		let clientParam = 'client_id=64daf439e9b579dd566620c0b07022706522d87b255d06dd01d5470b7f193b8d';

		let url = 'https://api.unsplash.com/photos/random?' + optionsString + clientParam;
		url = encodeURI(url);

		let message = Soup.Message.new('GET', url);

		if (message === null) {
			this._error("Could not create request.", callback);
			return;
		}

		let utmParameters = 'utm_source=RandomWallpaperGnome3&utm_medium=referral&utm_campaign=api-credit';

		session.queue_message(message, (session, message) => {
			let downloadMessage = null;
			let authorName, authorUrl, imageLinkUrl;

			try {
				let data = JSON.parse(message.response_body.data);

				authorName = data.user.name;
				authorUrl = encodeURI(data.user.links.html);
				imageLinkUrl = encodeURI(data.links.html);

				// check whether the download link contains parameters already
				let junctionSymbol = data.links.download_location.split('?').length > 1 ? '&' : '?';
				let downloadLocation = data.links.download_location + junctionSymbol + clientParam;
				downloadMessage = Soup.Message.new('GET', downloadLocation);
			} catch (e) {
				this._error("Unexpected response. (" + e + ")", callback);
				return;
			}

			if (message === null) {
				this._error("Could not create request.", callback);
				return;
			}

			session.queue_message(downloadMessage, (session, message) => {
				try {
					let downloadData = JSON.parse(message.response_body.data);

					if (callback) {
						let historyEntry = new HistoryModule.HistoryEntry(authorName, this.sourceName, encodeURI(downloadData.url));
						historyEntry.source.sourceUrl = encodeURI(this.sourceUrl + '?' + utmParameters);
						historyEntry.source.authorUrl = encodeURI(authorUrl + '?' + utmParameters);
						historyEntry.source.imageLinkUrl = imageLinkUrl + '?' + utmParameters;
						callback(historyEntry);
					}
				} catch (e) {
					this._error("Unexpected response. (" + e + ")", callback);
					return;
				}
			});
		});
	}

	_generateOptionsString() {
		let options = this.options;
		let optionsString = "";

		for (let key in options) {
			if (options.hasOwnProperty(key)) {
				if (options[key]) {
					optionsString += key + "=" + options[key] + "&";
				}
			}
		}

		return optionsString;
	}

	_readOptionsFromSettings() {
		this.options.query = this._settings.get('unsplash-keyword', 'string');

		this.options.username = this._settings.get('unsplash-username', 'string');
		if (this.options.username && this.options.username[0] === '@') {
			this.options.username = this.options.username.substring(1); // remove @ prefix
		}

		this.options.collections = this._settings.get('unsplash-collections', 'string').split(',').map(
			(elem) => {
				return elem.trim();
			});

		this.options.w = this._settings.get('image-width', 'int');
		this.options.h = this._settings.get('image-height', 'int');

		this.options.featured = this._settings.get('featured-only', 'boolean');
	}
};

var WallhavenAdapter = class extends BaseAdapter {

	constructor() {
		super();

		this.options = {
			'q': '',
			'apikey': '',
			'purity': '110', // SFW, sketchy
			'sorting': 'random',
			'categories': '111', // General, Anime, People
			'resolutions': ['1920x1200', '2560x1440']
		};

		this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_WALLHAVEN);
	}

	requestRandomImage(callback) {
		let session = new Soup.SessionAsync();

		this._readOptionsFromSettings();
		let optionsString = this._generateOptionsString();
		let url = 'https://wallhaven.cc/api/v1/search?' + encodeURI(optionsString);

		let message = Soup.Message.new('GET', url);

		session.queue_message(message, (session, message) => {
			let images = JSON.parse(message.response_body.data).data;

			if (!images || images.length === 0) {
				this._error("No image found. body:"+images, callback);
				return;
			}

			// get a random entry from the array
			let imageUrl = images[Math.floor(Math.random() * images.length)].path;

			let apiKey = this.options["apikey"];
			if(apiKey){
				imageUrl += "?apikey="+apiKey;
			}

			if (callback) {
				let historyEntry = new HistoryModule.HistoryEntry(null, 'Wallhaven', imageUrl);
				historyEntry.source.sourceUrl = 'https://wallhaven.cc/';
				historyEntry.source.imageLinkUrl = url;
				callback(historyEntry);
			}
		});
	}

	_generateOptionsString() {
		let options = this.options;
		let optionsString = "";

		for (let key in options) {
			if (options.hasOwnProperty(key)) {
				if (Array.isArray(options[key])) {
					optionsString += key + "=" + options[key].join() + "&";
				} else {
					if (options[key]) {
						optionsString += key + "=" + options[key] + "&";
					}
				}
			}
		}

		return optionsString;
	}

	_readOptionsFromSettings() {
		this.options.q = this._settings.get('wallhaven-keyword', 'string');
		this.options.apikey = this._settings.get('wallhaven-api-key', 'string');

		this.options.resolutions = this._settings.get('resolutions', 'string').split(',');
		this.options.resolutions = this.options.resolutions.map((elem) => {
			return elem.trim();
		});

		let categories = [];
		categories.push(+this._settings.get('category-general', 'boolean')); // + is implicit conversion to int
		categories.push(+this._settings.get('category-anime', 'boolean'));
		categories.push(+this._settings.get('category-people', 'boolean'));
		this.options.categories = categories.join('');

		let purity = [];
		purity.push(+this._settings.get('allow-sfw', 'boolean'));
		purity.push(+this._settings.get('allow-sketchy', 'boolean'));
		purity.push(+this._settings.get('allow-nsfw', 'boolean'));
		this.options.purity = purity.join('');
	}
};

var RedditAdapter = class extends BaseAdapter {

	constructor() {
		super();

		this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_REDDIT);
	}

	_ampDecode(string) {
		return string.replace(/\&/g, '&');
	}

	requestRandomImage(callback) {
		let session = new Soup.SessionAsync();

		const subreddits = this._settings.get('subreddits', 'string').split(',').map(s => s.trim()).join('+');
		const require_sfw = this._settings.get('allow-sfw', 'boolean');
		const url = encodeURI('https://www.reddit.com/r/' + subreddits + '.json');

		let message = Soup.Message.new('GET', url);

		if (message === null) {
			this._error("Could not create request.", callback);
			return;
		}

		session.queue_message(message, (session, message) => {
			try {
				const submissions = JSON.parse(message.response_body.data).data.children.filter(child => {
					if (child.data.post_hint !== 'image') return false;
					if (require_sfw) return child.data.over_18 === false;
					return true;
				});
				if (submissions.length === 0) {
					this._error("No suitable submissions found!", callback);
					return;
				}
				const random = Math.floor(Math.random() * submissions.length);
				const submission = submissions[random].data;
				const imageDownloadUrl = this._ampDecode(submission.preview.images[0].source.url);

				if (callback) {
					let historyEntry = new HistoryModule.HistoryEntry(null, 'Reddit', imageDownloadUrl);
					historyEntry.source.sourceUrl = 'https://www.reddit.com/' + submission.subreddit_name_prefixed;
					historyEntry.source.imageLinkUrl = 'https://www.reddit.com/' + submission.permalink;
					callback(historyEntry);
				}
			} catch (e) {
				this._error("Could not create request. (" + e + ")", callback);
			}
		});
	}

};

var GenericJsonAdapter = class extends BaseAdapter {

	constructor() {
		super();
		this._jsonPathParser = new JSONPath.JSONPathParser();
		this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_GENERIC_JSON);
	}

	requestRandomImage(callback) {
		let session = new Soup.SessionAsync();

		let url = this._settings.get("generic-json-request-url", "string");
		url = encodeURI(url);

		let message = Soup.Message.new('GET', url);

		if (message === null) {
			this._error("Could not create request.", callback);
			return;
		}

		session.queue_message(message, (session, message) => {
			try {
				let response = JSON.parse(message.response_body.data);
				let JSONPath = this._settings.get("generic-json-response-path", "string");
				let imageDownloadUrl = this._jsonPathParser.access(response, JSONPath);
				imageDownloadUrl = this._settings.get("generic-json-url-prefix", "string") + imageDownloadUrl;

				if (callback) {
					let historyEntry = new HistoryModule.HistoryEntry(null, 'Generic JSON Source', imageDownloadUrl);
					historyEntry.source.sourceUrl = imageDownloadUrl;
					callback(historyEntry);
				}
			} catch (e) {
				this._error("Unexpected response. (" + e + ")", callback);
			}
		});

	}

};
<|endoftext|>


<commit_before>'use strict'
var gulp = require('gulp');
var gulpTypescript = require('gulp-tsc');
var insert = require('gulp-insert');
var mocha = require('gulp-mocha');
var rename = require('gulp-rename');
var rollup = require('rollup');
var rollupTypescript = require('rollup-plugin-typescript');
var typescript = require('typescript');
var uglify = require('gulp-uglify');

var tests = [
    { name: 'NavigationRouting', to: 'navigationRouting.test.js' },
    { name: 'StateConfig', to: 'stateConfig.test.js' },
    { name: 'Navigation', to: 'navigation.test.js' },
    { name: 'NavigationData', to: 'navigationData.test.js' },
    { name: 'NavigationLink', to: 'navigationLink.test.js', folder: 'React', ext: 'tsx' },
    { name: 'NavigationBackLink', to: 'navigationBackLink.test.js', folder: 'React', ext: 'tsx' },
    { name: 'RefreshLink', to: 'refreshLink.test.js', folder: 'React', ext: 'tsx' }
];
function rollupTestTask(name, file, to) {
    return rollup.rollup({
        entry: file,
        external: ['assert', 'react', 'react-addons-test-utils'],
        plugins: [
            rollupTypescript({
                typescript: typescript,
                target: 'es3',
                module: 'es6',
                jsx: 'react'
            })
        ]
    }).then((bundle) => {
        bundle.write({
            format: 'cjs',
            dest: to
        });
    });
}
function testTask(file) {
    return gulp.src(file)
        .pipe(mocha({ reporter: 'progress' }));
}
var testTasks = tests.reduce((tasks, test) => {
    var folder = './Navigation' + (test.folder || '') + '/test/';
    var file = folder + test.name + 'Test.' + (test.ext || 'ts');
    var to = './build/dist/' + test.to;
    gulp.task('RollupTest' + test.name, () => rollupTestTask(test.name, file, to));
    gulp.task('Test' + test.name, ['RollupTest' + test.name], () => testTask(to));
    tasks.push('Test' + test.name);
    return tasks;
}, []);
gulp.task('test', testTasks);

var items = [
    require('./build/npm/navigation/package.json'),
    Object.assign({ globals: { react: 'React' } },
        require('./build/npm/navigation-react/package.json')),
    Object.assign({ globals: { knockout: 'ko' } },
        require('./build/npm/navigation-knockout/package.json')),
    Object.assign({ globals: { angular: 'angular' } },
        require('./build/npm/navigation-angular/package.json')),
    Object.assign({ globals: { '@cycle/dom': 'CycleDOM', rx: 'Rx' } },
        require('./build/npm/navigation-cycle/package.json')),
    Object.assign({ globals: { 'inferno-component': 'InfernoComponent',
            'inferno-create-element': 'InfernoCreateElement' } },
        require('./build/npm/navigation-inferno/package.json'))
];
function rollupTask(name, file, to, globals) {
    return rollup.rollup({
        entry: file,
        external: Object.keys(globals),
        plugins: [
            rollupTypescript({
                typescript: typescript,
                target: 'es3',
                module: 'es6'
            })
        ]
    }).then((bundle) => {
        bundle.write({
            format: 'iife',
            moduleName: name,
            globals: Object.assign({ navigation: 'Navigation'}, globals),
            dest: './build/dist/' + to
        });
    });
}
function buildTask(file, details) {
    var info = `/**
 * ${details.name} v${details.version}
 * (c) Graham Mendick - ${details.homepage}
 * License: ${details.license}
 */
`;
    return gulp.src('./build/dist/' + file)
        .pipe(insert.prepend(info))
        .pipe(gulp.dest('./build/dist'))
        .pipe(rename(file.replace(/js$/, 'min.js')))
        .pipe(uglify())
        .pipe(insert.prepend(info))
        .pipe(gulp.dest('./build/dist'));
}
function packageTask(name, file) {
    return gulp.src(file)
        .pipe(gulpTypescript())
        .pipe(gulp.dest('./build/npm/' + name + '/lib'));
}
var itemTasks = items.reduce((tasks, item) => {
    var packageName = item.name;
    var upperName = packageName.replace(/\b./g, (val) => val.toUpperCase());
    var name = upperName.replace('-', '');
    var tsFrom = './' + name + '/src/' + name + '.ts';
    var jsTo = packageName.replace('-', '.') + '.js';
    item.name = upperName.replace('-', ' ');
    gulp.task('Rollup' + name, () => rollupTask(name, tsFrom, jsTo, item.globals || {}));
    gulp.task('Build' + name, ['Rollup' + name], () => buildTask(jsTo, item));
    gulp.task('Package' + name, () => packageTask(packageName, tsFrom));
    tasks.buildTasks.push('Build' + name);
    tasks.packageTasks.push('Package' + name);
    return tasks;
}, { buildTasks: [], packageTasks: [] });
gulp.task('build', itemTasks.buildTasks);
gulp.task('package', itemTasks.packageTasks);
<commit_msg>Added fluent navigation test task<commit_after>'use strict'
var gulp = require('gulp');
var gulpTypescript = require('gulp-tsc');
var insert = require('gulp-insert');
var mocha = require('gulp-mocha');
var rename = require('gulp-rename');
var rollup = require('rollup');
var rollupTypescript = require('rollup-plugin-typescript');
var typescript = require('typescript');
var uglify = require('gulp-uglify');

var tests = [
    { name: 'NavigationRouting', to: 'navigationRouting.test.js' },
    { name: 'StateConfig', to: 'stateConfig.test.js' },
    { name: 'Navigation', to: 'navigation.test.js' },
    { name: 'NavigationData', to: 'navigationData.test.js' },
    { name: 'FluentNavigation', to: 'fluentNavigation.test.js' },
    { name: 'NavigationLink', to: 'navigationLink.test.js', folder: 'React', ext: 'tsx' },
    { name: 'NavigationBackLink', to: 'navigationBackLink.test.js', folder: 'React', ext: 'tsx' },
    { name: 'RefreshLink', to: 'refreshLink.test.js', folder: 'React', ext: 'tsx' }
];
function rollupTestTask(name, file, to) {
    return rollup.rollup({
        entry: file,
        external: ['assert', 'react', 'react-addons-test-utils'],
        plugins: [
            rollupTypescript({
                typescript: typescript,
                target: 'es3',
                module: 'es6',
                jsx: 'react'
            })
        ]
    }).then((bundle) => {
        bundle.write({
            format: 'cjs',
            dest: to
        });
    });
}
function testTask(file) {
    return gulp.src(file)
        .pipe(mocha({ reporter: 'progress' }));
}
var testTasks = tests.reduce((tasks, test) => {
    var folder = './Navigation' + (test.folder || '') + '/test/';
    var file = folder + test.name + 'Test.' + (test.ext || 'ts');
    var to = './build/dist/' + test.to;
    gulp.task('RollupTest' + test.name, () => rollupTestTask(test.name, file, to));
    gulp.task('Test' + test.name, ['RollupTest' + test.name], () => testTask(to));
    tasks.push('Test' + test.name);
    return tasks;
}, []);
gulp.task('test', testTasks);

var items = [
    require('./build/npm/navigation/package.json'),
    Object.assign({ globals: { react: 'React' } },
        require('./build/npm/navigation-react/package.json')),
    Object.assign({ globals: { knockout: 'ko' } },
        require('./build/npm/navigation-knockout/package.json')),
    Object.assign({ globals: { angular: 'angular' } },
        require('./build/npm/navigation-angular/package.json')),
    Object.assign({ globals: { '@cycle/dom': 'CycleDOM', rx: 'Rx' } },
        require('./build/npm/navigation-cycle/package.json')),
    Object.assign({ globals: { 'inferno-component': 'InfernoComponent',
            'inferno-create-element': 'InfernoCreateElement' } },
        require('./build/npm/navigation-inferno/package.json'))
];
function rollupTask(name, file, to, globals) {
    return rollup.rollup({
        entry: file,
        external: Object.keys(globals),
        plugins: [
            rollupTypescript({
                typescript: typescript,
                target: 'es3',
                module: 'es6'
            })
        ]
    }).then((bundle) => {
        bundle.write({
            format: 'iife',
            moduleName: name,
            globals: Object.assign({ navigation: 'Navigation'}, globals),
            dest: './build/dist/' + to
        });
    });
}
function buildTask(file, details) {
    var info = `/**
 * ${details.name} v${details.version}
 * (c) Graham Mendick - ${details.homepage}
 * License: ${details.license}
 */
`;
    return gulp.src('./build/dist/' + file)
        .pipe(insert.prepend(info))
        .pipe(gulp.dest('./build/dist'))
        .pipe(rename(file.replace(/js$/, 'min.js')))
        .pipe(uglify())
        .pipe(insert.prepend(info))
        .pipe(gulp.dest('./build/dist'));
}
function packageTask(name, file) {
    return gulp.src(file)
        .pipe(gulpTypescript())
        .pipe(gulp.dest('./build/npm/' + name + '/lib'));
}
var itemTasks = items.reduce((tasks, item) => {
    var packageName = item.name;
    var upperName = packageName.replace(/\b./g, (val) => val.toUpperCase());
    var name = upperName.replace('-', '');
    var tsFrom = './' + name + '/src/' + name + '.ts';
    var jsTo = packageName.replace('-', '.') + '.js';
    item.name = upperName.replace('-', ' ');
    gulp.task('Rollup' + name, () => rollupTask(name, tsFrom, jsTo, item.globals || {}));
    gulp.task('Build' + name, ['Rollup' + name], () => buildTask(jsTo, item));
    gulp.task('Package' + name, () => packageTask(packageName, tsFrom));
    tasks.buildTasks.push('Build' + name);
    tasks.packageTasks.push('Package' + name);
    return tasks;
}, { buildTasks: [], packageTasks: [] });
gulp.task('build', itemTasks.buildTasks);
gulp.task('package', itemTasks.packageTasks);
<|endoftext|>


<commit_before>(function($)
{

	jQuery.fn.soliloquy = function( username, options )
	{
		// SETUP SETTINGS
		var settings = jQuery.extend({}, jQuery.fn.soliloquy.defaults, options);

		var element = this;

		// RETRIEVE RESULTS
		var api_twitter = "http://twitter.com/status/user_timeline/"+username+".json?count=" + settings.posts + "&callback=?";

		$.getJSON(api_twitter, function(data)
		{
			$.each(data, function(i, item)
			{
				//alert( $(element).html() );
				$(element).append( buildPost( item ) );
			});
		});

		// $(this).html("" + username + "!" + settings.posts + "");

		return this;
	};

	function buildPost( post )
	{
		var html = "
";
		html += post.text;
		html += "
";
		return html;
	}

	// DEFAULTS
	jQuery.fn.soliloquy.defaults = {
		posts: 10
	};

})(jQuery);<commit_msg>added screen_name to feed<commit_after>(function($)
{

	jQuery.fn.soliloquy = function( username, options )
	{
		// SETUP SETTINGS
		var settings = jQuery.extend({}, jQuery.fn.soliloquy.defaults, options);

		var element = this;

		// RETRIEVE RESULTS
		var api_twitter = "http://twitter.com/status/user_timeline/"+username+".json?count=" + settings.posts + "&callback=?";

		$.getJSON(api_twitter, function(data)
		{
			$.each(data, function(i, item)
			{
				//alert( $(element).html() );
				$(element).append( buildTwitterPost( item ) );
			});
		});

		// $(this).html("" + username + "!" + settings.posts + "");

		return this;
	};

	function buildTwitterPost( post )
	{
		var html = "
";
		html += "" + post.user['screen_name'] + " ";
		html += post.text;
		html += "
";
		return html;
	}

	// DEFAULTS
	jQuery.fn.soliloquy.defaults = {
		posts: 10
	};

})(jQuery);<|endoftext|>


<commit_before>const assert = require('assert');
const express = require('express');
const router = express.Router();
const schemas = require('../schemas');

const chaos = require('../services/chaos');
const mongoose = require('../services/mongoose');
const Collage = mongoose.model('Collage');

const index = require('../index.js');

const absoluteUrl = (req, path) => {
  const host = req.get('x-forwarded-host') || req.get('host');
  return req.protocol + '://' + host + path;
};

const RTMP_PATTERN = /^rtmp:\/\/vod-kulturarv\.dr\.dk\/bonanza\/mp4:bonanza\/(.+\.mp4)$/;
const generateHLSUrlFromRTMP = (req, url) => {
  assert.equal(url.substring(0,4), 'rtmp', 'Expected a url over the RTMP');
  const match = RTMP_PATTERN.exec(url);
  if(match) {
    const filename = match[1];
    return 'http://vod-kulturarv.dr.dk/bonanza/mp4:bonanza/bonanza/' + filename + '/Playlist.m3u8';
  } else {
    throw new Error('Malformed URL');
  }
}

const deriveVideoUrls = (req, collage) => {
  return Promise.all(collage.videos.map(video => {
    return chaos.getVideoFiles(video).then(files => {
      if(files.rtmpMpeg4) {
        files.hls = generateHLSUrlFromRTMP(req, files.rtmpMpeg4);
      }
      video.videoData.files = files;
      return video;
    });
  })).then((videos) => {
    return collage;
  });
};

/* Upload a new collage */
router.post('/:id', function(req, res, next) {
  const id = req.params.id;
  const collageData = req.body;

  const valid = schemas.validate('Collage', collageData);
  assert.ok(valid, schemas.errorsText());

  Collage.createWithEncodedImages(id, collageData)
  .then(collage => {
    res.json({
      collage,
      valid
    });
  }, next);
});

router.delete('/:id', function(req, res, next) {
  const id = req.params.id;
  Collage.remove({ id }).then(response => {
    res.json(response);
  }, next);
});

router.get('/collages', function(req, res, next) {
  if(req.accepts(['html', 'json']) === 'json') {
    Collage.find().then(collages => {
      res.json(collages);
    });
  } else {
    next();
  }
});

router.get('/:id', function(req, res, next) {
  const id = req.params.id;
  Collage.findOne({id}).then(collage => {
    if(collage) {
      return deriveVideoUrls(req, collage.toObject());
    }
  }).then(collage => {
    if(req.accepts(['html', 'json']) === 'json') {
      // Disable caching of the JSON to prevent browsers from showing JSON
      // instead of a cached HTML version of this route
      res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
      res.json(collage);
    } else {
      const html = index.appendMetatags({
        'og:title': '',
        'og:image': '',
        'og:description': '',
        'og:url': ''
      });
      res.send(html);
    }
  }, next).then(null, next);
});

module.exports = router;
<commit_msg>Using sane values for the og: meta-tags<commit_after>const assert = require('assert');
const express = require('express');
const router = express.Router();
const schemas = require('../schemas');

const chaos = require('../services/chaos');
const mongoose = require('../services/mongoose');
const Collage = mongoose.model('Collage');

const index = require('../index.js');

const absoluteUrl = (req, path) => {
  const host = req.get('x-forwarded-host') || req.get('host');
  return req.protocol + '://' + host + path;
};

const RTMP_PATTERN = /^rtmp:\/\/vod-kulturarv\.dr\.dk\/bonanza\/mp4:bonanza\/(.+\.mp4)$/;
const generateHLSUrlFromRTMP = (req, url) => {
  assert.equal(url.substring(0,4), 'rtmp', 'Expected a url over the RTMP');
  const match = RTMP_PATTERN.exec(url);
  if(match) {
    const filename = match[1];
    return 'http://vod-kulturarv.dr.dk/bonanza/mp4:bonanza/bonanza/' + filename + '/Playlist.m3u8';
  } else {
    throw new Error('Malformed URL');
  }
}

const deriveVideoUrls = (req, collage) => {
  return Promise.all(collage.videos.map(video => {
    return chaos.getVideoFiles(video).then(files => {
      if(files.rtmpMpeg4) {
        files.hls = generateHLSUrlFromRTMP(req, files.rtmpMpeg4);
      }
      video.videoData.files = files;
      return video;
    });
  })).then((videos) => {
    return collage;
  });
};

/* Upload a new collage */
router.post('/:id', function(req, res, next) {
  const id = req.params.id;
  const collageData = req.body;

  const valid = schemas.validate('Collage', collageData);
  assert.ok(valid, schemas.errorsText());

  Collage.createWithEncodedImages(id, collageData)
  .then(collage => {
    res.json({
      collage,
      valid
    });
  }, next);
});

router.delete('/:id', function(req, res, next) {
  const id = req.params.id;
  Collage.remove({ id }).then(response => {
    res.json(response);
  }, next);
});

router.get('/collages', function(req, res, next) {
  if(req.accepts(['html', 'json']) === 'json') {
    Collage.find().then(collages => {
      res.json(collages);
    });
  } else {
    next();
  }
});

router.get('/:id', function(req, res, next) {
  const id = req.params.id;
  Collage.findOne({id}).then(collage => {
    if(collage) {
      return deriveVideoUrls(req, collage.toObject());
    }
  }).then(collage => {
    if(req.accepts(['html', 'json']) === 'json') {
      // Disable caching of the JSON to prevent browsers from showing JSON
      // instead of a cached HTML version of this route
      res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
      res.json(collage);
    } else {
      const html = index.appendMetatags({
        'og:title': 'Mit bybillede fra ' + collage.eventName,
        'og:image': collage.thumbnail,
        'og:description': '',
        'og:url': absoluteUrl(req, '/' + collage.id)
      });
      res.send(html);
    }
  }, next).then(null, next);
});

module.exports = router;
<|endoftext|>


<commit_before>/**
 * Created by nuintun on 2015/5/5.
 */

'use strict';

var path = require('path');
var gulp = require('gulp');
var rimraf = require('del');
var colors = require('colors/safe');
var transport = require('gulp-cmd');
var uglify = require('gulp-uglify');
var css = require('gulp-minify-css');
var plumber = require('gulp-plumber');

// set colors theme
colors.setTheme({
  input: 'grey',
  verbose: 'cyan',
  prompt: 'grey',
  info: 'green',
  data: 'grey',
  help: 'cyan',
  warn: 'yellow',
  debug: 'blue',
  error: 'red',
  inputBold: ['grey', 'bold'],
  verboseBold: ['cyan', 'bold'],
  promptBold: ['grey', 'bold'],
  infoBold: ['green', 'bold'],
  dataBold: ['grey', 'bold'],
  helpBold: ['cyan', 'bold'],
  warnBold: ['yellow', 'bold'],
  debugBold: ['blue', 'bold'],
  errorBold: ['red', 'bold']
});

// alias
var alias = {
  'jquery': 'base/jquery/1.11.2/jquery',
  'base': 'base/base/1.2.0/base',
  'class': 'base/class/1.2.0/class',
  'events': 'base/events/1.2.0/events',
  'widget': 'base/widget/1.2.0/widget',
  'template': 'base/template/3.0.3/template',
  'templatable': 'base/templatable/0.10.0/templatable',
  'iframe-shim': 'util/iframe-shim/1.1.0/iframe-shim',
  'position': 'util/position/1.1.0/position',
  'messenger': 'util/messenger/2.1.0/messenger',
  'mask': 'common/overlay/1.2.0/mask',
  'overlay': 'common/overlay/1.2.0/overlay',
  'dialog': 'common/dialog/1.5.1/dialog',
  'confirmbox': 'common/dialog/1.5.1/confirmbox'
};

var startTime = Date.now();

// complete callback
function complete(){
  var now = new Date();

  console.log(
    '  %s [%s] build complete ... %s %s',
    colors.verboseBold('gulp-cmd'),
    now.toLocaleString(),
    colors.infoBold(now - startTime),
    colors.verboseBold('ms')
  );
}

// clean task
gulp.task('clean', function (callback){
  rimraf('online', callback);
});

// runtime task
gulp.task('runtime', ['clean'], function (){
  gulp.src('assets/loader/**/*.js', { base: 'assets' })
    .pipe(uglify())
    .pipe(gulp.dest('online'));

  gulp.src('assets/?(loader|images)/**/*.!(js)', { base: 'assets' })
    .pipe(gulp.dest('online'));
});

// online task
gulp.task('online', ['runtime'], function (){
  // all js
  gulp.src('assets/js/**/*.js', { base: 'assets/js' })
    .pipe(transport({
      alias: alias,
      ignore: ['jquery'],
      include: function (id){
        return id.indexOf('view') === 0 ? 'all' : 'relative';
      },
      oncsspath: function (path){
        return path.replace('assets/', 'online/')
      }
    }))
    .pipe(uglify())
    .pipe(gulp.dest('online/js'))
    .on('end', complete);

  // other file
  gulp.src('assets/js/**/*.!(js|css|json|tpl|html)')
    .pipe(gulp.dest('online/js'));

  // css
  gulp.src('assets/css/**/*.*')
    .pipe(css({ compatibility: 'ie8' }))
    .pipe(gulp.dest('online/css'));
});

// develop task
gulp.task('default', ['runtime'], function (){
  // all file
  gulp.src('assets/js/**/*.*', { base: 'assets/js' })
    .pipe(transport({
      alias: alias,
      include: 'self',
      oncsspath: function (path){
        return path.replace('assets/', 'online/')
      }
    }))
    .pipe(gulp.dest('online/js'))
    .on('end', complete);

  gulp.src('assets/css/**/*.*', { base: 'assets' })
    .pipe(gulp.dest('online'));
});

// develop watch task
gulp.task('watch', ['default'], function (){
  var base = path.join(process.cwd(), 'assets');

  // watch all file
  gulp.watch('assets/js/**/*.*', function (e){
    if (e.type === 'deleted') {
      rimraf(path.resolve('online', path.relative(base, e.path)));
    } else {
      startTime = Date.now();

      gulp.src(e.path, { base: 'assets/js' })
        .pipe(plumber())
        .pipe(transport({
          alias: alias,
          include: 'self',
          cache: false,
          oncsspath: function (path){
            return path.replace('assets/', 'online/')
          }
        }))
        .pipe(gulp.dest('online/js'))
        .on('end', complete);
    }
  });

  // watch all file
  gulp.watch('assets/?(images|loader|css)/**/*.*', function (e){
    if (e.type === 'deleted') {
      rimraf(path.resolve('online', path.relative(base, e.path)));
    } else {
      startTime = Date.now();

      gulp.src(e.path, { base: 'assets' })
        .pipe(plumber())
        .pipe(gulp.dest('online'))
        .on('end', complete);
    }
  });
});
<commit_msg>add source<commit_after>/**
 * Created by nuintun on 2015/5/5.
 */

'use strict';

var path = require('path');
var gulp = require('gulp');
var rimraf = require('del');
var transport = require('gulp-cmd');
var uglify = require('gulp-uglify');
var css = require('gulp-minify-css');
var plumber = require('gulp-plumber');
var colors = transport.colors;

// alias
var alias = {
  'jquery': 'base/jquery/1.11.2/jquery',
  'base': 'base/base/1.2.0/base',
  'class': 'base/class/1.2.0/class',
  'events': 'base/events/1.2.0/events',
  'widget': 'base/widget/1.2.0/widget',
  'template': 'base/template/3.0.3/template',
  'templatable': 'base/templatable/0.10.0/templatable',
  'iframe-shim': 'util/iframe-shim/1.1.0/iframe-shim',
  'position': 'util/position/1.1.0/position',
  'messenger': 'util/messenger/2.1.0/messenger',
  'mask': 'common/overlay/1.2.0/mask',
  'overlay': 'common/overlay/1.2.0/overlay',
  'dialog': 'common/dialog/1.5.1/dialog',
  'confirmbox': 'common/dialog/1.5.1/confirmbox'
};

var startTime = Date.now();

// complete callback
function complete(){
  var now = new Date();

  console.log(
    '  %s [%s] build complete ... %s %s',
    colors.verbose('gulp-cmd'),
    now.toLocaleString(),
    colors.input(now - startTime),
    colors.info('ms')
  );
}

// clean task
gulp.task('clean', function (callback){
  rimraf('online', callback);
});

// runtime task
gulp.task('runtime', ['clean'], function (){
  gulp.src('assets/loader/**/*.js', { base: 'assets' })
    .pipe(uglify())
    .pipe(gulp.dest('online'));

  gulp.src('assets/?(loader|images)/**/*.!(js)', { base: 'assets' })
    .pipe(gulp.dest('online'));
});

// online task
gulp.task('online', ['runtime'], function (){
  // all js
  gulp.src('assets/js/**/*.js', { base: 'assets/js' })
    .pipe(transport({
      alias: alias,
      ignore: ['jquery'],
      include: function (id){
        return id.indexOf('view') === 0 ? 'all' : 'relative';
      },
      oncsspath: function (path){
        return path.replace('assets/', 'online/')
      }
    }))
    .pipe(uglify())
    .pipe(gulp.dest('online/js'))
    .on('end', complete);

  // other file
  gulp.src('assets/js/**/*.!(js|css|json|tpl|html)')
    .pipe(gulp.dest('online/js'));

  // css
  gulp.src('assets/css/**/*.*')
    .pipe(css({ compatibility: 'ie8' }))
    .pipe(gulp.dest('online/css'));
});

// develop task
gulp.task('default', ['runtime'], function (){
  // all file
  gulp.src('assets/js/**/*.*', { base: 'assets/js' })
    .pipe(transport({
      alias: alias,
      include: 'self',
      oncsspath: function (path){
        return path.replace('assets/', 'online/')
      }
    }))
    .pipe(gulp.dest('online/js'))
    .on('end', complete);

  gulp.src('assets/css/**/*.*', { base: 'assets' })
    .pipe(gulp.dest('online'));
});

// develop watch task
gulp.task('watch', ['default'], function (){
  var base = path.join(process.cwd(), 'assets');

  // watch all file
  gulp.watch('assets/js/**/*.*', function (e){
    if (e.type === 'deleted') {
      rimraf(path.resolve('online', path.relative(base, e.path)));
    } else {
      startTime = Date.now();

      gulp.src(e.path, { base: 'assets/js' })
        .pipe(plumber())
        .pipe(transport({
          alias: alias,
          include: 'self',
          cache: false,
          oncsspath: function (path){
            return path.replace('assets/', 'online/')
          }
        }))
        .pipe(gulp.dest('online/js'))
        .on('end', complete);
    }
  });

  // watch all file
  gulp.watch('assets/?(images|loader|css)/**/*.*', function (e){
    if (e.type === 'deleted') {
      rimraf(path.resolve('online', path.relative(base, e.path)));
    } else {
      startTime = Date.now();

      gulp.src(e.path, { base: 'assets' })
        .pipe(plumber())
        .pipe(gulp.dest('online'))
        .on('end', complete);
    }
  });
});
<|endoftext|>


<commit_before>"use strict";

angular.module("wuw.controllers")

.controller("LecturesWeeklyCtrl", function($scope, $ionicHistory, $ionicPopover, $state, $ionicPopup, $compile, $timeout, $filter, Lectures, Settings, uiCalendarConfig) {

    $scope.events = [];
    $scope.eventSource = [$scope.events];

    $scope.eventAfterRender = function(event, ele, view) {
        ionic.onGesture("tap", function(clickEvent) {

            // find the clicked calendar event
            var fci = clickEvent.currentTarget._fci;
            $scope.currEvent = $scope.events[fci];

            // use the fc-event-time div as popover position
            var target = clickEvent.currentTarget;
            var eventInner = target.childNodes[0];
            var eventTime = eventInner.childNodes[0];
            var relocated = clickEvent;
            relocated.currentTarget = eventTime;
            $scope.popover.show(eventTime);
        }, ele[0], {});
    };

    /* config object */
    $scope.uiConfig = {
        calendar: {
            allDaySlot: false,
            disableResizing:true,
            weekends: false, //TODO: look if we have a lecture on saturday, then set it to corresponding value
            minTime: "08:00:00",
            height: "9000",
            editable: false,
            defaultView: "agendaWeek",
            header: false,
            eventAfterRender: $scope.eventAfterRender
        }
    };

    $ionicPopover.fromTemplateUrl('templates/lecturePopover.html', {
        scope: $scope
    }).then(function(popover) {
        $scope.popover = popover;
    });

    /*
        used to assign events to the full calendar eventSource
        unfortunately: $scope.events = events; doesn't work
    */
    var assignEvents = function(events) {
        $scope.events.length = 0;
        for (var i = 0; i < events.length; i++) {
            $scope.events.push(events[i]);
        }
    };

    $scope.loadLectures = function() {
        Lectures.lecturesThisWeek().then(function(lectures){
            assignEvents(lectures);

            //hide an eventually shown error message
            $scope.$broadcast("czErrorMessage.hide");
        }, function(error) {
            if (error === "httpFailed") {
                // show the error message with some delay to prevent flickering
                $timeout(function() {
                    $scope.$broadcast("czErrorMessage.show");
                }, 300);
            }
        }).finally(function () {
            // remove the refresh spinner a little bit later to prevent flickering
            $timeout(function() {
                $scope.$broadcast("scroll.refreshComplete");
            }, 400);
        });
    };

    $scope.doRefresh = function() {
        $scope.loadLectures();
    };

    $scope.switchToList = function() {
        Settings.setSetting("lecturesView", "lecturesList");
        $ionicHistory.nextViewOptions({
            disableAnimate: true,
            disableBack: true
        });
        $state.go("tab.lecturesList", {location: "replace"});
    };

    $scope.$on('$ionicView.enter', function(){
        // get the number of selected lectures, if its zero, we display a message to select courses
        $scope.selectedLectures = JSON.parse(Settings.getSetting("selectedLectures") || "[]").length;

        // get lectures from cache, and if the cache is older then 10 seconds load from the API
        assignEvents(Lectures.fromCache("weekly"));
        if (Lectures.secondsSinceCache("weekly") > 10) {
            $scope.loadLectures();
        }
    });
});
<commit_msg>lecturesWeekly: clean up<commit_after>"use strict";

angular.module("wuw.controllers")

.controller("LecturesWeeklyCtrl", function($scope, $ionicHistory, $ionicPopover, $state, $ionicPopup, $compile, $timeout, $filter, Lectures, Settings, uiCalendarConfig) {

    $scope.events = [];
    $scope.eventSource = [$scope.events];

    $scope.eventAfterRender = function(event, ele, view) {
        ionic.onGesture("tap", function(clickEvent) {

            // find the clicked calendar event
            var fci = clickEvent.currentTarget._fci;
            $scope.currEvent = $scope.events[fci];

            // use the fc-event-time div as popover position
            var target = clickEvent.currentTarget;
            var eventInner = target.childNodes[0];
            var eventTime = eventInner.childNodes[0];
            $scope.popover.show(eventTime);
        }, ele[0], {});
    };

    /* config object */
    $scope.uiConfig = {
        calendar: {
            allDaySlot: false,
            disableResizing:true,
            weekends: false, //TODO: look if we have a lecture on saturday, then set it to corresponding value
            minTime: "08:00:00",
            height: "9000",
            editable: false,
            defaultView: "agendaWeek",
            header: false,
            eventAfterRender: $scope.eventAfterRender
        }
    };

    $ionicPopover.fromTemplateUrl('templates/lecturePopover.html', {
        scope: $scope
    }).then(function(popover) {
        $scope.popover = popover;
    });

    /*
        used to assign events to the full calendar eventSource
        unfortunately: $scope.events = events; doesn't work
    */
    var assignEvents = function(events) {
        $scope.events.length = 0;
        for (var i = 0; i < events.length; i++) {
            $scope.events.push(events[i]);
        }
    };

    $scope.loadLectures = function() {
        Lectures.lecturesThisWeek().then(function(lectures){
            assignEvents(lectures);

            //hide an eventually shown error message
            $scope.$broadcast("czErrorMessage.hide");
        }, function(error) {
            if (error === "httpFailed") {
                // show the error message with some delay to prevent flickering
                $timeout(function() {
                    $scope.$broadcast("czErrorMessage.show");
                }, 300);
            }
        }).finally(function () {
            // remove the refresh spinner a little bit later to prevent flickering
            $timeout(function() {
                $scope.$broadcast("scroll.refreshComplete");
            }, 400);
        });
    };

    $scope.doRefresh = function() {
        $scope.loadLectures();
    };

    $scope.switchToList = function() {
        Settings.setSetting("lecturesView", "lecturesList");
        $ionicHistory.nextViewOptions({
            disableAnimate: true,
            disableBack: true
        });
        $state.go("tab.lecturesList", {location: "replace"});
    };

    $scope.$on('$ionicView.enter', function(){
        // get the number of selected lectures, if its zero, we display a message to select courses
        $scope.selectedLectures = JSON.parse(Settings.getSetting("selectedLectures") || "[]").length;

        // get lectures from cache, and if the cache is older then 10 seconds load from the API
        assignEvents(Lectures.fromCache("weekly"));
        if (Lectures.secondsSinceCache("weekly") > 10) {
            $scope.loadLectures();
        }
    });
});
<|endoftext|>


<commit_before>import { compileToFunctions } from 'vue-template-compiler';
import mount from '../../../src/mount';
import Wrapper from '../../../src/Wrapper';

// Vue components for testing purposes
import Form from '../../resources/components/form/Form.vue';
import ClickComponent from '../../resources/components/event-components/ClickComponent.vue';
import ClickToggleComponent from '../../resources/components/event-components/ClickToggleComponent.vue';
import KeydownComponent from '../../resources/components/event-components/KeydownComponent.vue';
import Submit from '../../resources/components/form/Submit.vue';
import Paragraph from '../../resources/components/paragraph/Paragraph.vue';
import ComputedProperties from '../../resources/components/data-components/ComputedProperties.vue';
import Parent from '../../resources/components/nested-components/Parent.vue';
import SecondChild from '../../resources/components/nested-components/SecondChild.vue';
import Transition from '../../resources/components/nested-components/Transition.vue';
import SlotParent from '../../resources/components/slots/SlotParent.vue';

describe('Wrapper', () => {
  describe('find', () => {
    it('returns an array of Wrappers of elements matching tag selector passed', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);
      const divs = wrapper.find('p');
      expect(divs[0]).to.be.an.instanceOf(Wrapper);
      expect(divs.length).to.equal(2);
    });

    it('returns an array of Wrapper of elements matching class selector passed', () => {
      const wrapper = mount(Form);
      const input = wrapper.find('.input-text')[0];
      expect(input).to.be.an.instanceOf(Wrapper);
      expect(input.element.className).to.equal('input-text');
    });

    it('returns an array of Wrapper of elements matching class selector passed if they are nested in a transition', () => {
      const wrapper = mount(Transition);
      const children = wrapper.find('.child');
      expect(children.length).to.equal(3);
    });

    it('returns an array of Wrapper of elements matching class selector passed if they are declared inside a slot', () => {
      const wrapper = mount(SlotParent);
      const children = wrapper.find('.slot-footer-content');
      expect(children.length).to.equal(1);
    });

    it('returns an array of Wrappers of elements matching id selector passed', () => {
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];

      expect(input).to.be.an.instanceOf(Wrapper);
      expect(input.element.className).to.equal('input-text');
    });

    it('returns an array of Wrappers of elements matching attribute selector passed', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);
      expect(wrapper.find('[href="/"]').length).to.equal(1);
    });

    it('throws an error when passed an invalid DOM selector', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);
      const message = 'wrapper.find() must be passed a valid CSS selector or a Vue constructor';
      expect(() => wrapper.find('[href=&6"/"]')).to.throw(Error, message);
    });

    it('returns an array of Wrappers of elements matching selector with descendant combinator passed', () => {
      const compiled = compileToFunctions('

list
item

');
      const wrapper = mount(compiled);
      const divs = wrapper.find('div li');
      expect(divs[0]).to.be.an.instanceOf(Wrapper);
      expect(divs.length).to.equal(2);
    });

    it('does not return duplicate nodes', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);
      const divs = wrapper.find('div p');
      expect(divs[0]).to.be.an.instanceOf(Wrapper);
      expect(divs.length).to.equal(1);
    });

    it('returns an array of Wrappers of elements matching selector with direct descendant combinator passed', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);
      const divs = wrapper.find('div > ul');
      expect(divs[0]).to.be.an.instanceOf(Wrapper);
      expect(divs.length).to.equal(1);
    });

    it('returns an array of VueWrappers of Vue Components matching component', () => {
      const wrapper = mount(Parent);
      const secondChildComponents = wrapper.find(SecondChild);
      expect(secondChildComponents.length).to.equal(6);
    });

    it('returns array of VueWrappers of Vue Components matching component if component name in parent is different to filename', () => {
      const wrapper = mount(Form);
      const submit = wrapper.find(Submit);
      expect(submit.length).to.equal(1);
    });

    it('returns an array of VueWrappers of Vue Components matching component using dom node as reference', () => {
      const wrapper = mount(Parent);
      const div = wrapper.find('div')[0];
      const secondChildComponents = div.find(SecondChild);
      expect(secondChildComponents.length).to.equal(6);
    });

    it('returns an empty array if no nodes matching selector are found', () => {
      const wrapper = mount(Parent);
      const secondChildComponents = wrapper.find('pre');
      expect(secondChildComponents.length).to.equal(0);
    });

    it('throws an error if selector is not a valid avoriaz selector', () => {
      const wrapper = mount(Parent);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, { name: undefined }, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.find() must be passed a valid CSS selector or a Vue constructor';
        expect(() => wrapper.find(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('contains', () => {
    it('returns true if wrapper contains element', () => {
      const wrapper = mount(Form);
      expect(wrapper.contains('input')).to.equal(true);
    });

    it('returns true if wrapper contains Vue component', () => {
      const wrapper = mount(Form);
      expect(wrapper.contains(Submit)).to.equal(true);
    });

    it('returns true if wrapper that is not a vue component contains Vue component', () => {
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];

      expect(input.contains(Submit)).to.equal(true);
    });

    it('returns false if wrapper does not contain element', () => {
      const wrapper = mount(Form);
      expect(wrapper.contains('doesntexist')).to.equal(false);
    });

    it('throws an error if selector is not a valid avoriaz selector', () => {
      const wrapper = mount(Form);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, { name: undefined }, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.find() must be passed a valid CSS selector or a Vue constructor';
        expect(() => wrapper.contains(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('hasClass', () => {
    it('returns true if wrapper has class name', () => {
      const wrapper = mount(Form);
      expect(wrapper.hasClass('form')).to.equal(true);
    });

    it('returns false if wrapper does not have class name', () => {
      const wrapper = mount(Form);
      expect(wrapper.hasClass('not-class-name')).to.equal(false);
    });

    it('throws an error if selector is not a string', () => {
      const wrapper = mount(Form);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.hasClass() must be passed a string';
        expect(() => wrapper.hasClass(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('simulate', () => {
    it('causes click handler to fire when wrapper.simulate("click") is called on a child node', () => {
      const childClickHandler = sinon.stub();
      const wrapper = mount(ClickComponent, {
        propsData: { childClickHandler, parentClickHandler: () => {} },
      });
      const button = wrapper.find('#button')[0];
      button.simulate('click');

      expect(childClickHandler).to.be.calledOnce;
    });

    it('causes click handler to fire when wrapper.simulate("click") is fired on root node', () => {
      const parentClickHandler = sinon.stub();
      const wrapper = mount(ClickComponent, {
        propsData: { childClickHandler: () => {}, parentClickHandler },
      });
      wrapper.simulate('click');

      expect(parentClickHandler).to.be.calledOnce;
    });

    it('causes keydown handler to fire when wrapper.simulate("keydown") is fired on root node', () => {
      const keydownHandler = sinon.stub();
      const wrapper = mount(KeydownComponent, {
        propsData: { keydownHandler },
      });
      wrapper.simulate('keydown');

      expect(keydownHandler).to.be.calledOnce;
    });

    it('causes DOM to update after clickHandler method that changes components data is called', () => {
      const wrapper = mount(ClickToggleComponent);

      expect(wrapper.hasClass('active')).to.equal(false);

      wrapper.simulate('click');

      expect(wrapper.hasClass('active')).to.equal(true);
    });

    it('throws an error if type is not a string', () => {
      const wrapper = mount(Form);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.simulate() must be passed a string';
        expect(() => wrapper.simulate(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('html', () => {
    it('returns a VueWrappers HTML as a string', () => {
      const expectedHtml = '<input id="input-submit" type="submit" class="input-submit">';
      const wrapper = mount(Submit);

      expect(wrapper.html()).to.equal(expectedHtml);
    });

    it('returns a Wrappers HTML as a string', () => {
      const expectedHtml = '<input id="input-text" type="text" class="input-text">';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];

      expect(input.html()).to.equal(expectedHtml);
    });
  });

  describe('is', () => {
    it('returns true if root node matches tag selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('input')).to.equal(true);
    });

    it('returns true if root node matches class selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('.input-submit')).to.equal(true);
    });

    it('returns true if root node matches id selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('#input-submit')).to.equal(true);
    });

    it('returns true if root node matches Vue Component selector', () => {
      const wrapper = mount(Form);
      const submit = wrapper.find(Submit)[0];
      expect(submit.is(Submit)).to.equal(true);
    });

    it('returns false if root node is not a Vue Component', () => {
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(input.is(Submit)).to.equal(false);
    });

    it('returns false if root node does not match tag selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('p')).to.equal(false);
    });

    it('returns false if root node does not match class selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('.p')).to.equal(false);
    });

    it('returns false if root node does not match id selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('#p')).to.equal(false);
    });

    it('throws an error if selector is not a valid avoriaz selector', () => {
      const wrapper = mount(Form);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, { name: undefined }, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.is() must be passed a valid CSS selector or a Vue constructor';
        expect(() => wrapper.is(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('isEmpty', () => {
    it('returns true if node is empty', () => {
      const wrapper = mount(Submit);

      expect(wrapper.isEmpty()).to.equal(true);
    });

    it('returns false if node contains other nodes', () => {
      const wrapper = mount(Form);

      expect(wrapper.isEmpty()).to.equal(false);
    });
  });

  describe('name', () => {
    it('returns the name of the component it was called on', () => {
      const wrapper = mount(Submit);
      expect(wrapper.name()).to.equal('Submit');
    });

    it('returns the tag name of the element if it is not a Vue component', () => {
      const wrapper = mount(Form);
      expect(wrapper.find('#input-text')[0].name()).to.equal('input');
    });
  });

  describe('text', () => {
    it('returns text content of wrapper node', () => {
      const text = 'test text prop';
      const wrapper = mount(Paragraph, { propsData: { text } });
      expect(wrapper.text()).to.equal(text);
    });
  });

  describe('data', () => {
    it('returns the data object of the Vue instance', () => {
      const wrapper = mount(ComputedProperties);
      expect(wrapper.data()).to.deep.equal(ComputedProperties.data());
    });

    it('throws an error if node is not a Vue instance', () => {
      const message = 'wrapper.data() can only be called on a Vue instance';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(() => input.data()).throw(Error, message);
    });
  });

  describe('computed', () => {
    it('returns the computed object of the Vue instance', () => {
      const wrapper = mount(ComputedProperties);
      expect(wrapper.computed()).to.deep.equal(ComputedProperties.computed);
    });

    it('throws an error if node is not a Vue instance', () => {
      const message = 'wrapper.computed() can only be called on a Vue instance';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(() => input.computed()).throw(Error, message);
    });
  });

  describe('methods', () => {
    it('returns the methods object of the Vue instance', () => {
      const wrapper = mount(ClickToggleComponent);
      expect(wrapper.methods()).to.deep.equal(ClickToggleComponent.methods);
    });

    it('throws an error if node is not a Vue instance', () => {
      const message = 'wrapper.methods() can only be called on a Vue instance';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(() => input.methods()).throw(Error, message);
    });
  });

  describe('propsData', () => {
    it('returns props object of the Vue instance', () => {
      const propsData = {
        childClickHandler: () => 'childClickHandler',
        parentClickHandler: () => 'parentClickHandler',
      };
      const wrapper = mount(ClickComponent, { propsData });
      expect(wrapper.propsData()).to.deep.equal(propsData);
    });

    it('throws an error if node is not a Vue instance', () => {
      const message = 'wrapper.propsData() can only be called on a Vue instance';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(() => input.propsData()).throw(Error, message);
    });
  });
});
<commit_msg>improve find duplicate node test case<commit_after>import { compileToFunctions } from 'vue-template-compiler';
import mount from '../../../src/mount';
import Wrapper from '../../../src/Wrapper';

// Vue components for testing purposes
import Form from '../../resources/components/form/Form.vue';
import ClickComponent from '../../resources/components/event-components/ClickComponent.vue';
import ClickToggleComponent from '../../resources/components/event-components/ClickToggleComponent.vue';
import KeydownComponent from '../../resources/components/event-components/KeydownComponent.vue';
import Submit from '../../resources/components/form/Submit.vue';
import Paragraph from '../../resources/components/paragraph/Paragraph.vue';
import ComputedProperties from '../../resources/components/data-components/ComputedProperties.vue';
import Parent from '../../resources/components/nested-components/Parent.vue';
import SecondChild from '../../resources/components/nested-components/SecondChild.vue';
import Transition from '../../resources/components/nested-components/Transition.vue';
import SlotParent from '../../resources/components/slots/SlotParent.vue';

describe('Wrapper', () => {
  describe('find', () => {
    it('returns an array of Wrappers of elements matching tag selector passed', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);
      const divs = wrapper.find('p');
      expect(divs[0]).to.be.an.instanceOf(Wrapper);
      expect(divs.length).to.equal(2);
    });

    it('returns an array of Wrapper of elements matching class selector passed', () => {
      const wrapper = mount(Form);
      const input = wrapper.find('.input-text')[0];
      expect(input).to.be.an.instanceOf(Wrapper);
      expect(input.element.className).to.equal('input-text');
    });

    it('returns an array of Wrapper of elements matching class selector passed if they are nested in a transition', () => {
      const wrapper = mount(Transition);
      const children = wrapper.find('.child');
      expect(children.length).to.equal(3);
    });

    it('returns an array of Wrapper of elements matching class selector passed if they are declared inside a slot', () => {
      const wrapper = mount(SlotParent);
      const children = wrapper.find('.slot-footer-content');
      expect(children.length).to.equal(1);
    });

    it('returns an array of Wrappers of elements matching id selector passed', () => {
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];

      expect(input).to.be.an.instanceOf(Wrapper);
      expect(input.element.className).to.equal('input-text');
    });

    it('returns an array of Wrappers of elements matching attribute selector passed', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);
      expect(wrapper.find('[href="/"]').length).to.equal(1);
    });

    it('throws an error when passed an invalid DOM selector', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);
      const message = 'wrapper.find() must be passed a valid CSS selector or a Vue constructor';
      expect(() => wrapper.find('[href=&6"/"]')).to.throw(Error, message);
    });

    it('returns an array of Wrappers of elements matching selector with descendant combinator passed', () => {
      const compiled = compileToFunctions('

list
item

');
      const wrapper = mount(compiled);
      const divs = wrapper.find('div li');
      expect(divs[0]).to.be.an.instanceOf(Wrapper);
      expect(divs.length).to.equal(2);
    });

    it('does not return duplicate nodes', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);console.log(wrapper);
      const divs = wrapper.find('div p');
      expect(divs[0]).to.be.an.instanceOf(Wrapper);
      expect(divs.length).to.equal(2);
    });

    it('returns an array of Wrappers of elements matching selector with direct descendant combinator passed', () => {
      const compiled = compileToFunctions('

');
      const wrapper = mount(compiled);
      const divs = wrapper.find('div > ul');
      expect(divs[0]).to.be.an.instanceOf(Wrapper);
      expect(divs.length).to.equal(1);
    });

    it('returns an array of VueWrappers of Vue Components matching component', () => {
      const wrapper = mount(Parent);
      const secondChildComponents = wrapper.find(SecondChild);
      expect(secondChildComponents.length).to.equal(6);
    });

    it('returns array of VueWrappers of Vue Components matching component if component name in parent is different to filename', () => {
      const wrapper = mount(Form);
      const submit = wrapper.find(Submit);
      expect(submit.length).to.equal(1);
    });

    it('returns an array of VueWrappers of Vue Components matching component using dom node as reference', () => {
      const wrapper = mount(Parent);
      const div = wrapper.find('div')[0];
      const secondChildComponents = div.find(SecondChild);
      expect(secondChildComponents.length).to.equal(6);
    });

    it('returns an empty array if no nodes matching selector are found', () => {
      const wrapper = mount(Parent);
      const secondChildComponents = wrapper.find('pre');
      expect(secondChildComponents.length).to.equal(0);
    });

    it('throws an error if selector is not a valid avoriaz selector', () => {
      const wrapper = mount(Parent);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, { name: undefined }, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.find() must be passed a valid CSS selector or a Vue constructor';
        expect(() => wrapper.find(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('contains', () => {
    it('returns true if wrapper contains element', () => {
      const wrapper = mount(Form);
      expect(wrapper.contains('input')).to.equal(true);
    });

    it('returns true if wrapper contains Vue component', () => {
      const wrapper = mount(Form);
      expect(wrapper.contains(Submit)).to.equal(true);
    });

    it('returns true if wrapper that is not a vue component contains Vue component', () => {
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];

      expect(input.contains(Submit)).to.equal(true);
    });

    it('returns false if wrapper does not contain element', () => {
      const wrapper = mount(Form);
      expect(wrapper.contains('doesntexist')).to.equal(false);
    });

    it('throws an error if selector is not a valid avoriaz selector', () => {
      const wrapper = mount(Form);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, { name: undefined }, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.find() must be passed a valid CSS selector or a Vue constructor';
        expect(() => wrapper.contains(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('hasClass', () => {
    it('returns true if wrapper has class name', () => {
      const wrapper = mount(Form);
      expect(wrapper.hasClass('form')).to.equal(true);
    });

    it('returns false if wrapper does not have class name', () => {
      const wrapper = mount(Form);
      expect(wrapper.hasClass('not-class-name')).to.equal(false);
    });

    it('throws an error if selector is not a string', () => {
      const wrapper = mount(Form);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.hasClass() must be passed a string';
        expect(() => wrapper.hasClass(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('simulate', () => {
    it('causes click handler to fire when wrapper.simulate("click") is called on a child node', () => {
      const childClickHandler = sinon.stub();
      const wrapper = mount(ClickComponent, {
        propsData: { childClickHandler, parentClickHandler: () => {} },
      });
      const button = wrapper.find('#button')[0];
      button.simulate('click');

      expect(childClickHandler).to.be.calledOnce;
    });

    it('causes click handler to fire when wrapper.simulate("click") is fired on root node', () => {
      const parentClickHandler = sinon.stub();
      const wrapper = mount(ClickComponent, {
        propsData: { childClickHandler: () => {}, parentClickHandler },
      });
      wrapper.simulate('click');

      expect(parentClickHandler).to.be.calledOnce;
    });

    it('causes keydown handler to fire when wrapper.simulate("keydown") is fired on root node', () => {
      const keydownHandler = sinon.stub();
      const wrapper = mount(KeydownComponent, {
        propsData: { keydownHandler },
      });
      wrapper.simulate('keydown');

      expect(keydownHandler).to.be.calledOnce;
    });

    it('causes DOM to update after clickHandler method that changes components data is called', () => {
      const wrapper = mount(ClickToggleComponent);

      expect(wrapper.hasClass('active')).to.equal(false);

      wrapper.simulate('click');

      expect(wrapper.hasClass('active')).to.equal(true);
    });

    it('throws an error if type is not a string', () => {
      const wrapper = mount(Form);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.simulate() must be passed a string';
        expect(() => wrapper.simulate(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('html', () => {
    it('returns a VueWrappers HTML as a string', () => {
      const expectedHtml = '<input id="input-submit" type="submit" class="input-submit">';
      const wrapper = mount(Submit);

      expect(wrapper.html()).to.equal(expectedHtml);
    });

    it('returns a Wrappers HTML as a string', () => {
      const expectedHtml = '<input id="input-text" type="text" class="input-text">';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];

      expect(input.html()).to.equal(expectedHtml);
    });
  });

  describe('is', () => {
    it('returns true if root node matches tag selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('input')).to.equal(true);
    });

    it('returns true if root node matches class selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('.input-submit')).to.equal(true);
    });

    it('returns true if root node matches id selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('#input-submit')).to.equal(true);
    });

    it('returns true if root node matches Vue Component selector', () => {
      const wrapper = mount(Form);
      const submit = wrapper.find(Submit)[0];
      expect(submit.is(Submit)).to.equal(true);
    });

    it('returns false if root node is not a Vue Component', () => {
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(input.is(Submit)).to.equal(false);
    });

    it('returns false if root node does not match tag selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('p')).to.equal(false);
    });

    it('returns false if root node does not match class selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('.p')).to.equal(false);
    });

    it('returns false if root node does not match id selector', () => {
      const wrapper = mount(Submit);
      expect(wrapper.is('#p')).to.equal(false);
    });

    it('throws an error if selector is not a valid avoriaz selector', () => {
      const wrapper = mount(Form);
      const invalidSelectors = [
        undefined, null, NaN, 0, 2, true, false, () => {}, {}, { name: undefined }, [],
      ];
      invalidSelectors.forEach((invalidSelector) => {
        const message = 'wrapper.is() must be passed a valid CSS selector or a Vue constructor';
        expect(() => wrapper.is(invalidSelector)).to.throw(Error, message);
      });
    });
  });

  describe('isEmpty', () => {
    it('returns true if node is empty', () => {
      const wrapper = mount(Submit);

      expect(wrapper.isEmpty()).to.equal(true);
    });

    it('returns false if node contains other nodes', () => {
      const wrapper = mount(Form);

      expect(wrapper.isEmpty()).to.equal(false);
    });
  });

  describe('name', () => {
    it('returns the name of the component it was called on', () => {
      const wrapper = mount(Submit);
      expect(wrapper.name()).to.equal('Submit');
    });

    it('returns the tag name of the element if it is not a Vue component', () => {
      const wrapper = mount(Form);
      expect(wrapper.find('#input-text')[0].name()).to.equal('input');
    });
  });

  describe('text', () => {
    it('returns text content of wrapper node', () => {
      const text = 'test text prop';
      const wrapper = mount(Paragraph, { propsData: { text } });
      expect(wrapper.text()).to.equal(text);
    });
  });

  describe('data', () => {
    it('returns the data object of the Vue instance', () => {
      const wrapper = mount(ComputedProperties);
      expect(wrapper.data()).to.deep.equal(ComputedProperties.data());
    });

    it('throws an error if node is not a Vue instance', () => {
      const message = 'wrapper.data() can only be called on a Vue instance';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(() => input.data()).throw(Error, message);
    });
  });

  describe('computed', () => {
    it('returns the computed object of the Vue instance', () => {
      const wrapper = mount(ComputedProperties);
      expect(wrapper.computed()).to.deep.equal(ComputedProperties.computed);
    });

    it('throws an error if node is not a Vue instance', () => {
      const message = 'wrapper.computed() can only be called on a Vue instance';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(() => input.computed()).throw(Error, message);
    });
  });

  describe('methods', () => {
    it('returns the methods object of the Vue instance', () => {
      const wrapper = mount(ClickToggleComponent);
      expect(wrapper.methods()).to.deep.equal(ClickToggleComponent.methods);
    });

    it('throws an error if node is not a Vue instance', () => {
      const message = 'wrapper.methods() can only be called on a Vue instance';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(() => input.methods()).throw(Error, message);
    });
  });

  describe('propsData', () => {
    it('returns props object of the Vue instance', () => {
      const propsData = {
        childClickHandler: () => 'childClickHandler',
        parentClickHandler: () => 'parentClickHandler',
      };
      const wrapper = mount(ClickComponent, { propsData });
      expect(wrapper.propsData()).to.deep.equal(propsData);
    });

    it('throws an error if node is not a Vue instance', () => {
      const message = 'wrapper.propsData() can only be called on a Vue instance';
      const wrapper = mount(Form);
      const input = wrapper.find('#input-text')[0];
      expect(() => input.propsData()).throw(Error, message);
    });
  });
});
<|endoftext|>