<commit_before>/*jshint jquery: true, browser: true*/

/*
 * Name space
 */
var CBMONITOR = CBMONITOR || {};

CBMONITOR.Inventory = function () {};

/*
 * Panel with buttons related to cluster management
 */
CBMONITOR.Inventory.prototype.configureButtons = function() {
    "use strict";

    $(".inventorybtn:button")
        .css({
            fontSize: "77%"
        })
        .click(function() {
            switch(this.value) {
                case "Add cluster":
                    $("#dialog_new_cluster").dialog("open");
                    break;
                case "Add server":
                    $("#dialog_new_server").dialog("open");
                    break;
                case "Add bucket":
                    $("#dialog_new_bucket").dialog("open");
                    break;
                case "Edit":
                    //var selected_id = jstree.jstree("get_selected").attr("id");
                    //jstree.jstree("rename", selected_id);
                    break;
                case "Delete":
                    $("#dialog_delete").dialog("open");
                    break;
                default:
                    break;
            }
        });
};

/*
 * Inventory tree
 */
CBMONITOR.Inventory.prototype.configureTree = function() {
    "use strict";

    var jstree = $("#tree"),
        renc = $("#renc"),
        delc = $("#delc"),
        adds = $("#adds");

    // Disable buttons
    renc.addClass("ui-state-disabled");
    delc.addClass("ui-state-disabled");
    adds.addClass("ui-state-disabled");

    // Cleanup (bootstrap bug)
    jstree.remove();
    $("<div/>", {id: "tree"}).appendTo('#inventory');
    jstree = $("#tree");

    // Create tree
    jstree.jstree({
        "themes" : {
            "theme" : "default",
            "icons" : false
        },
        "crrm": {
            "move": {
                "check_move": function (m) {
                    var p = this._get_parent(m.o);
                    if (!p) {
                        return false;
                    }
                    p = p === -1 ? this.get_container() : p;
                    if (p === m.np) {
                        return true;
                    }
                    return p[0] && m.np[0] && p[0] === m.np[0];
                }
            }
        },
        "dnd": {
            "drop_target": false,
            "drag_target": false
        },
        "plugins": ["themes", "json_data", "dnd", "ui", "crrm"],
        "json_data": {
            "ajax" : {
                "url" : "/cbmonitor/get_tree_data/"
            }
        }
    });

    // Expand all nodes
    jstree.on("loaded.jstree", function() {
        jstree.jstree("open_all");
    });

    // Define binding
    jstree.bind("select_node.jstree", function (event, data) {
        var cls = data.rslt.obj.attr("class").split(" ")[0];
        switch(cls) {
            case "cluster":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            case "servers":
                adds.removeClass("ui-state-disabled");
                adds.prop("value", "Add server");
                adds.prop("innerHTML", "Add server");
                break;
            case "server":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            case "buckets":
                adds.removeClass("ui-state-disabled");
                adds.prop("value", "Add bucket");
                adds.prop("innerHTML", "Add bucket");
                break;
            case "bucket":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            default:
                break;
        }
    });
};

$(document).ready(function(){
    "use strict";

    CBMONITOR.inventory = new CBMONITOR.Inventory();
    CBMONITOR.inventory.configureButtons();
    CBMONITOR.inventory.configureTree();

    CBMONITOR.dialogs = new CBMONITOR.Dialogs();
    CBMONITOR.dialogs.configureAddNewCluster();
    CBMONITOR.dialogs.configureAddNewServer();
    CBMONITOR.dialogs.configureAddNewBucket();
    CBMONITOR.dialogs.configureDeleteItem();

});<commit_msg>don't expand all nodes<commit_after>/*jshint jquery: true, browser: true*/

/*
 * Name space
 */
var CBMONITOR = CBMONITOR || {};

CBMONITOR.Inventory = function () {};

/*
 * Panel with buttons related to cluster management
 */
CBMONITOR.Inventory.prototype.configureButtons = function() {
    "use strict";

    $(".inventorybtn:button")
        .css({
            fontSize: "77%"
        })
        .click(function() {
            switch(this.value) {
                case "Add cluster":
                    $("#dialog_new_cluster").dialog("open");
                    break;
                case "Add server":
                    $("#dialog_new_server").dialog("open");
                    break;
                case "Add bucket":
                    $("#dialog_new_bucket").dialog("open");
                    break;
                case "Edit":
                    //var selected_id = jstree.jstree("get_selected").attr("id");
                    //jstree.jstree("rename", selected_id);
                    break;
                case "Delete":
                    $("#dialog_delete").dialog("open");
                    break;
                default:
                    break;
            }
        });
};

/*
 * Inventory tree
 */
CBMONITOR.Inventory.prototype.configureTree = function() {
    "use strict";

    var jstree = $("#tree"),
        renc = $("#renc"),
        delc = $("#delc"),
        adds = $("#adds");

    // Disable buttons
    renc.addClass("ui-state-disabled");
    delc.addClass("ui-state-disabled");
    adds.addClass("ui-state-disabled");

    // Cleanup (bootstrap bug)
    jstree.remove();
    $("<div/>", {id: "tree"}).appendTo('#inventory');
    jstree = $("#tree");

    // Create tree
    jstree.jstree({
        "themes" : {
            "theme" : "default",
            "icons" : false
        },
        "crrm": {
            "move": {
                "check_move": function (m) {
                    var p = this._get_parent(m.o);
                    if (!p) {
                        return false;
                    }
                    p = p === -1 ? this.get_container() : p;
                    if (p === m.np) {
                        return true;
                    }
                    return p[0] && m.np[0] && p[0] === m.np[0];
                }
            }
        },
        "dnd": {
            "drop_target": false,
            "drag_target": false
        },
        "plugins": ["themes", "json_data", "dnd", "ui", "crrm"],
        "json_data": {
            "ajax" : {
                "url" : "/cbmonitor/get_tree_data/"
            }
        }
    });

    // Define binding
    jstree.bind("select_node.jstree", function (event, data) {
        var cls = data.rslt.obj.attr("class").split(" ")[0];
        switch(cls) {
            case "cluster":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            case "servers":
                adds.removeClass("ui-state-disabled");
                adds.prop("value", "Add server");
                adds.prop("innerHTML", "Add server");
                break;
            case "server":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            case "buckets":
                adds.removeClass("ui-state-disabled");
                adds.prop("value", "Add bucket");
                adds.prop("innerHTML", "Add bucket");
                break;
            case "bucket":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            default:
                break;
        }
    });
};

$(document).ready(function(){
    "use strict";

    CBMONITOR.inventory = new CBMONITOR.Inventory();
    CBMONITOR.inventory.configureButtons();
    CBMONITOR.inventory.configureTree();

    CBMONITOR.dialogs = new CBMONITOR.Dialogs();
    CBMONITOR.dialogs.configureAddNewCluster();
    CBMONITOR.dialogs.configureAddNewServer();
    CBMONITOR.dialogs.configureAddNewBucket();
    CBMONITOR.dialogs.configureDeleteItem();

});<|endoftext|>


