<commit_before>// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
import { get_version_timeline_content } from "./version_timeline_content_builder";

frappe.ui.form.NewTimeline = class {
	constructor(opts) {
		Object.assign(this, opts);
		this.make();
	}

	make() {
		this.timeline_wrapper = $(`<div class="new-timeline">`);
		this.timeline_items_wrapper = $(`<div class="timeline-items">`);
		this.timeline_actions_wrapper = $(`

		`);

		this.timeline_wrapper.append(this.timeline_actions_wrapper);
		this.timeline_wrapper.append(this.timeline_items_wrapper);

		this.parent.replaceWith(this.timeline_wrapper);
		this.timeline_items = [];
		this.render_timeline_items();
		this.setup_timeline_actions();
		this.setup_document_email_link();
	}

	refresh() {
		this.render_timeline_items();
	}

	setup_timeline_actions() {
		this.add_action_button(__('New Email'), () => this.compose_mail());
		if (frappe.boot.developer_mode) {
			this.timeline_actions_wrapper.append(`

					<input type="checkbox" class="custom-control-input" id="only-communication-switch">
					${__('Show Only Communications')}

`)
				.find('.custom-control-input')
				.change(e => {
					this.only_communication = e.target.checked;
					this.render_timeline_items();
				});
		}
	}

	setup_document_email_link() {
		let doc_info = this.doc_info || this.frm.get_docinfo();

		if (doc_info.document_email) {
			const link = `<a class="document-email-link">${doc_info.document_email}</a>`;
			const message = __("Send an email to {0} to link it here", [link.bold()]);

			this.document_email_link_wrapper = $(`

					${message}

			`);
			this.timeline_wrapper.prepend(this.document_email_link_wrapper);

			this.document_email_link_wrapper
				.find('.document-email-link')
				.on("click", e => {
					let text = $(e.target).text();
					frappe.utils.copy_to_clipboard(text);
				});
		}
	}

	add_action_button(label, action) {
		let action_btn = $(`<button class="btn btn-xs btn-default action-btn">${label}</button>`);
		action_btn.click(action);
		this.timeline_actions_wrapper.append(action_btn);
		return action_btn;
	}

	render_timeline_items() {
		this.timeline_items_wrapper.empty();
		this.timeline_items = [];
		this.doc_info = this.frm && this.frm.get_docinfo() || {};
		this.prepare_timeline_contents();

		this.timeline_items.sort((item1, item2) => new Date(item1.creation) - new Date(item2.creation));
		this.timeline_items.forEach(this.add_timeline_item.bind(this));
	}

	prepare_timeline_contents() {
		this.timeline_items.push(...this.get_communication_timeline_contents());
		this.timeline_items.push(...this.get_comment_timeline_contents());
		if (!this.only_communication) {
			this.timeline_items.push(...this.get_view_timeline_contents());
			this.timeline_items.push(...this.get_energy_point_timeline_contents());
			this.timeline_items.push(...this.get_version_timeline_contents());
			this.timeline_items.push(...this.get_share_timeline_contents());
		}
		// attachments
		// milestones
	}

	get_user_link(user) {
		const user_display_text = (frappe.user_info(user).fullname || '').bold();
		return frappe.utils.get_form_link('User', user, true, user_display_text);
	}

	add_timeline_item(item) {
		let timeline_item = this.get_timeline_item(item);
		this.timeline_items_wrapper.prepend(timeline_item);
		return timeline_item;
	}

	get_timeline_item(item) {
		const timeline_item = $(`<div class="timeline-item">`);

		if (item.icon) {
			timeline_item.append(`

					${frappe.utils.icon(item.icon, 'md')}

			`);
		} else if (item.timeline_indicator) {
			timeline_item.append(item.timeline_indicator);
		} else {
			timeline_item.append(`<div class="timeline-dot">`);
		}

		timeline_item.append(`<div class="timeline-content ${item.card ? 'frappe-card' : ''}">`);
		timeline_item.find('.timeline-content').append(item.content);
		if (!item.hide_timestamp && !item.card) {
			timeline_item.find('.timeline-content').append(`<div>${comment_when(item.creation)}</div>`);
		}
		return timeline_item;
	}

	get_view_timeline_contents() {
		let view_timeline_contents = [];
		(this.doc_info.views || []).forEach(view => {
			let view_content = `

						${__("{0} viewed", [this.get_user_link(view.owner)])}

			`;
			view_timeline_contents.push({
				creation: view.creation,
				content: view_content,
			});
		});
		return view_timeline_contents;
	}

	get_communication_timeline_contents() {
		let communication_timeline_contents = [];
		(this.doc_info.communications|| []).forEach(communication => {
			communication_timeline_contents.push({
				icon: 'mail',
				creation: communication.creation,
				card: true,
				content: this.get_communication_timeline_content(communication),
			});
		});
		return communication_timeline_contents;
	}

	get_communication_timeline_content(doc) {
		doc.owner = doc.sender;
		doc.user_full_name = doc.sender_full_name;
		let communication_content =  $(frappe.render_template('timeline_message_box', { doc }));
		this.setup_reply(communication_content, doc);
		return communication_content;
	}

	get_comment_timeline_contents() {
		let comment_timeline_contents = [];
		(this.doc_info.comments || []).forEach(comment => {
			comment_timeline_contents.push({
				icon: 'small-message',
				creation: comment.creation,
				card: true,
				content: this.get_comment_timeline_content(comment),
			});
		});
		return comment_timeline_contents;
	}

	get_comment_timeline_content(doc) {
		const comment_content = $(frappe.render_template('timeline_message_box', { doc }));
		this.setup_comment_actions(comment_content, doc);
		return comment_content;
	}

	get_version_timeline_contents() {
		let version_timeline_contents = [];
		(this.doc_info.versions || []).forEach(version => {
			const contents = get_version_timeline_content(version, this.frm);
			contents.forEach((content) => {
				version_timeline_contents.push({
					creation: version.creation,
					content: content,
				});
			});
		});
		return version_timeline_contents;
	}

	get_share_timeline_contents() {
		let share_timeline_contents = [];
		(this.doc_info.share_logs || []).forEach(share => {
			share_timeline_contents.push({
				creation: share.creation,
				content: share.content,
			});
		});
		return share_timeline_contents;
	}

	get_energy_point_timeline_contents() {
		let energy_point_timeline_contents = [];
		(this.doc_info.energy_point_logs || []).forEach(log => {
			let timeline_indicator = `

 0 ? 'appreciation': 'criticism'} bold">
				${log.points}

`;

			energy_point_timeline_contents.push({
				timeline_indicator: timeline_indicator,
				creation: log.creation,
				content: frappe.energy_points.format_form_log(log)
			});
		});
		return energy_point_timeline_contents;
	}

	setup_reply(communication_box, communication_doc) {
		let actions = communication_box.find('.actions');
		let reply = $(`<a class="action-btn reply">${frappe.utils.icon('reply', 'md')}</a>`).click(() => {
			this.compose_mail(communication_doc);
		});
		let reply_all = $(`<a class="action-btn reply-all">${frappe.utils.icon('reply-all', 'md')}</a>`).click(() => {
			this.compose_mail(communication_doc, true);
		});
		actions.append(reply);
		actions.append(reply_all);
	}

	compose_mail(communication_doc=null, reply_all=false) {
		const args = {
			doc: this.frm.doc,
			frm: this.frm,
			recipients: this.get_recipient(),
			is_a_reply: Boolean(communication_doc),
			title: communication_doc ? __('Reply') : null,
			last_email: communication_doc
		};

		if (communication_doc && reply_all) {
			args.cc = communication_doc.cc;
			args.bcc = communication_doc.bcc;
		}

		if (this.frm.doctype === "Communication") {
			args.txt = "";
			args.last_email = this.frm.doc;
			args.recipients = this.frm.doc.sender;
			args.subject = __("Re: {0}", [this.frm.doc.subject]);
		} else {
			const comment_value = frappe.markdown(this.frm.comment_box.get_value());
			args.txt = strip_html(comment_value) ? comment_value : '';
		}

		new frappe.views.CommunicationComposer(args);
	}

	get_recipient() {
		if (this.frm.email_field) {
			return this.frm.doc[this.frm.email_field];
		} else {
			return this.frm.doc.email_id || this.frm.doc.email || "";
		}
	}

	setup_comment_actions(comment_wrapper, doc) {
		let edit_wrapper = $(`<div class="comment-edit-box">`).hide();
		let edit_box = this.make_editable(edit_wrapper);
		let content_wrapper = comment_wrapper.find('.content');

		let delete_button = $(`
			<button class="btn btn-link action-btn icon-btn">
				${frappe.utils.icon('close', 'sm')}
			</button>
		`).click(() => this.delete_comment(doc.name));

		let dismiss_button = $(`
			<button class="btn btn-link action-btn icon-btn">
				${__('Dismiss')}
			</button>
		`).click(() => edit_button.toggle_edit_mode());
		dismiss_button.hide();

		edit_box.set_value(doc.content);

		edit_box.on_submit = (value) => {
			content_wrapper.empty();
			content_wrapper.append(value);
			edit_button.prop("disabled", true);
			edit_box.quill.enable(false);

			doc.content = value;
			this.update_comment(doc.name, value)
				.then(edit_button.toggle_edit_mode)
				.finally(() => {
					edit_button.prop("disabled", false);
					edit_box.quill.enable(true);
				});
		};

		content_wrapper.after(edit_wrapper);

		let edit_button = $(`<button class="btn btn-link action-btn">${__("Edit")}</a>`).click(() => {
			edit_button.edit_mode ? edit_box.submit() : edit_button.toggle_edit_mode();
		});

		edit_button.toggle_edit_mode = () => {
			edit_button.edit_mode = !edit_button.edit_mode;
			edit_button.text(edit_button.edit_mode ? __('Save') : __('Edit'));
			delete_button.toggle(!edit_button.edit_mode);
			dismiss_button.toggle(edit_button.edit_mode);
			edit_wrapper.toggle(edit_button.edit_mode);
			content_wrapper.toggle(!edit_button.edit_mode);
		};

		comment_wrapper.find('.actions').append(edit_button);
		comment_wrapper.find('.actions').append(dismiss_button);
		comment_wrapper.find('.actions').append(delete_button);
	}

	make_editable(container) {
		return frappe.ui.form.make_control({
			parent: container,
			df: {
				fieldtype: 'Comment',
				fieldname: 'comment',
				label: 'Comment'
			},
			// mentions: this.get_names_for_mentions(),
			render_input: true,
			only_input: true,
			no_wrapper: true
		});
	}

	update_comment(name, content) {
		return frappe.xcall('frappe.desk.form.utils.update_comment', { name, content })
			.then(() => {
				frappe.utils.play_sound('click');
			});
	}

	get_last_email(from_recipient) {
		let last_email = null;
		let communications = this.frm.get_docinfo().communications || [];
		let email = this.get_recipient();
		// REDESIGN TODO: What is this? Check again
		(communications.sort((a, b) =>  a.creation > b.creation ? -1 : 1 )).forEach(c => {
			if (c.communication_type === 'Communication' && c.communication_medium === "Email") {
				if (from_recipient) {
					if (c.sender.indexOf(email)!==-1) {
						last_email = c;
						return false;
					}
				} else {
					last_email = c;
					return false;
				}
			}

		});

		return last_email;
	}

	delete_comment(comment_name) {
		frappe.confirm(__('Delete comment?'), () => {
			return frappe.xcall("frappe.client.delete", {
				doctype: "Comment",
				name: comment_name
			}).then(() => {
				frappe.utils.play_sound("delete");
			});
		});
	}
};<commit_msg>fix: Show "Only Communication" switch if timeline has communications<commit_after>// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
import { get_version_timeline_content } from "./version_timeline_content_builder";

