socialnetworknews-web

A open-source Paper.li clone
git clone git://archive.git.mtrnord.blog/SocialNetworkNews/socialnetworknews-web.git
Log | Files | Refs | README | LICENSE

commit 538a7121576cd4d1aade5018620b7ae3398df18a
parent 8d9a3c54902a495d504b7cffa8d83e353b8949b8
Author: MTRNord <mtrnord1@gmail.com>
Date:   Tue, 27 Mar 2018 15:22:59 +0200

Do some linkifing and add meta tags dynamically

Diffstat:
M.angular-cli.json | 3+--
Mpackage.json | 1+
Msrc/app/tweet-list/tweet-list.component.html | 6+++---
Msrc/app/tweet-list/tweet-list.component.ts | 48++++++++++++++++++++++++++++--------------------
Asrc/app/utils/linkifier.ts | 9+++++++++
Asrc/app/utils/types/linkifyjs.d.ts | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/typings.d.ts | 5-----
Mtsconfig.json | 5+++--
Myarn.lock | 92++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
9 files changed, 195 insertions(+), 37 deletions(-)

diff --git a/.angular-cli.json b/.angular-cli.json @@ -1,7 +1,7 @@ { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "project": { - "name": "social-networks-news-web2" + "name": "social-networks-news-web" }, "apps": [ { @@ -12,7 +12,6 @@ "favicon.ico", "manifest.json" ], - "serviceWorker": true, "index": "index.html", "main": "main.ts", "polyfills": "polyfills.ts", diff --git a/package.json b/package.json @@ -34,6 +34,7 @@ "express": "^4.16.2", "font-awesome": "^4.7.0", "hammerjs": "^2.0.8", + "linkifyjs": "^2.1.6", "ng-http-loader": "^0.9.0", "ngx-avatar": "^2.9.0", "ngx-toastr": "^8.3.0", diff --git a/src/app/tweet-list/tweet-list.component.html b/src/app/tweet-list/tweet-list.component.html @@ -8,9 +8,9 @@ </div> <mat-card-header> <img src="https://twitter.com/{{item.username}}/profile_image" mat-card-avatar> - <mat-card-title><a href="{{item.userprofile_link}}">{{item.display_name}}</a></mat-card-title> + <mat-card-title><a rel="noopener noreferrer" target="_blank" href="{{item.userprofile_link}}">{{item.display_name}}</a></mat-card-title> <mat-card-subtitle *ngIf="!item.retweetby_display_name"><i class="fa fa-clock-o">&nbsp;</i>{{item.created_at.toLocaleString()}}</mat-card-subtitle> - <mat-card-subtitle *ngIf="item.retweetby_display_name"><i class="fa fa-clock-o">&nbsp;</i>{{item.created_at.toLocaleString()}}&nbsp;--&nbsp;Retweeted&nbsp;by: <a href="{{item.retweetby_userprofile_link}}">{{item.retweetby_display_name}}</a></mat-card-subtitle> + <mat-card-subtitle *ngIf="item.retweetby_display_name"><i class="fa fa-clock-o">&nbsp;</i>{{item.created_at.toLocaleString()}}&nbsp;--&nbsp;Retweeted&nbsp;by: <a rel="noopener noreferrer" target="_blank" href="{{item.retweetby_userprofile_link}}">{{item.retweetby_display_name}}</a></mat-card-subtitle> </mat-card-header> <a (click)="lightbox.show(lightboxItem)" > <img mat-card-image *ngIf="item.image_urls && item.image_urls[0]" [src]="item.image_urls[0]"> @@ -23,7 +23,7 @@ </div> </a> <mat-card-content> - {{item.text}} + {{item.text | linkify}} <br> <i class="fa fa-heart">&nbsp;</i>{{item.favorites.toLocaleString()}}&nbsp;<i class="fa fa-retweet">&nbsp;</i>{{item.retweets.toLocaleString()}} </mat-card-content> diff --git a/src/app/tweet-list/tweet-list.component.ts b/src/app/tweet-list/tweet-list.component.ts @@ -10,7 +10,14 @@ import 'rxjs/add/operator/take'; import 'rxjs/add/operator/concat'; import 'rxjs/add/observable/throw'; import {ToastrService} from 'ngx-toastr'; +import {Meta, Title} from '@angular/platform-browser'; import {Lightbox} from '../utils/lightbox'; +import * as linkify from 'linkifyjs'; +import hashtagL from 'linkifyjs/plugins/hashtag'; +import mentionL from 'linkifyjs/plugins/mention'; +hashtagL(linkify); +mentionL(linkify); + @Component({ selector: 'app-tweet-list', @@ -22,7 +29,7 @@ export class TweetListComponent implements OnInit { data: (TweetsEntity)[]; paperData: Paper; - constructor(private apiService: ApiService, private toastr: ToastrService, private lightbox: Lightbox) { + constructor(private apiService: ApiService, private toastr: ToastrService, private lightbox: Lightbox, private metaService: Meta, private titleService: Title) { Raven.captureBreadcrumb({ message: 'Showing Paper', category: 'paper', @@ -33,8 +40,19 @@ export class TweetListComponent implements OnInit { } ngOnInit() { + // Get API this.getYesterday(); this.getPaper(); + + // Set Meta Tags + this.metaService.addTags([ + { name: 'og:title', content: this.paperData.name }, + { name: 'og:description', content: this.paperData.description }, + { name: 'og:image', content: this.paperData.paper_image }, + { name: 'description', content: this.paperData.description }, + { name: 'author', content: this.paperData.author.username }, + ]); + this.titleService.setTitle( this.paperData.name ); } getPaper() { this.apiService.getPaper(this.uuid) @@ -96,23 +114,17 @@ export class TweetListComponent implements OnInit { ); } - private sort(arr: (TweetsEntity)[]): (TweetsEntity)[] { - const compare = (a, b): number => { - if ((a.image_urls && a.image_urls[0]) && !(b.image_urls && b.image_urls[0])) { - return -1; - } - if (!(a.image_urls && a.image_urls[0]) && (b.image_urls && b.image_urls[0])) { - return 1; - } - return 0; - }; + // TODO use this + private linkifyHash(text: string) { + hashtagL.find(text); + } - arr.sort(compare); - return arr; + // TODO use this + private linkifyMention(text: string) { + hashtagL.find(text); } - private chunk(arr: (TweetsEntity)[], size: number): (TweetsEntity)[][] { - // Todo sort with a point system + private sort(arr: (TweetsEntity)[]): (TweetsEntity)[] { const compare = (a, b): number => { if ((a.image_urls && a.image_urls[0]) && !(b.image_urls && b.image_urls[0])) { return -1; @@ -124,10 +136,6 @@ export class TweetListComponent implements OnInit { }; arr.sort(compare); - const newArr = []; - for (let i = 0; i < arr.length; i += size) { - newArr.push(arr.slice(i, i + size)); - } - return newArr; + return arr; } } diff --git a/src/app/utils/linkifier.ts b/src/app/utils/linkifier.ts @@ -0,0 +1,9 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import linkifyStr from 'linkifyjs/string'; + +@Pipe({name: 'linkify'}) +export class LinkifyPipe implements PipeTransform { + transform(str: string): string { + return str ? linkifyStr(str, {target: '_blank', attributes: {rel: 'noopener noreferrer'}}) : str; + } +} diff --git a/src/app/utils/types/linkifyjs.d.ts b/src/app/utils/types/linkifyjs.d.ts @@ -0,0 +1,63 @@ +// Type definitions for linkifyjs v2.1.3 +// Project: https://github.com/SoapBox/linkifyjs +// Definitions by: Aleksey Nemiro <https://github.com/alekseynemiro> +declare namespace LinkifyJs { + + interface ILinkifyOptions { + + /** Object of attributes to add to each new link. Note: the class and target attributes have dedicated options. */ + attributes?: any | (( href, type ) => void); + + /** class attribute to use for newly created links. */ + className?: string; + + /** Protocol that should be used in href attributes for URLs without a protocol (e.g., github.com). */ + defaultProtocol?: string; + + /** Add event listeners to newly created link elements. Takes a hash where each key is an standard event name and the value is an event handler. */ + events?: any | (( href, type ) => void); + + /** Format the text displayed by a linkified entity. e.g., truncate a long URL. */ + format?: (( value, type ) => void) | any; + + /** Similar to format, except the result of this function will be used as the href attribute of the new link. */ + formatHref?: (( href, type ) => void) | any; + + /** Prevent linkify from trying to parse links in the specified tags. This is useful when running linkify on arbitrary HTML. */ + ignoreTags?: Array<string>; + + /** If true, \n line breaks will automatically be converted to <br> tags. */ + nl2br?: boolean; + + /** The tag name to use for each link. For cases where you can’t use anchor tags. */ + tagName?: string | (( href, type ) => void) | any; + + /** target attribute for generated link. */ + target?: string | (( href, type ) => void) | any; + + /** If option resolves to false, the given value will not show up as a link. */ + validate?: boolean; + + } + + + type linkify = (value: string, options?: ILinkifyOptions) => string; + +} + +declare module 'linkifyjs' { + + export = LinkifyJs; + +} + +declare module 'linkifyjs/html' { + + let data: LinkifyJs.linkify; + + export default data; + +} + +declare var linkify: LinkifyJs.linkify; +declare var linkifyHtml: LinkifyJs.linkify; diff --git a/src/typings.d.ts b/src/typings.d.ts @@ -1,5 +0,0 @@ -/* SystemJS module definition */ -declare var module: NodeModule; -interface NodeModule { - id: string; -} diff --git a/tsconfig.json b/tsconfig.json @@ -9,12 +9,13 @@ "experimentalDecorators": true, "target": "es5", "typeRoots": [ - "node_modules/@types" + "node_modules/@types", + "src/app/utils/types" ], "lib": [ "es2017", "dom" ] }, - "include": ["node_modules/angular-bootstrap-md/**/*.ts", "src/**/*.ts"] + "include": ["src/**/*.ts"] } diff --git a/yarn.lock b/yarn.lock @@ -1593,6 +1593,10 @@ copy-webpack-plugin@~4.4.1: p-limit "^1.0.0" serialize-javascript "^1.4.0" +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1: version "2.5.3" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" @@ -2098,6 +2102,12 @@ encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" @@ -2500,6 +2510,18 @@ faye-websocket@~0.11.0: dependencies: websocket-driver ">=0.5.1" +fbjs@^0.8.16: + version "0.8.16" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.9" + file-loader@^1.1.5: version "1.1.11" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-1.1.11.tgz#6fe886449b0f2a936e43cabaac0cdbfb369506f8" @@ -3217,7 +3239,7 @@ iconv-lite@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" -iconv-lite@0.4.19: +iconv-lite@0.4.19, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -3562,7 +3584,7 @@ is-retina@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/is-retina/-/is-retina-1.0.3.tgz#d7401b286bea2ae37f62477588de504d0b8647e3" -is-stream@^1.1.0: +is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -3620,6 +3642,13 @@ isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -3723,6 +3752,10 @@ jasminewd2@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" +jquery@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + js-base64@^2.1.8: version "2.4.3" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.3.tgz#2e545ec2b0f2957f41356510205214e98fad6582" @@ -3996,6 +4029,14 @@ lie@~3.1.0: dependencies: immediate "~3.0.5" +linkifyjs@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-2.1.6.tgz#f1cc88a86ff8863196615857fd47eb193c0a26cb" + optionalDependencies: + jquery "^3.3.1" + react "^16.2.0" + react-dom "^16.2.0" + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -4102,7 +4143,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -4474,6 +4515,13 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-forge@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300" @@ -4690,7 +4738,7 @@ oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -5161,6 +5209,14 @@ promise@^7.1.1: dependencies: asap "~2.0.3" +prop-types@^15.6.0: + version "15.6.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.3.1" + object-assign "^4.1.1" + protractor@^5.1.2: version "5.3.0" resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.3.0.tgz#5df98201cbdaeb50826af6d05630ef1945bf9c32" @@ -5336,6 +5392,24 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-dom@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + +react@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + read-cache@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" @@ -5908,7 +5982,7 @@ set-value@^2.0.0: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -6704,6 +6778,10 @@ typedarray@^0.0.6, typedarray@~0.0.5: version "2.6.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" +ua-parser-js@^0.7.9: + version "0.7.17" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + uglify-es@^3.3.4: version "3.3.9" resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" @@ -7072,6 +7150,10 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" +whatwg-fetch@>=0.10.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" + when@^3.7.7: version "3.7.8" resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82"