├── .gitignore ├── example ├── .meteor │ ├── .gitignore │ ├── cordova-plugins │ ├── release │ ├── platforms │ ├── .finished-upgraders │ ├── packages │ ├── .id │ └── versions ├── packages │ └── yasinuslu:blaze-meta ├── example.css ├── example.html └── example.js ├── lib ├── meta.html └── meta.js ├── smart.json ├── .versions ├── package.js ├── LICENSE ├── versions.json ├── README.md └── tests └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .build* 2 | -------------------------------------------------------------------------------- /example/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /example/.meteor/cordova-plugins: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.0.3.1 2 | -------------------------------------------------------------------------------- /example/packages/yasinuslu:blaze-meta: -------------------------------------------------------------------------------- 1 | ../../ -------------------------------------------------------------------------------- /example/.meteor/platforms: -------------------------------------------------------------------------------- 1 | browser 2 | server 3 | -------------------------------------------------------------------------------- /example/example.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ 2 | -------------------------------------------------------------------------------- /lib/meta.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | -------------------------------------------------------------------------------- /example/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # 3 | # 'meteor add' and 'meteor remove' will edit this file for you, 4 | # but you can also edit it by hand. 5 | 6 | meteor-platform 7 | autopublish 8 | insecure 9 | yasinuslu:blaze-meta 10 | 11 | -------------------------------------------------------------------------------- /example/example.html: -------------------------------------------------------------------------------- 1 | 2 | example 3 | 4 | 5 | 6 |

Welcome to Meteor!