frappe.ui.form.NewTimeline = class {
	constructor(opts) {
		Object.assign(this, opts);
		this.make();
	}

	make() {
		this.timeline_wrapper = $(`<div class="new-timeline">`);
		this.timeline_items_wrapper = $(`<div class="timeline-items">`);
		this.timeline_actions_wrapper = $(`

		`);

		this.timeline_wrapper.append(this.timeline_actions_wrapper);
		this.timeline_wrapper.append(this.timeline_items_wrapper);

		this.parent.replaceWith(this.timeline_wrapper);
		this.timeline_items = [];
		this.render_timeline_items();
		this.setup_timeline_actions();
		this.setup_document_email_link();
	}

	refresh() {
		this.render_timeline_items();
	}

	setup_timeline_actions() {
		let doc_info = this.doc_info || this.frm.get_docinfo();
		this.add_action_button(__('New Email'), () => this.compose_mail());

		let has_communications = () => {
			let communications = doc_info.communications;
			let comments = doc_info.comments;
			return (communications || []).length || (comments || []).length;
		};

		if (has_communications()) {
			this.timeline_actions_wrapper.append(`

					<input type="checkbox" class="custom-control-input" id="only-communication-switch">

						${__('Show Only Communications')}

`)
				.find('.custom-control-input')
				.change(e => {
					this.only_communication = e.target.checked;
					this.render_timeline_items();
				});
		}
	}

	setup_document_email_link() {
		let doc_info = this.doc_info || this.frm.get_docinfo();

		if (doc_info.document_email) {
			const link = `<a class="document-email-link">${doc_info.document_email}</a>`;
			const message = __("Send an email to {0} to link it here", [link.bold()]);

			this.document_email_link_wrapper = $(`

					${message}

			`);
			this.timeline_wrapper.prepend(this.document_email_link_wrapper);

			this.document_email_link_wrapper
				.find('.document-email-link')
				.on("click", e => {
					let text = $(e.target).text();
					frappe.utils.copy_to_clipboard(text);
				});
		}
	}

	add_action_button(label, action) {
		let action_btn = $(`<button class="btn btn-xs btn-default action-btn">${label}</button>`);
		action_btn.click(action);
		this.timeline_actions_wrapper.append(action_btn);
		return action_btn;
	}

	render_timeline_items() {
		this.timeline_items_wrapper.empty();
		this.timeline_items = [];
		this.doc_info = this.frm && this.frm.get_docinfo() || {};
		this.prepare_timeline_contents();

		this.timeline_items.sort((item1, item2) => new Date(item1.creation) - new Date(item2.creation));
		this.timeline_items.forEach(this.add_timeline_item.bind(this));
	}

	prepare_timeline_contents() {
		this.timeline_items.push(...this.get_communication_timeline_contents());
		this.timeline_items.push(...this.get_comment_timeline_contents());
		if (!this.only_communication) {
			this.timeline_items.push(...this.get_view_timeline_contents());
			this.timeline_items.push(...this.get_energy_point_timeline_contents());
			this.timeline_items.push(...this.get_version_timeline_contents());
			this.timeline_items.push(...this.get_share_timeline_contents());
		}
		// attachments
		// milestones
	}

	get_user_link(user) {
		const user_display_text = (frappe.user_info(user).fullname || '').bold();
		return frappe.utils.get_form_link('User', user, true, user_display_text);
	}

	add_timeline_item(item) {
		let timeline_item = this.get_timeline_item(item);
		this.timeline_items_wrapper.prepend(timeline_item);
		return timeline_item;
	}

	get_timeline_item(item) {
		const timeline_item = $(`<div class="timeline-item">`);

		if (item.icon) {
			timeline_item.append(`

					${frappe.utils.icon(item.icon, 'md')}

			`);
		} else if (item.timeline_indicator) {
			timeline_item.append(item.timeline_indicator);
		} else {
			timeline_item.append(`<div class="timeline-dot">`);
		}

		timeline_item.append(`<div class="timeline-content ${item.card ? 'frappe-card' : ''}">`);
		timeline_item.find('.timeline-content').append(item.content);
		if (!item.hide_timestamp && !item.card) {
			timeline_item.find('.timeline-content').append(`<div>${comment_when(item.creation)}</div>`);
		}
		return timeline_item;
	}

	get_view_timeline_contents() {
		let view_timeline_contents = [];
		(this.doc_info.views || []).forEach(view => {
			let view_content = `

						${__("{0} viewed", [this.get_user_link(view.owner)])}

			`;
			view_timeline_contents.push({
				creation: view.creation,
				content: view_content,
			});
		});
		return view_timeline_contents;
	}

	get_communication_timeline_contents() {
		let communication_timeline_contents = [];
		(this.doc_info.communications|| []).forEach(communication => {
			communication_timeline_contents.push({
				icon: 'mail',
				creation: communication.creation,
				card: true,
				content: this.get_communication_timeline_content(communication),
			});
		});
		return communication_timeline_contents;
	}

	get_communication_timeline_content(doc) {
		doc.owner = doc.sender;
		doc.user_full_name = doc.sender_full_name;
		let communication_content =  $(frappe.render_template('timeline_message_box', { doc }));
		this.setup_reply(communication_content, doc);
		return communication_content;
	}

	get_comment_timeline_contents() {
		let comment_timeline_contents = [];
		(this.doc_info.comments || []).forEach(comment => {
			comment_timeline_contents.push({
				icon: 'small-message',
				creation: comment.creation,
				card: true,
				content: this.get_comment_timeline_content(comment),
			});
		});
		return comment_timeline_contents;
	}

	get_comment_timeline_content(doc) {
		const comment_content = $(frappe.render_template('timeline_message_box', { doc }));
		this.setup_comment_actions(comment_content, doc);
		return comment_content;
	}

	get_version_timeline_contents() {
		let version_timeline_contents = [];
		(this.doc_info.versions || []).forEach(version => {
			const contents = get_version_timeline_content(version, this.frm);
			contents.forEach((content) => {
				version_timeline_contents.push({
					creation: version.creation,
					content: content,
				});
			});
		});
		return version_timeline_contents;
	}

	get_share_timeline_contents() {
		let share_timeline_contents = [];
		(this.doc_info.share_logs || []).forEach(share => {
			share_timeline_contents.push({
				creation: share.creation,
				content: share.content,
			});
		});
		return share_timeline_contents;
	}

	get_energy_point_timeline_contents() {
		let energy_point_timeline_contents = [];
		(this.doc_info.energy_point_logs || []).forEach(log => {
			let timeline_indicator = `

 0 ? 'appreciation': 'criticism'} bold">
				${log.points}

`;

			energy_point_timeline_contents.push({
				timeline_indicator: timeline_indicator,
				creation: log.creation,
				content: frappe.energy_points.format_form_log(log)
			});
		});
		return energy_point_timeline_contents;
	}

	setup_reply(communication_box, communication_doc) {
		let actions = communication_box.find('.actions');
		let reply = $(`<a class="action-btn reply">${frappe.utils.icon('reply', 'md')}</a>`).click(() => {
			this.compose_mail(communication_doc);
		});
		let reply_all = $(`<a class="action-btn reply-all">${frappe.utils.icon('reply-all', 'md')}</a>`).click(() => {
			this.compose_mail(communication_doc, true);
		});
		actions.append(reply);
		actions.append(reply_all);
	}

	compose_mail(communication_doc=null, reply_all=false) {
		const args = {
			doc: this.frm.doc,
			frm: this.frm,
			recipients: this.get_recipient(),
			is_a_reply: Boolean(communication_doc),
			title: communication_doc ? __('Reply') : null,
			last_email: communication_doc
		};

		if (communication_doc && reply_all) {
			args.cc = communication_doc.cc;
			args.bcc = communication_doc.bcc;
		}

		if (this.frm.doctype === "Communication") {
			args.txt = "";
			args.last_email = this.frm.doc;
			args.recipients = this.frm.doc.sender;
			args.subject = __("Re: {0}", [this.frm.doc.subject]);
		} else {
			const comment_value = frappe.markdown(this.frm.comment_box.get_value());
			args.txt = strip_html(comment_value) ? comment_value : '';
		}

		new frappe.views.CommunicationComposer(args);
	}

	get_recipient() {
		if (this.frm.email_field) {
			return this.frm.doc[this.frm.email_field];
		} else {
			return this.frm.doc.email_id || this.frm.doc.email || "";
		}
	}

	setup_comment_actions(comment_wrapper, doc) {
		let edit_wrapper = $(`<div class="comment-edit-box">`).hide();
		let edit_box = this.make_editable(edit_wrapper);
		let content_wrapper = comment_wrapper.find('.content');

		let delete_button = $(`
			<button class="btn btn-link action-btn icon-btn">
				${frappe.utils.icon('close', 'sm')}
			</button>
		`).click(() => this.delete_comment(doc.name));

		let dismiss_button = $(`
			<button class="btn btn-link action-btn icon-btn">
				${__('Dismiss')}
			</button>
		`).click(() => edit_button.toggle_edit_mode());
		dismiss_button.hide();

		edit_box.set_value(doc.content);

		edit_box.on_submit = (value) => {
			content_wrapper.empty();
			content_wrapper.append(value);
			edit_button.prop("disabled", true);
			edit_box.quill.enable(false);

			doc.content = value;
			this.update_comment(doc.name, value)
				.then(edit_button.toggle_edit_mode)
				.finally(() => {
					edit_button.prop("disabled", false);
					edit_box.quill.enable(true);
				});
		};

		content_wrapper.after(edit_wrapper);

		let edit_button = $(`<button class="btn btn-link action-btn">${__("Edit")}</a>`).click(() => {
			edit_button.edit_mode ? edit_box.submit() : edit_button.toggle_edit_mode();
		});

		edit_button.toggle_edit_mode = () => {
			edit_button.edit_mode = !edit_button.edit_mode;
			edit_button.text(edit_button.edit_mode ? __('Save') : __('Edit'));
			delete_button.toggle(!edit_button.edit_mode);
			dismiss_button.toggle(edit_button.edit_mode);
			edit_wrapper.toggle(edit_button.edit_mode);
			content_wrapper.toggle(!edit_button.edit_mode);
		};

		comment_wrapper.find('.actions').append(edit_button);
		comment_wrapper.find('.actions').append(dismiss_button);
		comment_wrapper.find('.actions').append(delete_button);
	}

	make_editable(container) {
		return frappe.ui.form.make_control({
			parent: container,
			df: {
				fieldtype: 'Comment',
				fieldname: 'comment',
				label: 'Comment'
			},
			// mentions: this.get_names_for_mentions(),
			render_input: true,
			only_input: true,
			no_wrapper: true
		});
	}

	update_comment(name, content) {
		return frappe.xcall('frappe.desk.form.utils.update_comment', { name, content })
			.then(() => {
				frappe.utils.play_sound('click');
			});
	}

	get_last_email(from_recipient) {
		let last_email = null;
		let communications = this.frm.get_docinfo().communications || [];
		let email = this.get_recipient();
		// REDESIGN TODO: What is this? Check again
		(communications.sort((a, b) =>  a.creation > b.creation ? -1 : 1 )).forEach(c => {
			if (c.communication_type === 'Communication' && c.communication_medium === "Email") {
				if (from_recipient) {
					if (c.sender.indexOf(email)!==-1) {
						last_email = c;
						return false;
					}
				} else {
					last_email = c;
					return false;
				}
			}

		});

		return last_email;
	}

	delete_comment(comment_name) {
		frappe.confirm(__('Delete comment?'), () => {
			return frappe.xcall("frappe.client.delete", {
				doctype: "Comment",
				name: comment_name
			}).then(() => {
				frappe.utils.play_sound("delete");
			});
		});
	}
};<|endoftext|>