<commit_before>/* global test, module, sinon  */
(function (Backbone, _) {
    "use strict";

    var server,
        user,
        users,
        User,
        UserCollection;

    module( "REST XHR url tests", {
        setup: function() {
            User = Backbone.Model.extend({
                urlRoot: '/api/user'
            });

            UserCollection = Backbone.Collection.extend({
                model: User
            });

            server = sinon.fakeServer.create();

            this.setServerData = function (url, testData) {
                server.respondWith("GET", url, [200, {
                    "Content-Type": "application/json"
                }, JSON.stringify({})]);
            };
        },
        teardown: function () {
            server.restore();
        }
    });

    test("include: single option", 4, function() {
        this.setServerData("/api/user/1?" + encodeURIComponent("includes=role"));

        user = new User({'id': 1});
        user
            .include('role')
            .fetch();

        server.respond();
    });

    test("include: multiple options", 8, function () {
        this.setServerData("/api/user/1?" + encodeURIComponent("includes=role,organization"));

        user = new User({'id': 1});
        user
            .include('role', 'organization')
            .fetch();

        server.respond();
    });

    test("include: 2 level deep relationship", 8, function () {
        this.setServerData("/api/user/1?" + encodeURIComponent("includes=organization/role"));

        user = new User({'id': 1});
        user
            .include('organization.owner')
            .fetch();

        server.respond();
    });

    test("include: 3 level deep relationship", 8, function () {
        this.setServerData("/api/user/1?" + encodeURIComponent("includes=organization/role/stuff"));

        user = new User({'id': 1});
        user
            .include('organization.owner.role')
            .fetch();

        server.respond();
    });

    test("include: multiple option deep relationship", 8, function () {
        this.setServerData("/api/user/1?" + encodeURIComponent("includes=organization/role/stuff"));

        user = new User({'id': 1});
        user
            .include('organization.owner', 'organization.staff')
            .fetch();

        server.respond();
    });

    test("where: single field equal", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .where({
                role: {
                    '=': 'editor'
                }
            })
            .fetch();

        server.respond();
    });

    test("where: single field equal shorthand", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .where({
                role: 'editor'
            })
            .fetch();

        server.respond();
    });

    test("where: multiple fields", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .where({
                role: 'editor',
                createdBy: 4
            })
            .fetch();

        server.respond();
    });

    test("where: like field", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .where({
                firstName: 'Joh*'
            })
            .fetch();

        server.respond();
    });

    test("where: in list", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .where({
                role: {
                    'in': ['editor', 'author']
                }
            })
            .fetch();

        server.respond();
    });

    test("where: in list shorthand", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .where({
                role: ['editor', 'author']
            })
            .fetch();

        server.respond();
    });

    test("where: greater than", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .where({
                createdAt: {
                    '>': new Date()
                }
            })
            .fetch();

        server.respond();
    });

    test("where: deep relationship field", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .where({
                'organization.type': 'facility'
            })
            .fetch();

        server.respond();
    });

    test("limit", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .limit(10)
            .fetch();

        server.respond();
    });

    test("skip by integer", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .limit(10)
            .skip(2)
            .fetch();

        server.respond();
    });

    test("sortBy: single field shorthand", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .sortBy('lastName')
            .fetch();

        server.respond();
    });

    test("sortBy: single field ascending", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .sortBy({
                lastName: 'asc'
            })
            .fetch();

        server.respond();
    });

    test("sortBy: single field descending", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .sortBy({
                lastName: 'desc'
            })
            .fetch();

        server.respond();
    });

    test("sortBy: multiple fields", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent(""));

        users = new UserCollection();
        users
            .sortBy({
                lastName: 'desc',
                firstName: 'asc'
            })
            .fetch();

        server.respond();
    });

})(window.Backbone, window._);<commit_msg>Updated test scripts with correct URLs after discussion with Dan on our api syntax.<commit_after>/* global test, module, sinon  */
(function (Backbone, _) {
    "use strict";

    var server,
        user,
        users,
        User,
        UserCollection;

    module( "REST XHR url tests", {
        setup: function() {
            User = Backbone.Model.extend({
                urlRoot: '/api/user'
            });

            UserCollection = Backbone.Collection.extend({
                model: User
            });

            server = sinon.fakeServer.create();

            this.setServerData = function (url, testData) {
                server.respondWith("GET", url, [200, {
                    "Content-Type": "application/json"
                }, JSON.stringify({})]);
            };
        },
        teardown: function () {
            server.restore();
        }
    });

    test("include: single option", 4, function() {
        this.setServerData("/api/user/1?" + encodeURIComponent("with=role"));

        user = new User({'id': 1});
        user
            .include('role')
            .fetch();

        server.respond();
    });

    test("include: multiple options", 8, function () {
        this.setServerData("/api/user/1?" + encodeURIComponent("with=role,organization"));

        user = new User({'id': 1});
        user
            .include('role', 'organization')
            .fetch();

        server.respond();
    });

    test("include: 2 level deep relationship", 8, function () {
        this.setServerData("/api/user/1?" + encodeURIComponent("with=organization.owner"));

        user = new User({'id': 1});
        user
            .include('organization.owner')
            .fetch();

        server.respond();
    });

    test("include: 3 level deep relationship", 8, function () {
        this.setServerData("/api/user/1?" + encodeURIComponent("with=organization.role.stuff"));

        user = new User({'id': 1});
        user
            .include('organization.owner.role')
            .fetch();

        server.respond();
    });

    test("include: multiple option deep relationship", 8, function () {
        this.setServerData("/api/user/1?" + encodeURIComponent("with=organization.owner,organization.staff"));

        user = new User({'id': 1});
        user
            .include('organization.owner', 'organization.staff')
            .fetch();

        server.respond();
    });

    test("where: single field equal", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("role=editor"));

        users = new UserCollection();
        users
            .where({
                role: {
                    '=': 'editor'
                }
            })
            .fetch();

        server.respond();
    });

    test("where: single field equal shorthand", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("role=editor"));

        users = new UserCollection();
        users
            .where({
                role: 'editor'
            })
            .fetch();

        server.respond();
    });

    test("where: multiple fields", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("role=editor&createdBy=4"));

        users = new UserCollection();
        users
            .where({
                role: 'editor',
                createdBy: 4
            })
            .fetch();

        server.respond();
    });

    test("where: like field", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("firstName=like:Joh*"));

        users = new UserCollection();
        users
            .where({
                firstName: {
                    'like': 'Joh*'
                }
            })
            .fetch();

        server.respond();
    });

    test("where: in list", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("role=in:editor,author"));

        users = new UserCollection();
        users
            .where({
                role: {
                    'in': ['editor', 'author']
                }
            })
            .fetch();

        server.respond();
    });

    test("where: in list shorthand", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("role=in:editor,author"));

        users = new UserCollection();
        users
            .where({
                role: ['editor', 'author']
            })
            .fetch();

        server.respond();
    });

    test("where: greater than", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("createdAt=gt:10"));

        users = new UserCollection();
        users
            .where({
                createdAt: {
                    '>': 10
                }
            })
            .fetch();

        server.respond();
    });

    test("where: greater than", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("createdAt=lt:10"));

        users = new UserCollection();
        users
            .where({
                createdAt: {
                    '<': 10
                }
            })
            .fetch();

        server.respond();
    });

    test("where: deep relationship field", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("organization.type=facility"));

        users = new UserCollection();
        users
            .where({
                'organization.type': {
                    '=': 'facility'
                }
            })
            .fetch();

        server.respond();
    });

    test("where: deep relationship field shorthand", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("organization.type=facility"));

        users = new UserCollection();
        users
            .where({
                'organization.type': 'facility'
            })
            .fetch();

        server.respond();
    });

    test("limit", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("limit=10"));

        users = new UserCollection();
        users
            .limit(10)
            .fetch();

        server.respond();
    });

    test("skip by integer", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("limit=20,10"));

        users = new UserCollection();
        users
            .limit(10)
            .skip(2)
            .fetch();

        server.respond();
    });

    test("sortBy: single field shorthand", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("sortBy=lastName"));

        users = new UserCollection();
        users
            .sortBy('lastName')
            .fetch();

        server.respond();
    });

    test("sortBy: single field ascending", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("sortBy=lastName"));

        users = new UserCollection();
        users
            .sortBy({
                lastName: 'asc'
            })
            .fetch();

        server.respond();
    });

    test("sortBy: single field descending", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("sortyBy=-lastName"));

        users = new UserCollection();
        users
            .sortBy({
                lastName: 'desc'
            })
            .fetch();

        server.respond();
    });

    //TODO: Figure out order of importance for sort fields
    test("sortBy: multiple fields", 8, function () {
        this.setServerData("/api/user?" + encodeURIComponent("sortBy=-lastName,firstName"));

        users = new UserCollection();
        users
            .sortBy({
                lastName: 'desc',
                firstName: 'asc'
            })
            .fetch();

        server.respond();
    });

})(window.Backbone, window._);<|endoftext|>


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

/**
 * Internal dependencies
 */
import { renderHook, actHook as act } from '../../../../../tests/js/test-utils';
import {
	createTestRegistry,
	untilResolved,
} from '../../../../../tests/js/utils';
import { MODULES_TAGMANAGER, CONTEXT_WEB } from '../datastore/constants';
import * as factories from '../datastore/__factories__';
import useExistingTagEffect from './useExistingTagEffect';

