From 1cf1a4a016148bf4248df018fa2b66f015a3b8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 6 Oct 2020 17:25:51 +0200 Subject: [PATCH] MOBILE-3565 components: Icon component --- package-lock.json | 5 + package.json | 1 + src/app/components/components.module.ts | 27 +++++ src/app/components/icon/core-icon.html | 1 + src/app/components/icon/icon.scss | 52 +++++++++ src/app/components/icon/icon.ts | 135 ++++++++++++++++++++++++ src/assets/fonts/slash-icon.woff | Bin 0 -> 1144 bytes src/global.scss | 4 + 8 files changed, 225 insertions(+) create mode 100644 src/app/components/components.module.ts create mode 100644 src/app/components/icon/core-icon.html create mode 100644 src/app/components/icon/icon.scss create mode 100644 src/app/components/icon/icon.ts create mode 100644 src/assets/fonts/slash-icon.woff diff --git a/package-lock.json b/package-lock.json index bd88b08bc..aa7eda930 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8574,6 +8574,11 @@ "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", "dev": true }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", diff --git a/package.json b/package.json index 774cc91a8..b999cd2c8 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "cordova-support-google-services": "^1.2.1", "cordova.plugins.diagnostic": "^6.0.2", "es6-promise-plugin": "^4.2.2", + "font-awesome": "^4.7.0", "moment": "^2.29.0", "nl.kingsquare.cordova.background-audio": "^1.0.1", "phonegap-plugin-multidex": "^1.0.0", diff --git a/src/app/components/components.module.ts b/src/app/components/components.module.ts new file mode 100644 index 000000000..55bee79bb --- /dev/null +++ b/src/app/components/components.module.ts @@ -0,0 +1,27 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// 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. + +import { NgModule } from '@angular/core'; +import { CoreIconComponent } from './icon/icon'; + +@NgModule({ + declarations: [ + CoreIconComponent, + ], + imports: [], + exports: [ + CoreIconComponent, + ] +}) +export class CoreComponentsModule {} diff --git a/src/app/components/icon/core-icon.html b/src/app/components/icon/core-icon.html new file mode 100644 index 000000000..7c89b545c --- /dev/null +++ b/src/app/components/icon/core-icon.html @@ -0,0 +1 @@ +
diff --git a/src/app/components/icon/icon.scss b/src/app/components/icon/icon.scss new file mode 100644 index 000000000..0b3467edb --- /dev/null +++ b/src/app/components/icon/icon.scss @@ -0,0 +1,52 @@ +// TODO ionic 5 +:host-context([dir=rtl]) ion-icon { + &.core-icon-dir-flip, + &.fa-caret-right, + &.ion-md-send, &.ion-ios-send { + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1); + } +} + +// Slash +@font-face { + font-family: "Moodle Slash Icon"; + font-style: normal; + font-weight: 400; + src: url("/assets/fonts/slash-icon.woff") format("woff"); +} + +:host { + &.fa { + font-size: 24px; + } + + // Center font awesome icons + &.fa::before { + width: 1em; + height: 1em; + text-align: center; + } + + &.icon-slash { + position: relative; + &::after { + content: "/"; + font-family: "Moodle Slash Icon"; + font-size: 0.75em; + margin-top: 0.125em; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + text-align: center; + color: var(--ion-color-danger); + } + + &.fa::after { + font-size: 1em; + margin-top: 0; + } + } +} diff --git a/src/app/components/icon/icon.ts b/src/app/components/icon/icon.ts new file mode 100644 index 000000000..ff70d868e --- /dev/null +++ b/src/app/components/icon/icon.ts @@ -0,0 +1,135 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// 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. + +import { Component, Input, OnChanges, OnDestroy, ElementRef, SimpleChange } from '@angular/core'; + +/** + * Core Icon is a component that enables the posibility to add fontawesome icon to the html. It's recommended if both fontawesome + * or ionicons can be used in the name attribute. To use fontawesome just place the full icon name with the fa- prefix and + * the component will detect it. + * Check available icons at https://fontawesome.com/v4.7.0/icons/. + */ +@Component({ + selector: 'core-icon', + templateUrl: 'core-icon.html', + styleUrls: ['icon.scss'], +}) +export class CoreIconComponent implements OnChanges, OnDestroy { + // Common params. + @Input() name: string; + @Input('color') color?: string; + @Input('slash') slash?: boolean; // Display a red slash over the icon. + + // Ionicons params. + @Input('isActive') isActive?: boolean; + @Input('md') md?: string; + @Input('ios') ios?: string; + + // FontAwesome params. + @Input('fixed-width') fixedWidth: string; + + @Input('label') ariaLabel?: string; + @Input() flipRtl?: boolean; // Whether to flip the icon in RTL. Defaults to false. + + protected element: HTMLElement; + protected newElement: HTMLElement; + + constructor(el: ElementRef) { + this.element = el.nativeElement; + } + + /** + * Detect changes on input properties. + */ + ngOnChanges(changes: {[name: string]: SimpleChange}): void { + if (!changes.name || !this.name) { + return; + } + + const oldElement = this.newElement ? this.newElement : this.element; + + // Use a new created element to avoid ion-icon working. + // This is necessary to make the FontAwesome stuff work. + // It is also required to stop Ionic overriding the aria-label attribute. + this.newElement = document.createElement('ion-icon'); + if (this.name.startsWith('fa-')) { + this.newElement.classList.add('fa'); + this.newElement.classList.add(this.name); + if (this.isTrueProperty(this.fixedWidth)) { + this.newElement.classList.add('fa-fw'); + } + if (this.color) { + this.newElement.classList.add('fa-' + this.color); + } + } + + !this.ariaLabel && this.newElement.setAttribute('aria-hidden', 'true'); + !this.ariaLabel && this.newElement.setAttribute('role', 'presentation'); + this.ariaLabel && this.newElement.setAttribute('aria-label', this.ariaLabel); + this.ariaLabel && this.newElement.setAttribute('title', this.ariaLabel); + + const attrs = this.element.attributes; + for (let i = attrs.length - 1; i >= 0; i--) { + if (attrs[i].name == 'class') { + // We don't want to override the classes we already added. Add them one by one. + if (attrs[i].value) { + const classes = attrs[i].value.split(' '); + for (let j = 0; j < classes.length; j++) { + if (classes[j]) { + this.newElement.classList.add(classes[j]); + } + } + } + + } else { + this.newElement.setAttribute(attrs[i].name, attrs[i].value); + } + } + + if (this.slash) { + this.newElement.classList.add('icon-slash'); + } + + if (this.flipRtl) { + this.newElement.classList.add('core-icon-dir-flip'); + } + + oldElement.parentElement.replaceChild(this.newElement, oldElement); + } + + /** + * Check if the value is true or on. + * + * @param val value to be checked. + * @return If has a value equivalent to true. + */ + isTrueProperty(val: any): boolean { + if (typeof val === 'string') { + val = val.toLowerCase().trim(); + + return (val === 'true' || val === 'on' || val === ''); + } + + return !!val; + } + + /** + * Component destroyed. + */ + ngOnDestroy(): void { + if (this.newElement) { + this.newElement.remove(); + } + } +} diff --git a/src/assets/fonts/slash-icon.woff b/src/assets/fonts/slash-icon.woff new file mode 100644 index 0000000000000000000000000000000000000000..5e02178e49592d116b528e2e58d8b017adf71b4b GIT binary patch literal 1144 zcmXT-cXRU(3GruOV5wl>W&i@V3I;|HjR~CH+!PoXm~DVE{}>n;c~?x(Q+9I;@dfG) z0gB0haA(N#AMP%$Za^`RItj42D1(T9u)YycPYRF^lw(K;JCMYmoSRs{z`*nd$TtVd zIWh1tUCl^M1gc@=0Ez+CGnk3|*uF9YCP&>Sq9{<=|lW z-;kSF0pv5r0QqcS%oMzTconFCl@4Hy}kvRMNd7=VZgqAoEpVa|aArw$x2nf#K6nc3OC zC9URc!kH7CBB=?ilL8K$XkcNw6ca2VCGkb_%go;Y(#A&&q>bk|1}0!`j;Hn3i z(>r0WACsd<>-i7qJe?aCZIIGdY&`p>jg3qAh{MuWl`DD%db4vR=EQPIRoAk3$scI{ z%xSZ^r?ZuH_spI5|IV&XV~Bac&2;>|)c1L;vnoEv9F*jnw|d9H?a!rVDSe7LzO>@o zorFJgr!FeRBK|IUtA)h~+w-eVQstf_WPEy}HNlJie@=DisgUVpzM>UY^jKVIeeZOh(C#&@PH z*y1Pu?AEiDH$9dfa?n)uxBAB3VjSxZj<1A-w1xypHa9kb4UC^84%UdVu_~NpYEjtt z@Be>+Pyba{c(J*eu}Msha9H%|AU{LqbGAodeQ6BM|9g3kIdn~ADb!ztg<=tyCUMr z4hf6XhraCI{g6lQ+x>gOd)O^i6GfB1lc!r={30d0-WZ4*N~8YNTa2{r3A zw-(nqrUs@}xpg+VZCchev2o$jzNTcqpsc{ors|}^!Ys~7#uH*$SeSTxdV0JT-u+$2 z@+SGt_V>>_YtQ^XQup%jjc@+_x%cO%U6g0E_y5D0@Z9^itg6;wqtDZoUZ2U_`&l}z zXvv%8+!>MgqHiBi{A~SqzEXCsbNbIMQGLD>*IdqeUVdiIv4h{UyF9jMnDdJ>{B{X< zho=7q201oCHZg^>EJu0-co>*YGiU+x6u1PrUR}Hi$Y!|lW+#XO(z{(*fHVs*uL1yl CwzmTS literal 0 HcmV?d00001 diff --git a/src/global.scss b/src/global.scss index d854de84a..36c0be50d 100644 --- a/src/global.scss +++ b/src/global.scss @@ -9,6 +9,7 @@ * https://ionicframework.com/docs/layout/global-stylesheets */ + /* Core CSS required for Ionic components to work properly */ @import "~@ionic/angular/css/core.css"; @@ -24,3 +25,6 @@ @import "~@ionic/angular/css/text-alignment.css"; @import "~@ionic/angular/css/text-transformation.css"; @import "~@ionic/angular/css/flex-utils.css"; + +/* Font awesome */ +@import "~font-awesome/scss/font-awesome.scss";