<commit_before>import { fetch } from 'global';
import { getSourceType, init as initRefs } from '../modules/refs';

jest.mock('global', () => {
  const globalMock = {
    fetch: jest.fn(() => Promise.resolve({})),
  };
  // Change global.location value to handle edge cases
  // Add additional variations of global.location mock return values in this array.
  // NOTE: The order must match the order that global.location is called in the unit tests.
  const edgecaseLocations = [
    { origin: 'https://storybook.js.org', pathname: '/storybook/index.html' },
  ];
  // global.location value after all edgecaseLocations are returned
  const lastLocation = { origin: 'https://storybook.js.org', pathname: '/storybook/' };
  Object.defineProperties(globalMock, {
    location: {
      get: edgecaseLocations
        .reduce((mockFn, location) => mockFn.mockReturnValueOnce(location), jest.fn())
        .mockReturnValue(lastLocation),
    },
  });
  return globalMock;
});

const provider = {
  getConfig: () => ({
    refs: {
      fake: {
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      },
    },
  }),
};

const store = {
  getState: () => ({
    refs: {
      fake: {
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      },
    },
  }),
  setState: jest.fn(() => {}),
};

const emptyResponse = Promise.resolve({
  ok: true,
  json: async () => ({}),
});

const setupResponses = (
  a = emptyResponse,
  b = emptyResponse,
  c = emptyResponse,
  d = emptyResponse
) => {
  fetch.mockClear();
  store.setState.mockClear();

  fetch.mockImplementation((l, o) => {
    if (l.includes('stories') && o.credentials === 'omit') {
      return Promise.resolve({
        ok: a.ok,
        json: a.response,
      });
    }
    if (l.includes('stories') && o.credentials === 'include') {
      return Promise.resolve({
        ok: b.ok,
        json: b.response,
      });
    }
    if (l.includes('iframe')) {
      return Promise.resolve({
        ok: c.ok,
        json: c.response,
      });
    }
    if (l.includes('metadata')) {
      return Promise.resolve({
        ok: d.ok,
        json: d.response,
      });
    }
    return Promise.resolve({
      ok: false,
      json: () => {
        throw new Error('not ok');
      },
    });
  });
};

describe('Refs API', () => {
  describe('getSourceType(source)', () => {
    // These tests must be run first and in correct order.
    // The order matches the "edgecaseLocations" order in the 'global' mock function above.
    describe('edge cases', () => {
      it('returns "local" when source matches location with /index.html in path', () => {
        // mockReturnValue(edgecaseLocations[0])
        expect(getSourceType('https://storybook.js.org/storybook/iframe.html')).toEqual([
          'local',
          'https://storybook.js.org/storybook',
        ]);
      });
      it('returns "correct url" when source does not match location', () => {
        expect(getSourceType('https://external.com/storybook/')).toEqual([
          'external',
          'https://external.com/storybook',
        ]);
      });
    });
    // Other tests use "lastLocation" for the 'global' mock
    it('returns "local" when source matches location', () => {
      expect(getSourceType('https://storybook.js.org/storybook/iframe.html')).toEqual([
        'local',
        'https://storybook.js.org/storybook',
      ]);
    });
    it('returns "external" when source does not match location', () => {
      expect(getSourceType('https://external.com/storybook/iframe.html')).toEqual([
        'external',
        'https://external.com/storybook',
      ]);
    });
  });

  describe('checkRef', () => {
    it('on initialization it checks refs', async () => {
      // given
      initRefs({ provider, store });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
        ]
      `);
    });

    it('checks refs (all fail)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      setupResponses(
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('not ok');
          },
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "error": Object {
                "message": "Error: Loading of ref failed
          at fetch (lib/api/src/modules/refs.ts)

        URL: https://example.com

        We weren't able to load the above URL,
        it's possible a CORS error happened.

        Please check your dev-tools network tab.",
              },
              "id": "fake",
              "ready": false,
              "stories": undefined,
              "title": "Fake",
              "type": "auto-inject",
              "url": "https://example.com",
            },
          },
        }
      `);
    });

    it('checks refs (success)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      setupResponses(
        {
          ok: true,
          response: async () => ({ stories: {} }),
        },
        {
          ok: true,
          response: async () => ({ stories: {} }),
        },
        {
          ok: true,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: true,
          response: async () => ({
            versions: {},
          }),
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
          Array [
            "https://example.com/metadata.json",
            Object {
              "cache": "no-cache",
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "id": "fake",
              "ready": false,
              "stories": Object {},
              "title": "Fake",
              "type": "lazy",
              "url": "https://example.com",
              "versions": Object {},
            },
          },
        }
      `);
    });

    it('checks refs (auth)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      setupResponses(
        {
          ok: true,
          response: async () => ({ loginUrl: 'https://example.com/login' }),
        },
        {
          ok: false,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: true,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('not ok');
          },
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
          Array [
            "https://example.com/metadata.json",
            Object {
              "cache": "no-cache",
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "id": "fake",
              "loginUrl": "https://example.com/login",
              "ready": false,
              "stories": undefined,
              "title": "Fake",
              "type": "auto-inject",
              "url": "https://example.com",
            },
          },
        }
      `);
    });

    it('checks refs (mixed)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      fetch.mockClear();
      store.setState.mockClear();

      setupResponses(
        {
          ok: true,
          response: async () => ({ loginUrl: 'https://example.com/login' }),
        },
        {
          ok: true,
          response: async () => ({ stories: {} }),
        },
        {
          ok: true,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: true,
          response: async () => ({
            versions: { '1.0.0': 'https://example.com/v1', '2.0.0': 'https://example.com' },
          }),
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
          Array [
            "https://example.com/metadata.json",
            Object {
              "cache": "no-cache",
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "id": "fake",
              "ready": false,
              "stories": Object {},
              "title": "Fake",
              "type": "lazy",
              "url": "https://example.com",
              "versions": Object {
                "1.0.0": "https://example.com/v1",
                "2.0.0": "https://example.com",
              },
            },
          },
        }
      `);
    });

    it('checks refs (cors)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      setupResponses(
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        },
        {
          ok: true,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "id": "fake",
              "ready": false,
              "stories": undefined,
              "title": "Fake",
              "type": "auto-inject",
              "url": "https://example.com",
            },
          },
        }
      `);
    });
  });
});
<commit_msg>Update snapshots<commit_after>import { fetch } from 'global';
import { getSourceType, init as initRefs } from '../modules/refs';

jest.mock('global', () => {
  const globalMock = {
    fetch: jest.fn(() => Promise.resolve({})),
  };
  // Change global.location value to handle edge cases
  // Add additional variations of global.location mock return values in this array.
  // NOTE: The order must match the order that global.location is called in the unit tests.
  const edgecaseLocations = [
    { origin: 'https://storybook.js.org', pathname: '/storybook/index.html' },
  ];
  // global.location value after all edgecaseLocations are returned
  const lastLocation = { origin: 'https://storybook.js.org', pathname: '/storybook/' };
  Object.defineProperties(globalMock, {
    location: {
      get: edgecaseLocations
        .reduce((mockFn, location) => mockFn.mockReturnValueOnce(location), jest.fn())
        .mockReturnValue(lastLocation),
    },
  });
  return globalMock;
});

const provider = {
  getConfig: () => ({
    refs: {
      fake: {
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      },
    },
  }),
};

const store = {
  getState: () => ({
    refs: {
      fake: {
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      },
    },
  }),
  setState: jest.fn(() => {}),
};

const emptyResponse = Promise.resolve({
  ok: true,
  json: async () => ({}),
});

const setupResponses = (
  a = emptyResponse,
  b = emptyResponse,
  c = emptyResponse,
  d = emptyResponse
) => {
  fetch.mockClear();
  store.setState.mockClear();

  fetch.mockImplementation((l, o) => {
    if (l.includes('stories') && o.credentials === 'omit') {
      return Promise.resolve({
        ok: a.ok,
        json: a.response,
      });
    }
    if (l.includes('stories') && o.credentials === 'include') {
      return Promise.resolve({
        ok: b.ok,
        json: b.response,
      });
    }
    if (l.includes('iframe')) {
      return Promise.resolve({
        ok: c.ok,
        json: c.response,
      });
    }
    if (l.includes('metadata')) {
      return Promise.resolve({
        ok: d.ok,
        json: d.response,
      });
    }
    return Promise.resolve({
      ok: false,
      json: () => {
        throw new Error('not ok');
      },
    });
  });
};

