web.js 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import { WebPlugin, CapacitorException } from '@capacitor/core';
  2. import { CameraSource, CameraDirection } from './definitions';
  3. export class CameraWeb extends WebPlugin {
  4. async getPhoto(options) {
  5. // eslint-disable-next-line no-async-promise-executor
  6. return new Promise(async (resolve, reject) => {
  7. if (options.webUseInput || options.source === CameraSource.Photos) {
  8. this.fileInputExperience(options, resolve, reject);
  9. }
  10. else if (options.source === CameraSource.Prompt) {
  11. let actionSheet = document.querySelector('pwa-action-sheet');
  12. if (!actionSheet) {
  13. actionSheet = document.createElement('pwa-action-sheet');
  14. document.body.appendChild(actionSheet);
  15. }
  16. actionSheet.header = options.promptLabelHeader || 'Photo';
  17. actionSheet.cancelable = false;
  18. actionSheet.options = [
  19. { title: options.promptLabelPhoto || 'From Photos' },
  20. { title: options.promptLabelPicture || 'Take Picture' },
  21. ];
  22. actionSheet.addEventListener('onSelection', async (e) => {
  23. const selection = e.detail;
  24. if (selection === 0) {
  25. this.fileInputExperience(options, resolve, reject);
  26. }
  27. else {
  28. this.cameraExperience(options, resolve, reject);
  29. }
  30. });
  31. }
  32. else {
  33. this.cameraExperience(options, resolve, reject);
  34. }
  35. });
  36. }
  37. async pickImages(_options) {
  38. // eslint-disable-next-line no-async-promise-executor
  39. return new Promise(async (resolve, reject) => {
  40. this.multipleFileInputExperience(resolve, reject);
  41. });
  42. }
  43. async cameraExperience(options, resolve, reject) {
  44. if (customElements.get('pwa-camera-modal')) {
  45. const cameraModal = document.createElement('pwa-camera-modal');
  46. cameraModal.facingMode =
  47. options.direction === CameraDirection.Front ? 'user' : 'environment';
  48. document.body.appendChild(cameraModal);
  49. try {
  50. await cameraModal.componentOnReady();
  51. cameraModal.addEventListener('onPhoto', async (e) => {
  52. const photo = e.detail;
  53. if (photo === null) {
  54. reject(new CapacitorException('User cancelled photos app'));
  55. }
  56. else if (photo instanceof Error) {
  57. reject(photo);
  58. }
  59. else {
  60. resolve(await this._getCameraPhoto(photo, options));
  61. }
  62. cameraModal.dismiss();
  63. document.body.removeChild(cameraModal);
  64. });
  65. cameraModal.present();
  66. }
  67. catch (e) {
  68. this.fileInputExperience(options, resolve, reject);
  69. }
  70. }
  71. else {
  72. console.error(`Unable to load PWA Element 'pwa-camera-modal'. See the docs: https://capacitorjs.com/docs/web/pwa-elements.`);
  73. this.fileInputExperience(options, resolve, reject);
  74. }
  75. }
  76. fileInputExperience(options, resolve, reject) {
  77. let input = document.querySelector('#_capacitor-camera-input');
  78. const cleanup = () => {
  79. var _a;
  80. (_a = input.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(input);
  81. };
  82. if (!input) {
  83. input = document.createElement('input');
  84. input.id = '_capacitor-camera-input';
  85. input.type = 'file';
  86. input.hidden = true;
  87. document.body.appendChild(input);
  88. input.addEventListener('change', (_e) => {
  89. const file = input.files[0];
  90. let format = 'jpeg';
  91. if (file.type === 'image/png') {
  92. format = 'png';
  93. }
  94. else if (file.type === 'image/gif') {
  95. format = 'gif';
  96. }
  97. if (options.resultType === 'dataUrl' ||
  98. options.resultType === 'base64') {
  99. const reader = new FileReader();
  100. reader.addEventListener('load', () => {
  101. if (options.resultType === 'dataUrl') {
  102. resolve({
  103. dataUrl: reader.result,
  104. format,
  105. });
  106. }
  107. else if (options.resultType === 'base64') {
  108. const b64 = reader.result.split(',')[1];
  109. resolve({
  110. base64String: b64,
  111. format,
  112. });
  113. }
  114. cleanup();
  115. });
  116. reader.readAsDataURL(file);
  117. }
  118. else {
  119. resolve({
  120. webPath: URL.createObjectURL(file),
  121. format: format,
  122. });
  123. cleanup();
  124. }
  125. });
  126. input.addEventListener('cancel', (_e) => {
  127. reject(new CapacitorException('User cancelled photos app'));
  128. cleanup();
  129. });
  130. }
  131. input.accept = 'image/*';
  132. input.capture = true;
  133. if (options.source === CameraSource.Photos ||
  134. options.source === CameraSource.Prompt) {
  135. input.removeAttribute('capture');
  136. }
  137. else if (options.direction === CameraDirection.Front) {
  138. input.capture = 'user';
  139. }
  140. else if (options.direction === CameraDirection.Rear) {
  141. input.capture = 'environment';
  142. }
  143. input.click();
  144. }
  145. multipleFileInputExperience(resolve, reject) {
  146. let input = document.querySelector('#_capacitor-camera-input-multiple');
  147. const cleanup = () => {
  148. var _a;
  149. (_a = input.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(input);
  150. };
  151. if (!input) {
  152. input = document.createElement('input');
  153. input.id = '_capacitor-camera-input-multiple';
  154. input.type = 'file';
  155. input.hidden = true;
  156. input.multiple = true;
  157. document.body.appendChild(input);
  158. input.addEventListener('change', (_e) => {
  159. const photos = [];
  160. // eslint-disable-next-line @typescript-eslint/prefer-for-of
  161. for (let i = 0; i < input.files.length; i++) {
  162. const file = input.files[i];
  163. let format = 'jpeg';
  164. if (file.type === 'image/png') {
  165. format = 'png';
  166. }
  167. else if (file.type === 'image/gif') {
  168. format = 'gif';
  169. }
  170. photos.push({
  171. webPath: URL.createObjectURL(file),
  172. format: format,
  173. });
  174. }
  175. resolve({ photos });
  176. cleanup();
  177. });
  178. input.addEventListener('cancel', (_e) => {
  179. reject(new CapacitorException('User cancelled photos app'));
  180. cleanup();
  181. });
  182. }
  183. input.accept = 'image/*';
  184. input.click();
  185. }
  186. _getCameraPhoto(photo, options) {
  187. return new Promise((resolve, reject) => {
  188. const reader = new FileReader();
  189. const format = photo.type.split('/')[1];
  190. if (options.resultType === 'uri') {
  191. resolve({
  192. webPath: URL.createObjectURL(photo),
  193. format: format,
  194. saved: false,
  195. });
  196. }
  197. else {
  198. reader.readAsDataURL(photo);
  199. reader.onloadend = () => {
  200. const r = reader.result;
  201. if (options.resultType === 'dataUrl') {
  202. resolve({
  203. dataUrl: r,
  204. format: format,
  205. saved: false,
  206. });
  207. }
  208. else {
  209. resolve({
  210. base64String: r.split(',')[1],
  211. format: format,
  212. saved: false,
  213. });
  214. }
  215. };
  216. reader.onerror = e => {
  217. reject(e);
  218. };
  219. }
  220. });
  221. }
  222. async checkPermissions() {
  223. if (typeof navigator === 'undefined' || !navigator.permissions) {
  224. throw this.unavailable('Permissions API not available in this browser');
  225. }
  226. try {
  227. // https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query
  228. // the specific permissions that are supported varies among browsers that implement the
  229. // permissions API, so we need a try/catch in case 'camera' is invalid
  230. const permission = await window.navigator.permissions.query({
  231. name: 'camera',
  232. });
  233. return {
  234. camera: permission.state,
  235. photos: 'granted',
  236. };
  237. }
  238. catch (_a) {
  239. throw this.unavailable('Camera permissions are not available in this browser');
  240. }
  241. }
  242. async requestPermissions() {
  243. throw this.unimplemented('Not implemented on web.');
  244. }
  245. async pickLimitedLibraryPhotos() {
  246. throw this.unavailable('Not implemented on web.');
  247. }
  248. async getLimitedLibraryPhotos() {
  249. throw this.unavailable('Not implemented on web.');
  250. }
  251. }
  252. const Camera = new CameraWeb();
  253. export { Camera };
  254. //# sourceMappingURL=web.js.map