describe( 'useExistingTagEffect', () => {
	let registry;
	beforeEach( () => {
		registry = createTestRegistry();
		// Set settings to prevent fetch in resolver.
		registry.dispatch( MODULES_TAGMANAGER ).receiveGetSettings( {} );
		// Set set no existing tag.
		registry.dispatch( MODULES_TAGMANAGER ).receiveGetExistingTag( null );
	} );

	it( 'sets the accountID and containerID when there is an existing tag with permission', async () => {
		const account = factories.accountBuilder();
		// eslint-disable-next-line sitekit/acronym-case
		const accountID = account.accountId;
		const containers = factories.buildContainers(
			3,
			// eslint-disable-next-line sitekit/acronym-case
			{ accountId: account.accountId, usageContext: [ CONTEXT_WEB ] }
		);
		const [ firstContainer, existingContainer ] = containers;
		registry
			.dispatch( MODULES_TAGMANAGER )
			.receiveGetAccounts( [ account ] );
		registry
			.dispatch( MODULES_TAGMANAGER )
			.receiveGetContainers( containers, { accountID } );
		registry.dispatch( MODULES_TAGMANAGER ).setAccountID( accountID );
		registry
			.dispatch( MODULES_TAGMANAGER )
			// eslint-disable-next-line sitekit/acronym-case
			.setContainerID( firstContainer.publicId );
		registry
			.dispatch( MODULES_TAGMANAGER )
			// eslint-disable-next-line sitekit/acronym-case
			.setInternalContainerID( firstContainer.containerId );

		let rerender;
		await act(
			() =>
				new Promise( async ( resolve ) => {
					( { rerender } = renderHook( () => useExistingTagEffect(), {
						registry,
					} ) );
					await untilResolved(
						registry,
						MODULES_TAGMANAGER
					).getTagPermission( null );
					resolve();
				} )
		);

		expect( registry.select( MODULES_TAGMANAGER ).getContainerID() ).toBe(
			// eslint-disable-next-line sitekit/acronym-case
			firstContainer.publicId
		);
		expect(
			registry.select( MODULES_TAGMANAGER ).getInternalContainerID()
			// eslint-disable-next-line sitekit/acronym-case
		).toBe( firstContainer.containerId );

		await act(
			() =>
				new Promise( async ( resolve ) => {
					registry
						.dispatch( MODULES_TAGMANAGER )
						.receiveGetTagPermission(
							{ accountID, permission: true },
							// eslint-disable-next-line sitekit/acronym-case
							{ containerID: existingContainer.publicId }
						);
					registry
						.dispatch( MODULES_TAGMANAGER )
						// eslint-disable-next-line sitekit/acronym-case
						.receiveGetExistingTag( existingContainer.publicId );
					await untilResolved(
						registry,
						MODULES_TAGMANAGER
						// eslint-disable-next-line sitekit/acronym-case
					).getTagPermission( existingContainer.publicId );
					rerender();
					resolve();
				} )
		);

		expect( registry.select( MODULES_TAGMANAGER ).getContainerID() ).toBe(
			// eslint-disable-next-line sitekit/acronym-case
			existingContainer.publicId
		);
		expect(
			registry.select( MODULES_TAGMANAGER ).getInternalContainerID()
			// eslint-disable-next-line sitekit/acronym-case
		).toBe( existingContainer.containerId );
	} );

	it( 'turns off snippet display when the tag is displayed via a non sitekit method', async () => {
		const account = factories.accountBuilder();
		// eslint-disable-next-line sitekit/acronym-case
		const accountID = account.accountId;
		const container = factories.containerBuilder( {
			// eslint-disable-next-line sitekit/acronym-case
			accountId: account.accountId,
		} );
		registry
			.dispatch( MODULES_TAGMANAGER )
			.receiveGetAccounts( [ account ] );
		registry
			.dispatch( MODULES_TAGMANAGER )
			.receiveGetContainers( [ container ], { accountID } );
		registry.dispatch( MODULES_TAGMANAGER ).setAccountID( accountID );

		let rerender;
		await act(
			() =>
				new Promise( async ( resolve ) => {
					( { rerender } = renderHook( () => useExistingTagEffect(), {
						registry,
					} ) );
					await untilResolved(
						registry,
						MODULES_TAGMANAGER
					).getTagPermission( null );
					resolve();
				} )
		);

		await act(
			() =>
				new Promise( async ( resolve ) => {
					registry
						.dispatch( MODULES_TAGMANAGER )
						.receiveGetTagPermission(
							{ accountID, permission: true },
							// eslint-disable-next-line sitekit/acronym-case
							{ containerID: container.publicId }
						);
					registry
						.dispatch( MODULES_TAGMANAGER )
						// eslint-disable-next-line sitekit/acronym-case
						.receiveGetExistingTag( container.publicId );
					await untilResolved(
						registry,
						MODULES_TAGMANAGER
						// eslint-disable-next-line sitekit/acronym-case
					).getTagPermission( container.publicId );
					rerender();
					resolve();
				} )
		);

		expect( registry.select( MODULES_TAGMANAGER ).getUseSnippet() ).toBe(
			false
		);
	} );
} );
<commit_msg>Test order.<commit_after>/**
 * Tag Manager useExistingTagEffect hook tests.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import { renderHook, actHook as act } from '../../../../../tests/js/test-utils';
import {
	createTestRegistry,
	untilResolved,
} from '../../../../../tests/js/utils';
import { MODULES_TAGMANAGER, CONTEXT_WEB } from '../datastore/constants';
import * as factories from '../datastore/__factories__';
import useExistingTagEffect from './useExistingTagEffect';

describe( 'useExistingTagEffect', () => {
	let registry;
	beforeEach( () => {
		registry = createTestRegistry();
		// Set settings to prevent fetch in resolver.
		registry.dispatch( MODULES_TAGMANAGER ).receiveGetSettings( {} );
		// Set set no existing tag.
		registry.dispatch( MODULES_TAGMANAGER ).receiveGetExistingTag( null );
	} );

	it( 'turns off snippet display when the tag is displayed via a non sitekit method', async () => {
		const account = factories.accountBuilder();
		// eslint-disable-next-line sitekit/acronym-case
		const accountID = account.accountId;
		const container = factories.containerBuilder( {
			// eslint-disable-next-line sitekit/acronym-case
			accountId: account.accountId,
		} );
		registry
			.dispatch( MODULES_TAGMANAGER )
			.receiveGetAccounts( [ account ] );
		registry
			.dispatch( MODULES_TAGMANAGER )
			.receiveGetContainers( [ container ], { accountID } );
		registry.dispatch( MODULES_TAGMANAGER ).setAccountID( accountID );

		let rerender;
		await act(
			() =>
				new Promise( async ( resolve ) => {
					( { rerender } = renderHook( () => useExistingTagEffect(), {
						registry,
					} ) );
					await untilResolved(
						registry,
						MODULES_TAGMANAGER
					).getTagPermission( null );
					resolve();
				} )
		);

		await act(
			() =>
				new Promise( async ( resolve ) => {
					registry
						.dispatch( MODULES_TAGMANAGER )
						.receiveGetTagPermission(
							{ accountID, permission: true },
							// eslint-disable-next-line sitekit/acronym-case
							{ containerID: container.publicId }
						);
					registry
						.dispatch( MODULES_TAGMANAGER )
						// eslint-disable-next-line sitekit/acronym-case
						.receiveGetExistingTag( container.publicId );
					await untilResolved(
						registry,
						MODULES_TAGMANAGER
						// eslint-disable-next-line sitekit/acronym-case
					).getUseSnippet();
					rerender();
					resolve();
				} )
		);

		expect( registry.select( MODULES_TAGMANAGER ).getUseSnippet() ).toBe(
			false
		);
	} );
	it( 'sets the accountID and containerID when there is an existing tag with permission', async () => {
		const account = factories.accountBuilder();
		// eslint-disable-next-line sitekit/acronym-case
		const accountID = account.accountId;
		const containers = factories.buildContainers(
			3,
			// eslint-disable-next-line sitekit/acronym-case
			{ accountId: account.accountId, usageContext: [ CONTEXT_WEB ] }
		);
		const [ firstContainer, existingContainer ] = containers;
		registry
			.dispatch( MODULES_TAGMANAGER )
			.receiveGetAccounts( [ account ] );
		registry
			.dispatch( MODULES_TAGMANAGER )
			.receiveGetContainers( containers, { accountID } );
		registry.dispatch( MODULES_TAGMANAGER ).setAccountID( accountID );
		registry
			.dispatch( MODULES_TAGMANAGER )
			// eslint-disable-next-line sitekit/acronym-case
			.setContainerID( firstContainer.publicId );
		registry
			.dispatch( MODULES_TAGMANAGER )
			// eslint-disable-next-line sitekit/acronym-case
			.setInternalContainerID( firstContainer.containerId );

		let rerender;
		await act(
			() =>
				new Promise( async ( resolve ) => {
					( { rerender } = renderHook( () => useExistingTagEffect(), {
						registry,
					} ) );
					await untilResolved(
						registry,
						MODULES_TAGMANAGER
					).getTagPermission( null );
					resolve();
				} )
		);

		expect( registry.select( MODULES_TAGMANAGER ).getContainerID() ).toBe(
			// eslint-disable-next-line sitekit/acronym-case
			firstContainer.publicId
		);
		expect(
			registry.select( MODULES_TAGMANAGER ).getInternalContainerID()
			// eslint-disable-next-line sitekit/acronym-case
		).toBe( firstContainer.containerId );

		await act(
			() =>
				new Promise( async ( resolve ) => {
					registry
						.dispatch( MODULES_TAGMANAGER )
						.receiveGetTagPermission(
							{ accountID, permission: true },
							// eslint-disable-next-line sitekit/acronym-case
							{ containerID: existingContainer.publicId }
						);
					registry
						.dispatch( MODULES_TAGMANAGER )
						// eslint-disable-next-line sitekit/acronym-case
						.receiveGetExistingTag( existingContainer.publicId );
					await untilResolved(
						registry,
						MODULES_TAGMANAGER
						// eslint-disable-next-line sitekit/acronym-case
					).getTagPermission( existingContainer.publicId );
					rerender();
					resolve();
				} )
		);

		expect( registry.select( MODULES_TAGMANAGER ).getContainerID() ).toBe(
			// eslint-disable-next-line sitekit/acronym-case
			existingContainer.publicId
		);
		expect(
			registry.select( MODULES_TAGMANAGER ).getInternalContainerID()
			// eslint-disable-next-line sitekit/acronym-case
		).toBe( existingContainer.containerId );
	} );
} );
<|endoftext|>


<commit_before>/* ${name} version ${version}

   ${description}

   copyright (c) ${year} ${author}

   ${license} license.
*/

'use strict';

var proto = Object.create(HTMLElement.prototype),
    defaults = {};

/* sync attributes and properties */
Object.keys(defaults).forEach( function (key) {
  Object.defineProperty(proto, key, {
    get: function () {
      return this.getAttribute(key) || defaults[key];
    },
    set: function (val) {
      this.setAttribute(key, val);
    }
  });
});

proto.createdCallback = function () {
};

proto.attachedCallback = function () {
};

proto.detachedCallback = function () {
};

proto.attributeChangedCallback = function (attr, old, new_) {
};

var Constructor = document.registerElement(${name}, {
  prototype: proto
});

module.exports = Constructor;
<commit_msg>updated test/template.js to implement the fix for web-component/issues/1 https://github.com/phoenixstormcrow/web-component/issues/1<commit_after>/* ${name} version ${version}

   ${description}

   copyright (c) ${year} ${author}

   ${license} license.
*/

'use strict';

var proto = Object.create(HTMLElement.prototype),
    defaults = {};

/* sync attributes and properties */
Object.keys(defaults).forEach( function (key) {
  Object.defineProperty(proto, key, {
    get: function () {
      return this.getAttribute(key) || defaults[key];
    },
    set: function (val) {
      this.setAttribute(key, val);
    }
  });
});

proto.createdCallback = function () {
};

proto.attachedCallback = function () {
};

proto.detachedCallback = function () {
};

proto.attributeChangedCallback = function (attr, old, new_) {
};

var Constructor = document.registerElement('${name}', {
  prototype: proto
});

module.exports = Constructor;
<|endoftext|>


<commit_before>/*************************************************
 * Copyright (c) 2016 Ansible, Inc.
 *
 * All Rights Reserved
 *************************************************/

/**
 * @ngdoc function
 * @name controllers.function:Inventories
 * @description This controller's for the Inventory page
 */

