Project

General

Profile

1
import { Injectable, Inject } from '@angular/core';
2
import { DOCUMENT } from '@angular/common';
3
import {  Optional, RendererFactory2, ViewEncapsulation } from '@angular/core';
4

    
5
@Injectable()
6
export class SEOService {
7
   constructor( @Inject(DOCUMENT) private doc,
8
   private rendererFactory: RendererFactory2,
9
   @Inject(DOCUMENT) private document) {
10
   }
11

    
12
  createLinkForCanonicalURL(url:string, addParameters:boolean=true) {
13
   this.createLink(url,"relcan", "canonical", addParameters)
14
  }
15
  createLinkForCanonicalSearchURL(url:string, addParameters:boolean=true, ) {
16
    this.createLink(url,"relcan", "canonical", addParameters);
17
    this.createLink(url,"relnext", "next", addParameters)
18
    this.createLink(url,"relprev", "prev", addParameters)
19
  }
20
  createLinkForNextURL(url:string, addParameters:boolean=true) {
21
    this.createLink(url,"relnext", "next", addParameters)
22
  }
23
  createLinkForPrevURL(url:string, addParameters:boolean=true) {
24
    this.createLink(url,"relprev", "prev", addParameters)
25
  }
26

    
27
  createLink(url:string, id:string, relname:string, addParameters:boolean=true) {
28
    if(this.doc && (typeof this.doc.getElementById === "function" || typeof this.doc.createElement === "function") ){
29
      if(!addParameters && url && url.indexOf("?") != -1){
30
        url = url.substring(0,url.indexOf("?"));
31
      }
32
      if (typeof this.doc.getElementById === "function") {
33
        let currentLink: HTMLLinkElement = this.doc.getElementById(id);
34
        if(currentLink ){
35
          currentLink.setAttribute('href', url);
36
          return ;
37
        }
38
      }
39
      if (typeof this.doc.createElement === "function") {
40
        let link: HTMLLinkElement = this.doc.createElement('link');
41
        link.setAttribute('id', id);
42
        link.setAttribute('rel', relname);
43
        this.doc.head.appendChild(link);
44
        link.setAttribute('href', url);
45
      }
46

    
47
    }else{
48
      try {
49
        const renderer = this.rendererFactory.createRenderer(this.document, {
50
          id: '-1',
51
          encapsulation: ViewEncapsulation.None,
52
          styles: [],
53
          data: {}
54
        });
55

    
56
        const link = renderer.createElement('link');
57
        const head = this.document.head;
58

    
59
        if (head === null) {
60
          throw new Error('<head> not found within DOCUMENT.');
61
        }
62
        renderer.setAttribute(link, "rel", relname);
63
        renderer.setAttribute(link, "href", (addParameters)?url:url.split("?")[0]);
64
        renderer.setAttribute(link, "id", id);
65
        // [TODO]: get them to update the existing one (if it exists) ?
66
        renderer.appendChild(head, link);
67
      } catch (e) {
68
        console.error('Error within linkService : ', e);
69
      }
70
    }
71

    
72
  }
73
  removeLinkForNextURL() {
74
    this.removeLink("relnext", "next");
75
  }
76
  removeLinkForPrevURL() {
77
    this.removeLink("relprev", "prev");
78
  }
79
  removeLink(  id:string, relname:string) {
80
    if(this.doc && (typeof this.doc.getElementById === "function" || typeof this.doc.createElement === "function") ){
81
      if (typeof this.doc.getElementById === "function") {
82
        let currentLink: HTMLLinkElement = this.doc.getElementById(id);
83
        if(currentLink ){
84
          currentLink.setAttribute('href', "");
85
          currentLink.setAttribute('rel', "");
86
          return ;
87
        }
88
      }
89

    
90

    
91
    }
92

    
93
  }
94

    
95
}
96

    
97
/*
98
 * -- LinkService --        [Temporary]
99
 * @MarkPieszak
100
 *
101
 * Similar to Meta service but made to handle <link> creation for SEO purposes
102
 * -- NOTE: Soon there will be an overall DocumentService within Angular that handles Meta/Link everything
103
 */
104
//
105
// import { Injectable, Optional, RendererFactory2, ViewEncapsulation, Inject } from '@angular/core';
106
// import { DOCUMENT } from '@angular/platform-browser';
107
//
108
// @Injectable()
109
// export class LinkService {
110
//
111
//     constructor(
112
//         private rendererFactory: RendererFactory2,
113
//         @Inject(DOCUMENT) private document
114
//     ) {
115
//     }
116

    
117
    /**
118
     * Inject the State into the bottom of the <head>
119
     */
120
//     addTag(tag: LinkDefinition, forceCreation?: boolean) {
121
//
122
//         try {
123
//             const renderer = this.rendererFactory.createRenderer(this.document, {
124
//                 id: '-1',
125
//                 encapsulation: ViewEncapsulation.None,
126
//                 styles: [],
127
//                 data: {}
128
//             });
129
//
130
//             const link = renderer.createElement('link');
131
//             const head = this.document.head;
132
//             const selector = this._parseSelector(tag);
133
//
134
//             if (head === null) {
135
//                 throw new Error('<head> not found within DOCUMENT.');
136
//             }
137
//
138
//             Object.keys(tag).forEach((prop: string) => {
139
//                 return renderer.setAttribute(link, prop, tag[prop]);
140
//             });
141
//
142
//             // [TODO]: get them to update the existing one (if it exists) ?
143
//             renderer.appendChild(head, link);
144
//
145
//         } catch (e) {
146
//             console.error('Error within linkService : ', e);
147
//         }
148
//     }
149
//
150
//     private _parseSelector(tag: LinkDefinition): string {
151
//         // Possibly re-work this
152
//         const attr: string = tag.rel ? 'rel' : 'hreflang';
153
//         return `${attr}="${tag[attr]}"`;
154
//     }
155
// }
156

    
157
export declare type LinkDefinition = {
158
    charset?: string;
159
    crossorigin?: string;
160
    href?: string;
161
    hreflang?: string;
162
    media?: string;
163
    rel?: string;
164
    rev?: string;
165
    sizes?: string;
166
    target?: string;
167
    type?: string;
168
} & {
169
        [prop: string]: string;
170
    };
(1-1/2)