├── .classpath ├── .project ├── .settings ├── org.eclipse.jdt.core.prefs └── org.eclipse.m2e.core.prefs ├── README.md ├── angular-seo-filter ├── .classpath ├── .project ├── .settings │ ├── org.eclipse.jdt.core.prefs │ ├── org.eclipse.m2e.core.prefs │ ├── org.eclipse.wst.common.component │ ├── org.eclipse.wst.common.project.facet.core.xml │ └── org.eclipse.wst.validation.prefs ├── pom.xml ├── src │ └── main │ │ └── java │ │ └── net │ │ └── angularseo │ │ ├── AngularSEOConfig.java │ │ ├── SEOFilter.java │ │ ├── crawler │ │ ├── CachePageManager.java │ │ ├── CrawlRequest.java │ │ ├── CrawlTask.java │ │ ├── CrawlTaskManager.java │ │ └── Crawler.java │ │ ├── readme.txt │ │ └── util │ │ ├── URLUtils.java │ │ └── UserAgentUtil.java └── target │ └── classes │ └── net │ └── angularseo │ ├── AngularSEOConfig.class │ ├── SEOFilter.class │ ├── crawler │ ├── CachePageManager.class │ ├── CrawlRequest.class │ ├── CrawlTask.class │ ├── CrawlTaskManager.class │ └── Crawler.class │ ├── readme.txt │ └── util │ ├── URLUtils.class │ └── UserAgentUtil.class ├── angular-seo-web ├── .classpath ├── .project ├── .settings │ ├── .jsdtscope │ ├── org.eclipse.jdt.core.prefs │ ├── org.eclipse.m2e.core.prefs │ ├── org.eclipse.wst.common.component │ ├── org.eclipse.wst.common.project.facet.core.xml │ ├── org.eclipse.wst.jsdt.ui.superType.container │ ├── org.eclipse.wst.jsdt.ui.superType.name │ └── org.eclipse.wst.validation.prefs ├── pom.xml ├── src │ └── main │ │ ├── resources │ │ └── simplelogger.properties │ │ └── webapp │ │ ├── .idea │ │ ├── .name │ │ ├── deployment.xml │ │ ├── encodings.xml │ │ ├── modules.xml │ │ ├── scopes │ │ │ └── scope_settings.xml │ │ ├── vcs.xml │ │ ├── webapp.iml │ │ └── workspace.xml │ │ ├── ReadMe.txt │ │ ├── WEB-INF │ │ └── web.xml │ │ ├── angular │ │ ├── angular-sanitize.min.js │ │ └── angular.min.js │ │ ├── assets │ │ ├── css │ │ │ ├── styles-2.css │ │ │ ├── styles-3.css │ │ │ ├── styles-4.css │ │ │ └── styles.css │ │ ├── images │ │ │ └── profile.png │ │ ├── js │ │ │ ├── main.js │ │ │ └── min │ │ │ │ └── main-min.js │ │ ├── less │ │ │ ├── default │ │ │ │ ├── base.less │ │ │ │ ├── mixins.less │ │ │ │ ├── responsive.less │ │ │ │ ├── styles.less │ │ │ │ └── theme-default.less │ │ │ ├── theme-2 │ │ │ │ ├── base.less │ │ │ │ ├── mixins.less │ │ │ │ ├── responsive.less │ │ │ │ ├── styles.less │ │ │ │ └── theme-default.less │ │ │ ├── theme-3 │ │ │ │ ├── base.less │ │ │ │ ├── mixins.less │ │ │ │ ├── responsive.less │ │ │ │ ├── styles.less │ │ │ │ └── theme-default.less │ │ │ └── theme-4 │ │ │ │ ├── base.less │ │ │ │ ├── mixins.less │ │ │ │ ├── responsive.less │ │ │ │ ├── styles.less │ │ │ │ └── theme-default.less │ │ └── plugins │ │ │ ├── bootstrap │ │ │ ├── css │ │ │ │ ├── bootstrap-theme.css │ │ │ │ ├── bootstrap-theme.css.map │ │ │ │ ├── bootstrap-theme.min.css │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ └── bootstrap.min.css │ │ │ ├── fonts │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ └── glyphicons-halflings-regular.woff │ │ │ └── js │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.min.js │ │ │ │ └── npm.js │ │ │ ├── detectmobilebrowser.js │ │ │ ├── font-awesome │ │ │ ├── css │ │ │ │ ├── font-awesome.css │ │ │ │ └── font-awesome.min.css │ │ │ ├── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ └── fontawesome-webfont.woff │ │ │ ├── less │ │ │ │ ├── bordered-pulled.less │ │ │ │ ├── core.less │ │ │ │ ├── fixed-width.less │ │ │ │ ├── font-awesome.less │ │ │ │ ├── icons.less │ │ │ │ ├── larger.less │ │ │ │ ├── list.less │ │ │ │ ├── mixins.less │ │ │ │ ├── path.less │ │ │ │ ├── rotated-flipped.less │ │ │ │ ├── spinning.less │ │ │ │ ├── stacked.less │ │ │ │ └── variables.less │ │ │ └── scss │ │ │ │ ├── _bordered-pulled.scss │ │ │ │ ├── _core.scss │ │ │ │ ├── _fixed-width.scss │ │ │ │ ├── _icons.scss │ │ │ │ ├── _larger.scss │ │ │ │ ├── _list.scss │ │ │ │ ├── _mixins.scss │ │ │ │ ├── _path.scss │ │ │ │ ├── _rotated-flipped.scss │ │ │ │ ├── _spinning.scss │ │ │ │ ├── _stacked.scss │ │ │ │ ├── _variables.scss │ │ │ │ └── font-awesome.scss │ │ │ ├── jquery-1.11.1.min.js │ │ │ ├── jquery-migrate-1.2.1.min.js │ │ │ ├── jquery-scrollTo │ │ │ ├── .gitignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── bower.json │ │ │ ├── changes.txt │ │ │ ├── composer.json │ │ │ ├── demo │ │ │ │ ├── css │ │ │ │ │ ├── style.css │ │ │ │ │ └── style.old.css │ │ │ │ ├── index.html │ │ │ │ └── index.old.html │ │ │ ├── jquery.scrollTo.js │ │ │ ├── jquery.scrollTo.min.js │ │ │ ├── scrollTo.jquery.json │ │ │ └── tests │ │ │ │ ├── WinMaxY-compat.html │ │ │ │ ├── WinMaxY-quirks.html │ │ │ │ ├── WinMaxY-to-iframe-compat.html │ │ │ │ ├── WinMaxY-to-iframe-quirks.html │ │ │ │ ├── WinMaxY-with-iframe-compat.html │ │ │ │ ├── WinMaxY-with-iframe-quirks.html │ │ │ │ ├── index.html │ │ │ │ └── test.js │ │ │ ├── jquery.easing.1.3.js │ │ │ └── prism │ │ │ ├── min │ │ │ ├── prism-min.js │ │ │ └── prism.css │ │ │ ├── prism.css │ │ │ └── prism.js │ │ ├── favicon.ico │ │ ├── index.html │ │ └── js │ │ └── content.js └── target │ ├── classes │ └── simplelogger.properties │ └── m2e-wtp │ └── web-resources │ └── META-INF │ ├── MANIFEST.MF │ └── maven │ └── net.angularseo │ └── angular-seo-web │ ├── pom.properties │ └── pom.xml └── pom.xml /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | angular-seo 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 3 | org.eclipse.jdt.core.compiler.compliance=1.5 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.source=1.5 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What's AngularSEO 2 | 3 | AngularSEO Filter is a SEO solution for AJAX frond-end sites with a JavaEE backend. The AJAX frond-end can be AngularJS, ReactJS and other AJAX framework. 4 | 5 | # How it works? 6 | 7 | ## Integrate SEO filter on JEE server 8 | Add a filter into web.xml, and set its URL mapping to '/*'. 9 | 10 | ## Prerender static page snapshots 11 | When server started, SEO filter will crawl self site and generate static page snapshot for each one with all the dynamic content fully rendered. It will update the snapshots regularly according your config. 12 | 13 | ## Let crawlers see static content 14 | SEO filter identify the crawl request by checking the User-Agent keyword . If it is Googlebot, bingbot, etc, filter will response with the pre-rendered static page from the snapshot. Other normal reqeusts will be passed to original service. 15 | 16 | ## All hashbang URLs are well transformed 17 | All hashbang URLs will be transformed to normal format which can be crawled more easily. So, you needn't care any speical rule of hashbang URL crawling specification. 18 | 19 | e.g.
20 | http://abc.com/#!/about -> http://abc.com/_23_21/about
21 | http://abc.com/#/about -> http://abc.com/_23/about
22 | 23 | When user click the transformed URLs from search engines, the filter will converte them back to the original format. 24 | 25 | # Original AngularJS page source VS Rendered static page source 26 | 27 | Original AngularJS page source code: 28 | ``` 29 |
30 | ``` 31 | -> 32 | Rendered static page source code: 33 | ``` 34 |
the true message after binding
35 | ``` 36 | # Features 37 | 38 | * Easy setup: configure a filter only 39 | * Zero code change: needn't change any front-end and backend codes 40 | * Fast page loads: snapshot is prerendered & stored on the same server 41 | * Fully automated: it keeps working in the background after setup 42 | * It is FREE! 43 | * It is open source! 44 | 45 | # Requirements 46 | 47 | The static site is generated by [PhantomJS](http://phantomjs.org/), so it need be installed on the server. 48 | 49 | # Guide 50 | 51 | [Click here](https://github.com/johnhuang-cn/AngularSEO/wiki) for more details. 52 | 53 | # Contact 54 | 55 | John Huang: john.h.cn@gmail.com 56 | -------------------------------------------------------------------------------- /angular-seo-filter/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /angular-seo-filter/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | angular-seo-filter 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.common.project.facet.core.builder 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.validation.validationbuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.jem.workbench.JavaEMFNature 31 | org.eclipse.wst.common.modulecore.ModuleCoreNature 32 | org.eclipse.jdt.core.javanature 33 | org.eclipse.m2e.core.maven2Nature 34 | org.eclipse.wst.common.project.facet.core.nature 35 | 36 | 37 | -------------------------------------------------------------------------------- /angular-seo-filter/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 4 | org.eclipse.jdt.core.compiler.compliance=1.5 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.5 9 | -------------------------------------------------------------------------------- /angular-seo-filter/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /angular-seo-filter/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /angular-seo-filter/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /angular-seo-filter/.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /angular-seo-filter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | net.angularseo 5 | angular-seo 6 | 0.0.1-SNAPSHOT 7 | 8 | angular-seo-filter 9 | angular-seo-filter 10 | AngularJS SEO Filter 11 | 12 | 13 | javax.servlet 14 | javax.servlet-api 15 | 3.1.0 16 | 17 | 18 | org.seleniumhq.selenium 19 | selenium-java 20 | 2.46.0 21 | 22 | 23 | com.github.detro.ghostdriver 24 | phantomjsdriver 25 | 1.0.1 26 | 27 | 28 | org.slf4j 29 | slf4j-api 30 | 1.7.12 31 | 32 | 33 | commons-io 34 | commons-io 35 | 2.4 36 | 37 | 38 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/AngularSEOConfig.java: -------------------------------------------------------------------------------- 1 | package net.angularseo; 2 | 3 | public class AngularSEOConfig { 4 | private final static AngularSEOConfig config = new AngularSEOConfig(); 5 | 6 | // The time to wait js dynamic page finish loading 7 | public int waitForPageLoad = 5; 8 | 9 | // The interval the crawler re-crawl the site to generate the static page 10 | // the unit is hour 11 | public int cacheTimeout = 24; 12 | 13 | // The folder to save the static html 14 | public String cachePath; 15 | 16 | // Page encoding, default is "UTF-8" 17 | public String encoding = "UTF-8"; 18 | 19 | // Crawl depth, default is 2, index page and its sub link pages 20 | public int crawlDepth = 2; 21 | 22 | // Root url of this site, http://domain.name 23 | private String rootURL; 24 | 25 | public int maxCrawlThread = 5; 26 | 27 | private AngularSEOConfig() { 28 | } 29 | 30 | public static AngularSEOConfig getConfig() { 31 | return config; 32 | } 33 | 34 | public synchronized void setRootURL(String rootURL) { 35 | this.rootURL = rootURL; 36 | } 37 | 38 | public synchronized String getRootURL() { 39 | return rootURL; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/SEOFilter.java: -------------------------------------------------------------------------------- 1 | package net.angularseo; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import javax.servlet.Filter; 7 | import javax.servlet.FilterChain; 8 | import javax.servlet.FilterConfig; 9 | import javax.servlet.ServletException; 10 | import javax.servlet.ServletRequest; 11 | import javax.servlet.ServletResponse; 12 | import javax.servlet.UnavailableException; 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | 16 | import net.angularseo.crawler.CachePageManager; 17 | import net.angularseo.crawler.CrawlRequest; 18 | import net.angularseo.crawler.CrawlTaskManager; 19 | import net.angularseo.util.URLUtils; 20 | import net.angularseo.util.UserAgentUtil; 21 | 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * Servlet Filter implementation class RobotFilter 27 | */ 28 | public class SEOFilter implements Filter { 29 | 30 | // The time to wait js dynamic page finish loading 31 | private static int Default_WAIT_FOR_PAGE_LOAD = 5; 32 | // The interval the crawler re-crawl the site to generate the static page 33 | // the unit is hour 34 | private static int DEFAULT_CACHE_TIMEOUT = 24; 35 | 36 | private Logger logger = LoggerFactory.getLogger(SEOFilter.class); 37 | 38 | private boolean isFirst = true; 39 | 40 | /** 41 | * Default constructor. 42 | */ 43 | public SEOFilter() { 44 | } 45 | 46 | /** 47 | * @see Filter#init(FilterConfig) 48 | */ 49 | public void init(FilterConfig fConfig) throws ServletException { 50 | // Set the execute path of phantomjs 51 | String phanatomPath = fConfig.getInitParameter("phantomjs.binary.path"); 52 | if (phanatomPath == null) { 53 | throw new UnavailableException("Please set the phantomjs.binary.path param for RobotFilter in web.xml"); 54 | } 55 | File f = new File(phanatomPath); 56 | if (!f.exists()) { 57 | throw new UnavailableException("Cannot find phantomjs binary in given RobotFilter phantomjs.binary.path " + phanatomPath); 58 | } 59 | System.setProperty("phantomjs.binary.path", phanatomPath); 60 | 61 | // Set the time to wait the page finish loading 62 | String waitForPageLoadStr = fConfig.getInitParameter("waitForPageLoad"); 63 | int waitForPageLoad = Default_WAIT_FOR_PAGE_LOAD; 64 | if (waitForPageLoadStr != null) { 65 | try { 66 | waitForPageLoad = Integer.parseInt(waitForPageLoadStr); 67 | } catch (NumberFormatException e) { 68 | } 69 | } 70 | 71 | // Set customize robot user agent 72 | String robotUserAgent = fConfig.getInitParameter("robotUserAgents"); 73 | UserAgentUtil.initCustomizeAgents(robotUserAgent); 74 | 75 | // Get cache timeout, crawler will re-crawl when cache timeout 76 | String cacheTimeoutStr = fConfig.getInitParameter("cacheTimeout"); 77 | int cacheTimeout = DEFAULT_CACHE_TIMEOUT; 78 | if (cacheTimeoutStr != null) { 79 | try { 80 | cacheTimeout = Integer.parseInt(cacheTimeoutStr); 81 | } catch (NumberFormatException e) { 82 | } 83 | } 84 | 85 | // Get cache path 86 | String cachePath = fConfig.getInitParameter("cachePath"); 87 | if (cachePath == null) { 88 | throw new UnavailableException("Please set the cachePath param for RobotFilter in web.xml"); 89 | } 90 | 91 | // Get the default encoding of site 92 | String encoding = fConfig.getInitParameter("encoding"); 93 | if (encoding == null) { 94 | encoding = "UTF-8"; 95 | } 96 | 97 | // Get crawl depth 98 | String crawlDepthStr = fConfig.getInitParameter("crawlDepth"); 99 | int crawlDepth = 2; 100 | if (crawlDepthStr != null) { 101 | try { 102 | crawlDepth = Integer.parseInt(crawlDepthStr); 103 | } catch (NumberFormatException e) { 104 | } 105 | } 106 | 107 | logger.info("RobotFilter started with {}, {}, {}, {}, {}", phanatomPath, waitForPageLoad, robotUserAgent, cacheTimeout, cachePath); 108 | 109 | AngularSEOConfig config = AngularSEOConfig.getConfig(); 110 | config.cachePath = cachePath; 111 | config.cacheTimeout = cacheTimeout; 112 | config.waitForPageLoad = waitForPageLoad; 113 | config.encoding = encoding; 114 | config.crawlDepth = crawlDepth; 115 | 116 | CrawlTaskManager.getInstance().schedule(); 117 | } 118 | 119 | /** 120 | * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) 121 | */ 122 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 123 | HttpServletRequest req = (HttpServletRequest) request; 124 | if (isFirst) { 125 | String rootUrl = req.getRequestURL().toString(); 126 | // get http://host/ 127 | rootUrl = rootUrl.replaceFirst("(http://[^/]*).*", "$1"); 128 | AngularSEOConfig.getConfig().setRootURL(rootUrl); 129 | isFirst = false; 130 | } 131 | 132 | String userAgent = req.getHeader("User-Agent"); 133 | logger.debug(userAgent); 134 | if (UserAgentUtil.isRobot(req) && isTextRequest(req)) { 135 | logger.info("Search engine robot request: {}", userAgent); 136 | logger.info("Load static html for robot: " + (req.getRequestURL().toString() + "?" + req.getQueryString())); 137 | String url = req.getRequestURL().toString(); 138 | if (req.getQueryString() != null) { 139 | url += "?" + req.getQueryString(); 140 | } 141 | String html = CachePageManager.get(url); 142 | if (html == null) { 143 | // Crawl it then it can be crawled next time 144 | CrawlTaskManager.getInstance().addCrawlRequest(new CrawlRequest(url, 0)); 145 | chain.doFilter(request, response); 146 | } 147 | else { 148 | response.setCharacterEncoding(AngularSEOConfig.getConfig().encoding); 149 | response.getWriter().write(html); 150 | } 151 | } 152 | else { 153 | String url = req.getRequestURL().toString(); 154 | // _23 _21 _23_21 155 | if (URLUtils.isFromSearchEngine(url)) { 156 | String redirectUrl = URLUtils.toHashBang(url); 157 | redirectUrl +="?" + req.getQueryString(); 158 | ((HttpServletResponse) response).sendRedirect(redirectUrl); 159 | } 160 | else { 161 | chain.doFilter(request, response); 162 | } 163 | } 164 | } 165 | 166 | /** 167 | * Check if the request is for html page as far as possible 168 | */ 169 | private boolean isTextRequest(HttpServletRequest request) { 170 | String uri = request.getRequestURI(); 171 | int p = uri.lastIndexOf("/"); 172 | // requst for site default page 173 | if (p < 0) { 174 | return true; 175 | } 176 | 177 | String file = uri.substring(p + 1); 178 | p = file.indexOf("."); 179 | // without extention, usually is a html request 180 | if (p < 0) { 181 | return true; 182 | } 183 | 184 | String ext = file.substring(p + 1); 185 | if ("html".equals(ext) || "htm".equals(ext) || "jsp".equals(ext)) { 186 | return true; 187 | } 188 | 189 | return false; 190 | } 191 | 192 | /** 193 | * @see Filter#destroy() 194 | */ 195 | public void destroy() { 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/crawler/CachePageManager.java: -------------------------------------------------------------------------------- 1 | package net.angularseo.crawler; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import net.angularseo.AngularSEOConfig; 9 | import net.angularseo.SEOFilter; 10 | import net.angularseo.util.URLUtils; 11 | 12 | import org.apache.commons.io.FileUtils; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | public class CachePageManager { 17 | private static Logger logger = LoggerFactory.getLogger(SEOFilter.class); 18 | 19 | public static CachePageManager instance; 20 | private File cacheFolder; 21 | 22 | private CachePageManager(File cacheFolder) { 23 | this.cacheFolder = cacheFolder; 24 | } 25 | 26 | public synchronized static void init(File cacheFolder) { 27 | if (instance != null) { 28 | return; 29 | } 30 | 31 | instance = new CachePageManager(cacheFolder); 32 | } 33 | 34 | public static void save(String url, String pageSource, String encoding) { 35 | if (instance == null) { 36 | return; 37 | } 38 | 39 | url = URLUtils.escapeHashBang(url); 40 | String name = u2f(url); 41 | File f = new java.io.File(instance.cacheFolder, name); 42 | try { 43 | FileUtils.write(f, pageSource, encoding); 44 | } catch (IOException e) { 45 | logger.error("Save static page {} failed: {}", name, e.getMessage()); 46 | } 47 | } 48 | 49 | public static String get(String url) { 50 | String pageSource = ""; 51 | if (instance == null) { 52 | return pageSource; 53 | } 54 | 55 | String name = u2f(url); 56 | File f = new java.io.File(instance.cacheFolder, name); 57 | try { 58 | pageSource = FileUtils.readFileToString(f, AngularSEOConfig.getConfig().encoding); 59 | } catch (IOException e) { 60 | logger.error("Load static page {} failed: {}", name, e.getMessage()); 61 | } 62 | 63 | return pageSource; 64 | } 65 | 66 | /** 67 | * Url name to file name 68 | */ 69 | public static String u2f(String url) { 70 | url = url.replaceFirst("http://[^/]*/?", "/"); 71 | String name = url.replaceAll("[\\\\/:\\*\\?<>|\"]", "_"); 72 | name += ".html"; 73 | return name; 74 | } 75 | 76 | public static void main(String[] args) { 77 | String str = "\\/:*?<>|\""; 78 | str = str.replaceAll("[\\\\/:\\*\\?<>|\"]", "_"); 79 | System.out.println(str); 80 | 81 | String url = "http://www.abc.com/abc"; 82 | url = url.replaceFirst("http://[^/]*/?", "/"); 83 | System.out.println(url); 84 | 85 | url = "http://www.abc.com/abc?http://www.abc.com/"; 86 | url = url.replaceFirst("(http://[^/]*).*", "$1"); 87 | System.out.println(url); 88 | 89 | url = "http://www.abc.com/_23_21/a.html"; 90 | String reg = "[\\_23|\\_21]+"; 91 | System.out.println(url.matches(reg)); 92 | 93 | url = "http://www.abc.com/_23/a.html"; 94 | reg = "_23|_21"; 95 | System.out.println(url.matches(reg)); 96 | 97 | url = "http://www.abc.com/_21/a.html"; 98 | reg = "_23|_21"; 99 | System.out.println(url.matches(reg)); 100 | 101 | url = "http://www.abc.com/#/a.html"; 102 | reg = "_23|_21"; 103 | System.out.println(url.matches(reg)); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/crawler/CrawlRequest.java: -------------------------------------------------------------------------------- 1 | package net.angularseo.crawler; 2 | 3 | public class CrawlRequest { 4 | public String url; 5 | public int depth; 6 | 7 | public CrawlRequest(String url, int depth) { 8 | this.url = url; 9 | this.depth = depth; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/crawler/CrawlTask.java: -------------------------------------------------------------------------------- 1 | package net.angularseo.crawler; 2 | 3 | import java.util.Date; 4 | import java.util.Timer; 5 | import java.util.TimerTask; 6 | 7 | import net.angularseo.AngularSEOConfig; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | public class CrawlTask extends TimerTask { 13 | private Logger logger = LoggerFactory.getLogger(CrawlTask.class); 14 | 15 | /** 16 | * The task to crawl static pages 17 | * @param p cache properties 18 | * @param interval unit is hour 19 | */ 20 | public CrawlTask() { 21 | } 22 | 23 | @Override 24 | public void run() { 25 | logger.info("AngularSEO crawl task starting..."); 26 | 27 | // Crawl whole site 28 | CrawlTaskManager manager = CrawlTaskManager.getInstance(); 29 | 30 | // clear cralwed urls 31 | manager.clearUrls(); 32 | 33 | AngularSEOConfig config = AngularSEOConfig.getConfig(); 34 | while (config.getRootURL() == null) { 35 | try { 36 | Thread.sleep(5000); 37 | } catch (Exception e) { 38 | } 39 | } 40 | 41 | manager.addCrawlRequest(new CrawlRequest(config.getRootURL(), config.crawlDepth - 1)); 42 | 43 | // Check if all tasks finished 44 | while (!manager.isFinished()) { 45 | try { 46 | Thread.sleep(5000); 47 | } catch (Exception e) { 48 | } 49 | } 50 | 51 | // Update the time of this cache 52 | manager.updateCachedTime(); 53 | 54 | // Schedule next crawl 55 | Timer timer = new Timer(); 56 | long nextTime = AngularSEOConfig.getConfig().cacheTimeout * 3600 * 1000L; 57 | timer.schedule(new CrawlTask(), nextTime); 58 | logger.info("AngularSEO crawl task end, and next schedule time is " + new Date(System.currentTimeMillis() + nextTime).toString()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/crawler/CrawlTaskManager.java: -------------------------------------------------------------------------------- 1 | package net.angularseo.crawler; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.Date; 9 | import java.util.Properties; 10 | import java.util.Timer; 11 | import java.util.concurrent.Executors; 12 | import java.util.concurrent.ThreadPoolExecutor; 13 | 14 | import javax.servlet.UnavailableException; 15 | 16 | import net.angularseo.AngularSEOConfig; 17 | 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | public class CrawlTaskManager { 22 | public final static String PROP_LAST_CACHED_TIME = "last_cached_time"; 23 | private static CrawlTaskManager instance = new CrawlTaskManager(); 24 | 25 | private Logger logger = LoggerFactory.getLogger(CrawlTaskManager.class); 26 | 27 | private Properties cacheProperties; 28 | private String cacheFilePath; 29 | private ThreadPoolExecutor executor; 30 | ArrayList crawlUrls = new ArrayList(); 31 | 32 | private CrawlTaskManager() { 33 | executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(AngularSEOConfig.getConfig().maxCrawlThread); 34 | } 35 | 36 | public static CrawlTaskManager getInstance() { 37 | return instance; 38 | } 39 | 40 | /** 41 | * Schedule the crawl task to crawl the site periodically and generate the static page in the cache path 42 | * 43 | * @param interval the unit is hour 44 | * @param cachePath 45 | * @throws UnavailableException 46 | */ 47 | public void schedule() throws UnavailableException { 48 | AngularSEOConfig config = AngularSEOConfig.getConfig(); 49 | 50 | // Get cache path 51 | File cacheFolder = new File(config.cachePath); 52 | if (!cacheFolder.exists()) { 53 | boolean success = cacheFolder.mkdirs(); 54 | if (!success) { 55 | throw new UnavailableException("Cannot schedule crawl task, cachePath not exists and failed to create it: " + config.cachePath); 56 | } 57 | } 58 | 59 | // Init cache manager 60 | CachePageManager.init(cacheFolder); 61 | 62 | loadCacheProperties(cacheFolder); 63 | 64 | // Check the last cache time 65 | long nextTime = getNextTime(cacheFolder, config.cacheTimeout); 66 | Timer timer = new Timer(); 67 | logger.info("AngularSEO crawl task is scheduled on " + new Date(System.currentTimeMillis() + nextTime).toString()); 68 | timer.schedule(new CrawlTask(), nextTime); 69 | } 70 | 71 | private long getNextTime(File cacheFolder, int interval) throws UnavailableException { 72 | String lastCacheTimeStr = cacheProperties.getProperty("last_cached_time", "0"); 73 | long lastCacheTime = Long.parseLong(lastCacheTimeStr); 74 | 75 | long diff = System.currentTimeMillis() - lastCacheTime; 76 | if (diff >= interval * 3600L * 1000L) { 77 | return 0; 78 | } 79 | else { 80 | return interval * 3600L * 1000L - diff; 81 | } 82 | } 83 | 84 | private void loadCacheProperties(File cacheFolder) throws UnavailableException { 85 | if (cacheProperties != null) { 86 | return; 87 | } 88 | 89 | File f = new File(cacheFolder.getPath() + "/cache.properties"); 90 | if (!f.exists()) { 91 | try { 92 | f.createNewFile(); 93 | } catch (IOException e) { 94 | throw new UnavailableException("Cannot create file in cache path: " + f); 95 | } 96 | } 97 | 98 | FileInputStream in = null; 99 | try { 100 | in = new FileInputStream(f); 101 | Properties p = new Properties(); 102 | p.load(in); 103 | cacheProperties = p; 104 | cacheFilePath = f.getAbsolutePath(); 105 | } catch (Exception e) { 106 | throw new UnavailableException("Cannot load cache.properties in cache path: " + e.getMessage()); 107 | } 108 | finally { 109 | if (in != null) { 110 | try { 111 | in.close(); 112 | } catch (IOException e) { 113 | } 114 | } 115 | } 116 | } 117 | 118 | public void updateCachedTime() { 119 | cacheProperties.setProperty(CrawlTaskManager.PROP_LAST_CACHED_TIME, Long.toString(System.currentTimeMillis())); 120 | try { 121 | FileOutputStream out = new FileOutputStream(cacheFilePath); 122 | cacheProperties.store(out, "AngularSEO Cralwer"); 123 | } catch (Exception e) { 124 | logger.warn("Update cache.properties failed: " + e.getMessage()); 125 | } 126 | } 127 | 128 | public void addCrawlRequest(CrawlRequest req) { 129 | String rootUrl = AngularSEOConfig.getConfig().getRootURL(); 130 | synchronized (crawlUrls) { 131 | if (crawlUrls.indexOf(req.url) < 0 && req.url.indexOf(rootUrl) == 0) { // avoid crawling out of site 132 | crawlUrls.add(req.url); 133 | executor.execute(new Crawler(req)); 134 | } 135 | } 136 | } 137 | 138 | public void clearUrls() { 139 | synchronized (crawlUrls) { 140 | crawlUrls.clear(); 141 | } 142 | } 143 | 144 | public boolean isFinished() { 145 | while (executor.getTaskCount() != executor.getCompletedTaskCount()) { 146 | return false; 147 | } 148 | 149 | return true; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/crawler/Crawler.java: -------------------------------------------------------------------------------- 1 | package net.angularseo.crawler; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import net.angularseo.AngularSEOConfig; 8 | import net.angularseo.util.URLUtils; 9 | 10 | import org.openqa.selenium.By; 11 | import org.openqa.selenium.Dimension; 12 | import org.openqa.selenium.JavascriptExecutor; 13 | import org.openqa.selenium.WebDriver; 14 | import org.openqa.selenium.WebElement; 15 | import org.openqa.selenium.phantomjs.PhantomJSDriver; 16 | import org.openqa.selenium.remote.DesiredCapabilities; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | /** 21 | * Generate the static page of the given url 22 | * 23 | * @author john.huang 24 | * 25 | */ 26 | public class Crawler implements Runnable { 27 | private Logger logger = LoggerFactory.getLogger(Crawler.class); 28 | 29 | private CrawlRequest request; 30 | 31 | public Crawler(CrawlRequest request) { 32 | this.request = request; 33 | } 34 | 35 | public void run() { 36 | logger.info("# Start crawl page {}", request.url); 37 | AngularSEOConfig config = AngularSEOConfig.getConfig(); 38 | 39 | WebDriver driver = new PhantomJSDriver(DesiredCapabilities.phantomjs()); 40 | driver.manage().window().setSize(new Dimension(1280, 2024)); 41 | driver.manage().timeouts().implicitlyWait(config.waitForPageLoad, TimeUnit.SECONDS); 42 | 43 | driver.get(request.url); 44 | waitForLoad(); 45 | 46 | if (request.depth > 0) { 47 | driver = calculateSubLinks(driver); 48 | } 49 | 50 | String pageSource = driver.getPageSource(); 51 | String currentUrl = driver.getCurrentUrl(); 52 | 53 | // put page to cache folder 54 | String escapeUrl = URLUtils.escapeHashBang(currentUrl); 55 | CachePageManager.save(escapeUrl, pageSource, config.encoding); 56 | 57 | // The current url is matched with request url, the location may be changed by AngularJS script 58 | // need save both two 59 | if (!request.url.equals(currentUrl)) { 60 | CachePageManager.save(request.url, pageSource, config.encoding); 61 | } 62 | 63 | driver.quit(); 64 | logger.info("# Finished page {}", request.url); 65 | } 66 | 67 | private WebDriver calculateSubLinks(WebDriver driver) { 68 | // Get all links 69 | List eles = driver.findElements(By.tagName("a")); 70 | 71 | // Get all xpath of links 72 | String[] xpath = new String[eles.size()]; 73 | for (int i = 0; i < eles.size(); i++) { 74 | xpath[i] = getAbsoluteXPath((JavascriptExecutor)driver, eles.get(i)); 75 | } 76 | 77 | logger.info("Got all {} link elements of {}", eles.size(), request.url); 78 | 79 | // Get true url of the url by clicking it 80 | HashMap links = new HashMap(); 81 | for (int i = 0; i < xpath.length; i++) { 82 | try { 83 | WebElement ele = driver.findElement(By.xpath(xpath[i])); 84 | String link = getTrueLink(driver, ele); 85 | logger.info("Got target url {} of link {}", link, i); 86 | links.put(xpath[i], link); 87 | } catch (Exception e) { 88 | // It may because of PhantomJS driver crash, so reload it and try again 89 | // PhantomJS driver usually crashed after about 20 cycles 90 | logger.info("PhantomJS driver crashed, restarting now, the following PhantomJS error log can be ingored"); 91 | driver = restoreDriver(driver); 92 | 93 | try { 94 | WebElement ele = driver.findElement(By.xpath(xpath[i])); 95 | String link = getTrueLink(driver, ele); 96 | logger.info("Get target url {} of link {}", link, i); 97 | links.put(xpath[i], link); 98 | } catch (Exception e1) { 99 | logger.error("Link " + i + " cannot be found after back and reload, the link will be ignored: " + xpath[i]); 100 | continue; 101 | } 102 | } 103 | } 104 | 105 | // Set link with true url 106 | for (int i = 0; i < xpath.length; i++) { 107 | try { 108 | // It may because of PhantomJS driver crash, so reload it and try again 109 | // PhantomJS driver usually crashed after about 20 cycles 110 | WebElement ele = driver.findElement(By.xpath(xpath[i])); 111 | String url = links.get(xpath[i]); 112 | setAttribute((JavascriptExecutor)driver, ele, "href", URLUtils.escapeHashBang(url)); 113 | 114 | // Crawl sub link pages 115 | CrawlTaskManager.getInstance().addCrawlRequest(new CrawlRequest(url, request.depth - 1)); 116 | } catch (Exception e) { 117 | try { 118 | driver = restoreDriver(driver); 119 | WebElement ele = driver.findElement(By.xpath(xpath[i])); 120 | setAttribute((JavascriptExecutor)driver, ele, "href", URLUtils.escapeHashBang(links.get(xpath[i]))); 121 | } catch (Exception e1) { 122 | continue; 123 | } 124 | } 125 | } 126 | 127 | return driver; 128 | } 129 | 130 | public String getTrueLink(WebDriver driver, WebElement ele) { 131 | ((JavascriptExecutor) driver).executeScript("arguments[0].click();", ele); 132 | String link = driver.getCurrentUrl(); 133 | 134 | // back to original url 135 | driver.navigate().back(); 136 | return link; 137 | } 138 | 139 | public void waitForLoad() { 140 | try { 141 | Thread.sleep(AngularSEOConfig.getConfig().waitForPageLoad * 1000L); 142 | } catch (InterruptedException e) { 143 | } 144 | } 145 | 146 | public WebDriver restoreDriver(WebDriver driver) { 147 | driver.quit(); 148 | driver = new PhantomJSDriver(DesiredCapabilities.phantomjs()); 149 | driver.get(request.url); 150 | waitForLoad(); 151 | return driver; 152 | } 153 | 154 | public static void setAttribute(JavascriptExecutor driver, WebElement element, String attName, String attValue) { 155 | driver.executeScript("arguments[0].setAttribute(arguments[1], arguments[2]);", 156 | element, attName, attValue); 157 | } 158 | 159 | /** 160 | * From http://stackoverflow.com/questions/11986349/webdriver-selenium-api-identifying-a-webelement-in-xpath 161 | * 162 | * @param driver 163 | * @param element 164 | * @return 165 | */ 166 | // private static String getElementXPath(JavascriptExecutor driver, WebElement element) { 167 | // return (String) driver.executeScript("gPt=function(c){if(c.id!==''){return'id(\"'+c.id+'\")'}if(c===document.body){return c.tagName}var a=0;var e=c.parentNode.childNodes;for(var b=0;b= 0; i--) {"+ 223 | "comp = comps[i];"+ 224 | "xpath += '/' + comp.name.toLowerCase();"+ 225 | "if (comp.position !== null) {"+ 226 | "xpath += '[' + comp.position + ']';"+ 227 | "}"+ 228 | "}"+ 229 | 230 | "return xpath;"+ 231 | 232 | "} return absoluteXPath(arguments[0]);", 233 | element); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/readme.txt: -------------------------------------------------------------------------------- 1 | sample xml in web.xml 2 | 3 | 6 | 7 | 8 | AngularSEO Sample Web Application 9 | 10 | SEOFilter 11 | SEOFilter 12 | AngularSEO Filter 13 | net.angularseo.SEOFilter 14 | 15 | 16 | phantomjs.binary.path 17 | C:\\Users\\john.huang\\Desktop\\AngularJS SEO\\phw\\bin\\phantomjs.exe 18 | 19 | 22 | 23 | waitForPageLoad 24 | 3 25 | 26 | 29 | 30 | robotUserAgents 31 | YodaoBot|Zealbot 32 | 33 | 34 | 35 | cacheTimeout 36 | 24 37 | 38 | 39 | 40 | cachePath 41 | c:\\cache 42 | 43 | 44 | 45 | crawlDepth 46 | 2 47 | 48 | 49 | 50 | encoding 51 | UTF-8 52 | 53 | 54 | 55 | SEOFilter 56 | /* 57 | 58 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/util/URLUtils.java: -------------------------------------------------------------------------------- 1 | package net.angularseo.util; 2 | 3 | public class URLUtils { 4 | /** 5 | * Restore the escaped url to Hashbang url 6 | * Example: 7 | * http://example.com/_23_21/a/b -> http://example.com/#!/a/b 8 | * http://example.com/_23/a/b -> http://example.com/#/a/b 9 | * 10 | * @param url 11 | * @return 12 | */ 13 | public static String toHashBang(String url) { 14 | String hashBangUrl = url.replaceFirst("_23", "#"); 15 | hashBangUrl = hashBangUrl.replaceFirst("_21", "!"); 16 | return hashBangUrl; 17 | } 18 | 19 | /** 20 | * Escape the Hashbang url 21 | * example: 22 | * http://example.com/#!/a/b -> http://example.com/_23_21/a/b 23 | * http://example.com/#/a/b -> http://example.com/_23/a/b 24 | * 25 | * @param url 26 | * @return 27 | */ 28 | public static String escapeHashBang(String url) { 29 | String escapeUrl = url.replaceFirst("#", "_23"); 30 | escapeUrl = escapeUrl.replaceFirst("!", "_21"); 31 | return escapeUrl; 32 | } 33 | 34 | public static boolean isFromSearchEngine(String url) { 35 | return url.indexOf("_23") > 0 || url.indexOf("_21") > 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /angular-seo-filter/src/main/java/net/angularseo/util/UserAgentUtil.java: -------------------------------------------------------------------------------- 1 | package net.angularseo.util; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | public class UserAgentUtil { 6 | static String DEFAULT_ROBOT_USER_AGENTS = "Googlebot|Mediapartners-Google|AdsBot-Google|bingbot|Baiduspider|yahooseeker"; 7 | private static String[] ROBOT_USER_AGENTS = new String[]{}; 8 | 9 | public static void initCustomizeAgents(String robotUserAgent) { 10 | String allAgents = DEFAULT_ROBOT_USER_AGENTS; 11 | if (robotUserAgent != null) { 12 | allAgents += robotUserAgent; 13 | DEFAULT_ROBOT_USER_AGENTS = allAgents; 14 | } 15 | ROBOT_USER_AGENTS = allAgents.split("\\|"); 16 | } 17 | 18 | public static boolean isRobot(HttpServletRequest request) { 19 | String userAgent = request.getHeader("User-Agent"); 20 | if (userAgent == null) { 21 | return false; 22 | } 23 | 24 | for (String key : ROBOT_USER_AGENTS) { 25 | if (userAgent.indexOf(key) >= 0) { 26 | return true; 27 | } 28 | } 29 | 30 | return false; 31 | } 32 | 33 | // /** 34 | // * Refer to https://support.google.com/webmasters/answer/1061943?hl=en 35 | // * 36 | // * @param userAgent 37 | // * @return 38 | // */ 39 | // private static boolean isGoogleRobot(String userAgent) { 40 | // if (userAgent.indexOf("Googlebot") >= 0 || userAgent.indexOf("Googlebot") >= 0 || userAgent.indexOf("AdsBot-Google") >= 0) { 41 | // return true; 42 | // } 43 | // return false; 44 | // } 45 | // 46 | // /** 47 | // * Refer to http://useragentstring.com/pages/Bingbot/ 48 | // * 49 | // * @param userAgent 50 | // * @return 51 | // */ 52 | // private static boolean isBingRobot(String userAgent) { 53 | // if (userAgent.indexOf("bingbot") >= 0) { 54 | // return true; 55 | // } 56 | // return false; 57 | // } 58 | // 59 | // /** 60 | // * Refer to http://useragentstring.com/pages/Baiduspider/ 61 | // * 62 | // * @param userAgent 63 | // * @return 64 | // */ 65 | // private static boolean isBaiduRobot(String userAgent) { 66 | // if (userAgent.indexOf("Baiduspider") >= 0) { 67 | // return true; 68 | // } 69 | // return false; 70 | // } 71 | // 72 | // /** 73 | // * Refer to http://useragentstring.com/pages/YahooSeeker/ 74 | // * 75 | // * @param userAgent 76 | // * @return 77 | // */ 78 | // private static boolean isYahooRobot(String userAgent) { 79 | // if (userAgent.indexOf("yahooseeker") >= 0) { 80 | // return true; 81 | // } 82 | // return false; 83 | // } 84 | } 85 | -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/AngularSEOConfig.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-filter/target/classes/net/angularseo/AngularSEOConfig.class -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/SEOFilter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-filter/target/classes/net/angularseo/SEOFilter.class -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/crawler/CachePageManager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-filter/target/classes/net/angularseo/crawler/CachePageManager.class -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/crawler/CrawlRequest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-filter/target/classes/net/angularseo/crawler/CrawlRequest.class -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/crawler/CrawlTask.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-filter/target/classes/net/angularseo/crawler/CrawlTask.class -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/crawler/CrawlTaskManager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-filter/target/classes/net/angularseo/crawler/CrawlTaskManager.class -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/crawler/Crawler.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-filter/target/classes/net/angularseo/crawler/Crawler.class -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/readme.txt: -------------------------------------------------------------------------------- 1 | sample xml in web.xml 2 | 3 | 6 | 7 | 8 | AngularSEO Sample Web Application 9 | 10 | SEOFilter 11 | SEOFilter 12 | AngularSEO Filter 13 | net.angularseo.SEOFilter 14 | 15 | 16 | phantomjs.binary.path 17 | C:\\Users\\john.huang\\Desktop\\AngularJS SEO\\phw\\bin\\phantomjs.exe 18 | 19 | 22 | 23 | waitForPageLoad 24 | 3 25 | 26 | 29 | 30 | robotUserAgents 31 | YodaoBot|Zealbot 32 | 33 | 34 | 35 | cacheTimeout 36 | 24 37 | 38 | 39 | 40 | cachePath 41 | c:\\cache 42 | 43 | 44 | 45 | crawlDepth 46 | 2 47 | 48 | 49 | 50 | encoding 51 | UTF-8 52 | 53 | 54 | 55 | SEOFilter 56 | /* 57 | 58 | -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/util/URLUtils.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-filter/target/classes/net/angularseo/util/URLUtils.class -------------------------------------------------------------------------------- /angular-seo-filter/target/classes/net/angularseo/util/UserAgentUtil.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-filter/target/classes/net/angularseo/util/UserAgentUtil.class -------------------------------------------------------------------------------- /angular-seo-web/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /angular-seo-web/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | angular-seo-web 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.jem.workbench.JavaEMFNature 36 | org.eclipse.wst.common.modulecore.ModuleCoreNature 37 | org.eclipse.jdt.core.javanature 38 | org.eclipse.m2e.core.maven2Nature 39 | org.eclipse.wst.common.project.facet.core.nature 40 | org.eclipse.wst.jsdt.core.jsNature 41 | 42 | 43 | -------------------------------------------------------------------------------- /angular-seo-web/.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /angular-seo-web/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 4 | org.eclipse.jdt.core.compiler.compliance=1.5 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.5 9 | -------------------------------------------------------------------------------- /angular-seo-web/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /angular-seo-web/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | uses 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /angular-seo-web/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /angular-seo-web/.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /angular-seo-web/.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /angular-seo-web/.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /angular-seo-web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | net.angularseo 7 | angular-seo 8 | 0.0.1-SNAPSHOT 9 | 10 | angular-seo-web 11 | war 12 | angular-seo-web Maven Webapp 13 | http://maven.apache.org 14 | 15 | angular-seo-web 16 | 17 | 18 | 19 | javax.servlet 20 | javax.servlet-api 21 | 3.1.0 22 | 23 | 24 | javax.servlet.jsp 25 | jsp-api 26 | 2.2.1-b03 27 | 28 | 29 | net.angularseo 30 | angular-seo-filter 31 | 0.0.1-SNAPSHOT 32 | 33 | 34 | org.slf4j 35 | slf4j-jdk14 36 | 1.7.12 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | # SLF4J's SimpleLogger configuration file 2 | # Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. 3 | 4 | # Default logging detail level for all instances of SimpleLogger. 5 | # Must be one of ("trace", "debug", "info", "warn", or "error"). 6 | # If not specified, defaults to "info". 7 | org.slf4j.simpleLogger.defaultLogLevel=debug 8 | 9 | # Logging detail level for a SimpleLogger instance named "xxxxx". 10 | # Must be one of ("trace", "debug", "info", "warn", or "error"). 11 | # If not specified, the default logging detail level is used. 12 | #org.slf4j.simpleLogger.log.xxxxx= 13 | 14 | # Set to true if you want the current date and time to be included in output messages. 15 | # Default is false, and will output the number of milliseconds elapsed since startup. 16 | #org.slf4j.simpleLogger.showDateTime=false 17 | 18 | # The date and time format to be used in the output messages. 19 | # The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat. 20 | # If the format is not specified or is invalid, the default format is used. 21 | # The default format is yyyy-MM-dd HH:mm:ss:SSS Z. 22 | #org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z 23 | 24 | # Set to true if you want to output the current thread name. 25 | # Defaults to true. 26 | #org.slf4j.simpleLogger.showThreadName=true 27 | 28 | # Set to true if you want the Logger instance name to be included in output messages. 29 | # Defaults to true. 30 | #org.slf4j.simpleLogger.showLogName=true 31 | 32 | # Set to true if you want the last component of the name to be included in output messages. 33 | # Defaults to false. 34 | #org.slf4j.simpleLogger.showShortLogName=false -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/.idea/.name: -------------------------------------------------------------------------------- 1 | webapp -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/.idea/deployment.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/.idea/webapp.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Free Bootstrap Theme for developers 2 | 3 | Theme name: 4 | ======================================================================= 5 | devAid 6 | 7 | Theme version: 8 | ======================================================================= 9 | v1.0 10 | 11 | Release Date: 12 | ======================================================================= 13 | 04 Nov 2014 14 | 15 | Author: 16 | ======================================================================= 17 | Xiaoying Riley at 3rd Wave Media (http://themes.3rdwavemedia.com/) 18 | 19 | Contact: 20 | ======================================================================= 21 | Web: http://themes.3rdwavemedia.com/ 22 | Email: hello@3rdwavemedia.com 23 | Twitter: @3rdwave_themes 24 | 25 | License: 26 | ======================================================================= 27 | This template is free under the Creative Commons Attribution 3.0 License. 28 | https://creativecommons.org/licenses/by/3.0/ 29 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | AngularSEO Sample Web Application 7 | 8 | SEOFilter 9 | SEOFilter 10 | AngularSEO Filter 11 | net.angularseo.SEOFilter 12 | 13 | 14 | phantomjs.binary.path 15 | C:\\Users\\john.huang\\Desktop\\AngularJS SEO\\phw\\bin\\phantomjs.exe 16 | 17 | 20 | 21 | waitForPageLoad 22 | 3 23 | 24 | 27 | 28 | robotUserAgents 29 | YodaoBot|Zealbot 30 | 31 | 32 | 33 | cacheTimeout 34 | 24 35 | 36 | 37 | 38 | cachePath 39 | c:\\cache 40 | 41 | 42 | 43 | crawlDepth 44 | 1 45 | 46 | 47 | 48 | encoding 49 | UTF-8 50 | 51 | 52 | 53 | SEOFilter 54 | /* 55 | 56 | 57 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/images/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-web/src/main/webapp/assets/images/profile.png -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/js/main.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function($) { 2 | 3 | /* ======= Scrollspy ======= */ 4 | $('body').scrollspy({ target: '#header', offset: 400}); 5 | 6 | /* ======= Fixed header when scrolled ======= */ 7 | 8 | $(window).bind('scroll', function() { 9 | if ($(window).scrollTop() > 50) { 10 | $('#header').addClass('navbar-fixed-top'); 11 | } 12 | else { 13 | $('#header').removeClass('navbar-fixed-top'); 14 | } 15 | }); 16 | 17 | /* ======= ScrollTo ======= */ 18 | $('a.scrollto').on('click', function(e){ 19 | 20 | //store hash 21 | var target = this.hash; 22 | 23 | e.preventDefault(); 24 | 25 | $('body').scrollTo(target, 800, {offset: -70, 'axis':'y', easing:'easeOutQuad'}); 26 | //Collapse mobile menu after clicking 27 | if ($('.navbar-collapse').hasClass('in')){ 28 | $('.navbar-collapse').removeClass('in').addClass('collapse'); 29 | } 30 | 31 | }); 32 | 33 | }); -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/js/min/main-min.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function($){$("body").scrollspy({target:"#header",offset:400}),$(window).bind("scroll",function(){$(window).scrollTop()>50?$("#header").addClass("navbar-fixed-top"):$("#header").removeClass("navbar-fixed-top")}),$("a.scrollto").on("click",function(a){var e=this.hash;a.preventDefault(),$("body").scrollTo(e,800,{offset:-70,axis:"y",easing:"easeOutQuad"}),$(".navbar-collapse").hasClass("in")&&$(".navbar-collapse").removeClass("in").addClass("collapse")})}); -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/default/mixins.less: -------------------------------------------------------------------------------- 1 | .text-shadow (@string: 0 1px 3px rgba(0, 0, 0, 0.25)) { 2 | text-shadow: @string; 3 | } 4 | .box-shadow (@string) { 5 | -webkit-box-shadow: @string; 6 | -moz-box-shadow: @string; 7 | box-shadow: @string; 8 | } 9 | .drop-shadow (@x: 0, @y: 1px, @blur: 2px, @spread: 0, @alpha: 0.25) { 10 | -webkit-box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 11 | -moz-box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 12 | box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 13 | } 14 | .inner-shadow (@x: 0, @y: 1px, @blur: 2px, @spread: 0, @alpha: 0.25) { 15 | -webkit-box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 16 | -moz-box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 17 | box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 18 | } 19 | 20 | .box-sizing (@type: border-box) { 21 | -webkit-box-sizing: @type; 22 | -moz-box-sizing: @type; 23 | box-sizing: @type; 24 | } 25 | 26 | .border-radius (@radius: 5px) { 27 | -webkit-border-radius: @radius; 28 | -moz-border-radius: @radius; 29 | -ms-border-radius: @radius; 30 | -o-border-radius: @radius; 31 | border-radius: @radius; 32 | 33 | -moz-background-clip: padding; 34 | -webkit-background-clip: padding-box; 35 | background-clip: padding-box; 36 | } 37 | .border-radiuses (@topright: 0, @bottomright: 0, @bottomleft: 0, @topleft: 0) { 38 | -webkit-border-top-right-radius: @topright; 39 | -webkit-border-bottom-right-radius: @bottomright; 40 | -webkit-border-bottom-left-radius: @bottomleft; 41 | -webkit-border-top-left-radius: @topleft; 42 | 43 | -moz-border-radius-topright: @topright; 44 | -moz-border-radius-bottomright: @bottomright; 45 | -moz-border-radius-bottomleft: @bottomleft; 46 | -moz-border-radius-topleft: @topleft; 47 | 48 | border-top-right-radius: @topright; 49 | border-bottom-right-radius: @bottomright; 50 | border-bottom-left-radius: @bottomleft; 51 | border-top-left-radius: @topleft; 52 | 53 | -moz-background-clip: padding; 54 | -webkit-background-clip: padding-box; 55 | background-clip: padding-box; 56 | } 57 | 58 | .opacity (@opacity: 0.5) { 59 | -webkit-opacity: @opacity; 60 | -moz-opacity: @opacity; 61 | opacity: @opacity; 62 | } 63 | 64 | .gradient (@startColor: #eee, @endColor: white) { 65 | background-color: @startColor; 66 | background: -webkit-gradient(linear, left top, left bottom, from(@startColor), to(@endColor)); 67 | background: -webkit-linear-gradient(top, @startColor, @endColor); 68 | background: -moz-linear-gradient(top, @startColor, @endColor); 69 | background: -ms-linear-gradient(top, @startColor, @endColor); 70 | background: -o-linear-gradient(top, @startColor, @endColor); 71 | } 72 | .horizontal-gradient (@startColor: #eee, @endColor: white) { 73 | background-color: @startColor; 74 | background-image: -webkit-gradient(linear, left top, right top, from(@startColor), to(@endColor)); 75 | background-image: -webkit-linear-gradient(left, @startColor, @endColor); 76 | background-image: -moz-linear-gradient(left, @startColor, @endColor); 77 | background-image: -ms-linear-gradient(left, @startColor, @endColor); 78 | background-image: -o-linear-gradient(left, @startColor, @endColor); 79 | } 80 | 81 | .animation (@name, @duration: 300ms, @delay: 0, @ease: ease) { 82 | -webkit-animation: @name @duration @delay @ease; 83 | -moz-animation: @name @duration @delay @ease; 84 | -ms-animation: @name @duration @delay @ease; 85 | } 86 | 87 | .transition (@transition) { 88 | -webkit-transition: @transition; 89 | -moz-transition: @transition; 90 | -ms-transition: @transition; 91 | -o-transition: @transition; 92 | } 93 | .transform(@string){ 94 | -webkit-transform: @string; 95 | -moz-transform: @string; 96 | -ms-transform: @string; 97 | -o-transform: @string; 98 | } 99 | .scale (@factor) { 100 | -webkit-transform: scale(@factor); 101 | -moz-transform: scale(@factor); 102 | -ms-transform: scale(@factor); 103 | -o-transform: scale(@factor); 104 | } 105 | .rotate (@deg) { 106 | -webkit-transform: rotate(@deg); 107 | -moz-transform: rotate(@deg); 108 | -ms-transform: rotate(@deg); 109 | -o-transform: rotate(@deg); 110 | } 111 | .skew (@deg, @deg2) { 112 | -webkit-transform: skew(@deg, @deg2); 113 | -moz-transform: skew(@deg, @deg2); 114 | -ms-transform: skew(@deg, @deg2); 115 | -o-transform: skew(@deg, @deg2); 116 | } 117 | .translate (@x, @y:0) { 118 | -webkit-transform: translate(@x, @y); 119 | -moz-transform: translate(@x, @y); 120 | -ms-transform: translate(@x, @y); 121 | -o-transform: translate(@x, @y); 122 | } 123 | .translate3d (@x, @y: 0, @z: 0) { 124 | -webkit-transform: translate3d(@x, @y, @z); 125 | -moz-transform: translate3d(@x, @y, @z); 126 | -ms-transform: translate3d(@x, @y, @z); 127 | -o-transform: translate3d(@x, @y, @z); 128 | } 129 | .perspective (@value: 1000) { 130 | -webkit-perspective: @value; 131 | -moz-perspective: @value; 132 | -ms-perspective: @value; 133 | perspective: @value; 134 | } 135 | .transform-origin (@x:center, @y:center) { 136 | -webkit-transform-origin: @x @y; 137 | -moz-transform-origin: @x @y; 138 | -ms-transform-origin: @x @y; 139 | -o-transform-origin: @x @y; 140 | } 141 | 142 | .reset-box-sizing (@size:content-box) { 143 | &, 144 | *, 145 | *:before, 146 | *:after { 147 | .box-sizing(@size); 148 | } 149 | } 150 | 151 | .truncate (@max-width: 250px) { 152 | max-width: @max-width; 153 | white-space: nowrap; 154 | overflow: hidden; 155 | text-overflow: ellipsis; 156 | } 157 | 158 | .background-size (@string: contain) { 159 | -webkit-background-size: @string; 160 | -moz-background-size: @string; 161 | -o-background-size: @string; 162 | background-size: @string; 163 | } 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/default/responsive.less: -------------------------------------------------------------------------------- 1 | @import "mixins.less"; 2 | @import "theme-default.less"; 3 | 4 | /* Extra small devices (phones, less than 768px) */ 5 | @media (max-width: 767px) { 6 | 7 | .header .main-nav button { 8 | margin-right: 0; 9 | } 10 | 11 | .header .main-nav .navbar-collapse { 12 | padding-left: 15px; 13 | padding-right: 15px; 14 | } 15 | 16 | .promo .btns .btn { 17 | margin-right: 0; 18 | clear: both; 19 | display: block; 20 | margin-bottom: 30px; 21 | } 22 | 23 | .promo .title { 24 | font-size: 66px; 25 | } 26 | 27 | .promo .meta { 28 | margin-top: 60px; 29 | } 30 | 31 | .promo .meta li{ 32 | float: none; 33 | display: block; 34 | margin-bottom: 5px; 35 | } 36 | 37 | .contact .author-message { 38 | text-align: center; 39 | } 40 | 41 | .contact .author-message .profile { 42 | position: static; 43 | margin: 0 auto; 44 | margin-bottom: 30px; 45 | 46 | } 47 | 48 | .contact .author-message .speech-bubble { 49 | margin-left: 0; 50 | &:after { 51 | display: none; 52 | } 53 | } 54 | 55 | .contact .social-icons a { 56 | width:36px; 57 | height: 36px; 58 | padding-top: 7px; 59 | margin-right: 2px; 60 | .fa:before { 61 | font-size: 18px; 62 | } 63 | } 64 | 65 | 66 | } 67 | 68 | /* Small devices (tablets, 768px and up) */ 69 | @media (min-width: 768px) { 70 | 71 | } 72 | 73 | /* Medium devices (desktops, 992px and up) */ 74 | @media (min-width: 992px) { 75 | 76 | } 77 | 78 | /* Large devices (large desktops, 1200px and up) */ 79 | @media (min-width: 1200px) { 80 | 81 | } 82 | 83 | 84 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/default/styles.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Template Name: devAid - Responsive Website Template for developers 3 | * Version: 1.0 4 | * Author: Xiaoying Riley at 3rd Wave Media 5 | * Website: http://themes.3rdwavemedia.com/ 6 | * Twitter: @3rdwave_themes 7 | */ 8 | @import "theme-default.less"; 9 | @import "base.less"; 10 | @import "responsive.less"; 11 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/default/theme-default.less: -------------------------------------------------------------------------------- 1 | /* Default */ 2 | @color: #17baef; 3 | @color-2: #eebf3f; 4 | 5 | @text-color: #444; 6 | @text-secondary: #666; 7 | @grey: #999; 8 | @darker-grey: #666; 9 | @smoky-white: #f5f5f5; 10 | @divider: #efefef; 11 | @heart: #fb866a; 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-2/mixins.less: -------------------------------------------------------------------------------- 1 | .text-shadow (@string: 0 1px 3px rgba(0, 0, 0, 0.25)) { 2 | text-shadow: @string; 3 | } 4 | .box-shadow (@string) { 5 | -webkit-box-shadow: @string; 6 | -moz-box-shadow: @string; 7 | box-shadow: @string; 8 | } 9 | .drop-shadow (@x: 0, @y: 1px, @blur: 2px, @spread: 0, @alpha: 0.25) { 10 | -webkit-box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 11 | -moz-box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 12 | box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 13 | } 14 | .inner-shadow (@x: 0, @y: 1px, @blur: 2px, @spread: 0, @alpha: 0.25) { 15 | -webkit-box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 16 | -moz-box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 17 | box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 18 | } 19 | 20 | .box-sizing (@type: border-box) { 21 | -webkit-box-sizing: @type; 22 | -moz-box-sizing: @type; 23 | box-sizing: @type; 24 | } 25 | 26 | .border-radius (@radius: 5px) { 27 | -webkit-border-radius: @radius; 28 | -moz-border-radius: @radius; 29 | -ms-border-radius: @radius; 30 | -o-border-radius: @radius; 31 | border-radius: @radius; 32 | 33 | -moz-background-clip: padding; 34 | -webkit-background-clip: padding-box; 35 | background-clip: padding-box; 36 | } 37 | .border-radiuses (@topright: 0, @bottomright: 0, @bottomleft: 0, @topleft: 0) { 38 | -webkit-border-top-right-radius: @topright; 39 | -webkit-border-bottom-right-radius: @bottomright; 40 | -webkit-border-bottom-left-radius: @bottomleft; 41 | -webkit-border-top-left-radius: @topleft; 42 | 43 | -moz-border-radius-topright: @topright; 44 | -moz-border-radius-bottomright: @bottomright; 45 | -moz-border-radius-bottomleft: @bottomleft; 46 | -moz-border-radius-topleft: @topleft; 47 | 48 | border-top-right-radius: @topright; 49 | border-bottom-right-radius: @bottomright; 50 | border-bottom-left-radius: @bottomleft; 51 | border-top-left-radius: @topleft; 52 | 53 | -moz-background-clip: padding; 54 | -webkit-background-clip: padding-box; 55 | background-clip: padding-box; 56 | } 57 | 58 | .opacity (@opacity: 0.5) { 59 | -webkit-opacity: @opacity; 60 | -moz-opacity: @opacity; 61 | opacity: @opacity; 62 | } 63 | 64 | .gradient (@startColor: #eee, @endColor: white) { 65 | background-color: @startColor; 66 | background: -webkit-gradient(linear, left top, left bottom, from(@startColor), to(@endColor)); 67 | background: -webkit-linear-gradient(top, @startColor, @endColor); 68 | background: -moz-linear-gradient(top, @startColor, @endColor); 69 | background: -ms-linear-gradient(top, @startColor, @endColor); 70 | background: -o-linear-gradient(top, @startColor, @endColor); 71 | } 72 | .horizontal-gradient (@startColor: #eee, @endColor: white) { 73 | background-color: @startColor; 74 | background-image: -webkit-gradient(linear, left top, right top, from(@startColor), to(@endColor)); 75 | background-image: -webkit-linear-gradient(left, @startColor, @endColor); 76 | background-image: -moz-linear-gradient(left, @startColor, @endColor); 77 | background-image: -ms-linear-gradient(left, @startColor, @endColor); 78 | background-image: -o-linear-gradient(left, @startColor, @endColor); 79 | } 80 | 81 | .animation (@name, @duration: 300ms, @delay: 0, @ease: ease) { 82 | -webkit-animation: @name @duration @delay @ease; 83 | -moz-animation: @name @duration @delay @ease; 84 | -ms-animation: @name @duration @delay @ease; 85 | } 86 | 87 | .transition (@transition) { 88 | -webkit-transition: @transition; 89 | -moz-transition: @transition; 90 | -ms-transition: @transition; 91 | -o-transition: @transition; 92 | } 93 | .transform(@string){ 94 | -webkit-transform: @string; 95 | -moz-transform: @string; 96 | -ms-transform: @string; 97 | -o-transform: @string; 98 | } 99 | .scale (@factor) { 100 | -webkit-transform: scale(@factor); 101 | -moz-transform: scale(@factor); 102 | -ms-transform: scale(@factor); 103 | -o-transform: scale(@factor); 104 | } 105 | .rotate (@deg) { 106 | -webkit-transform: rotate(@deg); 107 | -moz-transform: rotate(@deg); 108 | -ms-transform: rotate(@deg); 109 | -o-transform: rotate(@deg); 110 | } 111 | .skew (@deg, @deg2) { 112 | -webkit-transform: skew(@deg, @deg2); 113 | -moz-transform: skew(@deg, @deg2); 114 | -ms-transform: skew(@deg, @deg2); 115 | -o-transform: skew(@deg, @deg2); 116 | } 117 | .translate (@x, @y:0) { 118 | -webkit-transform: translate(@x, @y); 119 | -moz-transform: translate(@x, @y); 120 | -ms-transform: translate(@x, @y); 121 | -o-transform: translate(@x, @y); 122 | } 123 | .translate3d (@x, @y: 0, @z: 0) { 124 | -webkit-transform: translate3d(@x, @y, @z); 125 | -moz-transform: translate3d(@x, @y, @z); 126 | -ms-transform: translate3d(@x, @y, @z); 127 | -o-transform: translate3d(@x, @y, @z); 128 | } 129 | .perspective (@value: 1000) { 130 | -webkit-perspective: @value; 131 | -moz-perspective: @value; 132 | -ms-perspective: @value; 133 | perspective: @value; 134 | } 135 | .transform-origin (@x:center, @y:center) { 136 | -webkit-transform-origin: @x @y; 137 | -moz-transform-origin: @x @y; 138 | -ms-transform-origin: @x @y; 139 | -o-transform-origin: @x @y; 140 | } 141 | 142 | .reset-box-sizing (@size:content-box) { 143 | &, 144 | *, 145 | *:before, 146 | *:after { 147 | .box-sizing(@size); 148 | } 149 | } 150 | 151 | .truncate (@max-width: 250px) { 152 | max-width: @max-width; 153 | white-space: nowrap; 154 | overflow: hidden; 155 | text-overflow: ellipsis; 156 | } 157 | 158 | .background-size (@string: contain) { 159 | -webkit-background-size: @string; 160 | -moz-background-size: @string; 161 | -o-background-size: @string; 162 | background-size: @string; 163 | } 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-2/responsive.less: -------------------------------------------------------------------------------- 1 | @import "mixins.less"; 2 | @import "theme-default.less"; 3 | 4 | /* Extra small devices (phones, less than 768px) */ 5 | @media (max-width: 767px) { 6 | 7 | .header .main-nav button { 8 | margin-right: 0; 9 | } 10 | 11 | .header .main-nav .navbar-collapse { 12 | padding-left: 15px; 13 | padding-right: 15px; 14 | } 15 | 16 | .promo .btns .btn { 17 | margin-right: 0; 18 | clear: both; 19 | display: block; 20 | margin-bottom: 30px; 21 | } 22 | 23 | .promo .title { 24 | font-size: 66px; 25 | } 26 | 27 | .promo .meta { 28 | margin-top: 60px; 29 | } 30 | 31 | .promo .meta li{ 32 | float: none; 33 | display: block; 34 | margin-bottom: 5px; 35 | } 36 | 37 | .contact .author-message { 38 | text-align: center; 39 | } 40 | 41 | .contact .author-message .profile { 42 | position: static; 43 | margin: 0 auto; 44 | margin-bottom: 30px; 45 | 46 | } 47 | 48 | .contact .author-message .speech-bubble { 49 | margin-left: 0; 50 | &:after { 51 | display: none; 52 | } 53 | } 54 | 55 | .contact .social-icons a { 56 | width:36px; 57 | height: 36px; 58 | padding-top: 7px; 59 | margin-right: 2px; 60 | .fa:before { 61 | font-size: 18px; 62 | } 63 | } 64 | 65 | 66 | } 67 | 68 | /* Small devices (tablets, 768px and up) */ 69 | @media (min-width: 768px) { 70 | 71 | } 72 | 73 | /* Medium devices (desktops, 992px and up) */ 74 | @media (min-width: 992px) { 75 | 76 | } 77 | 78 | /* Large devices (large desktops, 1200px and up) */ 79 | @media (min-width: 1200px) { 80 | 81 | } 82 | 83 | 84 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-2/styles.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Template Name: devAid - Responsive Website Template for developers 3 | * Version: 1.0 4 | * Author: Xiaoying Riley at 3rd Wave Media 5 | * Website: http://themes.3rdwavemedia.com/ 6 | * Twitter: @3rdwave_themes 7 | */ 8 | @import "theme-default.less"; 9 | @import "base.less"; 10 | @import "responsive.less"; 11 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-2/theme-default.less: -------------------------------------------------------------------------------- 1 | /* style-2.css */ 2 | @color: #b4ca65; 3 | @color-2: #dd7c4f; 4 | 5 | @text-color: #444; 6 | @text-secondary: #666; 7 | @grey: #999; 8 | @darker-grey: #666; 9 | @smoky-white: #f5f5f5; 10 | @divider: #efefef; 11 | @heart: #fb866a; 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-3/mixins.less: -------------------------------------------------------------------------------- 1 | .text-shadow (@string: 0 1px 3px rgba(0, 0, 0, 0.25)) { 2 | text-shadow: @string; 3 | } 4 | .box-shadow (@string) { 5 | -webkit-box-shadow: @string; 6 | -moz-box-shadow: @string; 7 | box-shadow: @string; 8 | } 9 | .drop-shadow (@x: 0, @y: 1px, @blur: 2px, @spread: 0, @alpha: 0.25) { 10 | -webkit-box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 11 | -moz-box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 12 | box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 13 | } 14 | .inner-shadow (@x: 0, @y: 1px, @blur: 2px, @spread: 0, @alpha: 0.25) { 15 | -webkit-box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 16 | -moz-box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 17 | box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 18 | } 19 | 20 | .box-sizing (@type: border-box) { 21 | -webkit-box-sizing: @type; 22 | -moz-box-sizing: @type; 23 | box-sizing: @type; 24 | } 25 | 26 | .border-radius (@radius: 5px) { 27 | -webkit-border-radius: @radius; 28 | -moz-border-radius: @radius; 29 | -ms-border-radius: @radius; 30 | -o-border-radius: @radius; 31 | border-radius: @radius; 32 | 33 | -moz-background-clip: padding; 34 | -webkit-background-clip: padding-box; 35 | background-clip: padding-box; 36 | } 37 | .border-radiuses (@topright: 0, @bottomright: 0, @bottomleft: 0, @topleft: 0) { 38 | -webkit-border-top-right-radius: @topright; 39 | -webkit-border-bottom-right-radius: @bottomright; 40 | -webkit-border-bottom-left-radius: @bottomleft; 41 | -webkit-border-top-left-radius: @topleft; 42 | 43 | -moz-border-radius-topright: @topright; 44 | -moz-border-radius-bottomright: @bottomright; 45 | -moz-border-radius-bottomleft: @bottomleft; 46 | -moz-border-radius-topleft: @topleft; 47 | 48 | border-top-right-radius: @topright; 49 | border-bottom-right-radius: @bottomright; 50 | border-bottom-left-radius: @bottomleft; 51 | border-top-left-radius: @topleft; 52 | 53 | -moz-background-clip: padding; 54 | -webkit-background-clip: padding-box; 55 | background-clip: padding-box; 56 | } 57 | 58 | .opacity (@opacity: 0.5) { 59 | -webkit-opacity: @opacity; 60 | -moz-opacity: @opacity; 61 | opacity: @opacity; 62 | } 63 | 64 | .gradient (@startColor: #eee, @endColor: white) { 65 | background-color: @startColor; 66 | background: -webkit-gradient(linear, left top, left bottom, from(@startColor), to(@endColor)); 67 | background: -webkit-linear-gradient(top, @startColor, @endColor); 68 | background: -moz-linear-gradient(top, @startColor, @endColor); 69 | background: -ms-linear-gradient(top, @startColor, @endColor); 70 | background: -o-linear-gradient(top, @startColor, @endColor); 71 | } 72 | .horizontal-gradient (@startColor: #eee, @endColor: white) { 73 | background-color: @startColor; 74 | background-image: -webkit-gradient(linear, left top, right top, from(@startColor), to(@endColor)); 75 | background-image: -webkit-linear-gradient(left, @startColor, @endColor); 76 | background-image: -moz-linear-gradient(left, @startColor, @endColor); 77 | background-image: -ms-linear-gradient(left, @startColor, @endColor); 78 | background-image: -o-linear-gradient(left, @startColor, @endColor); 79 | } 80 | 81 | .animation (@name, @duration: 300ms, @delay: 0, @ease: ease) { 82 | -webkit-animation: @name @duration @delay @ease; 83 | -moz-animation: @name @duration @delay @ease; 84 | -ms-animation: @name @duration @delay @ease; 85 | } 86 | 87 | .transition (@transition) { 88 | -webkit-transition: @transition; 89 | -moz-transition: @transition; 90 | -ms-transition: @transition; 91 | -o-transition: @transition; 92 | } 93 | .transform(@string){ 94 | -webkit-transform: @string; 95 | -moz-transform: @string; 96 | -ms-transform: @string; 97 | -o-transform: @string; 98 | } 99 | .scale (@factor) { 100 | -webkit-transform: scale(@factor); 101 | -moz-transform: scale(@factor); 102 | -ms-transform: scale(@factor); 103 | -o-transform: scale(@factor); 104 | } 105 | .rotate (@deg) { 106 | -webkit-transform: rotate(@deg); 107 | -moz-transform: rotate(@deg); 108 | -ms-transform: rotate(@deg); 109 | -o-transform: rotate(@deg); 110 | } 111 | .skew (@deg, @deg2) { 112 | -webkit-transform: skew(@deg, @deg2); 113 | -moz-transform: skew(@deg, @deg2); 114 | -ms-transform: skew(@deg, @deg2); 115 | -o-transform: skew(@deg, @deg2); 116 | } 117 | .translate (@x, @y:0) { 118 | -webkit-transform: translate(@x, @y); 119 | -moz-transform: translate(@x, @y); 120 | -ms-transform: translate(@x, @y); 121 | -o-transform: translate(@x, @y); 122 | } 123 | .translate3d (@x, @y: 0, @z: 0) { 124 | -webkit-transform: translate3d(@x, @y, @z); 125 | -moz-transform: translate3d(@x, @y, @z); 126 | -ms-transform: translate3d(@x, @y, @z); 127 | -o-transform: translate3d(@x, @y, @z); 128 | } 129 | .perspective (@value: 1000) { 130 | -webkit-perspective: @value; 131 | -moz-perspective: @value; 132 | -ms-perspective: @value; 133 | perspective: @value; 134 | } 135 | .transform-origin (@x:center, @y:center) { 136 | -webkit-transform-origin: @x @y; 137 | -moz-transform-origin: @x @y; 138 | -ms-transform-origin: @x @y; 139 | -o-transform-origin: @x @y; 140 | } 141 | 142 | .reset-box-sizing (@size:content-box) { 143 | &, 144 | *, 145 | *:before, 146 | *:after { 147 | .box-sizing(@size); 148 | } 149 | } 150 | 151 | .truncate (@max-width: 250px) { 152 | max-width: @max-width; 153 | white-space: nowrap; 154 | overflow: hidden; 155 | text-overflow: ellipsis; 156 | } 157 | 158 | .background-size (@string: contain) { 159 | -webkit-background-size: @string; 160 | -moz-background-size: @string; 161 | -o-background-size: @string; 162 | background-size: @string; 163 | } 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-3/responsive.less: -------------------------------------------------------------------------------- 1 | @import "mixins.less"; 2 | @import "theme-default.less"; 3 | 4 | /* Extra small devices (phones, less than 768px) */ 5 | @media (max-width: 767px) { 6 | 7 | .header .main-nav button { 8 | margin-right: 0; 9 | } 10 | 11 | .header .main-nav .navbar-collapse { 12 | padding-left: 15px; 13 | padding-right: 15px; 14 | } 15 | 16 | .promo .btns .btn { 17 | margin-right: 0; 18 | clear: both; 19 | display: block; 20 | margin-bottom: 30px; 21 | } 22 | 23 | .promo .title { 24 | font-size: 66px; 25 | } 26 | 27 | .promo .meta { 28 | margin-top: 60px; 29 | } 30 | 31 | .promo .meta li{ 32 | float: none; 33 | display: block; 34 | margin-bottom: 5px; 35 | } 36 | 37 | .contact .author-message { 38 | text-align: center; 39 | } 40 | 41 | .contact .author-message .profile { 42 | position: static; 43 | margin: 0 auto; 44 | margin-bottom: 30px; 45 | 46 | } 47 | 48 | .contact .author-message .speech-bubble { 49 | margin-left: 0; 50 | &:after { 51 | display: none; 52 | } 53 | } 54 | 55 | .contact .social-icons a { 56 | width:36px; 57 | height: 36px; 58 | padding-top: 7px; 59 | margin-right: 2px; 60 | .fa:before { 61 | font-size: 18px; 62 | } 63 | } 64 | 65 | 66 | } 67 | 68 | /* Small devices (tablets, 768px and up) */ 69 | @media (min-width: 768px) { 70 | 71 | } 72 | 73 | /* Medium devices (desktops, 992px and up) */ 74 | @media (min-width: 992px) { 75 | 76 | } 77 | 78 | /* Large devices (large desktops, 1200px and up) */ 79 | @media (min-width: 1200px) { 80 | 81 | } 82 | 83 | 84 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-3/styles.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Template Name: devAid - Responsive Website Template for developers 3 | * Version: 1.0 4 | * Author: Xiaoying Riley at 3rd Wave Media 5 | * Website: http://themes.3rdwavemedia.com/ 6 | * Twitter: @3rdwave_themes 7 | */ 8 | @import "theme-default.less"; 9 | @import "base.less"; 10 | @import "responsive.less"; 11 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-3/theme-default.less: -------------------------------------------------------------------------------- 1 | /* style-3.css */ 2 | @color: #6690b9; 3 | @color-2: #f46fa3; 4 | 5 | @text-color: #444; 6 | @text-secondary: #666; 7 | @grey: #999; 8 | @darker-grey: #666; 9 | @smoky-white: #f5f5f5; 10 | @divider: #efefef; 11 | @heart: #fb866a; 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-4/mixins.less: -------------------------------------------------------------------------------- 1 | .text-shadow (@string: 0 1px 3px rgba(0, 0, 0, 0.25)) { 2 | text-shadow: @string; 3 | } 4 | .box-shadow (@string) { 5 | -webkit-box-shadow: @string; 6 | -moz-box-shadow: @string; 7 | box-shadow: @string; 8 | } 9 | .drop-shadow (@x: 0, @y: 1px, @blur: 2px, @spread: 0, @alpha: 0.25) { 10 | -webkit-box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 11 | -moz-box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 12 | box-shadow: @x @y @blur @spread rgba(0, 0, 0, @alpha); 13 | } 14 | .inner-shadow (@x: 0, @y: 1px, @blur: 2px, @spread: 0, @alpha: 0.25) { 15 | -webkit-box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 16 | -moz-box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 17 | box-shadow: inset @x @y @blur @spread rgba(0, 0, 0, @alpha); 18 | } 19 | 20 | .box-sizing (@type: border-box) { 21 | -webkit-box-sizing: @type; 22 | -moz-box-sizing: @type; 23 | box-sizing: @type; 24 | } 25 | 26 | .border-radius (@radius: 5px) { 27 | -webkit-border-radius: @radius; 28 | -moz-border-radius: @radius; 29 | -ms-border-radius: @radius; 30 | -o-border-radius: @radius; 31 | border-radius: @radius; 32 | 33 | -moz-background-clip: padding; 34 | -webkit-background-clip: padding-box; 35 | background-clip: padding-box; 36 | } 37 | .border-radiuses (@topright: 0, @bottomright: 0, @bottomleft: 0, @topleft: 0) { 38 | -webkit-border-top-right-radius: @topright; 39 | -webkit-border-bottom-right-radius: @bottomright; 40 | -webkit-border-bottom-left-radius: @bottomleft; 41 | -webkit-border-top-left-radius: @topleft; 42 | 43 | -moz-border-radius-topright: @topright; 44 | -moz-border-radius-bottomright: @bottomright; 45 | -moz-border-radius-bottomleft: @bottomleft; 46 | -moz-border-radius-topleft: @topleft; 47 | 48 | border-top-right-radius: @topright; 49 | border-bottom-right-radius: @bottomright; 50 | border-bottom-left-radius: @bottomleft; 51 | border-top-left-radius: @topleft; 52 | 53 | -moz-background-clip: padding; 54 | -webkit-background-clip: padding-box; 55 | background-clip: padding-box; 56 | } 57 | 58 | .opacity (@opacity: 0.5) { 59 | -webkit-opacity: @opacity; 60 | -moz-opacity: @opacity; 61 | opacity: @opacity; 62 | } 63 | 64 | .gradient (@startColor: #eee, @endColor: white) { 65 | background-color: @startColor; 66 | background: -webkit-gradient(linear, left top, left bottom, from(@startColor), to(@endColor)); 67 | background: -webkit-linear-gradient(top, @startColor, @endColor); 68 | background: -moz-linear-gradient(top, @startColor, @endColor); 69 | background: -ms-linear-gradient(top, @startColor, @endColor); 70 | background: -o-linear-gradient(top, @startColor, @endColor); 71 | } 72 | .horizontal-gradient (@startColor: #eee, @endColor: white) { 73 | background-color: @startColor; 74 | background-image: -webkit-gradient(linear, left top, right top, from(@startColor), to(@endColor)); 75 | background-image: -webkit-linear-gradient(left, @startColor, @endColor); 76 | background-image: -moz-linear-gradient(left, @startColor, @endColor); 77 | background-image: -ms-linear-gradient(left, @startColor, @endColor); 78 | background-image: -o-linear-gradient(left, @startColor, @endColor); 79 | } 80 | 81 | .animation (@name, @duration: 300ms, @delay: 0, @ease: ease) { 82 | -webkit-animation: @name @duration @delay @ease; 83 | -moz-animation: @name @duration @delay @ease; 84 | -ms-animation: @name @duration @delay @ease; 85 | } 86 | 87 | .transition (@transition) { 88 | -webkit-transition: @transition; 89 | -moz-transition: @transition; 90 | -ms-transition: @transition; 91 | -o-transition: @transition; 92 | } 93 | .transform(@string){ 94 | -webkit-transform: @string; 95 | -moz-transform: @string; 96 | -ms-transform: @string; 97 | -o-transform: @string; 98 | } 99 | .scale (@factor) { 100 | -webkit-transform: scale(@factor); 101 | -moz-transform: scale(@factor); 102 | -ms-transform: scale(@factor); 103 | -o-transform: scale(@factor); 104 | } 105 | .rotate (@deg) { 106 | -webkit-transform: rotate(@deg); 107 | -moz-transform: rotate(@deg); 108 | -ms-transform: rotate(@deg); 109 | -o-transform: rotate(@deg); 110 | } 111 | .skew (@deg, @deg2) { 112 | -webkit-transform: skew(@deg, @deg2); 113 | -moz-transform: skew(@deg, @deg2); 114 | -ms-transform: skew(@deg, @deg2); 115 | -o-transform: skew(@deg, @deg2); 116 | } 117 | .translate (@x, @y:0) { 118 | -webkit-transform: translate(@x, @y); 119 | -moz-transform: translate(@x, @y); 120 | -ms-transform: translate(@x, @y); 121 | -o-transform: translate(@x, @y); 122 | } 123 | .translate3d (@x, @y: 0, @z: 0) { 124 | -webkit-transform: translate3d(@x, @y, @z); 125 | -moz-transform: translate3d(@x, @y, @z); 126 | -ms-transform: translate3d(@x, @y, @z); 127 | -o-transform: translate3d(@x, @y, @z); 128 | } 129 | .perspective (@value: 1000) { 130 | -webkit-perspective: @value; 131 | -moz-perspective: @value; 132 | -ms-perspective: @value; 133 | perspective: @value; 134 | } 135 | .transform-origin (@x:center, @y:center) { 136 | -webkit-transform-origin: @x @y; 137 | -moz-transform-origin: @x @y; 138 | -ms-transform-origin: @x @y; 139 | -o-transform-origin: @x @y; 140 | } 141 | 142 | .reset-box-sizing (@size:content-box) { 143 | &, 144 | *, 145 | *:before, 146 | *:after { 147 | .box-sizing(@size); 148 | } 149 | } 150 | 151 | .truncate (@max-width: 250px) { 152 | max-width: @max-width; 153 | white-space: nowrap; 154 | overflow: hidden; 155 | text-overflow: ellipsis; 156 | } 157 | 158 | .background-size (@string: contain) { 159 | -webkit-background-size: @string; 160 | -moz-background-size: @string; 161 | -o-background-size: @string; 162 | background-size: @string; 163 | } 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-4/responsive.less: -------------------------------------------------------------------------------- 1 | @import "mixins.less"; 2 | @import "theme-default.less"; 3 | 4 | /* Extra small devices (phones, less than 768px) */ 5 | @media (max-width: 767px) { 6 | 7 | .header .main-nav button { 8 | margin-right: 0; 9 | } 10 | 11 | .header .main-nav .navbar-collapse { 12 | padding-left: 15px; 13 | padding-right: 15px; 14 | } 15 | 16 | .promo .btns .btn { 17 | margin-right: 0; 18 | clear: both; 19 | display: block; 20 | margin-bottom: 30px; 21 | } 22 | 23 | .promo .title { 24 | font-size: 66px; 25 | } 26 | 27 | .promo .meta { 28 | margin-top: 60px; 29 | } 30 | 31 | .promo .meta li{ 32 | float: none; 33 | display: block; 34 | margin-bottom: 5px; 35 | } 36 | 37 | .contact .author-message { 38 | text-align: center; 39 | } 40 | 41 | .contact .author-message .profile { 42 | position: static; 43 | margin: 0 auto; 44 | margin-bottom: 30px; 45 | 46 | } 47 | 48 | .contact .author-message .speech-bubble { 49 | margin-left: 0; 50 | &:after { 51 | display: none; 52 | } 53 | } 54 | 55 | .contact .social-icons a { 56 | width:36px; 57 | height: 36px; 58 | padding-top: 7px; 59 | margin-right: 2px; 60 | .fa:before { 61 | font-size: 18px; 62 | } 63 | } 64 | 65 | 66 | } 67 | 68 | /* Small devices (tablets, 768px and up) */ 69 | @media (min-width: 768px) { 70 | 71 | } 72 | 73 | /* Medium devices (desktops, 992px and up) */ 74 | @media (min-width: 992px) { 75 | 76 | } 77 | 78 | /* Large devices (large desktops, 1200px and up) */ 79 | @media (min-width: 1200px) { 80 | 81 | } 82 | 83 | 84 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-4/styles.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Template Name: devAid - Responsive Website Template for developers 3 | * Version: 1.0 4 | * Author: Xiaoying Riley at 3rd Wave Media 5 | * Website: http://themes.3rdwavemedia.com/ 6 | * Twitter: @3rdwave_themes 7 | */ 8 | @import "theme-default.less"; 9 | @import "base.less"; 10 | @import "responsive.less"; 11 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/less/theme-4/theme-default.less: -------------------------------------------------------------------------------- 1 | /* style-4.css */ 2 | @color: #50c8c9; 3 | @color-2: #ffbe57; 4 | 5 | @text-color: #444; 6 | @text-secondary: #666; 7 | @grey: #999; 8 | @darker-grey: #666; 9 | @smoky-white: #f5f5f5; 10 | @divider: #efefef; 11 | @heart: #fb866a; 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-web/src/main/webapp/assets/plugins/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-web/src/main/webapp/assets/plugins/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-web/src/main/webapp/assets/plugins/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/bootstrap/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/detectmobilebrowser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery.browser.mobile (http://detectmobilebrowser.com/) 3 | * 4 | * jQuery.browser.mobile will be true if the browser is a mobile device 5 | * 6 | **/ 7 | (function(a){(jQuery.browser=jQuery.browser||{}).mobile=/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))})(navigator.userAgent||navigator.vendor||window.opera); -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-web/src/main/webapp/assets/plugins/font-awesome/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-web/src/main/webapp/assets/plugins/font-awesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-web/src/main/webapp/assets/plugins/font-awesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnhuang-cn/AngularSEO/c2cd698c1be36599a4dae382bc73ee57dadc6c02/angular-seo-web/src/main/webapp/assets/plugins/font-awesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .pull-right { float: right; } 11 | .pull-left { float: left; } 12 | 13 | .@{fa-css-prefix} { 14 | &.pull-left { margin-right: .3em; } 15 | &.pull-right { margin-left: .3em; } 16 | } 17 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal 14px/1 FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "spinning.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal 14px/1 FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | 13 | .fa-icon-rotate(@degrees, @rotation) { 14 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); 15 | -webkit-transform: rotate(@degrees); 16 | -ms-transform: rotate(@degrees); 17 | transform: rotate(@degrees); 18 | } 19 | 20 | .fa-icon-flip(@horiz, @vert, @rotation) { 21 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1); 22 | -webkit-transform: scale(@horiz, @vert); 23 | -ms-transform: scale(@horiz, @vert); 24 | transform: scale(@horiz, @vert); 25 | } 26 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 9 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 10 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 11 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 12 | font-weight: normal; 13 | font-style: normal; 14 | } 15 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/spinning.less: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | @-webkit-keyframes fa-spin { 10 | 0% { 11 | -webkit-transform: rotate(0deg); 12 | transform: rotate(0deg); 13 | } 14 | 100% { 15 | -webkit-transform: rotate(359deg); 16 | transform: rotate(359deg); 17 | } 18 | } 19 | 20 | @keyframes fa-spin { 21 | 0% { 22 | -webkit-transform: rotate(0deg); 23 | transform: rotate(0deg); 24 | } 25 | 100% { 26 | -webkit-transform: rotate(359deg); 27 | transform: rotate(359deg); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .pull-right { float: right; } 11 | .pull-left { float: left; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.pull-left { margin-right: .3em; } 15 | &.pull-right { margin-left: .3em; } 16 | } 17 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal 14px/1 FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal 14px/1 FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | 13 | @mixin fa-icon-rotate($degrees, $rotation) { 14 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); 15 | -webkit-transform: rotate($degrees); 16 | -ms-transform: rotate($degrees); 17 | transform: rotate($degrees); 18 | } 19 | 20 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 21 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); 22 | -webkit-transform: scale($horiz, $vert); 23 | -ms-transform: scale($horiz, $vert); 24 | transform: scale($horiz, $vert); 25 | } 26 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 9 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 10 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 11 | //src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 12 | font-weight: normal; 13 | font-style: normal; 14 | } 15 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_spinning.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | @-webkit-keyframes fa-spin { 10 | 0% { 11 | -webkit-transform: rotate(0deg); 12 | transform: rotate(0deg); 13 | } 14 | 100% { 15 | -webkit-transform: rotate(359deg); 16 | transform: rotate(359deg); 17 | } 18 | } 19 | 20 | @keyframes fa-spin { 21 | 0% { 22 | -webkit-transform: rotate(0deg); 23 | transform: rotate(0deg); 24 | } 25 | 100% { 26 | -webkit-transform: rotate(359deg); 27 | transform: rotate(359deg); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/font-awesome/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "spinning"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-migrate-1.2.1.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery Migrate v1.2.1 | (c) 2005, 2013 jQuery Foundation, Inc. and other contributors | jquery.org/license */ 2 | jQuery.migrateMute===void 0&&(jQuery.migrateMute=!0),function(e,t,n){function r(n){var r=t.console;i[n]||(i[n]=!0,e.migrateWarnings.push(n),r&&r.warn&&!e.migrateMute&&(r.warn("JQMIGRATE: "+n),e.migrateTrace&&r.trace&&r.trace()))}function a(t,a,i,o){if(Object.defineProperty)try{return Object.defineProperty(t,a,{configurable:!0,enumerable:!0,get:function(){return r(o),i},set:function(e){r(o),i=e}}),n}catch(s){}e._definePropertyBroken=!0,t[a]=i}var i={};e.migrateWarnings=[],!e.migrateMute&&t.console&&t.console.log&&t.console.log("JQMIGRATE: Logging is active"),e.migrateTrace===n&&(e.migrateTrace=!0),e.migrateReset=function(){i={},e.migrateWarnings.length=0},"BackCompat"===document.compatMode&&r("jQuery is not compatible with Quirks Mode");var o=e("",{size:1}).attr("size")&&e.attrFn,s=e.attr,u=e.attrHooks.value&&e.attrHooks.value.get||function(){return null},c=e.attrHooks.value&&e.attrHooks.value.set||function(){return n},l=/^(?:input|button)$/i,d=/^[238]$/,p=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,f=/^(?:checked|selected)$/i;a(e,"attrFn",o||{},"jQuery.attrFn is deprecated"),e.attr=function(t,a,i,u){var c=a.toLowerCase(),g=t&&t.nodeType;return u&&(4>s.length&&r("jQuery.fn.attr( props, pass ) is deprecated"),t&&!d.test(g)&&(o?a in o:e.isFunction(e.fn[a])))?e(t)[a](i):("type"===a&&i!==n&&l.test(t.nodeName)&&t.parentNode&&r("Can't change the 'type' of an input or button in IE 6/7/8"),!e.attrHooks[c]&&p.test(c)&&(e.attrHooks[c]={get:function(t,r){var a,i=e.prop(t,r);return i===!0||"boolean"!=typeof i&&(a=t.getAttributeNode(r))&&a.nodeValue!==!1?r.toLowerCase():n},set:function(t,n,r){var a;return n===!1?e.removeAttr(t,r):(a=e.propFix[r]||r,a in t&&(t[a]=!0),t.setAttribute(r,r.toLowerCase())),r}},f.test(c)&&r("jQuery.fn.attr('"+c+"') may use property instead of attribute")),s.call(e,t,a,i))},e.attrHooks.value={get:function(e,t){var n=(e.nodeName||"").toLowerCase();return"button"===n?u.apply(this,arguments):("input"!==n&&"option"!==n&&r("jQuery.fn.attr('value') no longer gets properties"),t in e?e.value:null)},set:function(e,t){var a=(e.nodeName||"").toLowerCase();return"button"===a?c.apply(this,arguments):("input"!==a&&"option"!==a&&r("jQuery.fn.attr('value', val) no longer sets properties"),e.value=t,n)}};var g,h,v=e.fn.init,m=e.parseJSON,y=/^([^<]*)(<[\w\W]+>)([^>]*)$/;e.fn.init=function(t,n,a){var i;return t&&"string"==typeof t&&!e.isPlainObject(n)&&(i=y.exec(e.trim(t)))&&i[0]&&("<"!==t.charAt(0)&&r("$(html) HTML strings must start with '<' character"),i[3]&&r("$(html) HTML text after last tag is ignored"),"#"===i[0].charAt(0)&&(r("HTML string cannot start with a '#' character"),e.error("JQMIGRATE: Invalid selector string (XSS)")),n&&n.context&&(n=n.context),e.parseHTML)?v.call(this,e.parseHTML(i[2],n,!0),n,a):v.apply(this,arguments)},e.fn.init.prototype=e.fn,e.parseJSON=function(e){return e||null===e?m.apply(this,arguments):(r("jQuery.parseJSON requires a valid JSON string"),null)},e.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||0>e.indexOf("compatible")&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e.browser||(g=e.uaMatch(navigator.userAgent),h={},g.browser&&(h[g.browser]=!0,h.version=g.version),h.chrome?h.webkit=!0:h.webkit&&(h.safari=!0),e.browser=h),a(e,"browser",e.browser,"jQuery.browser is deprecated"),e.sub=function(){function t(e,n){return new t.fn.init(e,n)}e.extend(!0,t,this),t.superclass=this,t.fn=t.prototype=this(),t.fn.constructor=t,t.sub=this.sub,t.fn.init=function(r,a){return a&&a instanceof e&&!(a instanceof t)&&(a=t(a)),e.fn.init.call(this,r,a,n)},t.fn.init.prototype=t.fn;var n=t(document);return r("jQuery.sub() is deprecated"),t},e.ajaxSetup({converters:{"text json":e.parseJSON}});var b=e.fn.data;e.fn.data=function(t){var a,i,o=this[0];return!o||"events"!==t||1!==arguments.length||(a=e.data(o,t),i=e._data(o,t),a!==n&&a!==i||i===n)?b.apply(this,arguments):(r("Use of jQuery.fn.data('events') is deprecated"),i)};var j=/\/(java|ecma)script/i,w=e.fn.andSelf||e.fn.addBack;e.fn.andSelf=function(){return r("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()"),w.apply(this,arguments)},e.clean||(e.clean=function(t,a,i,o){a=a||document,a=!a.nodeType&&a[0]||a,a=a.ownerDocument||a,r("jQuery.clean() is deprecated");var s,u,c,l,d=[];if(e.merge(d,e.buildFragment(t,a).childNodes),i)for(c=function(e){return!e.type||j.test(e.type)?o?o.push(e.parentNode?e.parentNode.removeChild(e):e):i.appendChild(e):n},s=0;null!=(u=d[s]);s++)e.nodeName(u,"script")&&c(u)||(i.appendChild(u),u.getElementsByTagName!==n&&(l=e.grep(e.merge([],u.getElementsByTagName("script")),c),d.splice.apply(d,[s+1,0].concat(l)),s+=l.length));return d});var Q=e.event.add,x=e.event.remove,k=e.event.trigger,N=e.fn.toggle,T=e.fn.live,M=e.fn.die,S="ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",C=RegExp("\\b(?:"+S+")\\b"),H=/(?:^|\s)hover(\.\S+|)\b/,A=function(t){return"string"!=typeof t||e.event.special.hover?t:(H.test(t)&&r("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'"),t&&t.replace(H,"mouseenter$1 mouseleave$1"))};e.event.props&&"attrChange"!==e.event.props[0]&&e.event.props.unshift("attrChange","attrName","relatedNode","srcElement"),e.event.dispatch&&a(e.event,"handle",e.event.dispatch,"jQuery.event.handle is undocumented and deprecated"),e.event.add=function(e,t,n,a,i){e!==document&&C.test(t)&&r("AJAX events should be attached to document: "+t),Q.call(this,e,A(t||""),n,a,i)},e.event.remove=function(e,t,n,r,a){x.call(this,e,A(t)||"",n,r,a)},e.fn.error=function(){var e=Array.prototype.slice.call(arguments,0);return r("jQuery.fn.error() is deprecated"),e.splice(0,0,"error"),arguments.length?this.bind.apply(this,e):(this.triggerHandler.apply(this,e),this)},e.fn.toggle=function(t,n){if(!e.isFunction(t)||!e.isFunction(n))return N.apply(this,arguments);r("jQuery.fn.toggle(handler, handler...) is deprecated");var a=arguments,i=t.guid||e.guid++,o=0,s=function(n){var r=(e._data(this,"lastToggle"+t.guid)||0)%o;return e._data(this,"lastToggle"+t.guid,r+1),n.preventDefault(),a[r].apply(this,arguments)||!1};for(s.guid=i;a.length>o;)a[o++].guid=i;return this.click(s)},e.fn.live=function(t,n,a){return r("jQuery.fn.live() is deprecated"),T?T.apply(this,arguments):(e(this.context).on(t,this.selector,n,a),this)},e.fn.die=function(t,n){return r("jQuery.fn.die() is deprecated"),M?M.apply(this,arguments):(e(this.context).off(t,this.selector||"**",n),this)},e.event.trigger=function(e,t,n,a){return n||C.test(e)||r("Global events are undocumented and deprecated"),k.call(this,e,t,n||document,a)},e.each(S.split("|"),function(t,n){e.event.special[n]={setup:function(){var t=this;return t!==document&&(e.event.add(document,n+"."+e.guid,function(){e.event.trigger(n,null,t,!0)}),e._data(this,n,e.guid++)),!1},teardown:function(){return this!==document&&e.event.remove(document,n+"."+e._data(this,n)),!1}}})}(jQuery,window); -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | node_modules 15 | npm-debug.log 16 | .DS_Store 17 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2007-2014 Ariel Flesler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/README.md: -------------------------------------------------------------------------------- 1 | # jQuery.ScrollTo 2 | 3 | ### Installation and usage 4 | 5 | Using [bower](https://github.com/twitter/bower): 6 | ```bash 7 | bower install jquery.scrollTo 8 | ``` 9 | Using [composer](http://getcomposer.org/download/): 10 | 11 | Either run 12 | 13 | ``` 14 | php composer.phar require --prefer-dist flesler/jquery.scrollto "*" 15 | ``` 16 | 17 | or add 18 | 19 | ``` 20 | "flesler/jquery.scrollto": "*" 21 | ``` 22 | 23 | to the require section of your composer.json. 24 | 25 | ### Downloading Manually 26 | 27 | If you want the latest stable version, get the latest release from the [releases page](https://github.com/flesler/jquery.scrollTo/releases). 28 | 29 | ### Notes 30 | 31 | * Apart from the target and duration, the plugin can receive a hash of settings. Documentation and examples are included in the source file. 32 | 33 | * If you are interested in animated "same-page-scrolling" using anchors(href="#some_id"), check http://github.com/flesler/jquery.localScroll 34 | 35 | * For a slideshow-like behavior using scrolling, check http://github.com/flesler/jquery.serialScroll 36 | 37 | * The target can be specified as: 38 | * A Number/String specifying a position using px or just the number. 39 | * A string selector that will be relative, to the element that is going to be scrolled, and must match at least one child. 40 | * A DOM element, logically child of the element to scroll. 41 | * A hash { top:x, left:y }, x and y can be any kind of number/string like described above. 42 | 43 | * The plugin supports relative animations 44 | 45 | * 'em' and '%' are not supported as part of the target, because they won't work with jQuery.fn.animate. 46 | 47 | * The plugin might fail to scroll an element, to an inner node that is nested in more scrollable elements. This seems like an odd situation anyway. 48 | 49 | * Both axes ( x, y -> left, top ) can be scrolled, you can send 'x', 'y', 'xy' or 'yx' as 'axis' inside the settings. 50 | 51 | * If 2 axis are scrolled, there's an option to queue the animations, so that the second will start once the first ended ('xy' and 'yx' will have different effects) 52 | 53 | * The option 'margin' can be set to true, then the margin of the target element, will be taken into account and will be deducted. 54 | 55 | * 'margin' will only be valid, if the target is a selector, a DOM element, or a jQuery Object. 56 | 57 | * The option 'offset' allows to scroll less or more than the actual target by a defined amount of pixels. Can be a number(both axes), { top:x, left:y } or a function that returns an object with top & left. 58 | 59 | * The option 'over' lets you add or deduct a fraction of the element's height and width from the final position. so over:0.5 will scroll to the middle of the object. can be specified with {top:x, left:y} 60 | 61 | * Don't forget the callback event is now called 'onAfter', and if queuing is activated, then 'onAfterFirst' can be used. 62 | 63 | * If the first axis to be scrolled, is already positioned, that animation will be skipped, to avoid a delay in the animation. 64 | 65 | * The call to the plugin can be made in 2 different ways: $(...).scrollTo( target, duration, settings ) or $(...).scrollTo( target, settings ). Where one of the settings is 'duration'. 66 | 67 | * If you find any bug, or you have any advice, don't hesitate to open an issue. 68 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery.scrollTo", 3 | "version": "1.4.11", 4 | "description": "Easy element scrolling using jQuery.", 5 | "homepage": "https://github.com/flesler/jquery.scrollTo", 6 | "main": [ 7 | "./jquery.scrollTo.js", 8 | "./jquery.scrollTo.min.js" 9 | ], 10 | "ignore": [ 11 | "**/.*", 12 | "demo", 13 | "tests", 14 | "changes.txt", 15 | "composer.json" 16 | ], 17 | "dependencies": { 18 | "jquery": ">=1.8" 19 | }, 20 | "keywords": [ 21 | "browser", "animated", "animation", 22 | "scrolling", "scroll", "links", "anchors" 23 | ], 24 | "author": { 25 | "name": "Ariel Flesler", 26 | "web": "http://flesler.blogspot.com/" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/changes.txt: -------------------------------------------------------------------------------- 1 | 1.4.11 2 | [Misc] 3 | - Reverted changes from 1.4.10 4 | 5 | 1.4.10 6 | [Enhancement] 7 | - Giving the plugin an AMD module id so it can be required (f.e by localScroll) 8 | 9 | 1.4.9 10 | [Enhancement] 11 | - "offset" setting can now be a function as well (#60) 12 | 13 | 1.4.8 14 | [Enhancement] 15 | - Added support for AMD 16 | 17 | 1.4.7 18 | [Misc] 19 | - Changed spacing 20 | - Changed licensing to MIT 21 | - Repo is compliant with official jquery plugins repository 22 | 23 | 1.4.6 24 | [Fix] 25 | - Fixed first argument of onAfter and onAfterFirst was original target and should be "parsed" target 26 | 27 | 1.4.5 28 | [Fix] 29 | - Fixed passing a negative scroll value crashes 30 | 31 | 1.4.4 32 | [Change] 33 | - Re-released as 1.4.4 to avoid issues with bower 34 | 35 | 1.4.3.1 36 | [Fix] 37 | - Fixed $.scrollTo(0) broken on 1.4.3 38 | 39 | 1.4.3 40 | [Enhancement] 41 | - Limit calculations can be disabled by setting the option 'limit' to false. 42 | - Null target or unmatching selector don't break and fail silently 43 | [Misc] 44 | - Removed support for the deprecated setting 'speed' 45 | [Fix] 46 | - Removed $.browser.webkit so the plugin works with jQuery +1.8 47 | 48 | 1.4.2 49 | [Feature] 50 | - The plugin support percentages as target ('50%' or {top:'50%', left:'45%'}) 51 | - Exposed the max() calculation as $.scrollTo.max 52 | [Enhancement] 53 | - Renamed $.fn.scrollable to $.fn._scrollable to avoid conflicts with other plugins 54 | [Fix] 55 | - Fixing max calculations for regular DOM elements 56 | 57 | 1.4.1 58 | [Feature] 59 | - The target can be 'max' to scroll to the end while keeping it elegant. 60 | [Enhancement] 61 | - Default duration is 0 for jquery +1.3. Means sync animation 62 | - The plugin works on all major browsers, on compat & quirks modes, including iframes. 63 | - In addition to window/document, if html or body are received, the plugin will choose the right one. 64 | [Fix] 65 | - The plugin accepts floating numbers, Thanks Ramin 66 | - Using jQuery.nodeName where neccessary so that this works on xml+xhtml 67 | - The max() internal function wasn't completely accurrate, now it is 98% (except for IE on quirks mode and it's not too noticeable). 68 | 69 | 1.4 70 | [Fix] 71 | - Fixed the problem when scrolling the window to absolute positioned elements on Safari. 72 | - Fixed the problem on Opera 9.5 when scrolling the window. That it always scrolls to 0. 73 | [Feature] 74 | - Added the settings object as 2nd argument to the onAfter callback. 75 | - The 3rd argument of scrollTo can be just a function and it's used as the onAfter. 76 | - Added full support for iframes (even max scroll calculation). 77 | - Instead of $.scrollTo, $(window).scrollTo() and $(document).scrollTo() can be used. 78 | - Added $().scrollable() that returns the real element to scroll, f.e: $(window).scrollable() == [body|html], works for iframes. 79 | [Enhancement] 80 | - Cleaned the code a bit, specially the comments 81 | 82 | 1.3.3 83 | [Change] 84 | - Changed the licensing from GPL to GPL+MIT. 85 | 86 | 1.3.2 87 | [Enhancement] 88 | - Small improvements to make the code shorter. 89 | [Change] 90 | - Removed the last argument received by onAfter as it was the same as the 'this' but jqueryfied. 91 | 92 | 1.3.1 93 | [Feature] 94 | - Exposed $.scrollTo.window() to get the element that needs to be animated, to scroll the window. 95 | - Added option 'over'. 96 | [Enhancement] 97 | - Made the code as short as possible. 98 | [Change] 99 | - Changed the arguments received by onAfter 100 | 101 | 1.3 102 | [Enhancement] 103 | - Added semicolon to the start, for safe file concatenation 104 | - Added a limit check, values below 0 or over the maximum are fixed. 105 | - Now it should work faster, only one of html or body go through all the processing, instead of both for all browsers. 106 | [Fix] 107 | - Fixed the behavior for Opera, which seemed to react to both changes on and . 108 | - The border is also reduced, when 'margin' is set to true. 109 | [Change] 110 | - The option speed has been renamed to duration. 111 | [Feature] 112 | - The duration can be specified with a number as 2nd argument, and the rest of the settings as the third ( like $().animate ) 113 | - Remade the demo 114 | 115 | 1.2.4 116 | [Enhancement] 117 | - The target can be in the form of { top:x, left:y } allowing different position for each axis. 118 | [Feature] 119 | - The option 'offset' has been added, to scroll behind or past the target. Can be a number(both axes) or { top:x, left:y }. 120 | 121 | 1.2.3 122 | [Feature] 123 | - Exposed the defaults. 124 | [Enhancement] 125 | - Made the callback functions receive more parameters. 126 | 127 | 1.2.2 128 | [Fix] 129 | - Fixed a bug, I didn't have to add the scrolled amount if it was body or html. 130 | 131 | 1.2 132 | [Change] 133 | - The option 'onafter' is now called 'onAfter'. 134 | [Feature] 135 | - Two axes can be scrolled together, this is set with the option 'axis'. 136 | - In case 2 axes are chosen, the scrolling can be queued: one scrolls, and then the other. 137 | - There's an intermediary event, 'onAfterFirst' called in case the axes are queued, after the first ends. 138 | - If the option 'margin' is set to true, the plugin will take in account, the margin of the target(no use if target is a value). -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flesler/jquery.scrollto", 3 | "description": "Easy element scrolling using jQuery.", 4 | "keywords": [ 5 | "browser", "animated", "animation", 6 | "scrolling", "scroll", "links", "anchors" 7 | ], 8 | "homepage": "https://github.com/flesler/jquery.scrollTo", 9 | "support": { 10 | "issues": "https://github.com/flesler/jquery.scrollTo/issues", 11 | "source": "https://github.com/flesler/jquery.scrollTo" 12 | }, 13 | "authors": [ 14 | { 15 | "name": "Ariel Flesler", 16 | "web": "http://flesler.blogspot.com/" 17 | } 18 | ], 19 | "require": { 20 | "components/jquery": ">=1.8" 21 | }, 22 | "extra": { 23 | "component": { 24 | "scripts": [ 25 | "jquery.scrollTo.js" 26 | ], 27 | "files": [ 28 | "jquery.scrollTo.min.js" 29 | ] 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/demo/css/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | padding:5px; 3 | height:1600px; 4 | font-family: Verdana, sans-serif; 5 | background-color: #DDD; 6 | } 7 | ul,li,h1,h2,h3,p{ 8 | list-style:none; 9 | padding:0; 10 | margin:0; 11 | } 12 | .part{ 13 | border:1px solid black; 14 | background-color:white; 15 | } 16 | .part h3{ 17 | color:#933; 18 | } 19 | #toc{ 20 | display:block; 21 | padding:10px; 22 | position:relative; 23 | margin:15px 0; 24 | float:left; 25 | width:305px; 26 | } 27 | #toc h3{ 28 | padding-bottom:10px; 29 | } 30 | #toc h3 strong{ 31 | font-size:13px; 32 | color:black; 33 | } 34 | #links{ 35 | border:1px solid black; 36 | width:210px; 37 | padding:10px; 38 | float:right; 39 | margin-top:-30px; 40 | } 41 | #links h3{ 42 | color:#933; 43 | } 44 | #links ul{ 45 | padding: 8px 0 3px 20px; 46 | } 47 | #links li{ 48 | list-style-type:circle; 49 | } 50 | #links a{ 51 | color:#69C; 52 | } 53 | 54 | #toc li, #links li{ 55 | list-style-type:circle; 56 | padding-left:5px; 57 | margin-left:15px; 58 | } 59 | #toc a{ 60 | color:#69C; 61 | } 62 | div.section{ 63 | border:1px black solid; 64 | width:950px; 65 | padding:10px; 66 | margin: 5px 0; 67 | position:relative; 68 | clear:both; 69 | } 70 | div.section h3{ 71 | margin-bottom:10px; 72 | } 73 | div.section li{ 74 | float:left; 75 | } 76 | div.pane{ 77 | overflow:auto; 78 | clear:left; 79 | margin: 10px 0 0 10px; 80 | position:relative; 81 | width:826px; 82 | height:322px; 83 | } 84 | ul.elements{ 85 | background-color:#5B739C; 86 | } 87 | ul.elements li{ 88 | width:200px; 89 | height:100px; 90 | font-weight:bolder; 91 | border:1px black solid; 92 | text-align:center; 93 | padding:50px; 94 | position:relative; 95 | background-color:#DDD; 96 | } 97 | ul.elements li a{ 98 | bottom:20px; 99 | color:#933; 100 | font-size:12px; 101 | left:125px; 102 | position:absolute; 103 | } 104 | ul.elements li p{ 105 | color:#666; 106 | } 107 | #pane-options ul.elements li{ 108 | margin:5px; 109 | } 110 | #pane-options{ 111 | margin-bottom:10px; 112 | } 113 | ul.links{ 114 | height:20px; 115 | overflow:hidden; 116 | } 117 | ul.links a{ 118 | color:#69C; 119 | margin:0pt 5px; 120 | } 121 | .clear{ 122 | clear:left; 123 | } 124 | h3 span{ 125 | position:absolute; 126 | } 127 | .message{ 128 | background:#EEE; 129 | border:1px solid #999; 130 | color:#333; 131 | font-size:12px; 132 | font-weight:normal; 133 | padding:1px; 134 | margin-top:2px; 135 | } 136 | 137 | h1{ 138 | color:#5B739C; 139 | } 140 | h1 strong{ 141 | font-size:13px; 142 | color:#777; 143 | } -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/demo/css/style.old.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-color: #DDD; 3 | } 4 | .container li,div.pane{ 5 | height:200px; 6 | font-weight:bolder; 7 | position:relative; 8 | } 9 | ul{ 10 | list-style:none; 11 | padding:0; 12 | margin:0; 13 | } 14 | .container a{ 15 | color:black; 16 | position:absolute; 17 | bottom:10px; 18 | } 19 | p{ 20 | margin:0; 21 | } 22 | .container{ 23 | border:1px black solid; 24 | margin:30px; 25 | overflow:auto; 26 | position:relative; 27 | width:80%; 28 | height:300px; 29 | } 30 | .container ul{ 31 | padding:0; 32 | } 33 | #x{ 34 | height:217px; 35 | } 36 | #x li,#xy li{ 37 | width:300px; 38 | float:left; 39 | } 40 | 41 | h1{ 42 | color:#5B739C; 43 | } 44 | h1 strong{ 45 | font-size:13px; 46 | color:#777; 47 | } 48 | 49 | #links{ 50 | border:1px solid black; 51 | width:210px; 52 | padding:10px; 53 | float:right; 54 | margin-top:-55px; 55 | background-color:white; 56 | } 57 | #links h3{ 58 | color:#933; 59 | margin:5px; 60 | } 61 | #links ul{ 62 | padding: 8px 0 3px 20px; 63 | } 64 | #links li{ 65 | list-style-type:circle; 66 | } 67 | #links a{ 68 | color:#69C; 69 | } -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/demo/index.old.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery.ScrollTo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 38 | 39 | 40 |

jQuery.ScrollTo by Ariel Flesler

41 |
52 |

53 | 54 |
55 | 65 |
66 | 67 | 87 | 88 |
89 | 121 |
122 |
123 |
124 |
125 |
126 |
127 | 128 | 129 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/jquery.scrollTo.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery.ScrollTo 3 | * Copyright (c) 2007-2014 Ariel Flesler - afleslergmailcom | http://flesler.blogspot.com 4 | * Licensed under MIT 5 | * http://flesler.blogspot.com/2007/10/jqueryscrollto.html 6 | * @projectDescription Easy element scrolling using jQuery. 7 | * @author Ariel Flesler 8 | * @version 1.4.11 9 | */ 10 | 11 | ;(function(plugin) { 12 | // AMD Support 13 | if (typeof define === 'function' && define.amd) { 14 | define(['jquery'], plugin); 15 | } else { 16 | plugin(jQuery); 17 | } 18 | }(function($) { 19 | 20 | var $scrollTo = $.scrollTo = function( target, duration, settings ) { 21 | return $(window).scrollTo( target, duration, settings ); 22 | }; 23 | 24 | $scrollTo.defaults = { 25 | axis:'xy', 26 | duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1, 27 | limit:true 28 | }; 29 | 30 | // Returns the element that needs to be animated to scroll the window. 31 | // Kept for backwards compatibility (specially for localScroll & serialScroll) 32 | $scrollTo.window = function( scope ) { 33 | return $(window)._scrollable(); 34 | }; 35 | 36 | // Hack, hack, hack :) 37 | // Returns the real elements to scroll (supports window/iframes, documents and regular nodes) 38 | $.fn._scrollable = function() { 39 | return this.map(function() { 40 | var elem = this, 41 | isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1; 42 | 43 | if (!isWin) 44 | return elem; 45 | 46 | var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem; 47 | 48 | return /webkit/i.test(navigator.userAgent) || doc.compatMode == 'BackCompat' ? 49 | doc.body : 50 | doc.documentElement; 51 | }); 52 | }; 53 | 54 | $.fn.scrollTo = function( target, duration, settings ) { 55 | if (typeof duration == 'object') { 56 | settings = duration; 57 | duration = 0; 58 | } 59 | if (typeof settings == 'function') 60 | settings = { onAfter:settings }; 61 | 62 | if (target == 'max') 63 | target = 9e9; 64 | 65 | settings = $.extend( {}, $scrollTo.defaults, settings ); 66 | // Speed is still recognized for backwards compatibility 67 | duration = duration || settings.duration; 68 | // Make sure the settings are given right 69 | settings.queue = settings.queue && settings.axis.length > 1; 70 | 71 | if (settings.queue) 72 | // Let's keep the overall duration 73 | duration /= 2; 74 | settings.offset = both( settings.offset ); 75 | settings.over = both( settings.over ); 76 | 77 | return this._scrollable().each(function() { 78 | // Null target yields nothing, just like jQuery does 79 | if (target == null) return; 80 | 81 | var elem = this, 82 | $elem = $(elem), 83 | targ = target, toff, attr = {}, 84 | win = $elem.is('html,body'); 85 | 86 | switch (typeof targ) { 87 | // A number will pass the regex 88 | case 'number': 89 | case 'string': 90 | if (/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)) { 91 | targ = both( targ ); 92 | // We are done 93 | break; 94 | } 95 | // Relative selector, no break! 96 | targ = $(targ,this); 97 | if (!targ.length) return; 98 | case 'object': 99 | // DOMElement / jQuery 100 | if (targ.is || targ.style) 101 | // Get the real position of the target 102 | toff = (targ = $(targ)).offset(); 103 | } 104 | 105 | var offset = $.isFunction(settings.offset) && settings.offset(elem, targ) || settings.offset; 106 | 107 | $.each( settings.axis.split(''), function( i, axis ) { 108 | var Pos = axis == 'x' ? 'Left' : 'Top', 109 | pos = Pos.toLowerCase(), 110 | key = 'scroll' + Pos, 111 | old = elem[key], 112 | max = $scrollTo.max(elem, axis); 113 | 114 | if (toff) {// jQuery / DOMElement 115 | attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] ); 116 | 117 | // If it's a dom element, reduce the margin 118 | if (settings.margin) { 119 | attr[key] -= parseInt(targ.css('margin'+Pos)) || 0; 120 | attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0; 121 | } 122 | 123 | attr[key] += offset[pos] || 0; 124 | 125 | if(settings.over[pos]) 126 | // Scroll to a fraction of its width/height 127 | attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos]; 128 | } else { 129 | var val = targ[pos]; 130 | // Handle percentage values 131 | attr[key] = val.slice && val.slice(-1) == '%' ? 132 | parseFloat(val) / 100 * max 133 | : val; 134 | } 135 | 136 | // Number or 'number' 137 | if (settings.limit && /^\d+$/.test(attr[key])) 138 | // Check the limits 139 | attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max ); 140 | 141 | // Queueing axes 142 | if (!i && settings.queue) { 143 | // Don't waste time animating, if there's no need. 144 | if (old != attr[key]) 145 | // Intermediate animation 146 | animate( settings.onAfterFirst ); 147 | // Don't animate this axis again in the next iteration. 148 | delete attr[key]; 149 | } 150 | }); 151 | 152 | animate( settings.onAfter ); 153 | 154 | function animate( callback ) { 155 | $elem.animate( attr, duration, settings.easing, callback && function() { 156 | callback.call(this, targ, settings); 157 | }); 158 | }; 159 | 160 | }).end(); 161 | }; 162 | 163 | // Max scrolling position, works on quirks mode 164 | // It only fails (not too badly) on IE, quirks mode. 165 | $scrollTo.max = function( elem, axis ) { 166 | var Dim = axis == 'x' ? 'Width' : 'Height', 167 | scroll = 'scroll'+Dim; 168 | 169 | if (!$(elem).is('html,body')) 170 | return elem[scroll] - $(elem)[Dim.toLowerCase()](); 171 | 172 | var size = 'client' + Dim, 173 | html = elem.ownerDocument.documentElement, 174 | body = elem.ownerDocument.body; 175 | 176 | return Math.max( html[scroll], body[scroll] ) 177 | - Math.min( html[size] , body[size] ); 178 | }; 179 | 180 | function both( val ) { 181 | return $.isFunction(val) || typeof val == 'object' ? val : { top:val, left:val }; 182 | }; 183 | 184 | // AMD requirement 185 | return $scrollTo; 186 | })); 187 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/jquery.scrollTo.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2007-2014 Ariel Flesler - afleslergmailcom | http://flesler.blogspot.com 3 | * Licensed under MIT 4 | * @author Ariel Flesler 5 | * @version 1.4.11 6 | */ 7 | ;(function(a){if(typeof define==='function'&&define.amd){define(['jquery'],a)}else{a(jQuery)}}(function($){var j=$.scrollTo=function(a,b,c){return $(window).scrollTo(a,b,c)};j.defaults={axis:'xy',duration:parseFloat($.fn.jquery)>=1.3?0:1,limit:true};j.window=function(a){return $(window)._scrollable()};$.fn._scrollable=function(){return this.map(function(){var a=this,isWin=!a.nodeName||$.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!isWin)return a;var b=(a.contentWindow||a).document||a.ownerDocument||a;return/webkit/i.test(navigator.userAgent)||b.compatMode=='BackCompat'?b.body:b.documentElement})};$.fn.scrollTo=function(f,g,h){if(typeof g=='object'){h=g;g=0}if(typeof h=='function')h={onAfter:h};if(f=='max')f=9e9;h=$.extend({},j.defaults,h);g=g||h.duration;h.queue=h.queue&&h.axis.length>1;if(h.queue)g/=2;h.offset=both(h.offset);h.over=both(h.over);return this._scrollable().each(function(){if(f==null)return;var d=this,$elem=$(d),targ=f,toff,attr={},win=$elem.is('html,body');switch(typeof targ){case'number':case'string':if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)){targ=both(targ);break}targ=$(targ,this);if(!targ.length)return;case'object':if(targ.is||targ.style)toff=(targ=$(targ)).offset()}var e=$.isFunction(h.offset)&&h.offset(d,targ)||h.offset;$.each(h.axis.split(''),function(i,a){var b=a=='x'?'Left':'Top',pos=b.toLowerCase(),key='scroll'+b,old=d[key],max=j.max(d,a);if(toff){attr[key]=toff[pos]+(win?0:old-$elem.offset()[pos]);if(h.margin){attr[key]-=parseInt(targ.css('margin'+b))||0;attr[key]-=parseInt(targ.css('border'+b+'Width'))||0}attr[key]+=e[pos]||0;if(h.over[pos])attr[key]+=targ[a=='x'?'width':'height']()*h.over[pos]}else{var c=targ[pos];attr[key]=c.slice&&c.slice(-1)=='%'?parseFloat(c)/100*max:c}if(h.limit&&/^\d+$/.test(attr[key]))attr[key]=attr[key]<=0?0:Math.min(attr[key],max);if(!i&&h.queue){if(old!=attr[key])animate(h.onAfterFirst);delete attr[key]}});animate(h.onAfter);function animate(a){$elem.animate(attr,g,h.easing,a&&function(){a.call(this,targ,h)})}}).end()};j.max=function(a,b){var c=b=='x'?'Width':'Height',scroll='scroll'+c;if(!$(a).is('html,body'))return a[scroll]-$(a)[c.toLowerCase()]();var d='client'+c,html=a.ownerDocument.documentElement,body=a.ownerDocument.body;return Math.max(html[scroll],body[scroll])-Math.min(html[d],body[d])};function both(a){return $.isFunction(a)||typeof a=='object'?a:{top:a,left:a}};return j})); 8 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/scrollTo.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scrollTo", 3 | "title": "Ariel Flesler's jQuery scrollTo", 4 | "description": "Easy element scrolling using jQuery.", 5 | "keywords": ["browser", "animated", "animation", "scrolling", "scroll", "links", "anchors"], 6 | "version": "1.4.11", 7 | "author": { 8 | "name": "Ariel Flesler", 9 | "email": "aflesler@gmail.com", 10 | "url": "http://flesler.blogspot.com" 11 | }, 12 | "maintainers": [{ 13 | "name": "Ariel Flesler", 14 | "email": "aflesler@gmail.com", 15 | "url": "http://flesler.blogspot.com" 16 | }], 17 | "licenses": [{ 18 | "type": "MIT", 19 | "url": "https://github.com/flesler/jquery.scrollTo/blob/master/LICENSE" 20 | }], 21 | "homepage": "https://github.com/flesler/jquery.scrollTo", 22 | "docs": "http://flesler.blogspot.com/2007/10/jqueryscrollto.html", 23 | "bugs": "https://github.com/flesler/jquery.scrollTo/issues", 24 | "download": "https://github.com/flesler/jquery.scrollTo/releases", 25 | "demo": "http://demos.flesler.com/jquery/scrollTo", 26 | "dependencies": { 27 | "jquery": ">=1.8" 28 | } 29 | } -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/tests/WinMaxY-compat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery.ScrollTo 6 | 7 | 8 | 9 | 10 | 11 |

jQuery.ScrollTo - Test Window MaxY - Compat Mode

12 | 13 |
14 |   15 |
16 | 19 | 20 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/tests/WinMaxY-quirks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jQuery.ScrollTo 5 | 6 | 7 | 8 | 9 | 10 |

jQuery.ScrollTo - Test Window MaxY - Quirks Mode

11 | 12 |
13 |   14 |
15 | 18 | 19 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/tests/WinMaxY-to-iframe-compat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery.ScrollTo 6 | 7 | 8 | 9 | 10 | 11 |

jQuery.ScrollTo - Test Window MaxY to Iframe - Compat Mode

12 | 13 | 14 | 15 | 20 | 21 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/tests/WinMaxY-to-iframe-quirks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jQuery.ScrollTo 5 | 6 | 7 | 8 | 9 | 10 |

jQuery.ScrollTo - Test Window MaxY to Iframe - Quirks Mode

11 | 12 | 13 | 14 | 19 | 20 | -------------------------------------------------------------------------------- /angular-seo-web/src/main/webapp/assets/plugins/jquery-scrollTo/tests/WinMaxY-with-iframe-compat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery.ScrollTo 6 | 7 | 8 |

jQuery.ScrollTo - Test Window MaxY - Compat Mode

9 | 10 |