function InventoriesList($scope, $rootScope, $location, $log,
    $stateParams, $compile, $filter, Rest, Alert, InventoryList, Prompt,
    ClearScope, ProcessErrors, GetBasePath, Wait, Find, Empty, $state, rbacUiControlService, Dataset) {

    let list = InventoryList,
        defaultUrl = GetBasePath('inventory');

    init();

    function init(){
        $scope.canAdd = false;

        rbacUiControlService.canAdd('inventory')
            .then(function(canAdd) {
                $scope.canAdd = canAdd;
            });

        $scope.$watchCollection(list.name, function(){
            _.forEach($scope[list.name], buildStatusIndicators);
        });

        // Search init
        $scope.list = list;
        $scope[`${list.iterator}_dataset`] = Dataset.data;
        $scope[list.name] = $scope[`${list.iterator}_dataset`].results;

        $rootScope.flashMessage = null;

    }

    function buildStatusIndicators(inventory){
            inventory.launch_class = "";
            if (inventory.has_inventory_sources) {
                if (inventory.inventory_sources_with_failures > 0) {
                    inventory.syncStatus = 'error';
                    inventory.syncTip = inventory.inventory_sources_with_failures + ' groups with sync failures. Click for details';
                }
                else {
                    inventory.syncStatus = 'successful';
                    inventory.syncTip = 'No inventory sync failures. Click for details.';
                }
            }
            else {
                inventory.syncStatus = 'na';
                inventory.syncTip = 'Not configured for inventory sync.';
                inventory.launch_class = "btn-disabled";
            }
            if (inventory.has_active_failures) {
                inventory.hostsStatus = 'error';
                inventory.hostsTip = inventory.hosts_with_active_failures + ' hosts with failures. Click for details.';
            }
            else if (inventory.total_hosts) {
                inventory.hostsStatus = 'successful';
                inventory.hostsTip = 'No hosts with failures. Click for details.';
            }
            else {
                inventory.hostsStatus = 'none';
                inventory.hostsTip = 'Inventory contains 0 hosts.';
            }
    }

    function ellipsis(a) {
        if (a.length > 20) {
            return a.substr(0,20) + '...';
        }
        return a;
    }

    function attachElem(event, html, title) {
        var elem = $(event.target).parent();
        try {
            elem.tooltip('hide');
            elem.popover('destroy');
        }
        catch(err) {
            //ignore
        }
        $('.popover').each(function() {
            // remove lingering popover
. Seems to be a bug in TB3 RC1
            $(this).remove();
        });
        $('.tooltip').each( function() {
            // close any lingering tool tipss
            $(this).hide();
        });
        elem.attr({
            "aw-pop-over": html,
            "data-popover-title": title,
            "data-placement": "right" });
        elem.removeAttr('ng-click');
        $compile(elem)($scope);
        $scope.triggerPopover(event);
    }
    if ($scope.removeHostSummaryReady) {
        $scope.removeHostSummaryReady();
    }
    $scope.removeHostSummaryReady = $scope.$on('HostSummaryReady', function(e, event, data) {

        var html, title = "Recent Jobs";
        Wait('stop');
        if (data.count > 0) {
            html = "
\n";
            html += "
\n";
            html += "
";
            html += "Status	";
            html += "Finished	";
            html += "Name	";
            html += "
\n";
            html += "
\n";
            html += "
\n";

            data.results.forEach(function(row) {
                html += "
\n";
                html += "	\n";
                html += "" + ($filter('longDate')(row.finished)).replace(/ /,'
') + "	";
                html += "" + $filter('sanitize')(ellipsis(row.name)) + "	";
                html += "
\n";
            });
            html += "
\n";
            html += "
\n";
        }
        else {
            html = "
No recent job data available for this inventory.
\n";
        }
        attachElem(event, html, title);
    });

    if ($scope.removeGroupSummaryReady) {
        $scope.removeGroupSummaryReady();
    }
    $scope.removeGroupSummaryReady = $scope.$on('GroupSummaryReady', function(e, event, inventory, data) {
        var html, title;

        Wait('stop');

        // Build the html for our popover
        html = "
\n";
        html += "
\n";
        html += "
";
        html += "Status	";
        html += "Last Sync	";
        html += "Group	";
        html += "
";
        html += "
\n";
        html += "
\n";
        data.results.forEach( function(row) {
            if (row.related.last_update) {
                html += "
";
                html += `	`;
                html += "" + ($filter('longDate')(row.last_updated)).replace(/ /,'
') + "	";
                html += "" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + "	";
                html += "
\n";
            }
            else {
                html += "
";
                html += "	";
                html += "NA	";
                html += "" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + "	";
                html += "
\n";
            }
        });
        html += "
\n";
        html += "
\n";
        title = "Sync Status";
        attachElem(event, html, title);
    });

    $scope.showGroupSummary = function(event, id) {
        try{
            var elem = $(event.target).parent();
            // if the popover is visible already, then exit the function here
            if(elem.data()['bs.popover'].tip().hasClass('in')){
                return;
            }
        }
        catch(err){
            var inventory;
            if (!Empty(id)) {
                inventory = Find({ list: $scope.inventories, key: 'id', val: id });
                if (inventory.syncStatus !== 'na') {
                    Wait('start');
                    Rest.setUrl(inventory.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5');
                    Rest.get()
                        .success(function(data) {
                            $scope.$emit('GroupSummaryReady', event, inventory, data);
                        })
                        .error(function(data, status) {
                            ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
                                msg: 'Call to ' + inventory.related.inventory_sources + ' failed. GET returned status: ' + status
                            });
                        });
                }
            }
        }
    };

    $scope.showHostSummary = function(event, id) {
        try{
            var elem = $(event.target).parent();
            // if the popover is visible already, then exit the function here
            if(elem.data()['bs.popover'].tip().hasClass('in')){
                return;
            }
        }
        catch(err){
            var url, inventory;
            if (!Empty(id)) {
                inventory = Find({ list: $scope.inventories, key: 'id', val: id });
                if (inventory.total_hosts > 0) {
                    Wait('start');
                    url = GetBasePath('jobs') + "?type=job&inventory=" + id + "&failed=";
                    url += (inventory.has_active_failures) ? 'true' : "false";
                    url += "&order_by=-finished&page_size=5";
                    Rest.setUrl(url);
                    Rest.get()
                        .success( function(data) {
                            $scope.$emit('HostSummaryReady', event, data);
                        })
                        .error( function(data, status) {
                            ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
                                msg: 'Call to ' + url + ' failed. GET returned: ' + status
                            });
                        });
                }
            }
        }
    };

    $scope.viewJob = function(url) {

        // Pull the id out of the URL
        var id = url.replace(/^\//, '').split('/')[3];

        $state.go('inventorySyncStdout', {id: id});

    };

    $scope.addInventory = function () {
        $state.go('inventories.add');
    };

    $scope.editInventory = function (id) {
        $state.go('inventories.edit', {inventory_id: id});
    };

    $scope.manageInventory = function(id){
      $location.path($location.path() + '/' + id + '/manage');
    };

    $scope.deleteInventory = function (id, name) {

        var action = function () {
            var url = defaultUrl + id + '/';
            Wait('start');
            $('#prompt-modal').modal('hide');
            Rest.setUrl(url);
            Rest.destroy()
                .success(function () {
                    if (parseInt($state.params.inventory_id) === id) {
                        $state.go("^", null, {reload: true});
                    } else {
                       $state.go('.', null, {reload: true});
                       Wait('stop');
                    }
                })
                .error(function (data, status) {
                    ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
                        msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status
                    });
                });
        };

        Prompt({
            hdr: 'Delete',
            body: '
Are you sure you want to delete the inventory below?

' + $filter('sanitize')(name) + '
',
            action: action,
            actionText: 'DELETE'
        });
    };

    // Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status
    $scope.viewJobs = function (id) {
        $location.url('/jobs/?inventory__int=' + id);
    };

    $scope.viewFailedJobs = function (id) {
        $location.url('/jobs/?inventory__int=' + id + '&status=failed');
    };
}

export default ['$scope', '$rootScope', '$location', '$log',
    '$stateParams', '$compile', '$filter', 'Rest', 'Alert', 'InventoryList',
    'Prompt', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', 'rbacUiControlService', 'Dataset', InventoriesList
];
<commit_msg>Remove reference to unused CSS class<commit_after>/*************************************************
 * Copyright (c) 2016 Ansible, Inc.
 *
 * All Rights Reserved
 *************************************************/

/**
 * @ngdoc function
 * @name controllers.function:Inventories
 * @description This controller's for the Inventory page
 */