7 | 8 | {{> hello}} 9 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /smart.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blaze-meta", 3 | "description": "A simple package that makes easy to manage your meta-data", 4 | "homepage": "https://github.com/yasinuslu/blaze-meta", 5 | "author": "Yasin Uslu(https://github.com/yasinuslu)", 6 | "version": "0.1.2", 7 | "git": "https://github.com/yasinuslu/blaze-meta.git" 8 | } -------------------------------------------------------------------------------- /example/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | m1tngpmy2gag1dsnwqj 8 | -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | if (Meteor.isClient) { 2 | // counter starts at 0 3 | Session.setDefault("counter", 0); 4 | 5 | Template.hello.helpers({ 6 | counter: function () { 7 | return Session.get("counter"); 8 | } 9 | }); 10 | 11 | Template.hello.events({ 12 | 'click button': function () { 13 | // increment the counter when button is clicked 14 | Session.set("counter", Session.get("counter") + 1); 15 | } 16 | }); 17 | } 18 | 19 | if (Meteor.isServer) { 20 | Meteor.startup(function () { 21 | // code to run on server at startup 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /.versions: -------------------------------------------------------------------------------- 1 | base64@1.0.3 2 | binary-heap@1.0.3 3 | blaze@2.1.2 4 | blaze-tools@1.0.3 5 | callback-hook@1.0.3 6 | check@1.0.5 7 | ddp@1.1.0 8 | deps@1.0.7 9 | ejson@1.0.6 10 | geojson-utils@1.0.3 11 | html-tools@1.0.4 12 | htmljs@1.0.4 13 | id-map@1.0.3 14 | jquery@1.11.3_2 15 | json@1.0.3 16 | local-test:yasinuslu:blaze-meta@0.3.3 17 | logging@1.0.7 18 | meteor@1.1.6 19 | minifiers@1.1.5 20 | minimongo@1.0.8 21 | mongo@1.1.0 22 | observe-sequence@1.0.6 23 | ordered-dict@1.0.3 24 | random@1.0.3 25 | reactive-dict@1.1.0 26 | reactive-var@1.0.5 27 | retry@1.0.3 28 | spacebars-compiler@1.0.6 29 | templating@1.1.1 30 | test-helpers@1.0.4 31 | tinytest@1.0.5 32 | tracker@1.0.7 33 | ui@1.0.6 34 | underscore@1.0.3 35 | yasinuslu:blaze-meta@0.3.3 36 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | summary: 'Blaze-meta makes it super simple to manage SEO data.', 3 | version: "0.3.3", 4 | git: "https://github.com/yasinuslu/blaze-meta.git", 5 | name: "yasinuslu:blaze-meta" 6 | }); 7 | 8 | Package.on_use(function(api) { 9 | api.use("underscore", "client"); 10 | api.use("tracker", "client"); 11 | api.use("reactive-dict", "client"); 12 | api.use("ui", "client"); 13 | api.use("templating", "client"); 14 | 15 | api.add_files("lib/meta.html", "client"); 16 | api.add_files("lib/meta.js", "client"); 17 | 18 | api.export("Meta"); 19 | 20 | // check if is this Meteor 0.9 and add 0.9 related code 21 | if (api.versionsFrom) { 22 | api.versionsFrom('METEOR@0.9.1'); 23 | } 24 | }); 25 | 26 | Package.on_test(function(api) { 27 | api.use(["yasinuslu:blaze-meta", "tinytest", "test-helpers", "underscore", "jquery"], "client"); 28 | 29 | api.add_files("tests/test.js", "client"); 30 | }); 31 | -------------------------------------------------------------------------------- /example/.meteor/versions: -------------------------------------------------------------------------------- 1 | application-configuration@1.0.4 2 | autopublish@1.0.2 3 | autoupdate@1.1.5 4 | base64@1.0.2 5 | binary-heap@1.0.2 6 | blaze@2.0.4 7 | blaze-tools@1.0.2 8 | boilerplate-generator@1.0.2 9 | callback-hook@1.0.2 10 | check@1.0.4 11 | ddp@1.0.14 12 | deps@1.0.6 13 | ejson@1.0.5 14 | fastclick@1.0.2 15 | follower-livedata@1.0.3 16 | geojson-utils@1.0.2 17 | html-tools@1.0.3 18 | htmljs@1.0.3 19 | http@1.0.10 20 | id-map@1.0.2 21 | insecure@1.0.2 22 | jquery@1.11.3 23 | json@1.0.2 24 | launch-screen@1.0.1 25 | livedata@1.0.12 26 | logging@1.0.6 27 | meteor@1.1.4 28 | meteor-platform@1.2.1 29 | minifiers@1.1.3 30 | minimongo@1.0.6 31 | mobile-status-bar@1.0.2 32 | mongo@1.0.11 33 | observe-sequence@1.0.4 34 | ordered-dict@1.0.2 35 | random@1.0.2 36 | reactive-dict@1.0.5 37 | reactive-var@1.0.4 38 | reload@1.1.2 39 | retry@1.0.2 40 | routepolicy@1.0.4 41 | session@1.0.5 42 | spacebars@1.0.5 43 | spacebars-compiler@1.0.4 44 | templating@1.0.11 45 | tracker@1.0.5 46 | ui@1.0.5 47 | underscore@1.0.2 48 | url@1.0.3 49 | webapp@1.1.6 50 | webapp-hashing@1.0.2 51 | yasinuslu:blaze-meta@0.3.2 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 MeteorHacks Pvt Ltd (Sri Lanka). 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | [ 4 | "base64", 5 | "1.0.1" 6 | ], 7 | [ 8 | "blaze", 9 | "2.0.2" 10 | ], 11 | [ 12 | "deps", 13 | "1.0.5" 14 | ], 15 | [ 16 | "ejson", 17 | "1.0.4" 18 | ], 19 | [ 20 | "geojson-utils", 21 | "1.0.1" 22 | ], 23 | [ 24 | "htmljs", 25 | "1.0.2" 26 | ], 27 | [ 28 | "id-map", 29 | "1.0.1" 30 | ], 31 | [ 32 | "jquery", 33 | "1.0.1" 34 | ], 35 | [ 36 | "json", 37 | "1.0.1" 38 | ], 39 | [ 40 | "meteor", 41 | "1.1.2" 42 | ], 43 | [ 44 | "minimongo", 45 | "1.0.4" 46 | ], 47 | [ 48 | "observe-sequence", 49 | "1.0.3" 50 | ], 51 | [ 52 | "ordered-dict", 53 | "1.0.1" 54 | ], 55 | [ 56 | "random", 57 | "1.0.1" 58 | ], 59 | [ 60 | "reactive-dict", 61 | "1.0.4" 62 | ], 63 | [ 64 | "reactive-var", 65 | "1.0.3" 66 | ], 67 | [ 68 | "session", 69 | "1.0.3" 70 | ], 71 | [ 72 | "templating", 73 | "1.0.8" 74 | ], 75 | [ 76 | "tracker", 77 | "1.0.3" 78 | ], 79 | [ 80 | "ui", 81 | "1.0.4" 82 | ], 83 | [ 84 | "underscore", 85 | "1.0.1" 86 | ] 87 | ], 88 | "pluginDependencies": [], 89 | "toolVersion": "meteor-tool@1.0.34", 90 | "format": "1.0" 91 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | blaze-meta 2 | ========== 3 | 4 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/yasinuslu/blaze-meta?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | A meteor package that makes it easy to manage meta-data 7 | 8 | ## This package is currently unmaintained 9 | 10 | - If you're looking for iron-router integration you should check out https://atmospherejs.com/lookback/seo 11 | 12 | This package will probably be deprecated in near future, check out https://github.com/kadirahq/meteor-dochead 13 | 14 | ``` 15 | meteor add yasinuslu:blaze-meta 16 | ``` 17 | 18 | ```js 19 | Meta.config({ 20 | options: { 21 | title: "Default Title", 22 | suffix: "Suffix" 23 | } 24 | }); 25 | 26 | Meta.setTitle("") => "Default Title" 27 | Meta.setTitle("test") => "test | Suffix" 28 | 29 | Meta.set("og:title", "Title"); 30 | Meta.set("og:description", "Description"); 31 | 32 | Meta.unset("og:title"); 33 | ``` 34 | 35 | or 36 | 37 | ```js 38 | Meta.set({ 39 | name: 'property', 40 | property: 'og:title', 41 | content: 'Titleee' 42 | }); 43 | ``` 44 | 45 | or 46 | 47 | ```js 48 | Meta.set([ 49 | { 50 | name: "name", 51 | property: "apple-mobile-web-app-capable", 52 | content: "yes" 53 | }, 54 | { 55 | name: "property", 56 | property: "og:locale", 57 | content: "en_GB" 58 | } 59 | ]); 60 | ``` 61 | 62 | which results in: 63 | 64 | ```html 65 | 66 | ``` 67 | 68 | It will be updated on DOM automatically. 69 | -------------------------------------------------------------------------------- /tests/test.js: -------------------------------------------------------------------------------- 1 | Tinytest.add("Title", function(test) { 2 | var config = { 3 | options: { 4 | title: "Default Title", 5 | suffix: "Suffix" 6 | } 7 | } 8 | 9 | Meta.config(config); 10 | 11 | Meta.setTitle(""); 12 | test.equal(Meta.getTitle(), config.options.title, "Is default title working ?"); 13 | 14 | Meta.setTitle("asd"); 15 | test.equal(Meta.getTitle(), "asd | " + config.options.suffix, "Is suffix working ?"); 16 | 17 | Meta.setTitle(function() { 18 | return "test" 19 | }); 20 | test.equal(Meta.getTitle(), "test | " + config.options.suffix, "can title be function ?"); 21 | }); 22 | 23 | // Tinytest.add("Tags", function(test) { 24 | // var meta = { 25 | // "og:title": "Titlee" 26 | // } 27 | 28 | // Meta.set("og:title", meta["og:title"]); 29 | // test.equal(Meta.hash()["og:title"], meta["og:title"], "Can i add meta tag"); 30 | 31 | // Meta.unset("og:title"); 32 | // test.isUndefined(Meta.hash()["og:title"], "Can i remove meta tag"); 33 | // }); 34 | 35 | testAsyncMulti("HTML", [ 36 | 37 | function(test, expect) { 38 | Meta.setTitle("test"); 39 | 40 | Tracker.flush(); 41 | 42 | Meteor.defer(expect(function() { 43 | test.equal(document.title, Meta.getTitle(), "is title set on DOM ?"); 44 | })); 45 | }, 46 | function(test, expect) { 47 | Meta.setTitle(function() { 48 | return "My Title" 49 | }); 50 | 51 | Tracker.flush(); 52 | 53 | Meteor.defer(expect(function() { 54 | test.equal(document.title, Meta.getTitle(), "is title set on DOM ?"); 55 | })); 56 | }, 57 | function(test, expect) { 58 | var title = "Open Graph Title"; 59 | Meta.set("og:title", title); 60 | Meta.set("removed", "Will be removed"); 61 | Meta.unset("removed"); 62 | 63 | Tracker.flush(); 64 | 65 | debugger; 66 | 67 | Meteor.defer(expect(function() { 68 | test.equal($("meta[property='og:title']").attr("content"), title, "is og:title set on DOM ?"); 69 | test.isUndefined($("meta[property='removed']").attr("content"), "can remove a tag on DOM ?"); 70 | })); 71 | }, 72 | 73 | function(test, expect) { 74 | 75 | Meta.set([ 76 | { 77 | name: "name", 78 | property: "apple-mobile-web-app-capable", 79 | content: "yes" 80 | }, 81 | { 82 | name: "property", 83 | property: "og:locale", 84 | content: "en_GB" 85 | }, 86 | { 87 | name: "attrName", 88 | property: "tag3", 89 | content: "attrContent" 90 | } 91 | ]); 92 | Meta.unset("tag3"); 93 | 94 | Tracker.flush(); 95 | 96 | debugger; 97 | 98 | Meteor.defer(expect(function() { 99 | test.equal($("meta[name='apple-mobile-web-app-capable']").attr("content"), "yes", "is apple-mobile-web-app-capable set on DOM?"); 100 | test.equal($("meta[property='og:locale']").attr("content"), "en_GB", "is og:locale set to en_GB on DOM?"); 101 | test.isUndefined($("meta[attrName='tag3']").attr("content"), "can remove tag3 on DOM ?"); 102 | })); 103 | } 104 | ]); -------------------------------------------------------------------------------- /lib/meta.js: -------------------------------------------------------------------------------- 1 | Meta = { 2 | options: { 3 | title: "Default Title", 4 | suffix: "Suffix for title", 5 | separator: " | " 6 | }, 7 | 8 | dict: new ReactiveDict(), 9 | 10 | converters: { 11 | title: function(title) { 12 | if (_.isFunction(title)) { 13 | title = title(); 14 | } 15 | 16 | if (_.isEmpty(title)) { 17 | return Meta.options.title || ""; 18 | } 19 | 20 | if (!_.isEmpty(Meta.options.suffix)) { 21 | title = title + Meta.options.separator + Meta.options.suffix; 22 | } 23 | 24 | return title; 25 | }, 26 | 27 | meta: function(property, content) { 28 | var options = _.isObject(property) ? property : { 29 | name: 'property', 30 | property: property, 31 | content: content 32 | }; 33 | 34 | return options; 35 | } 36 | }, 37 | 38 | init: function() { 39 | Meta.setTitle(""); 40 | }, 41 | 42 | config: function(opts) { 43 | _.extend(Meta.options, opts.options); 44 | _.extend(Meta.converters, opts.converters); 45 | }, 46 | 47 | setVar: function(key, value) { 48 | Meta.dict.set(key, value); 49 | }, 50 | 51 | getVar: function(key) { 52 | return Meta.dict.get(key); 53 | }, 54 | 55 | set: function(property, content) { 56 | var properties = property; 57 | if (!_.isArray(property)) { 58 | properties = new Array(property); 59 | } 60 | 61 | properties.forEach(function(property, key) { 62 | var meta; 63 | Tracker.nonreactive(function() { 64 | meta = Meta.getVar("tag") || {}; 65 | }); 66 | var m = Meta.converters.meta(property, content); 67 | meta[m.property] = m; 68 | Meta.setVar("tag", meta); 69 | }); 70 | 71 | }, 72 | 73 | unset: function(property) { 74 | var meta; 75 | Tracker.nonreactive(function() { 76 | meta = Meta.getVar("tag") || {}; 77 | }); 78 | var m = Meta.converters.meta(property); 79 | delete meta[m.property]; 80 | Meta.setVar("tag", meta); 81 | }, 82 | 83 | unsetAll: function () { 84 | _.each(Meta.arr(), function (item) { 85 | Meta.unset(item.property); 86 | }); 87 | }, 88 | 89 | setTitle: function(title) { 90 | Meta.setVar("title", Meta.converters.title(title)); 91 | }, 92 | 93 | getTitle: function() { 94 | return Meta.getVar("title"); 95 | }, 96 | 97 | arr: function() { 98 | var meta = Meta.getVar("tag"); 99 | return _.toArray(meta); 100 | }, 101 | 102 | hash: function() { 103 | return Meta.getVar("tag"); 104 | } 105 | }; 106 | 107 | Template.MetaTags.helpers({ 108 | 109 | tags: function() { 110 | return Meta.arr(); 111 | }, 112 | 113 | _MetaTag: function() { 114 | var attrs = {}; 115 | attrs[this.name] = this.property; 116 | attrs.content = this.content; 117 | return Blaze.Template(function() { 118 | return HTML.META(attrs); 119 | }); 120 | } 121 | }); 122 | 123 | Meteor.startup(function() { 124 | Meta.init(); 125 | 126 | Blaze.render(Template.MetaTags, document.head); 127 | 128 | Tracker.autorun(function() { 129 | document.title = Meta.getTitle(); 130 | }); 131 | }); 132 | --------------------------------------------------------------------------------