<commit_before>/**
 * TodoApp Controller
 */
(function() {

    'use strict';

    angular
        .module('TodoApp.Controllers', [])
        .controller('AppController', AppController);

    function AppController($scope) {

        $scope.todos = []; // Todo list holder array
        $scope.completedTodoCount = function() {
            var count = 0;

            angular.forEach($scope.todos, function(val) {
                if (val.isChecked) {
                    ++count;
                }
            });

            return count;
        };

        /**
         * Function: AddTodo
         *
         * Add a new todo
         */
        $scope.AddTodo = function() {
            if ( ! $scope.todo.length) { return; } // If title is empty, then don't add anything in the array.

            var item = {
                title: $scope.todo,
                isChecked: false
            };

            $scope.todos.push(item); // I push lang... :)
            $scope.todo = '';
        };

        /**
         * Function: RemoveTodo
         *
         * Remove a todo
         *
         * Parameter:
         *
         *     (Integer) index - The array index
         */
        $scope.RemoveTodo = function(index) {
            $scope.todos.splice(index, 1);

        };

    }

})();<commit_msg>[CHORE] Updated templates<commit_after>/**
 * TodoApp Controller
 */
(function() {

    'use strict';

    angular
        .module('TodoApp.Controllers', [])
        .controller('AppController', AppController);

    function AppController($scope) {

        $scope.todos = []; // Todo list holder array
        $scope.completedTodoCount = function() {
            var count = 0;

            angular.forEach($scope.todos, function(val) {
                if (val.isChecked) {
                    ++count;
                }
            });

            return count;
        };

        /**
         * Function: AddTodo
         *
         * Add a new todo
         */
        $scope.AddTodo = function() {

            if ( ! $scope.todo.length) { return; } // If title is empty, then don't add anything in the array.

            var item = {
                title: $scope.todo,
                isChecked: false
            };

            $scope.todos.push(item); // I push lang... :)
            $scope.todo = '';

        };

        /**
         * Function: RemoveTodo
         *
         * Remove a todo
         *
         * Parameter:
         *
         *     (Integer) index - The array index
         */
        $scope.RemoveTodo = function(index) {
            $scope.todos.splice(index, 1);

        };

    }

})();<|endoftext|>


<commit_before>$(document).ready(function(){
  init_madness();
});

function init_madness(){
  var canvas = document.getElementById("mad"),
  ctx = canvas.getContext("2d"),
  letters = [],
  phrases = ["Login", "March Madness", "Rock", "Paper", "Scissor"];

  for(var i = 97; i < 122; i++){
    letters.push(String.fromCharCode(i));
  }

  if(Math.floor(Math.random(0, 2)) == 1){
    use_phrases(phrases);
  }else{
    use_letters(letters);
  }
}

function use_phrases(text){

}

function use_letters(text){

}
<commit_msg>fixing the script<commit_after>$(document).ready(function(){
  init_madness();
});

function init_madness(){
  var canvas = document.getElementById("mad"),
  ctx = canvas.getContext("2d"),
  letters = [],
  phrases = ["Login", "March Madness", "Rock", "Paper", "Scissor"];

  for(var i = 97; i < 122; i++){
    letters.push(String.fromCharCode(i));
  }

  if(Math.floor(Math.random(0, 2)) == 1){
    use_phrases(phrases, Math.floor(Math.random(0, 2)));
  }else{
    use_letters(letters, Math.floor(Math.random(0, 2)));
  }
}

function use_phrases(text, num){

}

function use_letters(text, num){

}
<|endoftext|>


<commit_before>import React from 'react'
import Modal from 'app/components/modal'
import Loading from 'app/components/loading'
import Error from 'app/components/error'
import ImageIcon from 'app/components/imageicon'
import IconIcon from 'app/components/iconicon'
import {goto} from 'app/utils/store'
import store from 'app/utils/store'
const icon = require("app/../imgs/services.svg")
import {get_service_data} from '../utils'
import PluginScreen from 'app/components/plugin/screen'

import Empty from 'app/components/empty'
import Settings from 'app/containers/service/settings'
import Logs from 'app/containers/service/logs'
import DetailsTab from './detailstab'
import ExternalUrl from './externalurl'
import {i18n} from 'app/utils/i18n'
import TabBar from 'app/components/tabbar'
import {match_traits} from 'app/utils'
import { colorize } from 'app/utils'
import {simple_tag} from '../utils'
import PropTypes from 'prop-types'

const tab_options={
  details: DetailsTab,
  settings: Settings,
  logs: Logs
}

function get_plugin_component({tab, type}, props){
  if (type!="screen")
    return null
  let sp=tab.split('/')
  return (props) => (
    <PluginScreen
      key={type}
      data={{service: props.service, project: props.project}}
      plugin={sp[0]}
      component={sp[1]}
      service={props.service}
      />
  )
}
function get_external_url_component({tab, type}, props){
  if (type!="external url")
    return null
  const url = get_external_url(tab, props)
  return (props) => (
    <ExternalUrl url={url}/>
  )
}

function get_external_url_template(id, props){
  for(let eu of (props.external_urls || [])){
    if (eu.id==id){
      return eu
    }
  }
  return null
}
function get_external_url(id, props){
  const eu=get_external_url_template(id, props)
  if (!eu)
    return null

  let url = eu.extra.url
  const config = props.service.config
  Object.keys(config).map((k) => {
    url = url.replace(`{config.${k}}`, config[k])
  })
  return url
}

class Details extends React.Component{
  constructor(props){
    super(props)
    this.state = {tab: "details", type: "internal"}
  }
  setTab({tab, type}){
    this.setState({tab, type})
  }
  handleTabChange(id, type){
    if (type=="screen"){
      this.setTab({tab: id, type: "screen"})
    }
    else if (type=="external url"){
      const euc = get_external_url_template(id, this.props)
      if (!euc.extra.iframe){
        const url = get_external_url(id, this.props)
        if (!url)
          console.warn("Invalid URL from %o", id)
        else
          window.open(url)
      }
      else{
        this.setTab({tab: id, type: "external url"})
      }
    }
    else{
      this.setTab({tab: id})
    }
  }
  componentDidMount(){
    this.setTab({tab: "details"})
  }
  render(){
    const props = this.props
    const state = this.state
    if (props.service == "error" || props.template == "error"){
      return (
        <Error>{i18n("Error loading service details. Maybe it does not exist or user has no permissions.")}</Error>
      )
    }
    if (props.loading){
      return (
        <Loading>{i18n("Service details")}</Loading>
      )
    }
    let current_tab = state.tab

    let sections=[
      { name: i18n("Details"), id: "details" },
      { name: i18n("Settings"), id: "settings" },
      { name: i18n("Logs"), id: "logs" },
    ];

    props.screens.map( (s) => {
      if (match_traits({has: s.traits, any: props.service.traits})){
        sections.push({
          name: s.name,
          id: s.id,
          description: s.description,
          type: "screen"
        })
      }
    });

    (props.external_urls || []).map( (u) => {
      sections.push({
        name: u.name,
        id: u.id,
        description: u.description,
        type: "external url",
        icon: !u.extra.iframe ? "external" : null
      })
    })
    let CurrentTab = (
      tab_options[current_tab] ||
      get_plugin_component(state, props) ||
      get_external_url_component(state, props) ||
      Empty
    )

    let handleClose = undefined
    if (props.project)
      handleClose = () => goto(`/project/${props.project.shortname}/services`)

    return (

          {props.template.icon ? (

              <IconIcon icon={props.template.icon} plugin={props.template.plugin}/>

          ) : (
            <ImageIcon src={icon} name={props.service.name}/>
          )}

{i18n(props.service.name)}

            {i18n(props.template.name)}

          <TabBar tabs={sections.map( s => ({
            key: s.id,
            label: s.name,
            icon: s.icon,
            onClick: () => this.handleTabChange(s.id, s.type),
            active: (s.id == current_tab),
            description: s.title
          }) ) } />

            {(props.service.tags || []).map( s => simple_tag(s)).map( s => (

                {s}
                <i className={`ui rectangular label ${ colorize( s ) }`}/>

            ))}

          <CurrentTab {...props} service={props.service} template={props.template} onClose={handleClose} />

    )
  }
}

Details.propTypes = {
  screens: PropTypes.arrayOf(PropTypes.object),
  service: PropTypes.shape({
    uuid: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired,
    description: PropTypes.string,
    config: PropTypes.object.isRequired,
  }).isRequired,
  template: PropTypes.shape({
    name: PropTypes.string.isRequired,
    description: PropTypes.string,
    icon: PropTypes.string,
  }).isRequired
}

export default Details
<commit_msg>Style improvements<commit_after>import React from 'react'
import Modal from 'app/components/modal'
import Loading from 'app/components/loading'
import Error from 'app/components/error'
import ImageIcon from 'app/components/imageicon'
import IconIcon from 'app/components/iconicon'
import {goto} from 'app/utils/store'
import store from 'app/utils/store'
const icon = require("app/../imgs/services.svg")
import {get_service_data} from '../utils'
import PluginScreen from 'app/components/plugin/screen'