function InventoriesList($scope, $rootScope, $location, $log,
    $stateParams, $compile, $filter, Rest, Alert, InventoryList, Prompt,
    ClearScope, ProcessErrors, GetBasePath, Wait, Find, Empty, $state, rbacUiControlService, Dataset) {

    let list = InventoryList,
        defaultUrl = GetBasePath('inventory');

    init();

    function init(){
        $scope.canAdd = false;

        rbacUiControlService.canAdd('inventory')
            .then(function(canAdd) {
                $scope.canAdd = canAdd;
            });

        $scope.$watchCollection(list.name, function(){
            _.forEach($scope[list.name], buildStatusIndicators);
        });

        // Search init
        $scope.list = list;
        $scope[`${list.iterator}_dataset`] = Dataset.data;
        $scope[list.name] = $scope[`${list.iterator}_dataset`].results;

        $rootScope.flashMessage = null;

    }

    function buildStatusIndicators(inventory){
            inventory.launch_class = "";
            if (inventory.has_inventory_sources) {
                if (inventory.inventory_sources_with_failures > 0) {
                    inventory.syncStatus = 'error';
                    inventory.syncTip = inventory.inventory_sources_with_failures + ' groups with sync failures. Click for details';
                }
                else {
                    inventory.syncStatus = 'successful';
                    inventory.syncTip = 'No inventory sync failures. Click for details.';
                }
            }
            else {
                inventory.syncStatus = 'na';
                inventory.syncTip = 'Not configured for inventory sync.';
                inventory.launch_class = "btn-disabled";
            }
            if (inventory.has_active_failures) {
                inventory.hostsStatus = 'error';
                inventory.hostsTip = inventory.hosts_with_active_failures + ' hosts with failures. Click for details.';
            }
            else if (inventory.total_hosts) {
                inventory.hostsStatus = 'successful';
                inventory.hostsTip = 'No hosts with failures. Click for details.';
            }
            else {
                inventory.hostsStatus = 'none';
                inventory.hostsTip = 'Inventory contains 0 hosts.';
            }
    }

    function ellipsis(a) {
        if (a.length > 20) {
            return a.substr(0,20) + '...';
        }
        return a;
    }

    function attachElem(event, html, title) {
        var elem = $(event.target).parent();
        try {
            elem.tooltip('hide');
            elem.popover('destroy');
        }
        catch(err) {
            //ignore
        }
        $('.popover').each(function() {
            // remove lingering popover
. Seems to be a bug in TB3 RC1
            $(this).remove();
        });
        $('.tooltip').each( function() {
            // close any lingering tool tipss
            $(this).hide();
        });
        elem.attr({
            "aw-pop-over": html,
            "data-popover-title": title,
            "data-placement": "right" });
        elem.removeAttr('ng-click');
        $compile(elem)($scope);
        $scope.triggerPopover(event);
    }
    if ($scope.removeHostSummaryReady) {
        $scope.removeHostSummaryReady();
    }
    $scope.removeHostSummaryReady = $scope.$on('HostSummaryReady', function(e, event, data) {

        var html, title = "Recent Jobs";
        Wait('stop');
        if (data.count > 0) {
            html = "
\n";
            html += "
\n";
            html += "
";
            html += "Status	";
            html += "Finished	";
            html += "Name	";
            html += "
\n";
            html += "
\n";
            html += "
\n";

            data.results.forEach(function(row) {
                html += "
\n";
                html += "	\n";
                html += "" + ($filter('longDate')(row.finished)).replace(/ /,'
') + "	";
                html += "" + $filter('sanitize')(ellipsis(row.name)) + "	";
                html += "
\n";
            });
            html += "
\n";
            html += "
\n";
        }
        else {
            html = "
No recent job data available for this inventory.
\n";
        }
        attachElem(event, html, title);
    });

    if ($scope.removeGroupSummaryReady) {
        $scope.removeGroupSummaryReady();
    }
    $scope.removeGroupSummaryReady = $scope.$on('GroupSummaryReady', function(e, event, inventory, data) {
        var html, title;

        Wait('stop');

        // Build the html for our popover
        html = "
\n";
        html += "
\n";
        html += "
";
        html += "Status	";
        html += "Last Sync	";
        html += "Group	";
        html += "
";
        html += "
\n";
        html += "
\n";
        data.results.forEach( function(row) {
            if (row.related.last_update) {
                html += "
";
                html += `	`;
                html += "" + ($filter('longDate')(row.last_updated)).replace(/ /,'
') + "	";
                html += "" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + "	";
                html += "
\n";
            }
            else {
                html += "
";
                html += "	";
                html += "NA	";
                html += "" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + "	";
                html += "
\n";
            }
        });
        html += "
\n";
        html += "
\n";
        title = "Sync Status";
        attachElem(event, html, title);
    });

    $scope.showGroupSummary = function(event, id) {
        try{
            var elem = $(event.target).parent();
            // if the popover is visible already, then exit the function here
            if(elem.data()['bs.popover'].tip().hasClass('in')){
                return;
            }
        }
        catch(err){
            var inventory;
            if (!Empty(id)) {
                inventory = Find({ list: $scope.inventories, key: 'id', val: id });
                if (inventory.syncStatus !== 'na') {
                    Wait('start');
                    Rest.setUrl(inventory.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5');
                    Rest.get()
                        .success(function(data) {
                            $scope.$emit('GroupSummaryReady', event, inventory, data);
                        })
                        .error(function(data, status) {
                            ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
                                msg: 'Call to ' + inventory.related.inventory_sources + ' failed. GET returned status: ' + status
                            });
                        });
                }
            }
        }
    };

    $scope.showHostSummary = function(event, id) {
        try{
            var elem = $(event.target).parent();
            // if the popover is visible already, then exit the function here
            if(elem.data()['bs.popover'].tip().hasClass('in')){
                return;
            }
        }
        catch(err){
            var url, inventory;
            if (!Empty(id)) {
                inventory = Find({ list: $scope.inventories, key: 'id', val: id });
                if (inventory.total_hosts > 0) {
                    Wait('start');
                    url = GetBasePath('jobs') + "?type=job&inventory=" + id + "&failed=";
                    url += (inventory.has_active_failures) ? 'true' : "false";
                    url += "&order_by=-finished&page_size=5";
                    Rest.setUrl(url);
                    Rest.get()
                        .success( function(data) {
                            $scope.$emit('HostSummaryReady', event, data);
                        })
                        .error( function(data, status) {
                            ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
                                msg: 'Call to ' + url + ' failed. GET returned: ' + status
                            });
                        });
                }
            }
        }
    };

    $scope.viewJob = function(url) {

        // Pull the id out of the URL
        var id = url.replace(/^\//, '').split('/')[3];

        $state.go('inventorySyncStdout', {id: id});

    };

    $scope.addInventory = function () {
        $state.go('inventories.add');
    };

    $scope.editInventory = function (id) {
        $state.go('inventories.edit', {inventory_id: id});
    };

    $scope.manageInventory = function(id){
      $location.path($location.path() + '/' + id + '/manage');
    };

    $scope.deleteInventory = function (id, name) {

        var action = function () {
            var url = defaultUrl + id + '/';
            Wait('start');
            $('#prompt-modal').modal('hide');
            Rest.setUrl(url);
            Rest.destroy()
                .success(function () {
                    if (parseInt($state.params.inventory_id) === id) {
                        $state.go("^", null, {reload: true});
                    } else {
                       $state.go('.', null, {reload: true});
                       Wait('stop');
                    }
                })
                .error(function (data, status) {
                    ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
                        msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status
                    });
                });
        };

        Prompt({
            hdr: 'Delete',
            body: '
Are you sure you want to delete the inventory below?

' + $filter('sanitize')(name) + '
',
            action: action,
            actionText: 'DELETE'
        });
    };

    // Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status
    $scope.viewJobs = function (id) {
        $location.url('/jobs/?inventory__int=' + id);
    };

    $scope.viewFailedJobs = function (id) {
        $location.url('/jobs/?inventory__int=' + id + '&status=failed');
    };
}

export default ['$scope', '$rootScope', '$location', '$log',
    '$stateParams', '$compile', '$filter', 'Rest', 'Alert', 'InventoryList',
    'Prompt', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', 'rbacUiControlService', 'Dataset', InventoriesList
];
<|endoftext|>


<commit_before>if (Meteor.isServer) {
	Projects = new Meteor.Collection('projects');
  Meteor.startup(function () {
    return Meteor.methods({
    	removeAllPosts: function() {
    		return Projects.remove({});
    	}
    })
  });
}
<commit_msg>added 2nd commit of 1 Apr<commit_after>if (Meteor.isServer) {
	Projects = new Meteor.Collection('projects');
  Meteor.startup(function () {
    // code to run on server at startup
  });
}
<|endoftext|>


<commit_before>'use strict';
var assert = require('yeoman-assert');
var helpers = require('yeoman-test');
var fs = require('fs');
var os = require('os');
var path = require('path');

// TODO(bwavell): add a bunch more tests

