diff --git a/src/pipes/bytes-to-size.ts b/src/pipes/bytes-to-size.ts
new file mode 100644
index 000000000..a05ef7e4b
--- /dev/null
+++ b/src/pipes/bytes-to-size.ts
@@ -0,0 +1,51 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Pipe, PipeTransform } from '@angular/core';
+import { CoreLoggerProvider } from '../providers/logger';
+import { CoreTextUtilsProvider } from '../providers/utils/text';
+
+/**
+ * Pipe to turn a number in bytes to a human readable size (e.g. 5,25 MB).
+ */
+@Pipe({
+ name: 'coreBytesToSize',
+})
+export class CoreBytesToSizePipe implements PipeTransform {
+ protected logger;
+
+ constructor(logger: CoreLoggerProvider, private textUtils: CoreTextUtilsProvider) {
+ this.logger = logger.getInstance('CoreBytesToSizePipe');
+ }
+
+ /**
+ * Takes a number and turns it to a human readable size.
+ *
+ * @param {number|string} value The bytes to convert.
+ * @return {string} Readable bytes.
+ */
+ transform(value: number|string) : string {
+ if (typeof value == 'string') {
+ // Convert the value to a number.
+ const numberValue = parseInt(value, 10);
+ if (isNaN(numberValue)) {
+ this.logger.error('Invalid value received', value);
+ return value;
+ }
+ value = numberValue;
+ }
+
+ return this.textUtils.bytesToSize(value);
+ }
+}
diff --git a/src/pipes/create-links.ts b/src/pipes/create-links.ts
new file mode 100644
index 000000000..0cc66c27a
--- /dev/null
+++ b/src/pipes/create-links.ts
@@ -0,0 +1,35 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Pipe, PipeTransform } from '@angular/core';
+
+/**
+ * Pipe to search URLs that are not inside tags and add the corresponding tags.
+ */
+@Pipe({
+ name: 'coreCreateLinks',
+})
+export class CoreCreateLinksPipe implements PipeTransform {
+ private replacePattern = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])(?![^<]*>|[^<>]*<\/)/gim;
+
+ /**
+ * Takes some text and adds anchor tags to all links that aren't inside anchors.
+ *
+ * @param {string} text Text to treat.
+ * @return {string} Treated text.
+ */
+ transform(text: string) {
+ return text.replace(this.replacePattern, '$1');
+ }
+}
diff --git a/src/pipes/date-day-or-time.ts b/src/pipes/date-day-or-time.ts
new file mode 100644
index 000000000..d216c150a
--- /dev/null
+++ b/src/pipes/date-day-or-time.ts
@@ -0,0 +1,66 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Pipe, PipeTransform } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { CoreLoggerProvider } from '../providers/logger';
+import * as moment from 'moment';
+
+/**
+ * Filter to display a date using the day, or the time.
+ *
+ * This shows a short version of a date. Use this filter when you want
+ * the user to visualise when the action was done relatively to today's date.
+ *
+ * For instance, if the action happened during this day it will display the time,
+ * but when the action happened few days ago, it will display the day of the week.
+ *
+ * The older the date is, the more information about it will be displayed.
+ *
+ * This filter expects a timestamp NOT including milliseconds.
+ */
+@Pipe({
+ name: 'coreDateDayOrTime',
+})
+export class CoreDateDayOrTimePipe implements PipeTransform {
+ protected logger;
+
+ constructor(logger: CoreLoggerProvider, private translate: TranslateService) {
+ this.logger = logger.getInstance('CoreDateDayOrTimePipe');
+ }
+
+ /**
+ * Format a timestamp.
+ *
+ * @param {number|string} timestamp The UNIX timestamp (without milliseconds).
+ * @return {string} Formatted time.
+ */
+ transform(timestamp: string|number) : string {
+ if (typeof timestamp == 'string') {
+ // Convert the value to a number.
+ const numberTimestamp = parseInt(timestamp, 10);
+ if (isNaN(numberTimestamp)) {
+ this.logger.error('Invalid value received', timestamp);
+ return timestamp;
+ }
+ timestamp = numberTimestamp;
+ }
+
+ return moment(timestamp * 1000).calendar(null, {
+ sameDay: this.translate.instant('mm.core.dftimedate'),
+ lastDay: this.translate.instant('mm.core.dflastweekdate'),
+ lastWeek: this.translate.instant('mm.core.dflastweekdate')
+ });
+ }
+}
diff --git a/src/pipes/duration.ts b/src/pipes/duration.ts
new file mode 100644
index 000000000..c5bde0e2a
--- /dev/null
+++ b/src/pipes/duration.ts
@@ -0,0 +1,51 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Pipe, PipeTransform } from '@angular/core';
+import { CoreLoggerProvider } from '../providers/logger';
+import * as moment from 'moment';
+
+/**
+ * Filter to turn a number of seconds to a duration. E.g. 60 -> 1 minute.
+ */
+@Pipe({
+ name: 'coreDuration',
+})
+export class CoreDurationPipe implements PipeTransform {
+ protected logger;
+
+ constructor(logger: CoreLoggerProvider) {
+ this.logger = logger.getInstance('CoreBytesToSizePipe');
+ }
+
+ /**
+ * Turn a number of seconds to a duration. E.g. 60 -> 1 minute.
+ *
+ * @param {number|string} seconds The number of seconds.
+ * @return {string} Formatted duration.
+ */
+ transform(seconds: string|number) {
+ if (typeof seconds == 'string') {
+ // Convert the value to a number.
+ const numberSeconds = parseInt(seconds, 10);
+ if (isNaN(numberSeconds)) {
+ this.logger.error('Invalid value received', seconds);
+ return seconds;
+ }
+ seconds = numberSeconds;
+ }
+
+ return moment.duration(seconds * 1000).humanize();
+ }
+}
diff --git a/src/pipes/format-date.ts b/src/pipes/format-date.ts
new file mode 100644
index 000000000..d4c4b491a
--- /dev/null
+++ b/src/pipes/format-date.ts
@@ -0,0 +1,59 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Pipe, PipeTransform } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { CoreLoggerProvider } from '../providers/logger';
+import * as moment from 'moment';
+
+/**
+ * Filter to format a date.
+ */
+@Pipe({
+ name: 'coreFormatDate',
+})
+export class CoreFormatDatePipe implements PipeTransform {
+ protected logger;
+
+ constructor(logger: CoreLoggerProvider, private translate: TranslateService) {
+ this.logger = logger.getInstance('CoreDateDayOrTimePipe');
+ }
+
+ /**
+ * Format a date.
+ *
+ * @param {string|number} timestamp Timestamp to format (in milliseconds). If not defined, use current time.
+ * @param {string} format Format to use. It should be a string code to handle i18n (e.g. mm.core.dftimedate). If the code
+ * doesn't have a prefix, 'mm.core' will be used by default. E.g. 'dftimedate' -> 'mm.core.dftimedate'.
+ * @return {String} Formatted date.
+ */
+ transform(timestamp: string|number, format: string) {
+ timestamp = timestamp || Date.now();
+
+ if (typeof timestamp == 'string') {
+ // Convert the value to a number.
+ const numberTimestamp = parseInt(timestamp, 10);
+ if (isNaN(numberTimestamp)) {
+ this.logger.error('Invalid value received', timestamp);
+ return timestamp;
+ }
+ timestamp = numberTimestamp;
+ }
+
+ if (format.indexOf('.') == -1) {
+ format = 'mm.core.' + format;
+ }
+ return moment(timestamp).format(this.translate.instant(format));
+ }
+}
diff --git a/src/pipes/no-tags.ts b/src/pipes/no-tags.ts
new file mode 100644
index 000000000..d43e40794
--- /dev/null
+++ b/src/pipes/no-tags.ts
@@ -0,0 +1,34 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Pipe, PipeTransform } from '@angular/core';
+
+/**
+ * Pipe to remove HTML tags.
+ */
+@Pipe({
+ name: 'coreNoTags',
+})
+export class CoreNoTagsPipe implements PipeTransform {
+
+ /**
+ * Takes a text and removes HTML tags.
+ *
+ * @param {string} text The text to treat.
+ * @return {string} Treated text.
+ */
+ transform(text: string) : string {
+ return text.replace(/(<([^>]+)>)/ig, '');
+ }
+}
diff --git a/src/pipes/pipes.module.ts b/src/pipes/pipes.module.ts
new file mode 100644
index 000000000..b91eccfc6
--- /dev/null
+++ b/src/pipes/pipes.module.ts
@@ -0,0 +1,51 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { CoreBytesToSizePipe } from './bytes-to-size';
+import { CoreCreateLinksPipe } from './create-links';
+import { CoreDateDayOrTimePipe } from './date-day-or-time';
+import { CoreDurationPipe } from './duration';
+import { CoreFormatDatePipe } from './format-date';
+import { CoreNoTagsPipe } from './no-tags';
+import { CoreSecondsToHMSPipe } from './seconds-to-hms';
+import { CoreTimeAgoPipe } from './time-ago';
+import { CoreToLocaleStringPipe } from './to-locale-string';
+
+@NgModule({
+ declarations: [
+ CoreBytesToSizePipe,
+ CoreCreateLinksPipe,
+ CoreDateDayOrTimePipe,
+ CoreDurationPipe,
+ CoreFormatDatePipe,
+ CoreNoTagsPipe,
+ CoreSecondsToHMSPipe,
+ CoreTimeAgoPipe,
+ CoreToLocaleStringPipe
+ ],
+ imports: [],
+ exports: [
+ CoreBytesToSizePipe,
+ CoreCreateLinksPipe,
+ CoreDateDayOrTimePipe,
+ CoreDurationPipe,
+ CoreFormatDatePipe,
+ CoreNoTagsPipe,
+ CoreSecondsToHMSPipe,
+ CoreTimeAgoPipe,
+ CoreToLocaleStringPipe
+ ]
+})
+export class CorePipesModule {}
diff --git a/src/pipes/seconds-to-hms.ts b/src/pipes/seconds-to-hms.ts
new file mode 100644
index 000000000..c88164cbc
--- /dev/null
+++ b/src/pipes/seconds-to-hms.ts
@@ -0,0 +1,64 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Pipe, PipeTransform } from '@angular/core';
+import { CoreLoggerProvider } from '../providers/logger';
+import { CoreTextUtilsProvider } from '../providers/utils/text';
+import { CoreConstants } from '../core/constants';
+
+/**
+ * Pipe to convert a number of seconds to Hours:Minutes:Seconds.
+ *
+ * This converts a number of seconds to Hours:Minutes:Seconds. If the number of seconds is negative, returns 00:00:00.
+ */
+@Pipe({
+ name: 'coreSecondsToHMS',
+})
+export class CoreSecondsToHMSPipe implements PipeTransform {
+ protected logger;
+
+ constructor(logger: CoreLoggerProvider, private textUtils: CoreTextUtilsProvider) {
+ this.logger = logger.getInstance('CoreSecondsToHMSPipe');
+ }
+
+ /**
+ * Convert a number of seconds to Hours:Minutes:Seconds.
+ *
+ * @param {number|string} seconds Number of seconds.
+ * @return {string} Formatted seconds.
+ */
+ transform(seconds: string|number) : string {
+ let hours,
+ minutes;
+
+ if (!seconds || seconds < 0) {
+ seconds = 0;
+ } else if (typeof seconds == 'string') {
+ // Convert the value to a number.
+ const numberSeconds = parseInt(seconds, 10);
+ if (isNaN(numberSeconds)) {
+ this.logger.error('Invalid value received', seconds);
+ return seconds;
+ }
+ seconds = numberSeconds;
+ }
+
+ hours = Math.floor(seconds / CoreConstants.secondsHour);
+ seconds -= hours * CoreConstants.secondsHour;
+ minutes = Math.floor(seconds / CoreConstants.secondsMinute);
+ seconds -= minutes * CoreConstants.secondsMinute;
+
+ return this.textUtils.twoDigits(hours) + ':' + this.textUtils.twoDigits(minutes) + ':' + this.textUtils.twoDigits(seconds);
+ }
+}
diff --git a/src/pipes/time-ago.ts b/src/pipes/time-ago.ts
new file mode 100644
index 000000000..b1c7ad1c0
--- /dev/null
+++ b/src/pipes/time-ago.ts
@@ -0,0 +1,51 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Pipe, PipeTransform } from '@angular/core';
+import { CoreLoggerProvider } from '../providers/logger';
+import * as moment from 'moment';
+
+/**
+ * Pipe to turn a UNIX timestamp to "time ago".
+ */
+@Pipe({
+ name: 'coreTimeAgo',
+})
+export class CoreTimeAgoPipe implements PipeTransform {
+ protected logger;
+
+ constructor(logger: CoreLoggerProvider) {
+ this.logger = logger.getInstance('CoreTimeAgoPipe');
+ }
+
+ /**
+ * Turn a UNIX timestamp to "time ago".
+ *
+ * @param {number|string} timestamp The UNIX timestamp (without milliseconds).
+ * @return {string} Formatted time.
+ */
+ transform(timestamp: string|number) : string {
+ if (typeof timestamp == 'string') {
+ // Convert the value to a number.
+ const numberTimestamp = parseInt(timestamp, 10);
+ if (isNaN(numberTimestamp)) {
+ this.logger.error('Invalid value received', timestamp);
+ return timestamp;
+ }
+ timestamp = numberTimestamp;
+ }
+
+ return moment(timestamp * 1000).fromNow(true);
+ }
+}
diff --git a/src/pipes/to-locale-string.ts b/src/pipes/to-locale-string.ts
new file mode 100644
index 000000000..eb7aec685
--- /dev/null
+++ b/src/pipes/to-locale-string.ts
@@ -0,0 +1,58 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Pipe, PipeTransform } from '@angular/core';
+import { CoreLoggerProvider } from '../providers/logger';
+
+/**
+ * Filter to format a timestamp to a locale string. Timestamp can be in seconds or milliseconds.
+ */
+@Pipe({
+ name: 'coreToLocaleString',
+})
+export class CoreToLocaleStringPipe implements PipeTransform {
+ protected logger;
+
+ constructor(logger: CoreLoggerProvider) {
+ this.logger = logger.getInstance('CoreToLocaleStringPipe');
+ }
+
+ /**
+ * Format a timestamp to a locale string.
+ *
+ * @param {number|string} timestamp The timestamp (can be in seconds or milliseconds).
+ * @return {string} Formatted time.
+ */
+ transform(timestamp: number|string) : string {
+ if (typeof timestamp == 'string') {
+ // Convert the value to a number.
+ const numberTimestamp = parseInt(timestamp, 10);
+ if (isNaN(numberTimestamp)) {
+ this.logger.error('Invalid value received', timestamp);
+ return timestamp;
+ }
+ timestamp = numberTimestamp;
+ }
+
+ if (timestamp < 0) {
+ // Date not valid.
+ return '';
+ }
+ if (timestamp < 100000000000) {
+ // Timestamp is in seconds, convert it to milliseconds.
+ timestamp = timestamp * 1000;
+ }
+ return new Date(timestamp).toLocaleString();
+ }
+}