import Empty from 'app/components/empty'
import Settings from 'app/containers/service/settings'
import Logs from 'app/containers/service/logs'
import DetailsTab from './detailstab'
import ExternalUrl from './externalurl'
import {i18n} from 'app/utils/i18n'
import TabBar from 'app/components/tabbar'
import {match_traits} from 'app/utils'
import { colorize } from 'app/utils'
import {simple_tag} from '../utils'
import PropTypes from 'prop-types'

const tab_options={
  details: DetailsTab,
  settings: Settings,
  logs: Logs
}

function get_plugin_component({tab, type}, props){
  if (type!="screen")
    return null
  let sp=tab.split('/')
  return (props) => (
    <PluginScreen
      key={type}
      data={{service: props.service, project: props.project}}
      plugin={sp[0]}
      component={sp[1]}
      service={props.service}
      />
  )
}
function get_external_url_component({tab, type}, props){
  if (type!="external url")
    return null
  const url = get_external_url(tab, props)
  return (props) => (
    <ExternalUrl url={url}/>
  )
}

function get_external_url_template(id, props){
  for(let eu of (props.external_urls || [])){
    if (eu.id==id){
      return eu
    }
  }
  return null
}
function get_external_url(id, props){
  const eu=get_external_url_template(id, props)
  if (!eu)
    return null

  let url = eu.extra.url
  const config = props.service.config
  Object.keys(config).map((k) => {
    url = url.replace(`{config.${k}}`, config[k])
  })
  return url
}

class Details extends React.Component{
  constructor(props){
    super(props)
    this.state = {tab: "details", type: "internal"}
  }
  setTab({tab, type}){
    this.setState({tab, type})
  }
  handleTabChange(id, type){
    if (type=="screen"){
      this.setTab({tab: id, type: "screen"})
    }
    else if (type=="external url"){
      const euc = get_external_url_template(id, this.props)
      if (!euc.extra.iframe){
        const url = get_external_url(id, this.props)
        if (!url)
          console.warn("Invalid URL from %o", id)
        else
          window.open(url)
      }
      else{
        this.setTab({tab: id, type: "external url"})
      }
    }
    else{
      this.setTab({tab: id})
    }
  }
  componentDidMount(){
    this.setTab({tab: "details"})
  }
  render(){
    const props = this.props
    const state = this.state
    if (props.service == "error" || props.template == "error"){
      return (
        <Error>{i18n("Error loading service details. Maybe it does not exist or user has no permissions.")}</Error>
      )
    }
    if (props.loading){
      return (
        <Loading>{i18n("Service details")}</Loading>
      )
    }
    let current_tab = state.tab

    let sections=[
      { name: i18n("Details"), id: "details" },
      { name: i18n("Settings"), id: "settings" },
      { name: i18n("Logs"), id: "logs" },
    ];

    props.screens.map( (s) => {
      if (match_traits({has: s.traits, any: props.service.traits})){
        sections.push({
          name: s.name,
          id: s.id,
          description: s.description,
          type: "screen"
        })
      }
    });

    (props.external_urls || []).map( (u) => {
      sections.push({
        name: u.name,
        id: u.id,
        description: u.description,
        type: "external url",
        icon: !u.extra.iframe ? "external" : null
      })
    })
    let CurrentTab = (
      tab_options[current_tab] ||
      get_plugin_component(state, props) ||
      get_external_url_component(state, props) ||
      Empty
    )

    let handleClose = undefined
    if (props.project)
      handleClose = () => goto(`/project/${props.project.shortname}/services`)

    return (

          {props.template.icon ? (

              <IconIcon icon={props.template.icon} plugin={props.template.plugin}/>

          ) : (
            <ImageIcon src={icon} name={props.service.name}/>
          )}

{i18n(props.service.name)}

            {i18n(props.template.name)}

          <TabBar tabs={sections.map( s => ({
            key: s.id,
            label: s.name,
            icon: s.icon,
            onClick: () => this.handleTabChange(s.id, s.type),
            active: (s.id == current_tab),
            description: s.title
          }) ) } />

            {(props.service.tags || []).map( s => simple_tag(s)).map( s => (

                {s}
                <i className={`ui rectangular label ${ colorize( s ) }`}/>

            ))}

          <CurrentTab {...props} service={props.service} template={props.template} onClose={handleClose} />

    )
  }
}

Details.propTypes = {
  screens: PropTypes.arrayOf(PropTypes.object),
  service: PropTypes.shape({
    uuid: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired,
    description: PropTypes.string,
    config: PropTypes.object.isRequired,
  }).isRequired,
  template: PropTypes.shape({
    name: PropTypes.string.isRequired,
    description: PropTypes.string,
    icon: PropTypes.string,
  }).isRequired
}

export default Details
<|endoftext|>


<commit_before>import Ember from 'ember';
import DS from 'ember-data';
import decorateAdapter from './base-store/decorate-adapter';
import decorateSerializer from './base-store/decorate-serializer';
import decorateAPICall from './base-store/decorate-api-call';

/**
  Base class for application store.
  service:store should point to instance of that class.

  @class Store
  @namespace Offline
  @extends DS.Store
*/
export default DS.Store.extend({
  /**
    Store that use for making requests in online mode.
    It can be specified in application that use offline mode support.
    If it is not specified then instance of DS.Store
    is set as value of this property during initialization of {{#crossLink "BaseStore"}}{{/crossLink}} class.

    @property onlineStore
    @type DS.Store
  */
  onlineStore: null,

  /**
    Store that use for making requests in offline mode.
    By default it is set to global instane of {{#crossLink "LocalStore"}}{{/crossLink}} class.

    @property offlineStore
    @type DS.Store
  */
  offlineStore: null,
  offlineGlobals: Ember.inject.service('offline-globals'),

  /**
    Global instance of {{#crossLink "Syncer"}}{{/crossLink}} class that contains methods to sync model.

    @property syncer
    @type Syncer
    @readOnly
  */
  syncer: Ember.inject.service('syncer'),

  /*
    Store initialization.
  */
  init() {
    this._super(...arguments);
    let owner = Ember.getOwner(this);

    // Set online store if it is not specified in application explicitly.
    if (Ember.isNone(this.get('onlineStore'))) {
      let onlineStore = DS.Store.create(owner.ownerInjection());
      this.set('onlineStore', onlineStore);
    }

    // Set offline store.
    let offlineStore = owner.lookup('store:local');
    this.set('offlineStore', offlineStore);
  },

  /**
    This method returns a fresh collection from the server, regardless of if there is already records
    in the store or not.
    @method findAll
    @param {String} modelName
    @param {Object} options
    @param {Boolean} [options.useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
  */
  findAll(modelName, options) {
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = !Ember.isEmpty(options) && !Ember.isEmpty(options.useOnlineStore) ? options.useOnlineStore : null;
    let useOnlineStoreCondition = (useOnlineStore === true) || (useOnlineStore === null && this._isOnline());
    return useOnlineStoreCondition ? this._decorateMethodAndCall('all', 'findAll', arguments, 1) : offlineStore.findAll.apply(offlineStore, arguments);
  },

  /**
   * This method returns a record for a given type and id combination.
   * NOTE: this will trigger syncUp twice, this is OK. And since this is
   *  a public method, we probably want to preserve this.
    @method findRecord
    @param {String} modelName
    @param {String|Integer} id
    @param {Object} options
    @param {Boolean} [options.useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
   */
  findRecord(modelName, id, options) {
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = !Ember.isEmpty(options) && !Ember.isEmpty(options.useOnlineStore) ? options.useOnlineStore : null;
    let useOnlineStoreCondition = (useOnlineStore === true) || (useOnlineStore === null && this._isOnline());
    return useOnlineStoreCondition ? this._decorateMethodAndCall('single', 'findRecord', arguments, 2) : offlineStore.findRecord.apply(offlineStore, arguments);
  },

  /**
    This method is called by the record's `reload` method.
    This method calls the adapter's `find` method, which returns a promise. When
    **that** promise resolves, `reloadRecord` will resolve the promise returned
    by the record's `reload`.
    @method reloadRecord
    @private
    @param {DS.Model} internalModel
    @return {Promise} promise
  */
  reloadRecord() {
    let offlineStore = this.get('offlineStore');
    return this._isOnline() ? this._decorateMethodAndCall('single', 'reloadRecord', arguments, -1) : offlineStore.reloadRecord.apply(offlineStore, arguments);
  },

  /**
    Query for records that meet certain criteria. Resolves with [DS.RecordArray](http://emberjs.com/api/data/classes/DS.RecordArray.html).
	For more information see [query method](http://emberjs.com/api/data/classes/DS.Store.html#method_query) of [DS.Store](http://emberjs.com/api/data/classes/DS.Store.html).
    @method query
    @param {String} modelName
    @param {Object} query
    @param {Boolean} [query.useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
  */
  query(modelName, query) {
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = !Ember.isEmpty(query) && !Ember.isEmpty(query.useOnlineStore) ? query.useOnlineStore : null;
    if (!Ember.isEmpty(query) && !Ember.isEmpty(query.useOnlineStore)) {
      delete query.useOnlineStore;
    }

    let useOnlineStoreCondition = (useOnlineStore === true) || (useOnlineStore === null && this._isOnline());
    return useOnlineStoreCondition ? this._decorateMethodAndCall('multiple', 'query', arguments, -1) : offlineStore.query.apply(offlineStore, arguments);
  },

  /**
    Query for record that meet certain criteria. Resolves with single record.
    @method query
    @param {String} modelName
    @param {Object} query
    @param {Boolean} [query.useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
  */
  queryRecord(modelName, query) {
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = !Ember.isEmpty(query) && !Ember.isEmpty(query.useOnlineStore) ? query.useOnlineStore : null;
    if (!Ember.isEmpty(query) && !Ember.isEmpty(query.useOnlineStore)) {
      delete query.useOnlineStore;
    }

    let useOnlineStoreCondition = (useOnlineStore === true) || (useOnlineStore === null && this._isOnline());
    return useOnlineStoreCondition ?
           this._decorateMethodAndCall('single', 'queryRecord', arguments, -1) :
           offlineStore.queryRecord.apply(offlineStore, arguments);
  },

  /**
    Create a new record in the current store. The properties passed to this method are set on the newly created record.
    @method createRecord
    @param {String} modelName
    @param {Object} inputProperties A hash of properties to set on the newly created record.
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
  */
  createRecord() {
    return this._callSuperMethod('createRecord', 2, arguments);
  },

  /**
    For symmetry, a record can be deleted via the store.
    @method deleteRecord
    @param {DS.Model} record
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
  */
  deleteRecord() {
    return this._callSuperMethod('deleteRecord', 1, arguments);
  },

  /**
    Get the reference for the specified record.
    @method getReference
    @param {String} type
    @param {String|Integer} id
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {RecordReference} promise
  */
  getReference() {
    return this._callSuperMethod('getReference', 2, arguments);
  },

  /**
    Returns true if a record for a given type and ID is already loaded.
    @method hasRecordForId
    @param {String|DS.Model} modelName
    @param {String|Integer} inputId
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Boolean}
  */
  hasRecordForId() {
    return this._callSuperMethod('hasRecordForId', 2, arguments);
  },

  /**
    Converts a json payload into the normalized form that {{#crossLink "BaseStore/push:method"}}{{/crossLink}} expects.
    @method normalize
    @param {String} modelName The name of the model type for this payload
    @param {Object} payload
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Object} The normalized payload
  */
  normalize() {
    return this._callSuperMethod('normalize', 2, arguments);
  },

  /**
    This method returns a filtered array that contains all of the known records for a given type in the store.
    @method peekAll
    @param {String} modelName
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.RecordArray}
  */
  peekAll() {
    return this._callSuperMethod('peekAll', 1, arguments);
  },

  /**
    Get a record by a given type and ID without triggering a fetch.
    @method peekRecord
    @param {String} modelName
    @param {String|Integer} id
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.Model|null} Record
  */
  peekRecord() {
    return this._callSuperMethod('peekRecord', 2, arguments);
  },

  /**
    Push some data for a given type into the store.
    @method push
    @param {Object} data
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.Model|Array} The record(s) that was created or updated.
  */
  push() {
    return this._callSuperMethod('push', 1, arguments);
  },

  /**
    Push some raw data into the store.
    @method pushPayload
    @param {String} modelName
    @param {Object} inputPayload
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
  */
  pushPayload() {
    return this._callSuperMethod('pushPayload', 2, arguments);
  },

  /**
    This method returns if a certain record is already loaded in the store.
    @method recordIsLoaded
    @param {String} modelName
    @param {String|Integer} id
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Boolean}
  */
  recordIsLoaded() {
    return this._callSuperMethod('recordIsLoaded', 2, arguments);
  },

  /**
    This method unloads all records in the store.
    @method unloadAll
    @param {String} modelName
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
  */
  unloadAll() {
    return this._callSuperMethod('unloadAll', 1, arguments);
  },

  /**
    For symmetry, a record can be unloaded via the store. Only non-dirty records can be unloaded.
    @method unloadRecord
    @param {DS.Model} record
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
  */
  unloadRecord() {
    return this._callSuperMethod('unloadRecord', 1, arguments);
  },

  /**
    Returns an instance of the adapter for a given type.
    @method adapterFor
    @param {String} modelName
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.Adapter or subclass} Adapter
  */
  adapterFor(modelName, useOnlineStore) {
    let onlineStore = this.get('onlineStore');
    let offlineStore = this.get('offlineStore');
    let adapter = onlineStore.adapterFor(modelName);
    if (this.get('offlineGlobals.isOfflineEnabled')) {
      let useOnlineStoreCondition = useOnlineStore || (Ember.isNone(useOnlineStore) && this._isOnline());
      return useOnlineStoreCondition ? decorateAdapter.call(this, adapter, modelName) : offlineStore.adapterFor(modelName);
    } else {
      return adapter;
    }
  },

  /**
    Returns an instance of the serializer for a given type.
    @method serializerFor
    @param {String} modelName
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.Serializer or subclass} Serializer
  */
  serializerFor(modelName, useOnlineStore) {
    let onlineStore = this.get('onlineStore');
    let offlineStore = this.get('offlineStore');
    let serializer = onlineStore.serializerFor(modelName);
    if (this.get('offlineGlobals.isOfflineEnabled')) {
      let useOnlineStoreCondition = useOnlineStore || (Ember.isNone(useOnlineStore) && this._isOnline());
      return useOnlineStoreCondition ? decorateSerializer.call(this, serializer, modelName) : offlineStore.serializerFor(modelName);
    } else {
      return serializer;
    }
  },

  /*
    Decorate specified method of online store for add extra syncing features.
  */
  _decorateMethodAndCall(finderType, originMethodName, originMethodArguments, optionsIndex) {
    let onlineStore = this.get('onlineStore');
    let originMethod = onlineStore[originMethodName];
    let decoratedMethod = decorateAPICall(finderType, originMethod);
    if (optionsIndex > -1) {
      let options = originMethodArguments[optionsIndex];
      options = this.get('offlineGlobals.isOfflineEnabled') ? options : Ember.$.extend(true, { bypass: true }, options);
      originMethodArguments[optionsIndex] = options;
    }

    return decoratedMethod.apply(onlineStore, originMethodArguments);
  },

  /*
    Detect global online status.
  */
  _isOnline() {
    return this.get('offlineGlobals.isOnline');
  },

  /*
    Pass control flow to online or offline store depend on global online status
    and explicitly specified store to use.
  */
  _callSuperMethod(methodName, useOnlineStoreParamNum, ...args) {
    let onlineStore = this.get('onlineStore');
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = (args[0].length - 1) >= useOnlineStoreParamNum ? args[0][useOnlineStoreParamNum] : null;
    let useOnlineStoreCondition = useOnlineStore || (Ember.isNone(useOnlineStore) && this._isOnline());
    let offlineEnabled = this.get('offlineGlobals.isOfflineEnabled');
    return !offlineEnabled || (offlineEnabled && useOnlineStoreCondition) ?
      onlineStore[methodName].apply(onlineStore, args[0]) :
      offlineStore[methodName].apply(offlineStore, args[0]);
  }
});
<commit_msg>Feature base-store support offline schema<commit_after>import Ember from 'ember';
import DS from 'ember-data';
import decorateAdapter from './base-store/decorate-adapter';
import decorateSerializer from './base-store/decorate-serializer';
import decorateAPICall from './base-store/decorate-api-call';