describe('generator-alfresco:amp', function () {

  this.timeout(30000);

  var osTempDir = path.join(os.tmpdir(), 'temp-test');

  // We need a test project setup before we begin
  before(function (done) {
    helpers.run(path.join(__dirname, '../generators/app'))
      .inDir(osTempDir)
      .withOptions({ 'skip-install': true })
      .withPrompts({
        sdkVersion: '2.1.1',
        projectArtifactId: 'temp-test',
        removeDefaultSourceAmps: true,
      })
      .on('end', done);
  });

  describe('after creating both a repo and share amp', function () {

    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function() {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        }.bind(this))
        .withOptions({
          "force": true, // tests can't handle conflicts
          "war": 'both',
          "project-group-id": 'org.alfresco',
          "project-artifact-id": 'both-customizations',
          "project-version": '1.0.0-SNAPSHOT',
          "remove-default-source-samples": false,
          "create-parent": false,
          "parent-name": '',
          "parent-description": '',
          "repo-name": '',
          "repo-description": '',
        })
        .on('end', done);
    });

    it('amp files exist in project', function() {
      assert.file([
        path.join(osTempDir, 'customizations/both-customizations-repo-amp/pom.xml'),
        path.join(osTempDir, 'customizations/both-customizations-share-amp/pom.xml'),
      ]);
    });

  });

  describe('after creating repo amp', function () {

    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function() {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        }.bind(this))
        .withOptions({
          "force": true, // tests can't handle conflicts
          "war": 'repo',
          "project-group-id": 'org.alfresco',
          "project-artifact-id": 'repo-customizations',
          "project-version": '1.0.0-SNAPSHOT',
          "remove-default-source-samples": false,
          "create-parent": false,
          "parent-name": '',
          "parent-description": '',
          "repo-name": '',
          "repo-description": '',
        })
        .on('end', done);
    });

    it('repo amp files exist in project', function() {
      assert.file(path.join(osTempDir, 'customizations/repo-customizations-repo-amp/pom.xml'));
    });

    it('share amp files do NOT exist in project', function() {
      assert.noFile(path.join(osTempDir, 'customizations/repo-customizations-share-amp/pom.xml'));
    });

  });

  describe('after creating share amp', function () {

    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function() {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        }.bind(this))
        .withOptions({
          "force": true, // tests can't handle conflicts
          "war": 'share',
          "project-group-id": 'org.alfresco',
          "project-artifact-id": 'share-customizations',
          "project-version": '1.0.0-SNAPSHOT',
          "remove-default-source-samples": false,
          "create-parent": false,
          "parent-name": '',
          "parent-description": '',
          "repo-name": '',
          "repo-description": '',
        })
        .on('end', done);
    });

    it('share amp files exist in project', function() {
      assert.file(path.join(osTempDir, 'customizations/share-customizations-share-amp/pom.xml'));
    });

    it('repo amp files do NOT exist in project', function() {
      assert.noFile(path.join(osTempDir, 'customizations/share-customizations-repo-amp/pom.xml'));
    });

  });

  describe('after creating both repo and share amps in parent folder', function () {

    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function() {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        }.bind(this))
        .withOptions({
          "force": true, // tests can't handle conflicts
          "war": 'both',
          "project-group-id": 'org.alfresco',
          "project-artifact-id": 'both-parent',
          "project-version": '1.0.0-SNAPSHOT',
          "remove-default-source-samples": false,
          "create-parent": true,
          "parent-name": '',
          "parent-description": '',
          "repo-name": '',
          "repo-description": '',
        })
        .on('end', done);
    });

    it('amp files exist under the parent project folder', function() {
      assert.file([
        path.join(osTempDir, 'customizations/both-parent-parent/pom.xml'),
        path.join(osTempDir, 'customizations/both-parent-parent/both-parent-repo-amp/pom.xml'),
        path.join(osTempDir, 'customizations/both-parent-parent/both-parent-share-amp/pom.xml'),
      ]);
    });

  });

  describe('when creating amp with invalid war type', function() {

    before(function(done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function() {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        }.bind(this))
        .withOptions({
          "force": true, // tests can't handle conflicts
          "war": 'asdf',
          "project-artifact-id": 'invalid-war-type',
          "remove-default-source-samples": true,
        })
        .on('end', done);
    });

    it('nothing is created', function() {
      assert.noFile([
        path.join(osTempDir, 'customizations/invalid-war-type-repo-amp/pom.xml'),
        path.join(osTempDir, 'customizations/invalid-war-type-share-amp/pom.xml'),
      ]);
    });

  });

});
<commit_msg>increase amp sub-gen test coverage (#59)<commit_after>'use strict';
/* eslint-env node, mocha */
var assert = require('yeoman-assert');
var helpers = require('yeoman-test');
var os = require('os');
var path = require('path');

// TODO(bwavell): add a bunch more tests

describe('generator-alfresco:amp', function () {
  this.timeout(30000);

  var osTempDir = path.join(os.tmpdir(), 'temp-test');

  // We need a test project setup before we begin
  before(function (done) {
    helpers.run(path.join(__dirname, '../generators/app'))
      .inDir(osTempDir)
      .withOptions({ 'skip-install': true })
      .withPrompts({
        sdkVersion: '2.1.1',
        projectArtifactId: 'temp-test',
        removeDefaultSourceAmps: true,
      })
      .on('end', done);
  });

  describe('after creating both a repo and share amp', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function () {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        })
        .withOptions({
          'force': true, // tests can't handle conflicts
          'war': 'both',
          'project-group-id': 'org.alfresco',
          'project-artifact-id': 'both-customizations',
          'project-version': '1.0.0-SNAPSHOT',
          'remove-default-source-samples': false,
          'create-parent': false,
          'parent-name': '',
          'parent-description': '',
          'repo-name': '',
          'repo-description': '',
        })
        .on('end', done);
    });
  });

  describe('after creating both a repo and share amp and removing samples', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function () {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        })
        .withOptions({
          'force': true, // tests can't handle conflicts
          'war': 'both',
          'project-group-id': 'org.alfresco',
          'project-artifact-id': 'remove-samples',
          'project-version': '1.0.0-SNAPSHOT',
          'remove-default-source-samples': true,
          'create-parent': false,
          'parent-name': '',
          'parent-description': '',
          'repo-name': '',
          'repo-description': '',
        })
        .on('end', done);
    });

    it('amp files exist in project', function () {
      assert.file([
        path.join(osTempDir, 'customizations/remove-samples-repo-amp/pom.xml'),
        path.join(osTempDir, 'customizations/remove-samples-share-amp/pom.xml'),
      ]);
    });

    it('sample files do not exist in project', function () {
      assert.noFile([
        path.join(osTempDir, 'customizations/remove-samples-repo-amp/src/main/amp/web/css/demoamp.css'),
        path.join(osTempDir, 'customizations/remove-samples-share-amp/src/main/amp/web/js/example/widgets/TemplateWidget.js'),
      ]);
    });
  });

  describe('after creating both a repo and share amp via prompts', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function () {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        })
        .withOptions({
          'force': true, // tests can't handle conflicts
        })
        .withPrompts({
          'war': 'Both repo & share',
          'projectGroupId': 'org.alfresco',
          'projectArtifactIdPrefix': 'prompts',
          'projectVersion': '1.0.0-SNAPSHOT',
          'removeDefaultSourceSamples': false,
          'createParent': false,
          'parentName': 'parent name',
          'parentDescription': 'parent description',
          'repoName': 'repo name',
          'repoDescription': 'repo description',
          'shareName': 'share name',
          'shareDescription': 'share description',
        })
        .on('end', done);
    });

    it('amp files exist in project', function () {
      assert.file([
        path.join(osTempDir, 'customizations/prompts-repo-amp/pom.xml'),
        path.join(osTempDir, 'customizations/prompts-share-amp/pom.xml'),
      ]);
    });
  });

  describe('after creating repo amp', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function () {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        })
        .withOptions({
          'force': true, // tests can't handle conflicts
          'war': 'repo',
          'project-group-id': 'org.alfresco',
          'project-artifact-id': 'repo-customizations',
          'project-version': '1.0.0-SNAPSHOT',
          'remove-default-source-samples': false,
          'create-parent': false,
          'parent-name': '',
          'parent-description': '',
          'repo-name': '',
          'repo-description': '',
        })
        .on('end', done);
    });

    it('repo amp files exist in project', function () {
      assert.file(path.join(osTempDir, 'customizations/repo-customizations-repo-amp/pom.xml'));
    });

    it('share amp files do NOT exist in project', function () {
      assert.noFile(path.join(osTempDir, 'customizations/repo-customizations-share-amp/pom.xml'));
    });
  });

  describe('after creating share amp', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function () {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        })
        .withOptions({
          'force': true, // tests can't handle conflicts
          'war': 'share',
          'project-group-id': 'org.alfresco',
          'project-artifact-id': 'share-customizations',
          'project-version': '1.0.0-SNAPSHOT',
          'remove-default-source-samples': false,
          'create-parent': false,
          'parent-name': '',
          'parent-description': '',
          'repo-name': '',
          'repo-description': '',
        })
        .on('end', done);
    });

    it('share amp files exist in project', function () {
      assert.file(path.join(osTempDir, 'customizations/share-customizations-share-amp/pom.xml'));
    });

    it('repo amp files do NOT exist in project', function () {
      assert.noFile(path.join(osTempDir, 'customizations/share-customizations-repo-amp/pom.xml'));
    });
  });

  describe('after creating both repo and share amps in parent folder', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function () {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        })
        .withOptions({
          'force': true, // tests can't handle conflicts
          'war': 'both',
          'project-group-id': 'org.alfresco',
          'project-artifact-id': 'both-parent',
          'project-version': '1.0.0-SNAPSHOT',
          'remove-default-source-samples': false,
          'create-parent': true,
          'parent-name': 'parent name',
          'parent-description': 'parent description',
          'repo-name': 'repo name',
          'repo-description': 'repo description',
        })
        .on('end', done);
    });

    it('amp files exist under the parent project folder', function () {
      assert.file([
        path.join(osTempDir, 'customizations/both-parent-parent/pom.xml'),
        path.join(osTempDir, 'customizations/both-parent-parent/both-parent-repo-amp/pom.xml'),
        path.join(osTempDir, 'customizations/both-parent-parent/both-parent-share-amp/pom.xml'),
      ]);
    });
  });

  describe('when creating amp with invalid war type', function () {
    before(function (done) {
      helpers.run(path.join(__dirname, '../generators/amp'))
        // generator will create a temp directory and make sure it's empty
        .inTmpDir(function () {
          // HACK: we want our test to run inside the previously generated
          // directory and we don't want it to be empty, so this is a hack
          // for that.
          process.chdir(osTempDir);
        })
        .withOptions({
          'force': true, // tests can't handle conflicts
          'war': 'asdf',
          'project-artifact-id': 'invalid-war-type',
          'remove-default-source-samples': true,
        })
        .on('end', done);
    });

    it('nothing is created', function () {
      assert.noFile([
        path.join(osTempDir, 'customizations/invalid-war-type-repo-amp/pom.xml'),
        path.join(osTempDir, 'customizations/invalid-war-type-share-amp/pom.xml'),
      ]);
    });
  });
});
<|endoftext|>


<commit_before><commit_msg>fix(CreateServiceModal.js): reset hasChangesApplied flag on discard<commit_after><|endoftext|>


<commit_before><commit_msg>make enough bottom padding for rotated labels<commit_after><|endoftext|>


<commit_before>/*
 * angucomplete-alt
 * Autocomplete directive for AngularJS
 * This is a fork of Daryl Rowland's angucomplete with some extra features.
 * By Hidenari Nozaki
 */

/*! Copyright (c) 2014 Hidenari Nozaki and contributors | Licensed under the MIT license */

'use strict';