describe('Refs API', () => {
  describe('getSourceType(source)', () => {
    // These tests must be run first and in correct order.
    // The order matches the "edgecaseLocations" order in the 'global' mock function above.
    describe('edge cases', () => {
      it('returns "local" when source matches location with /index.html in path', () => {
        // mockReturnValue(edgecaseLocations[0])
        expect(getSourceType('https://storybook.js.org/storybook/iframe.html')).toEqual([
          'local',
          'https://storybook.js.org/storybook',
        ]);
      });
      it('returns "correct url" when source does not match location', () => {
        expect(getSourceType('https://external.com/storybook/')).toEqual([
          'external',
          'https://external.com/storybook',
        ]);
      });
    });
    // Other tests use "lastLocation" for the 'global' mock
    it('returns "local" when source matches location', () => {
      expect(getSourceType('https://storybook.js.org/storybook/iframe.html')).toEqual([
        'local',
        'https://storybook.js.org/storybook',
      ]);
    });
    it('returns "external" when source does not match location', () => {
      expect(getSourceType('https://external.com/storybook/iframe.html')).toEqual([
        'external',
        'https://external.com/storybook',
      ]);
    });
  });

  describe('checkRef', () => {
    it('on initialization it checks refs', async () => {
      // given
      initRefs({ provider, store });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
        ]
      `);
    });

    it('checks refs (all fail)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      setupResponses(
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('not ok');
          },
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "error": Object {
                "message": "Error: Loading of ref failed
          at fetch (lib/api/src/modules/refs.ts)

        URL: https://example.com

        We weren't able to load the above URL,
        it's possible a CORS error happened.

        Please check your dev-tools network tab.",
              },
              "id": "fake",
              "ready": false,
              "stories": undefined,
              "title": "Fake",
              "type": "auto-inject",
              "url": "https://example.com",
            },
          },
        }
      `);
    });

    it('checks refs (success)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      setupResponses(
        {
          ok: true,
          response: async () => ({ stories: {} }),
        },
        {
          ok: true,
          response: async () => ({ stories: {} }),
        },
        {
          ok: true,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: true,
          response: async () => ({
            versions: {},
          }),
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
          Array [
            "https://example.com/metadata.json",
            Object {
              "cache": "no-cache",
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "error": undefined,
              "id": "fake",
              "ready": false,
              "stories": Object {},
              "title": "Fake",
              "type": "lazy",
              "url": "https://example.com",
              "versions": Object {},
            },
          },
        }
      `);
    });

    it('checks refs (auth)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      setupResponses(
        {
          ok: true,
          response: async () => ({ loginUrl: 'https://example.com/login' }),
        },
        {
          ok: false,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: true,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('not ok');
          },
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
          Array [
            "https://example.com/metadata.json",
            Object {
              "cache": "no-cache",
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "error": undefined,
              "id": "fake",
              "loginUrl": "https://example.com/login",
              "ready": false,
              "stories": undefined,
              "title": "Fake",
              "type": "auto-inject",
              "url": "https://example.com",
            },
          },
        }
      `);
    });

    it('checks refs (mixed)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      fetch.mockClear();
      store.setState.mockClear();

      setupResponses(
        {
          ok: true,
          response: async () => ({ loginUrl: 'https://example.com/login' }),
        },
        {
          ok: true,
          response: async () => ({ stories: {} }),
        },
        {
          ok: true,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: true,
          response: async () => ({
            versions: { '1.0.0': 'https://example.com/v1', '2.0.0': 'https://example.com' },
          }),
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
          Array [
            "https://example.com/metadata.json",
            Object {
              "cache": "no-cache",
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "error": undefined,
              "id": "fake",
              "ready": false,
              "stories": Object {},
              "title": "Fake",
              "type": "lazy",
              "url": "https://example.com",
              "versions": Object {
                "1.0.0": "https://example.com/v1",
                "2.0.0": "https://example.com",
              },
            },
          },
        }
      `);
    });

    it('checks refs (cors)', async () => {
      // given
      const { api } = initRefs({ provider, store }, { runCheck: false });

      setupResponses(
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        },
        {
          ok: true,
          response: async () => {
            throw new Error('not ok');
          },
        },
        {
          ok: false,
          response: async () => {
            throw new Error('Failed to fetch');
          },
        }
      );

      await api.checkRef({
        id: 'fake',
        url: 'https://example.com',
        title: 'Fake',
      });

      expect(fetch.mock.calls).toMatchInlineSnapshot(`
        Array [
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "include",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/stories.json",
            Object {
              "credentials": "omit",
              "headers": Object {
                "Accept": "application/json",
              },
            },
          ],
          Array [
            "https://example.com/iframe.html",
            Object {
              "cors": "no-cors",
              "credentials": "omit",
            },
          ],
        ]
      `);

      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`
        Object {
          "refs": Object {
            "fake": Object {
              "error": undefined,
              "id": "fake",
              "ready": false,
              "stories": undefined,
              "title": "Fake",
              "type": "auto-inject",
              "url": "https://example.com",
            },
          },
        }
      `);
    });
  });
});
<|endoftext|>


<commit_before>/*
 * Copyright 2016 resin.io
 *
 * 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
 *
 *    http://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.
 */

'use strict'

const _ = require('lodash')
const path = require('path')
const imageStream = require('../sdk/image-stream')
const fileExtensions = require('./file-extensions')

/**
 * @summary Build an extension list getter from a type
 * @function
 * @private
 *
 * @param {String} type - file type
 * @returns {Function} extension list getter
 *
 * @example
 * const extensions = getExtensionsFromTypeGetter('archive')();
 */
const getExtensionsFromTypeGetter = (type) => {
  return () => {
    return _.map(_.filter(imageStream.supportedFileTypes, {
      type
    }), 'extension')
  }
}

/**
 * @summary Get compressed extensions
 * @function
 * @public
 *
 * @returns {String[]} compressed extensions
 *
 * @example
 * _.each(supportedFormats.getCompressedExtensions(), (extension) => {
 *   console.log('We support the ' + extension + ' compressed file format');
 * });
 */
exports.getCompressedExtensions = getExtensionsFromTypeGetter('compressed')

/**
 * @summary Get non compressed extensions
 * @function
 * @public
 *
 * @returns {String[]} no compressed extensions
 *
 * @example
 * _.each(supportedFormats.getNonCompressedExtensions(), (extension) => {
 *   console.log('We support the ' + extension + ' file format');
 * });
 */
exports.getNonCompressedExtensions = getExtensionsFromTypeGetter('image')

/**
 * @summary Get archive extensions
 * @function
 * @public
 *
 * @returns {String[]} archive extensions
 *
 * @example
 * _.each(supportedFormats.getArchiveExtensions(), (extension) => {
 *   console.log('We support the ' + extension + ' file format');
 * });
 */
exports.getArchiveExtensions = getExtensionsFromTypeGetter('archive')

/**
 * @summary Get all supported extensions
 * @function
 * @public
 *
 * @returns {String[]} extensions
 *
 * @example
 * _.each(supportedFormats.getAllExtensions(), (extension) => {
 *   console.log('We support the ' + extension + ' format');
 * });
 */
exports.getAllExtensions = () => {
  return _.map(imageStream.supportedFileTypes, 'extension')
}

/**
 * @summary Check if an image is supported
 * @function
 * @public
 *
 * @param {String} imagePath - image path
 * @returns {Boolean} whether the image is supported
 *
 * @example
 * if (supportedFormats.isSupportedImage('foo.iso.bz2')) {
 *   console.log('The image is supported!');
 * }
 */
exports.isSupportedImage = (imagePath) => {
  const lastExtension = fileExtensions.getLastFileExtension(imagePath)
  const penultimateExtension = fileExtensions.getPenultimateFileExtension(imagePath)

  if (_.some([
    _.includes(exports.getNonCompressedExtensions(), lastExtension),
    _.includes(exports.getArchiveExtensions(), lastExtension)
  ])) {
    return true
  }

  if (_.every([
    _.includes(exports.getCompressedExtensions(), lastExtension),
    _.includes(exports.getNonCompressedExtensions(), penultimateExtension)
  ])) {
    return true
  }

  return _.isNil(penultimateExtension) &&
    _.includes(exports.getCompressedExtensions(), lastExtension)
}

/**
 * @summary Check if an image seems to be a Windows image
 * @function
 * @public
 *
 * @param {String} imagePath - image path
 * @returns {Boolean} whether the image seems to be a Windows image
 *
 * @example
 * if (supportedFormats.looksLikeWindowsImage('path/to/en_windows_7_ultimate_with_sp1_x86_dvd_u_677460.iso')) {
 *   console.log('Looks like a Windows image');
 * }
 */
exports.looksLikeWindowsImage = (imagePath) => {
  const regex = /windows|win7|win8|win10|winxp/i
  return regex.test(path.basename(imagePath))
}
<commit_msg>Remove usage of old sdk in supported-formats<commit_after>/*
 * Copyright 2016 resin.io
 *
 * 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
 *
 *    http://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.
 */

'use strict'

const sdk = require('etcher-sdk')
const _ = require('lodash')
const mime = require('mime')
const path = require('path')

const fileExtensions = require('./file-extensions')

/**
 * @summary Get compressed extensions
 * @function
 * @public
 *
 * @returns {String[]} compressed extensions
 *
 * @example
 * _.each(supportedFormats.getCompressedExtensions(), (extension) => {
 *   console.log('We support the ' + extension + ' compressed file format');
 * });
 */
exports.getCompressedExtensions = () => {
  const result = []
  for (const [ mimetype, cls ] of sdk.sourceDestination.SourceDestination.mimetypes.entries()) {
    if (cls.prototype instanceof sdk.sourceDestination.CompressedSource) {
      const mtype = mime.getExtension(mimetype)
      if (mtype != null) {
        result.push(mtype)
      }
    }
  }
  return result
}

/**
 * @summary Get non compressed extensions
 * @function
 * @public
 *
 * @returns {String[]} no compressed extensions
 *
 * @example
 * _.each(supportedFormats.getNonCompressedExtensions(), (extension) => {
 *   console.log('We support the ' + extension + ' file format');
 * });
 */
exports.getNonCompressedExtensions = () => {
  return sdk.sourceDestination.SourceDestination.imageExtensions
}

/**
 * @summary Get archive extensions
 * @function
 * @public
 *
 * @returns {String[]} archive extensions
 *
 * @example
 * _.each(supportedFormats.getArchiveExtensions(), (extension) => {
 *   console.log('We support the ' + extension + ' file format');
 * });
 */
exports.getArchiveExtensions = () => {
  return [ 'zip', 'etch' ]
}

/**
 * @summary Get all supported extensions
 * @function
 * @public
 *
 * @returns {String[]} extensions
 *
 * @example
 * _.each(supportedFormats.getAllExtensions(), (extension) => {
 *   console.log('We support the ' + extension + ' format');
 * });
 */
exports.getAllExtensions = () => {
  return [ ...exports.getArchiveExtensions(), ...exports.getNonCompressedExtensions(), ...exports.getCompressedExtensions() ]
}

/**
 * @summary Check if an image is supported
 * @function
 * @public
 *
 * @param {String} imagePath - image path
 * @returns {Boolean} whether the image is supported
 *
 * @example
 * if (supportedFormats.isSupportedImage('foo.iso.bz2')) {
 *   console.log('The image is supported!');
 * }
 */
exports.isSupportedImage = (imagePath) => {
  const lastExtension = fileExtensions.getLastFileExtension(imagePath)
  const penultimateExtension = fileExtensions.getPenultimateFileExtension(imagePath)

  if (_.some([
    _.includes(exports.getNonCompressedExtensions(), lastExtension),
    _.includes(exports.getArchiveExtensions(), lastExtension)
  ])) {
    return true
  }

  if (_.every([
    _.includes(exports.getCompressedExtensions(), lastExtension),
    _.includes(exports.getNonCompressedExtensions(), penultimateExtension)
  ])) {
    return true
  }

  return _.isNil(penultimateExtension) &&
    _.includes(exports.getCompressedExtensions(), lastExtension)
}

/**
 * @summary Check if an image seems to be a Windows image
 * @function
 * @public
 *
 * @param {String} imagePath - image path
 * @returns {Boolean} whether the image seems to be a Windows image
 *
 * @example
 * if (supportedFormats.looksLikeWindowsImage('path/to/en_windows_7_ultimate_with_sp1_x86_dvd_u_677460.iso')) {
 *   console.log('Looks like a Windows image');
 * }
 */
exports.looksLikeWindowsImage = (imagePath) => {
  const regex = /windows|win7|win8|win10|winxp/i
  return regex.test(path.basename(imagePath))
}
<|endoftext|>


<commit_before>'use strict';

let mutator,
    figureClass,
    figureColor,
    figureForm,
    sizes,
    figureX,
    figureY,
    arrCoords,
    count;

const forms = ["circle", "square"],
      sizeValues = ["30px", "40px", "50px", "60px"],
      greenRange = ['#abf977','#a8f877','#a5f776','#a0f775','#9cf575','#99f574','#96f474','#93f473','#8ff273','#8af172','#86f172','#81f071','#7eef71','#7bee70','#77ed70','#72ed6f','#6deb6f','#68eb6e','#62ea6d','#5ee96d','#5ae86d','#56e76c','#50e76c','#49e56b','#42e46b','#39e36a','#30e369','#23e269','#18e168','#00e068'],
      orangeRange = ['#e05900','#e05c00','#e05f00','#e06100','#e06400','#e16700','#e16900','#e16c00','#e16f00','#e17100','#e17300','#e17700','#e17800','#e17b00','#e17e00','#e18000','#e18300','#e18500','#e18700','#e18900','#e18b00','#e18e00','#e19000','#e19300','#e19400','#e19600','#e09a00','#e09c00','#e09d00','#e0a000'];

arrCoords = [];

const changePosition = () => {
  figureX = getRandom(0, (document.body.clientWidth - 60));;
  figureY = getRandom(35, (document.body.clientHeight - 60 - 200));
};

const countPosition = () => {
  return arrCoords.some(function(item, index) {
    return ( (figureX <= item.left + 70 && figureX >= item.left - 70) && (figureY <= item.top + 70 && figureY >= item.top - 70));
  });
};

let getRandom = (min, max) => {
  return Math.round(Math.random() * (max - min) + min);
}

if (document.body.clientWidth > 500) {
  count = getRandom(12, 18);
} else {
  count = getRandom(4, 8);
}

document.querySelector('.countFigure').innerHTML = `Количество фигурок: ${count}`;
document.querySelector('.score').innerHTML = `Счёт: 0`;
console.log(count);

for(let i = 0; i < count; i++) {

    mutator = getRandom(0, 20);

    figureForm = forms[getRandom(0, 1)];
    sizes = sizeValues[getRandom(0, 3)];

    if (mutator > 10) {
      figureClass = "orange";
      figureColor = orangeRange[getRandom(0, orangeRange.length)];
    } else {
      figureClass = "green";
      figureColor = greenRange[getRandom(0, greenRange.length)];
    }

    changePosition();
    // console.log(document.body.clientWidth)
    while (countPosition() === true) {
      changePosition();
      countPosition();
    }

    if (countPosition() === false) {
      arrCoords.push({left: figureX, top: figureY});
      document.body.innerHTML += `<div class='figure draggable ${figureForm} ${figureClass}' style='left: ${figureX}px; top: ${figureY}px; height: ${sizes}; width: ${sizes}; background-color: ${figureColor}'></div>`;
    }
    console.log(arrCoords);
    // let greenColor = greenRange[Math.ceil(Math.random() * (greenRange.length - 0) + 0)];
    // let orangeColor = orangeRange[Math.ceil(Math.random() * (orangeRange.length - 0) + 0)];

    // document.body.innerHTML += `<div class='${square} ${itemClass}' style='left: ${figureX}px; top: ${figureY}px; background-color: ${orangeColor}'></div>`;

    // console.log(mutator);
}

let getCoords = (elem) => {
  let box = elem.getBoundingClientRect();

  return {
    top: box.top + pageYOffset,
    left: box.left + pageXOffset,
    width: box.width
  };
}

let DragManager = new function() {

  let dragObject = {};

  let self = this;

  let onMouseDown = (e) => {

    if (e.which != 1) return;

    let elem = e.target.closest('.draggable');
    if (!elem) return;

    dragObject.elem = elem;

    // запомним, что элемент нажат на текущих координатах pageX/pageY
    dragObject.downX = e.pageX;
    dragObject.downY = e.pageY;

    return false;
  };

  let startDrag = (e) => {
    let avatar = dragObject.avatar;

    // инициировать начало переноса
    document.body.appendChild(avatar);
    avatar.style.zIndex = 9999;
    avatar.style.position = 'absolute';
  };

  let createAvatar = (e) => {

    // запомнить старые свойства, чтобы вернуться к ним при отмене переноса
    let avatar = dragObject.elem;
    let old = {
      parent: avatar.parentNode,
      nextSibling: avatar.nextSibling,
      position: avatar.position || '',
      left: avatar.left || '',
      top: avatar.top || '',
      zIndex: avatar.zIndex || ''
    };

    // функция для отмены переноса
    avatar.rollback = function() {
      old.parent.insertBefore(avatar, old.nextSibling);
      avatar.style.position = old.position;
      avatar.style.left = old.left;
      avatar.style.top = old.top;
      avatar.style.zIndex = old.zIndex
    };

    return avatar;
  }

  let onMouseMove = (e) => {
    if (!dragObject.elem) return; // элемент не зажат

    if (!dragObject.avatar) { // если перенос неначат...
      let moveX = e.pageX - dragObject.downX;
      let moveY = e.pageY - dragObject.downY;

      // если мышь передвинулась в нажатом состоянии недостаточно далеко
      if (Math.abs(moveX) < 3 && Math.abs(moveY) < 3) {
        return;
      }

      // начинаем перенос
      dragObject.avatar = createAvatar(e); // создать аватар
      if (!dragObject.avatar) { // отмена переноса, нельзя "захватить" за эту часть элемента
        dragObject = {};
        return;
      }

      // аватар создан успешно
      // создать вспомогательные свойства shiftX/shiftY
      coords = getCoords(dragObject.avatar);
      dragObject.shiftX = dragObject.downX - coords.left;
      dragObject.shiftY = dragObject.downY - coords.top;
      console.log(document.body.scrollWidth);
      startDrag(e); // отобразить начало переноса
    }
    let coords = getCoords(dragObject.avatar);
    // отобразить перенос объекта при каждом движении мыши
    dragObject.avatar.style.left = e.pageX - dragObject.shiftX + 'px';
    dragObject.avatar.style.top = e.pageY - dragObject.shiftY + 'px';
    console.log(coords);
    if ((parseInt(dragObject.avatar.style.left)) > (document.body.clientWidth - coords.width))  {
      dragObject.avatar.style.left = document.body.clientWidth - coords.width + 'px';
    } else if (parseInt(dragObject.avatar.style.left) < 0) {
      dragObject.avatar.style.left = 0 + 'px';
    }

    return false;
  };

  let findDroppable = (event) => {
    // спрячем переносимый элемент
    dragObject.avatar.hidden = true;

    // получить самый вложенный элемент под курсором мыши
    let elem = document.elementFromPoint(event.clientX, event.clientY);

    // показать переносимый элемент обратно
    dragObject.avatar.hidden = false;

    if (elem == null) {
      // такое возможно, если курсор мыши "вылетел" за границу окна
      return null;
    }

    return elem.closest('.droppable');
  };

  let finishDrag = (e) => {
    let dropElem = findDroppable(e);

    if (!dropElem) {
      self.onDragCancel(dragObject);
    } else {
      self.onDragEnd(dragObject, dropElem);
    }
  };

  let onMouseUp = (e) => {
    if (dragObject.avatar) { // если перенос идет
      finishDrag(e);
    }

    // перенос либо не начинался, либо завершился
    // в любом случае очистим "состояние переноса" dragObject
    dragObject = {};
  };

  document.onmousemove = onMouseMove;
  document.onmouseup = onMouseUp;
  document.onmousedown = onMouseDown;

  this.onDragEnd = function(dragObject, dropElem) {};
  this.onDragCancel = function(dragObject) {};

};<commit_msg>touch wip start developing<commit_after>'use strict';

let mutator,
    figureClass,
    figureColor,
    figureForm,
    sizes,
    figureX,
    figureY,
    arrCoords,
    count;

const forms = ["circle", "square"],
      sizeValues = ["30px", "40px", "50px", "60px"],
      greenRange = ['#abf977','#a8f877','#a5f776','#a0f775','#9cf575','#99f574','#96f474','#93f473','#8ff273','#8af172','#86f172','#81f071','#7eef71','#7bee70','#77ed70','#72ed6f','#6deb6f','#68eb6e','#62ea6d','#5ee96d','#5ae86d','#56e76c','#50e76c','#49e56b','#42e46b','#39e36a','#30e369','#23e269','#18e168','#00e068'],
      orangeRange = ['#e05900','#e05c00','#e05f00','#e06100','#e06400','#e16700','#e16900','#e16c00','#e16f00','#e17100','#e17300','#e17700','#e17800','#e17b00','#e17e00','#e18000','#e18300','#e18500','#e18700','#e18900','#e18b00','#e18e00','#e19000','#e19300','#e19400','#e19600','#e09a00','#e09c00','#e09d00','#e0a000'];

arrCoords = [];

const changePosition = () => {
  figureX = getRandom(0, (document.body.clientWidth - 60));;
  figureY = getRandom(35, (document.body.clientHeight - 60 - 200));
};

const countPosition = () => {
  return arrCoords.some(function(item, index) {
    return ( (figureX <= item.left + 70 && figureX >= item.left - 70) && (figureY <= item.top + 70 && figureY >= item.top - 70));
  });
};

let getRandom = (min, max) => {
  return Math.round(Math.random() * (max - min) + min);
}

if (document.body.clientWidth > 500) {
  count = getRandom(12, 18);
} else {
  count = getRandom(4, 8);
}

document.querySelector('.countFigure').innerHTML = `Количество фигурок: ${count}`;
document.querySelector('.score').innerHTML = `Счёт: 0`;

for(let i = 0; i < count; i++) {

    mutator = getRandom(0, 20);

    figureForm = forms[getRandom(0, 1)];
    sizes = sizeValues[getRandom(0, 3)];

    if (mutator > 10) {
      figureClass = "orange";
      figureColor = orangeRange[getRandom(0, orangeRange.length)];
    } else {
      figureClass = "green";
      figureColor = greenRange[getRandom(0, greenRange.length)];
    }

    changePosition();
    countPosition();

    if (countPosition() === true) {
      changePosition();
      countPosition();
    }

    if (countPosition() === false) {
      arrCoords.push({left: figureX, top: figureY});
      document.body.innerHTML += `<div
                                  class='figure draggable ${figureForm} ${figureClass}'
                                  style='left: ${figureX}px; top: ${figureY}px;
                                  height: ${sizes}; width: ${sizes};
                                  background-color: ${figureColor}'>
                                  </div>`;
    }
}

let getCoords = (elem) => {
  let box = elem.getBoundingClientRect();

  return {
    top: box.top + pageYOffset,
    left: box.left + pageXOffset,
    width: box.width
  };
}

let DragManager = new function() {

  let dragObject = {};

  let self = this;

  let onMouseDown = (e) => {

    if (e.which != 1) return;

    let elem = e.target.closest('.draggable');
    if (!elem) return;

    dragObject.elem = elem;

    // запомним, что элемент нажат на текущих координатах pageX/pageY
    dragObject.downX = e.pageX;
    dragObject.downY = e.pageY;

    return false;
  };

  let startDrag = (e) => {
    let avatar = dragObject.avatar;

    // инициировать начало переноса
    document.body.appendChild(avatar);
    avatar.style.zIndex = 9999;
    avatar.style.position = 'absolute';
  };

  let createAvatar = (e) => {

    // запомнить старые свойства, чтобы вернуться к ним при отмене переноса
    let avatar = dragObject.elem;
    let old = {
      parent: avatar.parentNode,
      nextSibling: avatar.nextSibling,
      position: avatar.position || '',
      left: avatar.left || '',
      top: avatar.top || '',
      zIndex: avatar.zIndex || ''
    };

    // функция для отмены переноса
    avatar.rollback = function() {
      old.parent.insertBefore(avatar, old.nextSibling);
      avatar.style.position = old.position;
      avatar.style.left = old.left;
      avatar.style.top = old.top;
      avatar.style.zIndex = old.zIndex
    };

    return avatar;
  }

  let onMouseMove = (e) => {
    if (!dragObject.elem) return; // элемент не зажат

    if (!dragObject.avatar) { // если перенос неначат...
      let moveX = e.pageX - dragObject.downX;
      let moveY = e.pageY - dragObject.downY;

      // если мышь передвинулась в нажатом состоянии недостаточно далеко
      if (Math.abs(moveX) < 3 && Math.abs(moveY) < 3) {
        return;
      }

      // начинаем перенос
      dragObject.avatar = createAvatar(e); // создать аватар
      if (!dragObject.avatar) { // отмена переноса, нельзя "захватить" за эту часть элемента
        dragObject = {};
        return;
      }

      // аватар создан успешно
      // создать вспомогательные свойства shiftX/shiftY
      coords = getCoords(dragObject.avatar);
      dragObject.shiftX = dragObject.downX - coords.left;
      dragObject.shiftY = dragObject.downY - coords.top;
      console.log(document.body.scrollWidth);
      startDrag(e); // отобразить начало переноса
    }
    let coords = getCoords(dragObject.avatar);
    // отобразить перенос объекта при каждом движении мыши
    dragObject.avatar.style.left = e.pageX - dragObject.shiftX + 'px';
    dragObject.avatar.style.top = e.pageY - dragObject.shiftY + 'px';
    console.log(coords);
    if ((parseInt(dragObject.avatar.style.left)) > (document.body.clientWidth - coords.width))  {
      dragObject.avatar.style.left = document.body.clientWidth - coords.width + 'px';
    } else if (parseInt(dragObject.avatar.style.left) < 0) {
      dragObject.avatar.style.left = 0 + 'px';
    }

    return false;
  };

  let findDroppable = (event) => {
    // спрячем переносимый элемент
    dragObject.avatar.hidden = true;

    // получить самый вложенный элемент под курсором мыши
    let elem = document.elementFromPoint(event.clientX, event.clientY);

    // показать переносимый элемент обратно
    dragObject.avatar.hidden = false;

    if (elem == null) {
      // такое возможно, если курсор мыши "вылетел" за границу окна
      return null;
    }

    return elem.closest('.droppable');
  };

  let finishDrag = (e) => {
    let dropElem = findDroppable(e);

    if (!dropElem) {
      self.onDragCancel(dragObject);
    } else {
      self.onDragEnd(dragObject, dropElem);
    }
  };

  let onMouseUp = (e) => {
    if (dragObject.avatar) { // если перенос идет
      finishDrag(e);
    }

    // перенос либо не начинался, либо завершился
    // в любом случае очистим "состояние переноса" dragObject
    dragObject = {};
  };

  document.addEventListener("mousemove", onMouseMove);
  document.addEventListener("touchmove", onMouseMove);

  document.addEventListener("mouseup", onMouseUp);
  document.addEventListener("touchend", onMouseUp);

  document.addEventListener("mousedown", onMouseDown);
  document.addEventListener("touchstart", onMouseDown);

  this.onDragEnd = function(dragObject, dropElem) {};
  this.onDragCancel = function(dragObject) {};

};<|endoftext|>


<commit_before>'use babel';

import { CompositeDisposable } from 'atom';
import findDeps from 'atom-selected-requires';
import pkgConf from 'pkg-conf';
import path from 'path';
import relative from 'relative-require-regex';
import core from 'resolve/lib/core.json';
import $ from 'jquery';
import { spawn } from 'child_process';
import { MessagePanelView, PlainMessageView } from 'atom-message-panel';
import split from 'split';
import Combine from 'combine-stream';
import ansiHTML from 'ansi-to-html';
import pkgDir from 'pkg-dir';
import which from 'which';
import isModuleInstalled from './is-module-installed';

const convert = new ansiHTML({
	newline: false,
	escapeXML: false,
	stream: true
});
const ansiToHtml = content => convert.toHtml( content );

let pos = {
	top: 0,
	left: 0,
};
let deps = [];
let $tooltip;
let tooltipDispose;

const TYPE_DEPENDENCIES = 1;
const TYPE_DEV_DEPENDENCIES = 2;

export default {
	subscriptions: null,
	panel: null,
	cp: null,
	root: null,
	config: {
		npmRegisteryName: {
			type: 'string',
			default: 'npm',
			enum: [ 'npm', 'cnpm' ]
		}
	},

	install( root, deps, type ) {
		if( !root ) {
			atom.notifications.addError('project root not found', {});
			return;
		}

		if( this.cp ) {
			this.cp.kill();
			this.cp = null;
		}

		var npmRegisteryName = atom.config.get( 'atom-select-npm-install.npmRegisteryName' );

		var newPath = process.env.Path + ':/usr/bin/node:/usr/local/bin';
		npmName = process.platform === 'win32' ? `${npmRegisteryName}.cmd` : npmRegisteryName;
		which(npmName, {
			path: newPath
		}, ( err, npm ) => {
			if( err ) {
				console.log( 'err', err );
				return err;
			}

			console.log( 'cnpm', npm );

			const cp = spawn(
				npm,
				[ 'install', ...deps, type === TYPE_DEV_DEPENDENCIES ? '-D' : '-S', '-d' ],
				{
					cwd: root,
				}
			);

			// this.installing = true;

			const panel = this.panel || new MessagePanelView({
				title: `${npmRegisteryName} install`,
				autoScroll: true
			});

			panel.clear();
			panel.attach();

			const output = new Combine([ cp.stdout, cp.stderr ]);
			output.pipe( split() ).on('data', ( line ) => {
				line = ansiToHtml( line ).replace(/ /g, function( match, offset, total ) {
					if( /^ *$/.test( total.slice( 0, offset ) ) ) {
						return ' ';
					} else {
						return ' ';
					}
				})
				panel.add(new PlainMessageView({
					message: line,
					raw: true
				}));
				panel.updateScroll();
			});

			cp.on('close', function (code) {
				console.log('child process exited with code ' + code);
			});

			this.cp = cp;
			this.panel = panel;
		})
	},

	activate( state ) {
		this.subscriptions = new CompositeDisposable();

		this.subscriptions.add( atom.workspace.observeTextEditors( editor => {
			// only support those file extensions
			if( !/\.(js|jsx|es6|tag|vue)$/.test( editor.getPath() ) ) {
				return;
			}

			const editorElement = atom.views.getView( editor );
			const $editorElement = $( editorElement );
			const $editorScrollElement = $( editorElement.shadowRoot ).find( '.scroll-view' );

			$editorElement.off( 'mousemove' ).on( 'mousemove', e => {
				const offset = $editorElement.offset();
				pos.top = e.pageY;
				pos.left = e.pageX;
			} );

			$editorElement.off( 'mouseup' ).on( 'mouseup', e => {
				console.log( deps );
				if (typeof $tooltip !== 'undefined') {
					$tooltip.remove();
				}
				if (typeof tooltipDispose !== 'undefined') {
					tooltipDispose.dispose();
				}

				if (deps.length > 0) {
					$tooltip = $( `

									${deps.map(dep => {
										return `

														<input id="atom-select-npm-install:${dep}" data-value="${dep}" type="checkbox" checked="checked">

${dep}

										`;
									}).join('')}

										<input class="J_installAsDevDependencies" id="atom-select-npm-install:devDependencies" type="checkbox">

Install as devDependencies

								<button class="J_install">install</button>

					` ).css( {
						top: pos.top + 1,
						left: pos.left + 1,
						transform: 'translateX(-50%)',
						'-webkit-transform': 'translateX(-50%)',
					} ).find( '.J_install' ).on( 'click', () => {
						// filter selected deps
						let checkboxes = $tooltip.find( '.J_deps input[type="checkbox"]:checked' );
						const deps = [].slice.call( checkboxes ).map(c => {
							return c.getAttribute( 'data-value' );
						});

						// dep type
						let type = TYPE_DEPENDENCIES;
						const installAsDevDependencies = $tooltip.find( '.J_installAsDevDependencies' )[0].checked;
						if( installAsDevDependencies ) {
							type = TYPE_DEV_DEPENDENCIES;
						}

						this.install( this.root, deps, type );
						// $tooltip.remove();
					} ).end();
					$( 'body' ).append( $tooltip );
				}
			} );

			this.subscriptions.add( editor.onDidChangeSelectionRange( e => {
				const bufferRange = e.newBufferRange;
				const cursor = e.selection.cursor;

				deps = [];

				if (bufferRange.isEmpty()) {
					return;
				}
				const content = editor.getTextInBufferRange( bufferRange );
				if (!content.includes( 'require' ) && !content.includes( 'import' )) {
					return;
				}

				try {
					deps = findDeps( editor );
				} catch( e ) {
					atom.notifications.addError(`failed to resolve dependencies`, {});
					throw e;
				}
				deps = deps
					.filter( name => !relative().test( name ) )
					.filter( name => core.indexOf( name ) === -1 )
					.map( dir => dir.split( '/' )[0] )
					// .filter( name => !(name in pkgDeps) )

				this.root = pkgDir.sync( editor.getPath() );
				if( this.root ) {
					deps = deps.filter(name => !isModuleInstalled( name, this.root ));
				}

				// const filepath = editor.getPath();
				// const cwd = path.dirname( filepath );
				//
				// Promise.all( [
				// 	pkgConf( 'dependencies', {
				// 		cwd
				// 	} ),
				// 	pkgConf( 'devDependencies', {
				// 		cwd
				// 	} ),
				// ] ).then( ret => {
				// 	const pkgDeps = [
				// 		...Object.keys( ret[0] ),
				// 		...Object.keys( ret[1] )
				// 	];
				//
				// 	console.log( 'pkgDeps', pkgDeps );
				// } );
			} ) );
		} ) );
	},

	deactivate() {
		this.subscriptions.dispose();
	},

	serialize() {
		return {};
	},
};
<commit_msg>:zap:remove tooltip when active pane item is changed<commit_after>'use babel';

import { CompositeDisposable } from 'atom';
import findDeps from 'atom-selected-requires';
import pkgConf from 'pkg-conf';
import path from 'path';
import relative from 'relative-require-regex';
import core from 'resolve/lib/core.json';
import $ from 'jquery';
import { spawn } from 'child_process';
import { MessagePanelView, PlainMessageView } from 'atom-message-panel';
import split from 'split';
import Combine from 'combine-stream';
import ansiHTML from 'ansi-to-html';
import pkgDir from 'pkg-dir';
import which from 'which';
import isModuleInstalled from './is-module-installed';

const convert = new ansiHTML({
	newline: false,
	escapeXML: false,
	stream: true
});
const ansiToHtml = content => convert.toHtml( content );

let pos = {
	top: 0,
	left: 0,
};
let deps = [];
let $tooltip;
let tooltipDispose;

const TYPE_DEPENDENCIES = 1;
const TYPE_DEV_DEPENDENCIES = 2;

export default {
	subscriptions: null,
	panel: null,
	cp: null,
	root: null,
	config: {
		npmRegisteryName: {
			type: 'string',
			default: 'npm',
			enum: [ 'npm', 'cnpm' ]
		}
	},

	install( root, deps, type ) {
		if( !root ) {
			atom.notifications.addError('project root not found', {});
			return;
		}

		if( this.cp ) {
			this.cp.kill();
			this.cp = null;
		}

		var npmRegisteryName = atom.config.get( 'atom-select-npm-install.npmRegisteryName' );

		var newPath = process.env.Path + ':/usr/bin/node:/usr/local/bin';
		npmName = process.platform === 'win32' ? `${npmRegisteryName}.cmd` : npmRegisteryName;
		which(npmName, {
			path: newPath
		}, ( err, npm ) => {
			if( err ) {
				console.log( 'err', err );
				return err;
			}

			console.log( 'cnpm', npm );

			const cp = spawn(
				npm,
				[ 'install', ...deps, type === TYPE_DEV_DEPENDENCIES ? '-D' : '-S', '-d' ],
				{
					cwd: root,
				}
			);

			// this.installing = true;

			const panel = this.panel || new MessagePanelView({
				title: `${npmRegisteryName} install`,
				autoScroll: true
			});

			panel.clear();
			panel.attach();

			const output = new Combine([ cp.stdout, cp.stderr ]);
			output.pipe( split() ).on('data', ( line ) => {
				line = ansiToHtml( line ).replace(/ /g, function( match, offset, total ) {
					if( /^ *$/.test( total.slice( 0, offset ) ) ) {
						return ' ';
					} else {
						return ' ';
					}
				})
				panel.add(new PlainMessageView({
					message: line,
					raw: true
				}));
				panel.updateScroll();
			});

			cp.on('close', function (code) {
				console.log('child process exited with code ' + code);
			});

			this.cp = cp;
			this.panel = panel;
		})
	},

	activate( state ) {
		this.subscriptions = new CompositeDisposable();

		this.subscriptions.add( atom.workspace.onDidStopChangingActivePaneItem(() => {
			if (typeof $tooltip !== 'undefined') {
				$tooltip.remove();
			}
		}) );

		this.subscriptions.add( atom.workspace.observeTextEditors( editor => {
			// only support those file extensions
			if( !/\.(js|jsx|es6|tag|vue)$/.test( editor.getPath() ) ) {
				return;
			}

			const editorElement = atom.views.getView( editor );
			const $editorElement = $( editorElement );
			const $editorScrollElement = $( editorElement.shadowRoot ).find( '.scroll-view' );

			$editorElement.off( 'mousemove' ).on( 'mousemove', e => {
				const offset = $editorElement.offset();
				pos.top = e.pageY;
				pos.left = e.pageX;
			} );

			$editorElement.off( 'mouseup' ).on( 'mouseup', e => {
				// console.log( deps );
				if (typeof $tooltip !== 'undefined') {
					$tooltip.remove();
				}
				if (typeof tooltipDispose !== 'undefined') {
					tooltipDispose.dispose();
				}

				if (deps.length > 0) {
					$tooltip = $( `

									${deps.map(dep => {
										return `

														<input id="atom-select-npm-install:${dep}" data-value="${dep}" type="checkbox" checked="checked">

${dep}

										`;
									}).join('')}

										<input class="J_installAsDevDependencies" id="atom-select-npm-install:devDependencies" type="checkbox">

Install as devDependencies

								<button class="J_install">install</button>

					` ).css( {
						top: pos.top + 1,
						left: pos.left + 1,
						transform: 'translateX(-50%)',
						'-webkit-transform': 'translateX(-50%)',
					} ).find( '.J_install' ).on( 'click', () => {
						// filter selected deps
						let checkboxes = $tooltip.find( '.J_deps input[type="checkbox"]:checked' );
						const deps = [].slice.call( checkboxes ).map(c => {
							return c.getAttribute( 'data-value' );
						});

						// dep type
						let type = TYPE_DEPENDENCIES;
						const installAsDevDependencies = $tooltip.find( '.J_installAsDevDependencies' )[0].checked;
						if( installAsDevDependencies ) {
							type = TYPE_DEV_DEPENDENCIES;
						}

						this.install( this.root, deps, type );
						// $tooltip.remove();
					} ).end();
					$( 'body' ).append( $tooltip );
				}
			} );

			this.subscriptions.add( editor.onDidChangeSelectionRange( e => {
				const bufferRange = e.newBufferRange;
				const cursor = e.selection.cursor;

				deps = [];

				if (bufferRange.isEmpty()) {
					return;
				}
				const content = editor.getTextInBufferRange( bufferRange );
				if (!content.includes( 'require' ) && !content.includes( 'import' )) {
					return;
				}

				try {
					deps = findDeps( editor );
				} catch( e ) {
					atom.notifications.addError(`failed to resolve dependencies`, {});
					throw e;
				}
				deps = deps
					.filter( name => !relative().test( name ) )
					.filter( name => core.indexOf( name ) === -1 )
					.map( dir => dir.split( '/' )[0] )
					// .filter( name => !(name in pkgDeps) )

				this.root = pkgDir.sync( editor.getPath() );
				if( this.root ) {
					deps = deps.filter(name => !isModuleInstalled( name, this.root ));
				}

				// const filepath = editor.getPath();
				// const cwd = path.dirname( filepath );
				//
				// Promise.all( [
				// 	pkgConf( 'dependencies', {
				// 		cwd
				// 	} ),
				// 	pkgConf( 'devDependencies', {
				// 		cwd
				// 	} ),
				// ] ).then( ret => {
				// 	const pkgDeps = [
				// 		...Object.keys( ret[0] ),
				// 		...Object.keys( ret[1] )
				// 	];
				//
				// 	console.log( 'pkgDeps', pkgDeps );
				// } );
			} ) );
		} ) );
	},

	deactivate() {
		this.subscriptions.dispose();
	},

	serialize() {
		return {};
	},
};
<|endoftext|>


<commit_before>// Commons
module.exports = {
  HEADERS : "headers",
  CHARSET_DEFAULT : "utf-8",

  SPEC_V02 : "0.2",
  SPEC_V03 : "0.3",

  DEFAULT_SPEC_VERSION_HEADER : "ce-specversion",

  ENCODING_BASE64 : "base64",

  DATA_ATTRIBUTE : "data",

  MIME_JSON         : "application/json",
  MIME_OCTET_STREAM : "application/octet-stream",
  MIME_CE           : "application/cloudevents",
  MIME_CE_JSON      : "application/cloudevents+json",

  HEADER_CONTENT_TYPE : "content-type",

  DEFAULT_CONTENT_TYPE : "application/json; charset=utf-8",
  DEFAULT_CE_CONTENT_TYPE : "application/cloudevents+json; charset=utf-8",

  BINARY_HEADERS_02 : {
    TYPE              : "ce-type",
    SPEC_VERSION      : "ce-specversion",
    SOURCE            : "ce-source",
    ID                : "ce-id",
    TIME              : "ce-time",
    SCHEMA_URL        : "ce-schemaurl",
    EXTENSIONS_PREFIX : "ce-"
  },
  STRUCTURED_ATTRS_02 : {
    TYPE         : "type",
    SPEC_VERSION : "specversion",
    SOURCE       : "source",
    ID           : "id",
    TIME         : "time",
    SCHEMA_URL   : "schemaurl",
    CONTENT_TYPE : "contenttype",
    DATA         : "data"
  },

  BINARY_HEADERS_03 : {
    TYPE              : "ce-type",
    SPEC_VERSION      : "ce-specversion",
    SOURCE            : "ce-source",
    ID                : "ce-id",
    TIME              : "ce-time",
    SCHEMA_URL        : "ce-schemaurl",
    CONTENT_ENCONDING : "ce-datacontentencoding",
    SUBJECT           : "ce-subject",
    EXTENSIONS_PREFIX : "ce-"
  },
  STRUCTURED_ATTRS_03 : {
    TYPE              : "type",
    SPEC_VERSION      : "specversion",
    SOURCE            : "source",
    ID                : "id",
    TIME              : "time",
    SCHEMA_URL        : "schemaurl",
    CONTENT_ENCONDING : "datacontentencoding",
    CONTENT_TYPE      : "datacontenttype",
    SUBJECT           : "subject",
    DATA              : "data"
  },

  BINARY_HEADERS_1 : {
    TYPE              : "ce-type",
    SPEC_VERSION      : "ce-specversion",
    SOURCE            : "ce-source",
    ID                : "ce-id",
    TIME              : "ce-time",
    DATA_SCHEMA       : "ce-dataschema",
    SUBJECT           : "ce-subject",
    EXTENSIONS_PREFIX : "ce-"
  }
};
<commit_msg>Constants for spec 1.0<commit_after>// Commons
module.exports = {
  HEADERS : "headers",
  CHARSET_DEFAULT : "utf-8",

  SPEC_V02 : "0.2",
  SPEC_V03 : "0.3",

  DEFAULT_SPEC_VERSION_HEADER : "ce-specversion",

  ENCODING_BASE64 : "base64",

  DATA_ATTRIBUTE : "data",

  MIME_JSON         : "application/json",
  MIME_OCTET_STREAM : "application/octet-stream",
  MIME_CE           : "application/cloudevents",
  MIME_CE_JSON      : "application/cloudevents+json",

  HEADER_CONTENT_TYPE : "content-type",

  DEFAULT_CONTENT_TYPE : "application/json; charset=utf-8",
  DEFAULT_CE_CONTENT_TYPE : "application/cloudevents+json; charset=utf-8",

  BINARY_HEADERS_02 : {
    TYPE              : "ce-type",
    SPEC_VERSION      : "ce-specversion",
    SOURCE            : "ce-source",
    ID                : "ce-id",
    TIME              : "ce-time",
    SCHEMA_URL        : "ce-schemaurl",
    EXTENSIONS_PREFIX : "ce-"
  },
  STRUCTURED_ATTRS_02 : {
    TYPE         : "type",
    SPEC_VERSION : "specversion",
    SOURCE       : "source",
    ID           : "id",
    TIME         : "time",
    SCHEMA_URL   : "schemaurl",
    CONTENT_TYPE : "contenttype",
    DATA         : "data"
  },

  BINARY_HEADERS_03 : {
    TYPE              : "ce-type",
    SPEC_VERSION      : "ce-specversion",
    SOURCE            : "ce-source",
    ID                : "ce-id",
    TIME              : "ce-time",
    SCHEMA_URL        : "ce-schemaurl",
    CONTENT_ENCONDING : "ce-datacontentencoding",
    SUBJECT           : "ce-subject",
    EXTENSIONS_PREFIX : "ce-"
  },
  STRUCTURED_ATTRS_03 : {
    TYPE              : "type",
    SPEC_VERSION      : "specversion",
    SOURCE            : "source",
    ID                : "id",
    TIME              : "time",
    SCHEMA_URL        : "schemaurl",
    CONTENT_ENCONDING : "datacontentencoding",
    CONTENT_TYPE      : "datacontenttype",
    SUBJECT           : "subject",
    DATA              : "data"
  },

  BINARY_HEADERS_1 : {
    TYPE              : "ce-type",
    SPEC_VERSION      : "ce-specversion",
    SOURCE            : "ce-source",
    ID                : "ce-id",
    TIME              : "ce-time",
    DATA_SCHEMA       : "ce-dataschema",
    SUBJECT           : "ce-subject",
    EXTENSIONS_PREFIX : "ce-"
  },
  STRUCTURED_ATTRS_1 : {
    TYPE              : "type",
    SPEC_VERSION      : "specversion",
    SOURCE            : "source",
    ID                : "id",
    TIME              : "time",
    DATA_SCHEMA       : "dataschema",
    CONTENT_TYPE      : "datacontenttype",
    SUBJECT           : "subject",
    DATA              : "data",
    DATA_BASE64       : "data_base64"
  }
};
<|endoftext|>


<commit_before>'use strict';

let {Main} = require('./Main');
let component = new Main({});
document.getElementById('main').appendChild(component.element);
<commit_msg>use const for Main and component<commit_after>'use strict';

const {Main} = require('./Main');
const component = new Main({});
document.getElementById('main').appendChild(component.element);
<|endoftext|>


<commit_before>frappe.provide("frappe.ui.form");

frappe.ui.form.PrintPreview = Class.extend({
	init: function (opts) {
		$.extend(this, opts);
		this.make();
		this.bind_events();
	},
	make: function () {
		this.wrapper = this.frm.page.add_view("print", frappe.render_template("print_layout", {}));

		// only system manager can edit
		this.wrapper.find(".btn-print-edit").toggle(frappe.user.has_role("System Manager"));
	},
	bind_events: function () {
		var me = this;
		this.wrapper.find(".btn-print-close").click(function () {
			me.frm.hide_print();
		});

		// hide print view on pressing escape, only if there is no focus on any input
		$(document).on("keydown", function (e) {
			if (e.which === 27 && me.frm && e.target === document.body) {
				me.frm.hide_print();
			}
		});

		this.print_formats = frappe.meta.get_print_formats(this.frm.meta.name);
		this.print_letterhead = this.wrapper
			.find(".print-letterhead")
			.on("change", function () { me.print_sel.trigger("change"); })
			.prop("checked", cint(
				(frappe.model.get_doc(":Print Settings", "Print Settings")
					|| { with_letterhead: 1 }).with_letterhead) ? true : false);
		this.print_sel = this.wrapper
			.find(".print-preview-select")
			.on("change", function () {
				me.multilingual_preview()
			});

		//On selection of language get code and pass it to preview method
		this.language_sel = this.wrapper
			.find(".languages")
			.on("change", function () {
				me.lang_code = me.language_sel.val()
				me.multilingual_preview()
			});

		this.wrapper.find(".btn-print-print").click(function () {
			if (me.is_old_style()) {
				me.print_old_style();
			} else {
				me.printit();
			}
		});

		this.wrapper.find(".btn-print-preview").click(function () {
			if (me.is_old_style()) {
				me.new_page_preview_old_style();
			} else {
				me.new_page_preview();
			}
		});

		this.wrapper.find(".btn-download-pdf").click(function () {
			if (!me.is_old_style()) {
				var w = window.open(
					frappe.urllib.get_full_url("/api/method/frappe.utils.print_format.download_pdf?"
						+ "doctype=" + encodeURIComponent(me.frm.doc.doctype)
						+ "&name=" + encodeURIComponent(me.frm.doc.name)
						+ "&format=" + me.selected_format()
						+ "&no_letterhead=" + (me.with_letterhead() ? "0" : "1")
						+ (me.lang_code ? ("&_lang=" + me.lang_code) : ""))
				);
				if (!w) {
					frappe.msgprint(__("Please enable pop-ups")); return;
				}
			}
		});

		this.wrapper.find(".btn-print-edit").on("click", function () {
			var print_format = me.get_print_format();
			if (print_format && print_format.name) {
				if (print_format.print_format_builder) {
					frappe.set_route("print-format-builder", print_format.name);
				} else {
					frappe.set_route("Form", "Print Format", print_format.name);
				}
			} else {
				// start a new print format
				frappe.prompt({
					fieldname: "print_format_name", fieldtype: "Data", reqd: 1,
					label: "New Print Format Name"
				}, function (data) {
					frappe.route_options = {
						make_new: true,
						doctype: me.frm.doctype,
						name: data.print_format_name
					};
					frappe.set_route("print-format-builder");
				}, __("New Custom Print Format"), __("Start"));
			}
		});
	},
	set_user_lang: function () {
		this.lang_code = this.frm.doc.language;
		// Load all languages in the field
		this.language_sel.empty()
			.add_options(frappe.get_languages())
			.val(this.lang_code);
		this.preview();
	},
	multilingual_preview: function () {
		var me = this;
		if (this.is_old_style()) {
			me.wrapper.find(".btn-download-pdf").toggle(false);
			me.set_style();
			me.preview_old_style();
		} else {
			me.wrapper.find(".btn-download-pdf").toggle(true);
			me.preview();
		}
	},
	preview: function () {
		var me = this;
		this.get_print_html(function (out) {
			me.wrapper.find(".print-format").html(out.html);
			me.show_footer();
			me.set_style(out.style);
		});
	},
	show_footer: function() {
		// footer is hidden by default as reqd by pdf generation
		// simple hack to show it in print preview
		this.wrapper.find('.print-format').css('position', 'relative');
		this.wrapper.find('#footer-html').attr('style', `
			display: block !important;
			position: absolute;
			bottom: 0.75in;
		`);
	},
	printit: function () {
		this.new_page_preview(true);
	},
	new_page_preview: function (printit) {
		var me = this;
		var w = window.open(frappe.urllib.get_full_url("/printview?"
			+ "doctype=" + encodeURIComponent(me.frm.doc.doctype)
			+ "&name=" + encodeURIComponent(me.frm.doc.name)
			+ (printit ? "&trigger_print=1" : "")
			+ "&format=" + me.selected_format()
			+ "&no_letterhead=" + (me.with_letterhead() ? "0" : "1")
			+ (me.lang_code ? ("&_lang=" + me.lang_code) : "")));
		if (!w) {
			frappe.msgprint(__("Please enable pop-ups")); return;
		}
	},
	get_print_html: function (callback) {
		frappe.call({
			method: "frappe.www.printview.get_html_and_style",
			args: {
				doc: this.frm.doc,
				print_format: this.selected_format(),
				no_letterhead: !this.with_letterhead() ? 1 : 0,
				_lang: this.lang_code
			},
			callback: function (r) {
				if (!r.exc) {
					callback(r.message);
				}
			}
		});
	},
	preview_old_style: function () {
		var me = this;
		this.with_old_style({
			format: me.print_sel.val(),
			callback: function (html) {
				me.wrapper.find(".print-format").html('
'
					+ __("Warning: This Print Format is in old style and cannot be generated via the API.")
					+ '
'
					+ html);
			},
			no_letterhead: !this.with_letterhead(),
			only_body: true,
			no_heading: true
		});
	},
	refresh_print_options: function () {
		this.print_formats = frappe.meta.get_print_formats(this.frm.doctype);
		return this.print_sel
			.empty().add_options(this.print_formats);
	},
	with_old_style: function (opts) {
		frappe.require("/assets/js/print_format_v3.min.js", function () {
			_p.build(opts.format, opts.callback, opts.no_letterhead, opts.only_body, opts.no_heading);
		});
	},
	print_old_style: function () {
		var me = this;
		frappe.require("/assets/js/print_format_v3.min.js", function () {
			_p.build(me.print_sel.val(), _p.go,
				!me.with_letterhead());
		});
	},
	new_page_preview_old_style: function () {
		var me = this;
		frappe.require("/assets/js/print_format_v3.min.js", function () {
			_p.build(me.print_sel.val(), _p.preview, !me.with_letterhead());
		});
	},
	selected_format: function () {
		return this.print_sel.val() || this.frm.meta.default_print_format || "Standard";
	},
	is_old_style: function (format) {
		return this.get_print_format(format).print_format_type === "Client";
	},
	get_print_format: function (format) {
		if (!format) {
			format = this.selected_format();
		}

		if (locals["Print Format"] && locals["Print Format"][format]) {
			return locals["Print Format"][format]
		} else {
			return {}
		}
	},
	with_letterhead: function () {
		return this.print_letterhead.is(":checked") ? 1 : 0;
	},
	set_style: function (style) {
		frappe.dom.set_style(style || frappe.boot.print_css, "print-style");
	}
});

frappe.ui.get_print_settings = function (pdf, callback, letter_head) {
	var print_settings = locals[":Print Settings"]["Print Settings"];

	var default_letter_head = locals[":Company"] && frappe.defaults.get_default('company')
		? locals[":Company"][frappe.defaults.get_default('company')]["default_letter_head"]
		: '';

	var columns = [{
		fieldtype: "Check",
		fieldname: "with_letter_head",
		label: __("With Letter head")
	}, {
		fieldtype: "Select",
		fieldname: "letter_head",
		label: __("Letter Head"),
		depends_on: "with_letter_head",
		options: $.map(frappe.boot.letter_heads, function (i, d) { return d }),
		default: letter_head || default_letter_head
	}];

	if (pdf) {
		columns.push({
			fieldtype: "Select",
			fieldname: "orientation",
			label: __("Orientation"),
			options: "Landscape\nPortrait",
			default: "Landscape"
		})
	}

	frappe.prompt(columns, function (data) {
		var data = $.extend(print_settings, data);
		if (!data.with_letter_head) {
			data.letter_head = null;
		}
		if (data.letter_head) {
			data.letter_head = frappe.boot.letter_heads[print_settings.letter_head];
		}
		callback(data);
	}, __("Print Settings"));
}
<commit_msg>Fix footer overlap in print preview (#3866)<commit_after>frappe.provide("frappe.ui.form");

frappe.ui.form.PrintPreview = Class.extend({
	init: function (opts) {
		$.extend(this, opts);
		this.make();
		this.bind_events();
	},
	make: function () {
		this.wrapper = this.frm.page.add_view("print", frappe.render_template("print_layout", {}));

		// only system manager can edit
		this.wrapper.find(".btn-print-edit").toggle(frappe.user.has_role("System Manager"));
	},
	bind_events: function () {
		var me = this;
		this.wrapper.find(".btn-print-close").click(function () {
			me.frm.hide_print();
		});

		// hide print view on pressing escape, only if there is no focus on any input
		$(document).on("keydown", function (e) {
			if (e.which === 27 && me.frm && e.target === document.body) {
				me.frm.hide_print();
			}
		});

		this.print_formats = frappe.meta.get_print_formats(this.frm.meta.name);
		this.print_letterhead = this.wrapper
			.find(".print-letterhead")
			.on("change", function () { me.print_sel.trigger("change"); })
			.prop("checked", cint(
				(frappe.model.get_doc(":Print Settings", "Print Settings")
					|| { with_letterhead: 1 }).with_letterhead) ? true : false);
		this.print_sel = this.wrapper
			.find(".print-preview-select")
			.on("change", function () {
				me.multilingual_preview()
			});

		//On selection of language get code and pass it to preview method
		this.language_sel = this.wrapper
			.find(".languages")
			.on("change", function () {
				me.lang_code = me.language_sel.val()
				me.multilingual_preview()
			});

		this.wrapper.find(".btn-print-print").click(function () {
			if (me.is_old_style()) {
				me.print_old_style();
			} else {
				me.printit();
			}
		});

		this.wrapper.find(".btn-print-preview").click(function () {
			if (me.is_old_style()) {
				me.new_page_preview_old_style();
			} else {
				me.new_page_preview();
			}
		});

		this.wrapper.find(".btn-download-pdf").click(function () {
			if (!me.is_old_style()) {
				var w = window.open(
					frappe.urllib.get_full_url("/api/method/frappe.utils.print_format.download_pdf?"
						+ "doctype=" + encodeURIComponent(me.frm.doc.doctype)
						+ "&name=" + encodeURIComponent(me.frm.doc.name)
						+ "&format=" + me.selected_format()
						+ "&no_letterhead=" + (me.with_letterhead() ? "0" : "1")
						+ (me.lang_code ? ("&_lang=" + me.lang_code) : ""))
				);
				if (!w) {
					frappe.msgprint(__("Please enable pop-ups")); return;
				}
			}
		});

		this.wrapper.find(".btn-print-edit").on("click", function () {
			var print_format = me.get_print_format();
			if (print_format && print_format.name) {
				if (print_format.print_format_builder) {
					frappe.set_route("print-format-builder", print_format.name);
				} else {
					frappe.set_route("Form", "Print Format", print_format.name);
				}
			} else {
				// start a new print format
				frappe.prompt({
					fieldname: "print_format_name", fieldtype: "Data", reqd: 1,
					label: "New Print Format Name"
				}, function (data) {
					frappe.route_options = {
						make_new: true,
						doctype: me.frm.doctype,
						name: data.print_format_name
					};
					frappe.set_route("print-format-builder");
				}, __("New Custom Print Format"), __("Start"));
			}
		});
	},
	set_user_lang: function () {
		this.lang_code = this.frm.doc.language;
		// Load all languages in the field
		this.language_sel.empty()
			.add_options(frappe.get_languages())
			.val(this.lang_code);
		this.preview();
	},
	multilingual_preview: function () {
		var me = this;
		if (this.is_old_style()) {
			me.wrapper.find(".btn-download-pdf").toggle(false);
			me.set_style();
			me.preview_old_style();
		} else {
			me.wrapper.find(".btn-download-pdf").toggle(true);
			me.preview();
		}
	},
	preview: function () {
		var me = this;
		this.get_print_html(function (out) {
			me.wrapper.find(".print-format").html(out.html);
			me.show_footer();
			me.set_style(out.style);
		});
	},
	show_footer: function() {
		// footer is hidden by default as reqd by pdf generation
		// simple hack to show it in print preview
		this.wrapper.find('.page-break').css({
			'display': 'flex',
			'flex-direction': 'column'
		});
		this.wrapper.find('#footer-html').attr('style', `
			display: block !important;
			order: 1;
			margin-top: 20px;
		`);
	},
	printit: function () {
		this.new_page_preview(true);
	},
	new_page_preview: function (printit) {
		var me = this;
		var w = window.open(frappe.urllib.get_full_url("/printview?"
			+ "doctype=" + encodeURIComponent(me.frm.doc.doctype)
			+ "&name=" + encodeURIComponent(me.frm.doc.name)
			+ (printit ? "&trigger_print=1" : "")
			+ "&format=" + me.selected_format()
			+ "&no_letterhead=" + (me.with_letterhead() ? "0" : "1")
			+ (me.lang_code ? ("&_lang=" + me.lang_code) : "")));
		if (!w) {
			frappe.msgprint(__("Please enable pop-ups")); return;
		}
	},
	get_print_html: function (callback) {
		frappe.call({
			method: "frappe.www.printview.get_html_and_style",
			args: {
				doc: this.frm.doc,
				print_format: this.selected_format(),
				no_letterhead: !this.with_letterhead() ? 1 : 0,
				_lang: this.lang_code
			},
			callback: function (r) {
				if (!r.exc) {
					callback(r.message);
				}
			}
		});
	},
	preview_old_style: function () {
		var me = this;
		this.with_old_style({
			format: me.print_sel.val(),
			callback: function (html) {
				me.wrapper.find(".print-format").html('
'
					+ __("Warning: This Print Format is in old style and cannot be generated via the API.")
					+ '
'
					+ html);
			},
			no_letterhead: !this.with_letterhead(),
			only_body: true,
			no_heading: true
		});
	},
	refresh_print_options: function () {
		this.print_formats = frappe.meta.get_print_formats(this.frm.doctype);
		return this.print_sel
			.empty().add_options(this.print_formats);
	},
	with_old_style: function (opts) {
		frappe.require("/assets/js/print_format_v3.min.js", function () {
			_p.build(opts.format, opts.callback, opts.no_letterhead, opts.only_body, opts.no_heading);
		});
	},
	print_old_style: function () {
		var me = this;
		frappe.require("/assets/js/print_format_v3.min.js", function () {
			_p.build(me.print_sel.val(), _p.go,
				!me.with_letterhead());
		});
	},
	new_page_preview_old_style: function () {
		var me = this;
		frappe.require("/assets/js/print_format_v3.min.js", function () {
			_p.build(me.print_sel.val(), _p.preview, !me.with_letterhead());
		});
	},
	selected_format: function () {
		return this.print_sel.val() || this.frm.meta.default_print_format || "Standard";
	},
	is_old_style: function (format) {
		return this.get_print_format(format).print_format_type === "Client";
	},
	get_print_format: function (format) {
		if (!format) {
			format = this.selected_format();
		}

		if (locals["Print Format"] && locals["Print Format"][format]) {
			return locals["Print Format"][format]
		} else {
			return {}
		}
	},
	with_letterhead: function () {
		return this.print_letterhead.is(":checked") ? 1 : 0;
	},
	set_style: function (style) {
		frappe.dom.set_style(style || frappe.boot.print_css, "print-style");
	}
});

frappe.ui.get_print_settings = function (pdf, callback, letter_head) {
	var print_settings = locals[":Print Settings"]["Print Settings"];

	var default_letter_head = locals[":Company"] && frappe.defaults.get_default('company')
		? locals[":Company"][frappe.defaults.get_default('company')]["default_letter_head"]
		: '';

	var columns = [{
		fieldtype: "Check",
		fieldname: "with_letter_head",
		label: __("With Letter head")
	}, {
		fieldtype: "Select",
		fieldname: "letter_head",
		label: __("Letter Head"),
		depends_on: "with_letter_head",
		options: $.map(frappe.boot.letter_heads, function (i, d) { return d }),
		default: letter_head || default_letter_head
	}];

	if (pdf) {
		columns.push({
			fieldtype: "Select",
			fieldname: "orientation",
			label: __("Orientation"),
			options: "Landscape\nPortrait",
			default: "Landscape"
		})
	}

	frappe.prompt(columns, function (data) {
		var data = $.extend(print_settings, data);
		if (!data.with_letter_head) {
			data.letter_head = null;
		}
		if (data.letter_head) {
			data.letter_head = frappe.boot.letter_heads[print_settings.letter_head];
		}
		callback(data);
	}, __("Print Settings"));
}
<|endoftext|>


<commit_before>
var schema = {};

schema.profile = new SimpleSchema({
  firstName: {
    type: String,
    regEx: /^[a-zA-Z-]{2,25}$/,
    optional: true
  },
  lastName: {
    type: String,
    regEx: /^[a-zA-Z]{2,25}$/,
    optional: true
  }
});

schema.user = new SimpleSchema({
  emails: {
    type: [Object]
  },
  "emails.$.address": {
    type: String,
    regEx: SimpleSchema.RegEx.Email
  },
  "emails.$.verified": {
    type: Boolean
  },
  profile: {
    type: schema.profile,
    optional: true
  },
  services: {
    type: Object,
    optional: true,
    blackbox: true
  },
  roles: {
    type: Object,
    optional: true,
    blackbox: true
  },
  status: {
    type: Object,
    optional: true,
    blackbox: true
  },
  createdAt: {
    type: Date
  }
});

Meteor.users.attachSchema(schema.user);
<commit_msg>User schema update<commit_after>
var schema = {};

schema.profile = new SimpleSchema({
  firstName: {
    type: String,
    regEx: /^[a-zA-Z-]{2,25}$/,
    optional: true
  },
  lastName: {
    type: String,
    regEx: /^[a-zA-Z]{2,25}$/,
    optional: true
  },
  photo: {
    type: String,
    optional: true
  }
});

schema.user = new SimpleSchema({
  emails: {
    type: [Object]
  },
  "emails.$.address": {
    type: String,
    regEx: SimpleSchema.RegEx.Email
  },
  "emails.$.verified": {
    type: Boolean
  },
  profile: {
    type: schema.profile,
    optional: true
  },
  services: {
    type: Object,
    optional: true,
    blackbox: true
  },
  roles: {
    type: Object,
    optional: true,
    blackbox: true
  },
  status: {
    type: Object,
    optional: true,
    blackbox: true
  },
  createdAt: {
    type: Date
  }
});

Meteor.users.attachSchema(schema.user);
<|endoftext|>