/**
  Base class for application store.
  service:store should point to instance of that class.

  @class Store
  @namespace Offline
  @extends DS.Store
*/
export default DS.Store.extend({
  /**
    Store offline schemas for all databases.

    @property _offlineSchema
    @type Object
    @private
    @default 'Schema of 1 version for internal models addon'
  */
  _offlineSchema: {
    'ember-flexberry-data': {
      1: {
        'i-c-s-soft-s-t-o-r-m-n-e-t-business-audit-objects-audit-entity':
          'id,objectPrimaryKey,operationTime,operationType,executionResult,source,serializedField,' +
          'createTime,creator,editTime,editor,user,objectType,*auditFields',
        'i-c-s-soft-s-t-o-r-m-n-e-t-business-audit-objects-audit-field':
          'id,field,caption,oldValue,newValue,mainChange,auditEntity',
        'i-c-s-soft-s-t-o-r-m-n-e-t-business-audit-objects-object-type':
          'id,name',
        'i-c-s-soft-s-t-o-r-m-n-e-t-security-agent':
          'id,name,login,pwd,isUser,isGroup,isRole,connString,enabled,email,full,read,insert,update,' +
          'delete,execute,createTime,creator,editTime,editor',
        'i-c-s-soft-s-t-o-r-m-n-e-t-security-link-group':
          'id,createTime,creator,editTime,editor,group,user',
        'i-c-s-soft-s-t-o-r-m-n-e-t-security-session':
          'id,userKey,startedAt,lastAccess,closed',
      },
    },
  },

  /**
    Store that use for making requests in online mode.
    It can be specified in application that use offline mode support.
    If it is not specified then instance of DS.Store
    is set as value of this property during initialization of {{#crossLink "BaseStore"}}{{/crossLink}} class.

    @property onlineStore
    @type DS.Store
  */
  onlineStore: null,

  /**
    Store that use for making requests in offline mode.
    By default it is set to global instane of {{#crossLink "LocalStore"}}{{/crossLink}} class.

    @property offlineStore
    @type DS.Store
  */
  offlineStore: null,
  offlineGlobals: Ember.inject.service('offline-globals'),

  /**
    Set schema for your database.

    @example
      ```javascript
      // app/services/store.js
      ...
        init() {
          this.set('offlineSchema', {
            <name of database>: {
              <number of version>: {
                <name of model>: <table definition>,
              },
            },
            dbName: {
              1: {
                modelName: 'id,attribute1,attribute2,belongsToRelationship1,belongsToRelationship2,*hasManyRelationship1,*hasManyRelationship2',
                changedModelName: 'id,attribute1,attribute2',
                thisModelWillBeRemovedInNextVersion: 'id,attribute1',
              },
              2: {
                newModelName: 'id,attribute1',
                changedModelName: 'id,attribute1,attribute3,attribute4',
                thisModelWillBeRemovedInNextVersion: null,
              },
            },
          });
          return this._super(...arguments);
        },
      ...
      ```

    @property offlineSchema
    @type Object
  */
  offlineSchema: Ember.computed({
    get() {
      return this.get('_offlineSchema');
    },
    set(key, value) {
      let offlineSchema = this.get('offlineSchema');
      for (let db in value) {
        if (offlineSchema.hasOwnProperty(db)) {
          for (let version in value[db]) {
            let schema = offlineSchema[db][version] || {};
            offlineSchema[db][version] = Ember.merge(schema, value[db][version]);
          }
        } else {
          offlineSchema[db] = value[db];
        }
      }

      return this.set('_offlineSchema', offlineSchema);
    },
  }),

  /**
    Global instance of {{#crossLink "Syncer"}}{{/crossLink}} class that contains methods to sync model.

    @property syncer
    @type Syncer
    @readOnly
  */
  syncer: Ember.inject.service('syncer'),

  /*
    Store initialization.
  */
  init() {
    this._super(...arguments);
    let owner = Ember.getOwner(this);

    // Set online store if it is not specified in application explicitly.
    if (Ember.isNone(this.get('onlineStore'))) {
      let onlineStore = DS.Store.create(owner.ownerInjection());
      this.set('onlineStore', onlineStore);
    }

    // Set offline store.
    let offlineStore = owner.lookup('store:local');
    this.set('offlineStore', offlineStore);
  },

  /**
    This method returns a fresh collection from the server, regardless of if there is already records
    in the store or not.
    @method findAll
    @param {String} modelName
    @param {Object} options
    @param {Boolean} [options.useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
  */
  findAll(modelName, options) {
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = !Ember.isEmpty(options) && !Ember.isEmpty(options.useOnlineStore) ? options.useOnlineStore : null;
    let useOnlineStoreCondition = (useOnlineStore === true) || (useOnlineStore === null && this._isOnline());
    return useOnlineStoreCondition ? this._decorateMethodAndCall('all', 'findAll', arguments, 1) : offlineStore.findAll.apply(offlineStore, arguments);
  },

  /**
   * This method returns a record for a given type and id combination.
   * NOTE: this will trigger syncUp twice, this is OK. And since this is
   *  a public method, we probably want to preserve this.
    @method findRecord
    @param {String} modelName
    @param {String|Integer} id
    @param {Object} options
    @param {Boolean} [options.useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
   */
  findRecord(modelName, id, options) {
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = !Ember.isEmpty(options) && !Ember.isEmpty(options.useOnlineStore) ? options.useOnlineStore : null;
    let useOnlineStoreCondition = (useOnlineStore === true) || (useOnlineStore === null && this._isOnline());
    return useOnlineStoreCondition ? this._decorateMethodAndCall('single', 'findRecord', arguments, 2) : offlineStore.findRecord.apply(offlineStore, arguments);
  },

  /**
    This method is called by the record's `reload` method.
    This method calls the adapter's `find` method, which returns a promise. When
    **that** promise resolves, `reloadRecord` will resolve the promise returned
    by the record's `reload`.
    @method reloadRecord
    @private
    @param {DS.Model} internalModel
    @return {Promise} promise
  */
  reloadRecord() {
    let offlineStore = this.get('offlineStore');
    return this._isOnline() ? this._decorateMethodAndCall('single', 'reloadRecord', arguments, -1) : offlineStore.reloadRecord.apply(offlineStore, arguments);
  },

  /**
    Query for records that meet certain criteria. Resolves with [DS.RecordArray](http://emberjs.com/api/data/classes/DS.RecordArray.html).
	For more information see [query method](http://emberjs.com/api/data/classes/DS.Store.html#method_query) of [DS.Store](http://emberjs.com/api/data/classes/DS.Store.html).
    @method query
    @param {String} modelName
    @param {Object} query
    @param {Boolean} [query.useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
  */
  query(modelName, query) {
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = !Ember.isEmpty(query) && !Ember.isEmpty(query.useOnlineStore) ? query.useOnlineStore : null;
    if (!Ember.isEmpty(query) && !Ember.isEmpty(query.useOnlineStore)) {
      delete query.useOnlineStore;
    }

    let useOnlineStoreCondition = (useOnlineStore === true) || (useOnlineStore === null && this._isOnline());
    return useOnlineStoreCondition ? this._decorateMethodAndCall('multiple', 'query', arguments, -1) : offlineStore.query.apply(offlineStore, arguments);
  },

  /**
    Query for record that meet certain criteria. Resolves with single record.
    @method query
    @param {String} modelName
    @param {Object} query
    @param {Boolean} [query.useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
  */
  queryRecord(modelName, query) {
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = !Ember.isEmpty(query) && !Ember.isEmpty(query.useOnlineStore) ? query.useOnlineStore : null;
    if (!Ember.isEmpty(query) && !Ember.isEmpty(query.useOnlineStore)) {
      delete query.useOnlineStore;
    }

    let useOnlineStoreCondition = (useOnlineStore === true) || (useOnlineStore === null && this._isOnline());
    return useOnlineStoreCondition ?
           this._decorateMethodAndCall('single', 'queryRecord', arguments, -1) :
           offlineStore.queryRecord.apply(offlineStore, arguments);
  },

  /**
    Create a new record in the current store. The properties passed to this method are set on the newly created record.
    @method createRecord
    @param {String} modelName
    @param {Object} inputProperties A hash of properties to set on the newly created record.
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Promise} promise
  */
  createRecord() {
    return this._callSuperMethod('createRecord', 2, arguments);
  },

  /**
    For symmetry, a record can be deleted via the store.
    @method deleteRecord
    @param {DS.Model} record
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
  */
  deleteRecord() {
    return this._callSuperMethod('deleteRecord', 1, arguments);
  },

  /**
    Get the reference for the specified record.
    @method getReference
    @param {String} type
    @param {String|Integer} id
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {RecordReference} promise
  */
  getReference() {
    return this._callSuperMethod('getReference', 2, arguments);
  },

  /**
    Returns true if a record for a given type and ID is already loaded.
    @method hasRecordForId
    @param {String|DS.Model} modelName
    @param {String|Integer} inputId
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Boolean}
  */
  hasRecordForId() {
    return this._callSuperMethod('hasRecordForId', 2, arguments);
  },

  /**
    Converts a json payload into the normalized form that {{#crossLink "BaseStore/push:method"}}{{/crossLink}} expects.
    @method normalize
    @param {String} modelName The name of the model type for this payload
    @param {Object} payload
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Object} The normalized payload
  */
  normalize() {
    return this._callSuperMethod('normalize', 2, arguments);
  },

  /**
    This method returns a filtered array that contains all of the known records for a given type in the store.
    @method peekAll
    @param {String} modelName
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.RecordArray}
  */
  peekAll() {
    return this._callSuperMethod('peekAll', 1, arguments);
  },

  /**
    Get a record by a given type and ID without triggering a fetch.
    @method peekRecord
    @param {String} modelName
    @param {String|Integer} id
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.Model|null} Record
  */
  peekRecord() {
    return this._callSuperMethod('peekRecord', 2, arguments);
  },

  /**
    Push some data for a given type into the store.
    @method push
    @param {Object} data
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.Model|Array} The record(s) that was created or updated.
  */
  push() {
    return this._callSuperMethod('push', 1, arguments);
  },

  /**
    Push some raw data into the store.
    @method pushPayload
    @param {String} modelName
    @param {Object} inputPayload
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
  */
  pushPayload() {
    return this._callSuperMethod('pushPayload', 2, arguments);
  },

  /**
    This method returns if a certain record is already loaded in the store.
    @method recordIsLoaded
    @param {String} modelName
    @param {String|Integer} id
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {Boolean}
  */
  recordIsLoaded() {
    return this._callSuperMethod('recordIsLoaded', 2, arguments);
  },

  /**
    This method unloads all records in the store.
    @method unloadAll
    @param {String} modelName
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
  */
  unloadAll() {
    return this._callSuperMethod('unloadAll', 1, arguments);
  },

  /**
    For symmetry, a record can be unloaded via the store. Only non-dirty records can be unloaded.
    @method unloadRecord
    @param {DS.Model} record
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
  */
  unloadRecord() {
    return this._callSuperMethod('unloadRecord', 1, arguments);
  },

  /**
    Returns an instance of the adapter for a given type.
    @method adapterFor
    @param {String} modelName
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.Adapter or subclass} Adapter
  */
  adapterFor(modelName, useOnlineStore) {
    let onlineStore = this.get('onlineStore');
    let offlineStore = this.get('offlineStore');
    let adapter = onlineStore.adapterFor(modelName);
    if (this.get('offlineGlobals.isOfflineEnabled')) {
      let useOnlineStoreCondition = useOnlineStore || (Ember.isNone(useOnlineStore) && this._isOnline());
      return useOnlineStoreCondition ? decorateAdapter.call(this, adapter, modelName) : offlineStore.adapterFor(modelName);
    } else {
      return adapter;
    }
  },

  /**
    Returns an instance of the serializer for a given type.
    @method serializerFor
    @param {String} modelName
    @param {Boolean} [useOnlineStore] Allow to explicitly specify online or offline store using independently of global online status
    @return {DS.Serializer or subclass} Serializer
  */
  serializerFor(modelName, useOnlineStore) {
    let onlineStore = this.get('onlineStore');
    let offlineStore = this.get('offlineStore');
    let serializer = onlineStore.serializerFor(modelName);
    if (this.get('offlineGlobals.isOfflineEnabled')) {
      let useOnlineStoreCondition = useOnlineStore || (Ember.isNone(useOnlineStore) && this._isOnline());
      return useOnlineStoreCondition ? decorateSerializer.call(this, serializer, modelName) : offlineStore.serializerFor(modelName);
    } else {
      return serializer;
    }
  },

  /*
    Decorate specified method of online store for add extra syncing features.
  */
  _decorateMethodAndCall(finderType, originMethodName, originMethodArguments, optionsIndex) {
    let onlineStore = this.get('onlineStore');
    let originMethod = onlineStore[originMethodName];
    let decoratedMethod = decorateAPICall(finderType, originMethod);
    if (optionsIndex > -1) {
      let options = originMethodArguments[optionsIndex];
      options = this.get('offlineGlobals.isOfflineEnabled') ? options : Ember.$.extend(true, { bypass: true }, options);
      originMethodArguments[optionsIndex] = options;
    }

    return decoratedMethod.apply(onlineStore, originMethodArguments);
  },

  /*
    Detect global online status.
  */
  _isOnline() {
    return this.get('offlineGlobals.isOnline');
  },

  /*
    Pass control flow to online or offline store depend on global online status
    and explicitly specified store to use.
  */
  _callSuperMethod(methodName, useOnlineStoreParamNum, ...args) {
    let onlineStore = this.get('onlineStore');
    let offlineStore = this.get('offlineStore');
    let useOnlineStore = (args[0].length - 1) >= useOnlineStoreParamNum ? args[0][useOnlineStoreParamNum] : null;
    let useOnlineStoreCondition = useOnlineStore || (Ember.isNone(useOnlineStore) && this._isOnline());
    let offlineEnabled = this.get('offlineGlobals.isOfflineEnabled');
    return !offlineEnabled || (offlineEnabled && useOnlineStoreCondition) ?
      onlineStore[methodName].apply(onlineStore, args[0]) :
      offlineStore[methodName].apply(offlineStore, args[0]);
  }
});
<|endoftext|>