angular.module('angucomplete-alt', [] ).directive('angucompleteAlt', ['$parse', '$http', '$sce', '$timeout', function ($parse, $http, $sce, $timeout) {
  // keyboard events
  var KEY_DW  = 40;
  var KEY_UP  = 38;
  var KEY_ES  = 27;
  var KEY_EN  = 13;
  var KEY_BS  =  8;
  var KEY_DEL = 46;
  var KEY_TAB =  9;

  var MIN_LENGTH = 3;
  var PAUSE = 500;
  var BLUR_TIMEOUT = 200;

  // string constants
  var REQUIRED_CLASS = 'autocomplete-required';
  var TEXT_SEARCHING = 'Searching...';
  var TEXT_NORESULTS = 'No results found';

  return {
    restrict: 'EA',
    require: '^?form',
    scope: {
      selectedObject: '=',
      localData: '=',
      remoteUrlRequestFormatter: '=',
      remoteUrlResponseFormatter: '=',
      id: '@',
      placeholder: '@',
      remoteUrl: '@',
      remoteUrlDataField: '@',
      titleField: '@',
      descriptionField: '@',
      imageField: '@',
      inputClass: '@',
      pause: '@',
      searchFields: '@',
      minlength: '@',
      matchClass: '@',
      clearSelected: '@',
      overrideSuggestions: '@',
      fieldRequired: '@',
      fieldRequiredClass: '@'
    },
    template:
      '
' +
      '  <input id="{{id}}_value" ng-model="searchStr" type="text" placeholder="{{placeholder}}" class="{{inputClass}}" ng-focus="resetHideResults()" ng-blur="hideResults()" autocapitalize="off" autocorrect="off" autocomplete="off"/>' +
      '
' +
      '

' +
      '

' +
      '
' +
      '
' +
      '        ' +
      '

' +
      '
' +
      '

' +
      '
{{ result.title }}
' +
      '

' +
      '
{{result.description}}
' +
      '
' +
      '
' +
      '
',
    link: function(scope, elem, attrs, ctrl) {
      var inputField = elem.find('input');
      var minlength = MIN_LENGTH;
      var searchTimer = null;
      var lastSearchTerm = null;
      var hideTimer;
      var requiredClassName = REQUIRED_CLASS;
      var responseFormatter;

      scope.currentIndex = null;
      scope.searching = false;
      scope.searchStr = null;

      // for IE8 quirkiness about event.which
      function ie8EventNormalizer(event) {
        return event.which ? event.which : event.keyCode;
      }

      function callOrAssign(value) {
        if (typeof scope.selectedObject === 'function') {
          scope.selectedObject(value);
        }
        else {
          scope.selectedObject = value;
        }

        handleRequired(true);
      }

      function returnFunctionOrIdentity(fn) {
        return fn && typeof fn === 'function' ? fn : function(data) { return data; };
      }

      function setInputString(str) {
        callOrAssign({originalObject: str});

        if (scope.clearSelected) {
          scope.searchStr = null;
        }
        scope.showDropdown = false;
        scope.results = [];
      }

      function isNewSearchNeeded(newTerm, oldTerm) {
        return newTerm.length >= minlength && newTerm !== oldTerm;
      }

      function extractTitle(data) {
        // split title fields and run extractValue for each and join with ' '
        return scope.titleField.split(',')
          .map(function(field) {
            return extractValue(data, field);
          })
          .join(' ');
      }

      function extractValue(obj, key) {
        var keys, result;
        if (key) {
          keys= key.split('.');
          result = obj;
          keys.forEach(function(k) { result = result[k]; });
        }
        else {
          result = obj;
        }
        return result;
      }

      function findMatchString(target, str) {
        var result, matches, re = new RegExp(str, 'i');
        if (!target) { return; }
        matches = target.match(re);
        if (matches) {
          result = target.replace(re,
              ''+ matches[0] +'');
        }
        else {
          result = target;
        }
        return $sce.trustAsHtml(result);
      }

      function handleRequired(valid) {
        if (scope.fieldRequired && ctrl) {
          ctrl.$setValidity(requiredClassName, valid);
        }
      }

      function keyupHandler(event) {
        var which = ie8EventNormalizer(event);
        if (which === KEY_UP || which === KEY_DW || which === KEY_EN) {
          event.preventDefault();
        } else {
          if (!scope.searchStr || scope.searchStr === '') {
            scope.showDropdown = false;
            lastSearchTerm = null;
          } else if (isNewSearchNeeded(scope.searchStr, lastSearchTerm)) {
            lastSearchTerm = scope.searchStr;
            scope.showDropdown = true;
            scope.currentIndex = -1;
            scope.results = [];

            if (searchTimer) {
              $timeout.cancel(searchTimer);
            }

            scope.searching = true;

            searchTimer = $timeout(function() {
              scope.searchTimerComplete(scope.searchStr);
            }, scope.pause);
          }
          handleRequired(false);
        }
      }

      function specialKeyHandler(event) {
        var which = ie8EventNormalizer(event);
        if (which === KEY_ES) {
          scope.results = [];
          scope.showDropdown = false;
          scope.$apply();
        } else if (which === KEY_BS || which === KEY_DEL) {
          scope.$apply();
        }
      }

      function keydownHandler(event) {
        var which = ie8EventNormalizer(event);
        if (which === KEY_EN && scope.results) {
          event.preventDefault();
          if (scope.currentIndex >= 0 && scope.currentIndex < scope.results.length) {
            scope.selectResult(scope.results[scope.currentIndex]);
            scope.$apply();
          } else {
            if (scope.overrideSuggestions) {
              setInputString(scope.searchStr);
              scope.$apply();
            }
            else {
              scope.results = [];
              scope.$apply();
            }
          }
        } else if (which === KEY_DW && scope.results) {
          if ((scope.currentIndex + 1) < scope.results.length) {
            scope.$apply(function() {
              scope.currentIndex ++;
            });
          }
        } else if (which === KEY_UP && scope.results) {
          if (scope.currentIndex >= 1) {
            scope.$apply(function() {
              scope.currentIndex --;
            });
          }
        } else if (which === KEY_TAB && scope.results) {
          if (scope.currentIndex === -1) {
            event.preventDefault();
            scope.selectResult(scope.results[0]);
            scope.$apply();
          }
        }
      }

      function httpSuccessCallbackGen(str) {
        return function(responseData, status, headers, config) {
          scope.searching = false;
          scope.processResults(
            extractValue(responseFormatter(responseData), scope.remoteUrlDataField),
            str);
        };
      }

      function httpErrorCallback(errorRes, status, headers, config) {
        console.error('http error');
      }

      function getRemoteResults(str) {
        var params = {},
            url = scope.remoteUrl + str;
        if (scope.remoteUrlRequestFormatter) {
          params = {params: scope.remoteUrlRequestFormatter(str)};
          url = scope.remoteUrl;
        }
        $http.get(url, params)
          .success(httpSuccessCallbackGen(str))
          .error(httpErrorCallback);
      }

      function getLocalResults(str) {
        var i, match, s,
            searchFields = scope.searchFields.split(','),
            matches = [];

        for (i = 0; i < scope.localData.length; i++) {
          match = false;

          for (s = 0; s < searchFields.length; s++) {
            match = match || (scope.localData[i][searchFields[s]].toLowerCase().indexOf(str.toLowerCase()) >= 0);
          }

          if (match) {
            matches[matches.length] = scope.localData[i];
          }
        }

        scope.searching = false;
        scope.processResults(matches, str);
      }

      scope.hideResults = function() {
        hideTimer = $timeout(function() {
          scope.showDropdown = false;
        }, BLUR_TIMEOUT);
      };

      scope.resetHideResults = function() {
        if (hideTimer) {
          $timeout.cancel(hideTimer);
        }
      };

      scope.processResults = function(responseData, str) {
        var i, description, image, text;

        if (responseData && responseData.length > 0) {
          scope.results = [];

          for (i = 0; i < responseData.length; i++) {
            if (scope.titleField && scope.titleField !== '') {
              text = extractTitle(responseData[i]);
            }

            description = '';
            if (scope.descriptionField) {
              description = extractValue(responseData[i], scope.descriptionField);
            }

            image = '';
            if (scope.imageField) {
              image = extractValue(responseData[i], scope.imageField);
            }

            if (scope.matchClass) {
              text = findMatchString(text, str);
              description = findMatchString(description, str);
            }

            scope.results[scope.results.length] = {
              title: text,
              description: description,
              image: image,
              originalObject: responseData[i]
            };
          }
        } else {
          scope.results = [];
        }
      };

      scope.searchTimerComplete = function(str) {
        // Begin the search
        if (str.length < minlength) {
          return;
        }
        if (scope.localData) {
          getLocalResults(str);
        }
        else {
          getRemoteResults(str);
        }
      };

      scope.hoverRow = function(index) {
        scope.currentIndex = index;
      };

      scope.selectResult = function(result) {
        // Restore original values
        if (scope.matchClass) {
          result.title = extractTitle(result.originalObject);
          result.description = extractValue(result.originalObject, scope.descriptionField);
        }

        if (scope.clearSelected) {
          scope.searchStr = null;
        }
        else {
          scope.searchStr = lastSearchTerm = result.title;
        }
        callOrAssign(result);
        scope.showDropdown = false;
        scope.results = [];
      };

      // check required
      if (scope.fieldRequiredClass && scope.fieldRequiredClass !== '') {
        requiredClassName = scope.fieldRequiredClass;
      }

      // check min length
      if (scope.minlength && scope.minlength !== '') {
        minlength = scope.minlength;
      }

      // check pause time
      if (!scope.pause) {
        scope.pause = PAUSE;
      }

      // check clearSelected
      if (!scope.clearSelected) {
        scope.clearSelected = false;
      }

      // check override suggestions
      if (!scope.overrideSuggestions) {
        scope.overrideSuggestions = false;
      }

      // set strings for "Searching..." and "No results"
      scope.textSearching = attrs.textSearching ? attrs.textSearching : TEXT_SEARCHING;
      scope.textNoResults = attrs.textNoResults ? attrs.textNoResults : TEXT_NORESULTS;

      // register events
      inputField.on('keydown', keydownHandler);
      inputField.on('keyup', specialKeyHandler);
      inputField.on('keyup', keyupHandler);

      // set response formatter
      responseFormatter = returnFunctionOrIdentity(scope.remoteUrlResponseFormatter);
      // start with false
      handleRequired(false);
    }
  };
}]);
<commit_msg>Fix required support: - preventDefault for TAB was not needed - wrongly identifing required state once form becomes valid<commit_after>/*
 * angucomplete-alt
 * Autocomplete directive for AngularJS
 * This is a fork of Daryl Rowland's angucomplete with some extra features.
 * By Hidenari Nozaki
 */

/*! Copyright (c) 2014 Hidenari Nozaki and contributors | Licensed under the MIT license */

'use strict';