<commit_before>import resolver from './helpers/resolver';
import {
  setResolver
} from 'ember-qunit';
import { start } from 'ember-cli-qunit';
import './helpers/flash-message';

setResolver(resolver);
start();
<commit_msg>Add loadEmberExam to test-helper<commit_after>import resolver from './helpers/resolver';
import {
  setResolver
} from 'ember-qunit';
import { start } from 'ember-cli-qunit';
import './helpers/flash-message';
import loadEmberExam from 'ember-exam/test-support/load';

loadEmberExam();
setResolver(resolver);
start();
<|endoftext|>


<commit_before>"use strict";
var sanitizeHtml = require('sanitize-html');
var htmlNamesToColorCodes = {
    white: '\u000300',
    black: '\u000301',
    navy: '\u000302',
    green: '\u000303',
    maroon: '\u000304',
    red: '\u000305',
    purple: '\u000306',
    olive: '\u000307',
    yellow: '\u000308',
    lime: '\u000309',
    teal: '\u000310',
    aqua: '\u000311',
    blue: '\u000312',
    fuchsia: '\u000313',
    gray: '\u000314',
    silver: '\u000315'
};
// store the reverse mapping
var colorCodesToHtmlNames = {};
var htmlNames = Object.keys(htmlNamesToColorCodes);
for (var i=0; i<htmlNames.length; i++) {
    var htmlName = htmlNames[i];
    colorCodesToHtmlNames[htmlNamesToColorCodes[htmlName]] = htmlName;
}

var STYLE_BOLD = '\u0002';
var STYLE_ITALICS = '\u001d';
var STYLE_UNDERLINE = '\u001f';
var STYLE_CODES = [STYLE_BOLD, STYLE_ITALICS, STYLE_UNDERLINE];
var RESET_CODE = '\u000f';

module.exports.htmlToIrc = function(html) {
    if (!html) {
        return html;
    }

    // Sanitize the HTML first to allow us to regex parse this (which also does
    // things like case-sensitivity and spacing)
    var cleanHtml = sanitizeHtml(html, {
        allowedTags: ["b", "i", "u", "strong", "font"],
        allowedAttributes: {
            font: ["color"]
        }
    });

    // noddy find/replace on OPEN tags is possible now
    var replacements = [
        [//g, STYLE_BOLD], [//g, STYLE_UNDERLINE], [//g, STYLE_ITALICS],
        [//g, STYLE_BOLD]
    ];
    Object.keys(htmlNamesToColorCodes).forEach(function(htmlColor) {
        replacements.push([
            new RegExp('', 'g'),
            htmlNamesToColorCodes[htmlColor]
        ]);
    });
    for (var i=0; i<replacements.length; i++) {
        var rep = replacements[i];
        cleanHtml = cleanHtml.replace(rep[0], rep[1]);
    }
    // this needs a single pass through to fix up the reset codes, as they
    // 'close' all open tags. This pass through checks which tags are open and
    // then reopens them after a reset code.
    var openStyleCodes = [];
    var openColorCode = null;
    var closeTagsToStyle = {
        "": STYLE_BOLD,
        "": STYLE_UNDERLINE,
        "": STYLE_ITALICS,
        "": STYLE_BOLD
    };
    var closeTags = Object.keys(closeTagsToStyle);
    var replacement;
    for (var i=0; i<cleanHtml.length; i++) {
        var ch = cleanHtml[i];
        if (STYLE_CODES.indexOf(ch) >= 0) {
            openStyleCodes.push(ch);
        }
        else if (colorCodesToHtmlNames[ch]) {
            openColorCode = ch;
        }
        else if (ch === "<") {
            if (cleanHtml.indexOf("", i) === i) {
                replacement = RESET_CODE + openStyleCodes.join("");
                cleanHtml = cleanHtml.replace(
                    "", replacement
                );
                openColorCode = null;
                i += (replacement.length-1);
            }
            else {
                for (var j=0; j<closeTags.length; j++) {
                    var closeTag = closeTags[j];
                    if (cleanHtml.indexOf(closeTag, i) === i) {
                        // replace close tag with a reset and pop off the open
                        // formatting code, then reopen remaining tags
                        openStyleCodes.splice(openStyleCodes.indexOf(
                            closeTagsToStyle[closeTag]
                        ), 1);
                        replacement = RESET_CODE + openStyleCodes.join("");
                        cleanHtml = cleanHtml.replace(
                            closeTag, replacement
                        );
                        i += (replacement.length-1);
                    }
                }
            }
        }
    }
    // unescape html characters
    var escapeChars = [
        [/>/g, '>'], [/</g, '<'], [/"/g, '"'], [/&/g, '&']
    ];
    escapeChars.forEach(function(escapeSet) {
        cleanHtml = cleanHtml.replace(escapeSet[0], escapeSet[1]);
    });

    return cleanHtml;
};

module.exports.ircToHtml = function(text) {
    // Color codes look like 003xx or 003xx,yy (xx=foreground, yy=background)
    // We want to match until it hits another color (starting 003) or hits the
    // reset code 000f. That is the 'end tag', represented as a non-greedy match
    // for the reset code, or any character until 003.
    //
    //                  Foreground          Background      End 'tag'
    //                 ______|_______       ____|____    _______|________
    //                /              \     /         \  /                \
    var colorRegex = /(\003[0-9]{1,2})[,]?([0-9]{1,2})?(.*?\u000f|[^\003]+)/;
    var groups;
    if (colorRegex.test(text)) {
        while (groups = colorRegex.exec(text)) {
            // ignore bg for now (groups[2])

            // this text includes the reset code so the code can be applied for
            // each formatting code. We'll strip it later on.
            var coloredText = groups[3];
            text = text.replace(
                groups[0],
                ''+
                coloredText+
                ''
            );
        }
    }

    // styles: bold, italics, underline
    var styleCodes = [
        [/\x02(.*?\x0f|[^\x02]+)(\x02)?/, ["", ""]],
        [/\x1f(.*?\x0f|[^\x1f]+)(\x1f)?/, ["", ""]],
        [/\x1d(.*?\x0f|[^\x1d]+)(\x1d)?/, ["", ""]]
    ];
    for (var i=0; i


<commit_before>var Promise = require('promise-polyfill');
if (!window.Promise) {
  window.Promise = Promise;
}
var GeoPackageAPI = require('@ngageoint/geopackage');

var geoPackageCache = {};

L.GeoPackageTileLayer = L.GridLayer.extend({
	options: {
		layerName: '',
    geoPackageUrl: '',
    geoPackage: undefined,
    noCache: false
	},
	initialize: function initialize(options) {
		options = L.setOptions(this, options);
		L.GridLayer.prototype.initialize.call(this, options);
	},
	onAdd: function onAdd(map) {
		L.GridLayer.prototype.onAdd.call(this, map);
    var layer = this;

    if (layer.options.geoPackage) {
      layer.geoPackage = layer.options.geoPackage;
      layer.geoPackageLoaded = true;
      return;
    }

    if (!layer.options.noCache && geoPackageCache[layer.options.geoPackageUrl]) {
      console.log('GeoPackage was %s loaded, pulling from cache', layer.options.geoPackageUrl);
      layer.geoPackageLoaded = true;
      layer.geoPackage = geoPackageCache[layer.options.geoPackageUrl];
      return;
    }

    layer.geoPackageLoaded = false;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', this.options.geoPackageUrl, true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(e) {
      var uInt8Array = new Uint8Array(this.response);
      GeoPackageAPI.open(uInt8Array, function(err, gp) {
        console.timeEnd('Loading GeoPackage ' + layer.options.geoPackageUrl);
        layer.geoPackageLoaded = true;
        layer.geoPackage = gp;
        geoPackageCache[layer.options.geoPackageUrl] = layer.options.noCache || gp;
      });
    };
    console.time('Loading GeoPackage ' + layer.options.geoPackageUrl);
    xhr.send();
	},
	onRemove: function onRemove(map) {
		L.GridLayer.prototype.onRemove.call(this, map);
	},
  createTile: function(tilePoint, done) {
    var canvas = L.DomUtil.create('canvas', 'leaflet-tile');
    var size = this.getTileSize();
    canvas.width = size.x;
    canvas.height = size.y;
    maybeDrawTile(this, tilePoint, canvas, done);
    return canvas;
  }
});

function maybeDrawTile(gridLayer, tilePoint, canvas, dpme) {
  var geoPackage = gridLayer.geoPackage;
  var layerName = gridLayer.options.layerName;
  var map = gridLayer._map;
  if (!geoPackage) {
    // not loaded yet, just wait
    setTimeout(maybeDrawTile, 250, gridLayer, tilePoint, canvas, callback);
    return;
  }
  setTimeout(function() {
    console.time('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + tilePoint.z);

    if (map.options.crs === L.CRS.EPSG4326) {
      var tileSize = gridLayer.getTileSize(),
      nwPoint = tilePoint.scaleBy(tileSize),
      sePoint = nwPoint.add(tileSize),
      nw = map.unproject(nwPoint, tilePoint.z),
      se = map.unproject(sePoint, tilePoint.z);
      console.log('Draw 4326 tile');
      GeoPackageAPI.draw4326TileInCanvas(geoPackage, layerName, se.lat, nw.lng, nw.lat, se.lng, tilePoint.z, canvas.width, canvas.height, canvas)
      .then(function() {
        console.timeEnd('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + tilePoint.z);
        callback(err, canvas);
      });
    } else {
      GeoPackageAPI.drawXYZTileInCanvas(geoPackage, layerName, tilePoint.x, tilePoint.y, tilePoint.z, canvas.width, canvas.height, canvas)
      .then(function() {
        console.timeEnd('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + tilePoint.z);
        callback(err, canvas);
      });
    }
  }, 0);
}

L.geoPackageTileLayer = function(opts){
	return new L.GeoPackageTileLayer(opts);
}

L.GeoPackageFeatureLayer = L.GeoJSON.extend({
	options: {
		layerName: '',
    geoPackageUrl: '',
    noCache: false,
    style: function (feature) {
      return {
        color: "#00F",
        weight: 2,
        opacity: 1
      };
    },
    pointToLayer: function(feature, latlng) {
      return L.circleMarker(latlng, {
        radius: 2
      });
    }
	},
	initialize: function initialize(data, options) {
		options = L.setOptions(this, options);
		L.GeoJSON.prototype.initialize.call(this, data, options);
	},
	onAdd: function onAdd(map) {
		L.GeoJSON.prototype.onAdd.call(this, map);
    var layer = this;

    if (layer.options.geoPackage) {
      layer.geoPackage = layer.options.geoPackage;
      layer.geoPackageLoaded = true;
      var results = GeoPackageAPI.iterateGeoJSONFeaturesFromTable(layer.geoPackage, layer.options.layerName);
      for (var geoJson of results.results) {
        layer.addData(geoJson);
      }
      return;
    }

    if (!layer.options.noCache && geoPackageCache[layer.options.geoPackageUrl]) {
      console.log('GeoPackage was %s loaded, pulling from cache', layer.options.geoPackageUrl);
      layer.geoPackageLoaded = true;
      layer.geoPackage = geoPackageCache[layer.options.geoPackageUrl];
      var results = GeoPackageAPI.iterateGeoJSONFeaturesFromTable(layer.geoPackage, layer.options.layerName);
      for (var geoJson of results.results) {
        layer.addData(geoJson);
      }
      return;
    }
    layer.geoPackageLoaded = false;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', this.options.geoPackageUrl, true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(e) {
      var uInt8Array = new Uint8Array(this.response);
      GeoPackageAPI.openGeoPackageByteArray(uInt8Array, function(err, gp) {
        console.timeEnd('Loading GeoPackage ' + layer.options.geoPackageUrl);
        layer.geoPackageLoaded = true;
        layer.geoPackage = gp;
        geoPackageCache[layer.options.geoPackageUrl] = layer.options.noCache || gp;
        var results = GeoPackageAPI.iterateGeoJSONFeaturesFromTable(layer.geoPackage, layer.options.layerName);
        for (var geoJson of results.results) {
          layer.addData(geoJson);
        }
      });
    };
    console.time('Loading GeoPackage ' + layer.options.geoPackageUrl);
    xhr.send();
	}
});

L.geoPackageFeatureLayer = function(data, opts){
	return new L.GeoPackageFeatureLayer(data, opts);
}
<commit_msg>correcting the done callback name<commit_after>var Promise = require('promise-polyfill');
if (!window.Promise) {
  window.Promise = Promise;
}
var GeoPackageAPI = require('@ngageoint/geopackage');

var geoPackageCache = {};

L.GeoPackageTileLayer = L.GridLayer.extend({
	options: {
		layerName: '',
    geoPackageUrl: '',
    geoPackage: undefined,
    noCache: false
	},
	initialize: function initialize(options) {
		options = L.setOptions(this, options);
		L.GridLayer.prototype.initialize.call(this, options);
	},
	onAdd: function onAdd(map) {
		L.GridLayer.prototype.onAdd.call(this, map);
    var layer = this;

    if (layer.options.geoPackage) {
      layer.geoPackage = layer.options.geoPackage;
      layer.geoPackageLoaded = true;
      return;
    }

    if (!layer.options.noCache && geoPackageCache[layer.options.geoPackageUrl]) {
      console.log('GeoPackage was %s loaded, pulling from cache', layer.options.geoPackageUrl);
      layer.geoPackageLoaded = true;
      layer.geoPackage = geoPackageCache[layer.options.geoPackageUrl];
      return;
    }

    layer.geoPackageLoaded = false;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', this.options.geoPackageUrl, true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(e) {
      var uInt8Array = new Uint8Array(this.response);
      GeoPackageAPI.open(uInt8Array, function(err, gp) {
        console.timeEnd('Loading GeoPackage ' + layer.options.geoPackageUrl);
        layer.geoPackageLoaded = true;
        layer.geoPackage = gp;
        geoPackageCache[layer.options.geoPackageUrl] = layer.options.noCache || gp;
      });
    };
    console.time('Loading GeoPackage ' + layer.options.geoPackageUrl);
    xhr.send();
	},
	onRemove: function onRemove(map) {
		L.GridLayer.prototype.onRemove.call(this, map);
	},
  createTile: function(tilePoint, done) {
    var canvas = L.DomUtil.create('canvas', 'leaflet-tile');
    var size = this.getTileSize();
    canvas.width = size.x;
    canvas.height = size.y;
    maybeDrawTile(this, tilePoint, canvas, done);
    return canvas;
  }
});

function maybeDrawTile(gridLayer, tilePoint, canvas, done) {
  var geoPackage = gridLayer.geoPackage;
  var layerName = gridLayer.options.layerName;
  var map = gridLayer._map;
  if (!geoPackage) {
    // not loaded yet, just wait
    setTimeout(maybeDrawTile, 250, gridLayer, tilePoint, canvas, done);
    return;
  }
  setTimeout(function() {
    console.time('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + tilePoint.z);

    if (map.options.crs === L.CRS.EPSG4326) {
      var tileSize = gridLayer.getTileSize(),
      nwPoint = tilePoint.scaleBy(tileSize),
      sePoint = nwPoint.add(tileSize),
      nw = map.unproject(nwPoint, tilePoint.z),
      se = map.unproject(sePoint, tilePoint.z);
      console.log('Draw 4326 tile');
      GeoPackageAPI.draw4326TileInCanvas(geoPackage, layerName, se.lat, nw.lng, nw.lat, se.lng, tilePoint.z, canvas.width, canvas.height, canvas)
      .then(function() {
        console.timeEnd('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + tilePoint.z);
        done(null, canvas);
      });
    } else {
      GeoPackageAPI.drawXYZTileInCanvas(geoPackage, layerName, tilePoint.x, tilePoint.y, tilePoint.z, canvas.width, canvas.height, canvas)
      .then(function() {
        console.timeEnd('Draw tile ' + tilePoint.x + ', ' + tilePoint.y + ' zoom: ' + tilePoint.z);
        done(null, canvas);
      });
    }
  }, 0);
}

L.geoPackageTileLayer = function(opts){
	return new L.GeoPackageTileLayer(opts);
}

L.GeoPackageFeatureLayer = L.GeoJSON.extend({
	options: {
		layerName: '',
    geoPackageUrl: '',
    geoPackage: undefined,
    noCache: false,
    style: function (feature) {
      return {
        color: "#00F",
        weight: 2,
        opacity: 1
      };
    },
    pointToLayer: function(feature, latlng) {
      return L.circleMarker(latlng, {
        radius: 2
      });
    }
	},
	initialize: function initialize(data, options) {
		options = L.setOptions(this, options);
		L.GeoJSON.prototype.initialize.call(this, data, options);
	},
	onAdd: function onAdd(map) {
		L.GeoJSON.prototype.onAdd.call(this, map);
    var layer = this;

    if (layer.options.geoPackage) {
      layer.geoPackage = layer.options.geoPackage;
      layer.geoPackageLoaded = true;
      var results = GeoPackageAPI.iterateGeoJSONFeaturesFromTable(layer.geoPackage, layer.options.layerName);
      for (var geoJson of results.results) {
        layer.addData(geoJson);
      }
      return;
    }

    if (!layer.options.noCache && geoPackageCache[layer.options.geoPackageUrl]) {
      console.log('GeoPackage was %s loaded, pulling from cache', layer.options.geoPackageUrl);
      layer.geoPackageLoaded = true;
      layer.geoPackage = geoPackageCache[layer.options.geoPackageUrl];
      var results = GeoPackageAPI.iterateGeoJSONFeaturesFromTable(layer.geoPackage, layer.options.layerName);
      for (var geoJson of results.results) {
        layer.addData(geoJson);
      }
      return;
    }
    layer.geoPackageLoaded = false;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', this.options.geoPackageUrl, true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(e) {
      var uInt8Array = new Uint8Array(this.response);
      GeoPackageAPI.openGeoPackageByteArray(uInt8Array, function(err, gp) {
        console.timeEnd('Loading GeoPackage ' + layer.options.geoPackageUrl);
        layer.geoPackageLoaded = true;
        layer.geoPackage = gp;
        geoPackageCache[layer.options.geoPackageUrl] = layer.options.noCache || gp;
        var results = GeoPackageAPI.iterateGeoJSONFeaturesFromTable(layer.geoPackage, layer.options.layerName);
        for (var geoJson of results.results) {
          layer.addData(geoJson);
        }
      });
    };
    console.time('Loading GeoPackage ' + layer.options.geoPackageUrl);
    xhr.send();
	}
});

L.geoPackageFeatureLayer = function(data, opts){
	return new L.GeoPackageFeatureLayer(data, opts);
}
<|endoftext|>


<commit_before>import React from 'react'

import Sajari from './Sajari'

/**
 * Sample that has a function to enable the overlay.
 */
const SampleApp = ({ enableOverlay }) => (

    {enableOverlay() ? null : null}

Sajari Overlay

This provides a clean and familiar interface focused on the search experience.

    <button onClick={enableOverlay}>Activate Overlay</button>

Features

Instant Search as you type

Results backed by smart textual analysis and machine learning

Easy to use categories and filters

    <Sajari/>

)

export default SampleApp
<commit_msg>Remove overlay defaulting to open on page load<commit_after>import React from 'react'

import Sajari from './Sajari'

/**
 * Sample that has a function to enable the overlay.
 */
const SampleApp = ({ enableOverlay }) => (

Sajari Overlay

This provides a clean and familiar interface focused on the search experience.

    <button onClick={enableOverlay}>Activate Overlay</button>

Features

Instant Search as you type

Results backed by smart textual analysis and machine learning

Easy to use categories and filters

    <Sajari/>

)

export default SampleApp
<|endoftext|>


<commit_before>
  var v = "1.3.2";

  if (window.jQuery === undefined || window.jQuery.fn.jquery < v) {
    var done = false;
    var script = document.createElement("script");
    script.src = "http://ajax.googleapis.com/ajax/libs/jquery/" + v + "/jquery.min.js";
    script.onload = script.onreadystatechange = function(){
      if (!done && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
        done = true;
        initMyBookmarklet();
      }
    };
    document.getElementsByTagName("head")[0].appendChild(script);
  } else {
    initMyBookmarklet();
  }

function initMyBookmarklet(){
  var
      method = {},
      $overlay,
      $modal,
      $content,
      $close;

  // Horizontally center the modal in the viewport
  method.center = function () {
    var top, left;

    top = Math.max($modal.outerHeight() - $(window).height(), 0);
    left = Math.max($(window).width() - $modal.outerWidth(), 0) / 2;

    $modal.css({
      top:top + $(window).scrollTop(),
      left:left + $(window).scrollLeft()
    });
  };

  // Open the modal
  method.open = function (settings) {
    $content.empty().append(settings.content);

    $modal.css({
        width: settings.width || 'auto',
        height: settings.height || 'auto'
    });

    method.center();
    $(window).bind('resize.modal', method.center);
    $modal.show();
    $overlay.show();
  };

  // Close the modal
  method.close = function () {
    $modal.hide();
    $overlay.hide();
    $content.empty();
    $(window).unbind('resize.modal');
  };

  // Generate the HTML and add it to the document
  $overlay = $('

');
  $modal = $('

');
  $content = $('

');
  $close = $('close');

  $modal.hide();
  $overlay.hide();
  $modal.append($content, $close);

  $close.click(function(e){
    e.preventDefault();
    method.close();
  });

  $('body').append($overlay, $modal);
  // Wait until the DOM has loaded before querying the document
  $.get('new_wire.html', function(data){
    method.open({content: data});
  });
}<commit_msg>tweaks<commit_after>//(function (){

  var v = "1.7.2";

  if (window.jQuery === undefined || window.jQuery.fn.jquery < v) {
    var done = false;
    var script = document.createElement("script");
    script.src = "//ajax.googleapis.com/ajax/libs/jquery/" + v + "/jquery.min.js";
    script.onload = script.onreadystatechange = function(){
      if (!done && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
        done = true;
        initMyBookmarklet();
      }
    };
    document.getElementsByTagName("head")[0].appendChild(script);
  } else {
    initMyBookmarklet();
  }

  function initMyBookmarklet(){
    var
        method = {},
        $overlay,
        $modal,
        $content,
        $close;

    // Horizontally center the modal in the viewport
    method.center = function () {
      var top, left;

      top = Math.max($modal.outerHeight() - $(window).height(), 0);
      left = Math.max($(window).width() - $modal.outerWidth(), 0) / 2;

      $modal.css({
        top:top + $(window).scrollTop(),
        left:left + $(window).scrollLeft()
      });
    };

    // Open the modal
    method.open = function (settings) {
      $content.empty().append(settings.content);

      $modal.css({
          width: settings.width || 'auto',
          height: settings.height || 'auto'
      });

      method.center();
      $(window).bind('resize.modal', method.center);
      $modal.show();
      $overlay.show();
    };

    // Close the modal
    method.close = function () {
      $modal.hide();
      $overlay.hide();
      $content.empty();
      $(window).unbind('resize.modal');
    };

    // Generate the HTML and add it to the document
    $overlay = $('

');
    $modal = $('

');
    $content = $('

');
    $close = $('close');

    $modal.hide();
    $overlay.hide();
    $modal.append($content, $close);

    $close.click(function(e){
      e.preventDefault();
      method.close();
    });

    $('body').append($overlay, $modal);
    // Wait until the DOM has loaded before querying the document
    $.get('new_wire.html', function(data){
      method.open({content: data});
    });
  }

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