angular.module('angucomplete-alt', [] ).directive('angucompleteAlt', ['$parse', '$http', '$sce', '$timeout', function ($parse, $http, $sce, $timeout) {
  // keyboard events
  var KEY_DW  = 40;
  var KEY_UP  = 38;
  var KEY_ES  = 27;
  var KEY_EN  = 13;
  var KEY_BS  =  8;
  var KEY_DEL = 46;
  var KEY_TAB =  9;

  var MIN_LENGTH = 3;
  var PAUSE = 500;
  var BLUR_TIMEOUT = 200;

  // string constants
  var REQUIRED_CLASS = 'autocomplete-required';
  var TEXT_SEARCHING = 'Searching...';
  var TEXT_NORESULTS = 'No results found';

  return {
    restrict: 'EA',
    require: '^?form',
    scope: {
      selectedObject: '=',
      localData: '=',
      remoteUrlRequestFormatter: '=',
      remoteUrlResponseFormatter: '=',
      id: '@',
      placeholder: '@',
      remoteUrl: '@',
      remoteUrlDataField: '@',
      titleField: '@',
      descriptionField: '@',
      imageField: '@',
      inputClass: '@',
      pause: '@',
      searchFields: '@',
      minlength: '@',
      matchClass: '@',
      clearSelected: '@',
      overrideSuggestions: '@',
      fieldRequired: '@',
      fieldRequiredClass: '@'
    },
    template:
      '
' +
      '  <input id="{{id}}_value" ng-model="searchStr" type="text" placeholder="{{placeholder}}" class="{{inputClass}}" ng-focus="resetHideResults()" ng-blur="hideResults()" autocapitalize="off" autocorrect="off" autocomplete="off"/>' +
      '
' +
      '

' +
      '

' +
      '
' +
      '
' +
      '        ' +
      '

' +
      '
' +
      '

' +
      '
{{ result.title }}
' +
      '

' +
      '
{{result.description}}
' +
      '
' +
      '
' +
      '
',
    link: function(scope, elem, attrs, ctrl) {
      var inputField = elem.find('input');
      var minlength = MIN_LENGTH;
      var searchTimer = null;
      var lastSearchTerm = null;
      var hideTimer;
      var requiredClassName = REQUIRED_CLASS;
      var responseFormatter;
      var validState = null;

      scope.currentIndex = null;
      scope.searching = false;
      scope.searchStr = null;

      // for IE8 quirkiness about event.which
      function ie8EventNormalizer(event) {
        return event.which ? event.which : event.keyCode;
      }

      function callOrAssign(value) {
        if (typeof scope.selectedObject === 'function') {
          scope.selectedObject(value);
        }
        else {
          scope.selectedObject = value;
        }

        handleRequired(true);
      }

      function returnFunctionOrIdentity(fn) {
        return fn && typeof fn === 'function' ? fn : function(data) { return data; };
      }

      function setInputString(str) {
        callOrAssign({originalObject: str});

        if (scope.clearSelected) {
          scope.searchStr = null;
        }
        scope.showDropdown = false;
        scope.results = [];
      }

      function isNewSearchNeeded(newTerm, oldTerm) {
        return newTerm.length >= minlength && newTerm !== oldTerm;
      }

      function extractTitle(data) {
        // split title fields and run extractValue for each and join with ' '
        return scope.titleField.split(',')
          .map(function(field) {
            return extractValue(data, field);
          })
          .join(' ');
      }

      function extractValue(obj, key) {
        var keys, result;
        if (key) {
          keys= key.split('.');
          result = obj;
          keys.forEach(function(k) { result = result[k]; });
        }
        else {
          result = obj;
        }
        return result;
      }

      function findMatchString(target, str) {
        var result, matches, re = new RegExp(str, 'i');
        if (!target) { return; }
        matches = target.match(re);
        if (matches) {
          result = target.replace(re,
              ''+ matches[0] +'');
        }
        else {
          result = target;
        }
        return $sce.trustAsHtml(result);
      }

      function handleRequired(valid) {
        validState = scope.searchStr;
        if (scope.fieldRequired && ctrl) {
          ctrl.$setValidity(requiredClassName, valid);
        }
      }

      function keyupHandler(event) {
        var which = ie8EventNormalizer(event);
        if (which === KEY_UP || which === KEY_DW || which === KEY_EN) {
          event.preventDefault();
        }
        else {
          if (!scope.searchStr || scope.searchStr === '') {
            scope.showDropdown = false;
            lastSearchTerm = null;
          } else if (isNewSearchNeeded(scope.searchStr, lastSearchTerm)) {
            lastSearchTerm = scope.searchStr;
            scope.showDropdown = true;
            scope.currentIndex = -1;
            scope.results = [];

            if (searchTimer) {
              $timeout.cancel(searchTimer);
            }

            scope.searching = true;

            searchTimer = $timeout(function() {
              scope.searchTimerComplete(scope.searchStr);
            }, scope.pause);
          }

          if (validState && validState !== scope.searchStr) {
            handleRequired(false);
          }
        }
      }

      function specialKeyHandler(event) {
        var which = ie8EventNormalizer(event);
        if (which === KEY_ES) {
          scope.results = [];
          scope.showDropdown = false;
          scope.$apply();
        } else if (which === KEY_BS || which === KEY_DEL) {
          scope.$apply();
        }
      }

      function keydownHandler(event) {
        var which = ie8EventNormalizer(event);
        if (which === KEY_EN && scope.results) {
          event.preventDefault();
          if (scope.currentIndex >= 0 && scope.currentIndex < scope.results.length) {
            scope.selectResult(scope.results[scope.currentIndex]);
            scope.$apply();
          } else {
            if (scope.overrideSuggestions) {
              setInputString(scope.searchStr);
              scope.$apply();
            }
            else {
              scope.results = [];
              scope.$apply();
            }
          }
        } else if (which === KEY_DW && scope.results) {
          if ((scope.currentIndex + 1) < scope.results.length) {
            scope.$apply(function() {
              scope.currentIndex ++;
            });
          }
        } else if (which === KEY_UP && scope.results) {
          if (scope.currentIndex >= 1) {
            scope.$apply(function() {
              scope.currentIndex --;
            });
          }
        } else if (which === KEY_TAB && scope.results && scope.results.length > 0) {
          if (scope.currentIndex === -1) {
            scope.selectResult(scope.results[0]);
            scope.$apply();
          }
        }
      }

      function httpSuccessCallbackGen(str) {
        return function(responseData, status, headers, config) {
          scope.searching = false;
          scope.processResults(
            extractValue(responseFormatter(responseData), scope.remoteUrlDataField),
            str);
        };
      }

      function httpErrorCallback(errorRes, status, headers, config) {
        console.error('http error');
      }

      function getRemoteResults(str) {
        var params = {},
            url = scope.remoteUrl + str;
        if (scope.remoteUrlRequestFormatter) {
          params = {params: scope.remoteUrlRequestFormatter(str)};
          url = scope.remoteUrl;
        }
        $http.get(url, params)
          .success(httpSuccessCallbackGen(str))
          .error(httpErrorCallback);
      }

      function getLocalResults(str) {
        var i, match, s,
            searchFields = scope.searchFields.split(','),
            matches = [];

        for (i = 0; i < scope.localData.length; i++) {
          match = false;

          for (s = 0; s < searchFields.length; s++) {
            match = match || (scope.localData[i][searchFields[s]].toLowerCase().indexOf(str.toLowerCase()) >= 0);
          }

          if (match) {
            matches[matches.length] = scope.localData[i];
          }
        }

        scope.searching = false;
        scope.processResults(matches, str);
      }

      scope.hideResults = function() {
        hideTimer = $timeout(function() {
          scope.showDropdown = false;
        }, BLUR_TIMEOUT);
      };

      scope.resetHideResults = function() {
        if (hideTimer) {
          $timeout.cancel(hideTimer);
        }
      };

      scope.processResults = function(responseData, str) {
        var i, description, image, text;

        if (responseData && responseData.length > 0) {
          scope.results = [];

          for (i = 0; i < responseData.length; i++) {
            if (scope.titleField && scope.titleField !== '') {
              text = extractTitle(responseData[i]);
            }

            description = '';
            if (scope.descriptionField) {
              description = extractValue(responseData[i], scope.descriptionField);
            }

            image = '';
            if (scope.imageField) {
              image = extractValue(responseData[i], scope.imageField);
            }

            if (scope.matchClass) {
              text = findMatchString(text, str);
              description = findMatchString(description, str);
            }

            scope.results[scope.results.length] = {
              title: text,
              description: description,
              image: image,
              originalObject: responseData[i]
            };
          }
        } else {
          scope.results = [];
        }
      };

      scope.searchTimerComplete = function(str) {
        // Begin the search
        if (str.length < minlength) {
          return;
        }
        if (scope.localData) {
          getLocalResults(str);
        }
        else {
          getRemoteResults(str);
        }
      };

      scope.hoverRow = function(index) {
        scope.currentIndex = index;
      };

      scope.selectResult = function(result) {
        // Restore original values
        if (scope.matchClass) {
          result.title = extractTitle(result.originalObject);
          result.description = extractValue(result.originalObject, scope.descriptionField);
        }

        if (scope.clearSelected) {
          scope.searchStr = null;
        }
        else {
          scope.searchStr = lastSearchTerm = result.title;
        }
        callOrAssign(result);
        scope.showDropdown = false;
        scope.results = [];
      };

      // check required
      if (scope.fieldRequiredClass && scope.fieldRequiredClass !== '') {
        requiredClassName = scope.fieldRequiredClass;
      }

      // check min length
      if (scope.minlength && scope.minlength !== '') {
        minlength = scope.minlength;
      }

      // check pause time
      if (!scope.pause) {
        scope.pause = PAUSE;
      }

      // check clearSelected
      if (!scope.clearSelected) {
        scope.clearSelected = false;
      }

      // check override suggestions
      if (!scope.overrideSuggestions) {
        scope.overrideSuggestions = false;
      }

      // check override suggestions
      if (scope.fieldRequired && ctrl) {
        // start with false
        handleRequired(false);
      }

      // set strings for "Searching..." and "No results"
      scope.textSearching = attrs.textSearching ? attrs.textSearching : TEXT_SEARCHING;
      scope.textNoResults = attrs.textNoResults ? attrs.textNoResults : TEXT_NORESULTS;

      // register events
      inputField.on('keydown', keydownHandler);
      inputField.on('keyup', specialKeyHandler);
      inputField.on('keyup', keyupHandler);

      // set response formatter
      responseFormatter = returnFunctionOrIdentity(scope.remoteUrlResponseFormatter);
    }
  };
}]);
<|endoftext|>