summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/node_modules/okschema/index.js5
-rw-r--r--examples/db.json24
-rw-r--r--examples/index.js1
-rw-r--r--themes/okadmin/public/css/main.css50
-rw-r--r--themes/okadmin/public/js/app.js26
-rw-r--r--themes/okadmin/public/js/parser.js282
-rw-r--r--themes/okadmin/templates/partials/inputs.liquid10
-rw-r--r--themes/okadmin/templates/partials/tail.liquid2
8 files changed, 392 insertions, 8 deletions
diff --git a/app/node_modules/okschema/index.js b/app/node_modules/okschema/index.js
index 0544c79..355a2ee 100644
--- a/app/node_modules/okschema/index.js
+++ b/app/node_modules/okschema/index.js
@@ -21,6 +21,11 @@ var types = {
// Let parent handle validation
assertValid: function(spec, value) {}
},
+ 'video': {
+ parent: {type: 'string'},
+ // Let parent handle validation
+ assertValid: function(spec, value) {}
+ },
'enum': {
parent: {type: 'string'},
assertValid: function(spec, value) {
diff --git a/examples/db.json b/examples/db.json
index ab4f7e1..6c2d428 100644
--- a/examples/db.json
+++ b/examples/db.json
@@ -4,15 +4,22 @@
{
"type": "pretzel",
"description": "really a very tasty bread! yup yes",
- "color": "blue",
+ "color": "green",
"id": "pretzel",
- "title": "",
+ "title": "Pretzel Chips",
"images": [
{
"uri": "cool",
"caption": "cool"
}
- ]
+ ],
+ "video": {
+ "url": "",
+ "type": "",
+ "token": "",
+ "title": "",
+ "thumb": ""
+ }
},
{
"type": "bagel",
@@ -23,9 +30,16 @@
"images": [
{
"uri": "http://del.h-cdn.co/assets/cm/15/10/54f928d7ada8d_-_1347910942518.jpg",
- "caption": "beep"
+ "caption": "boop"
}
- ]
+ ],
+ "video": {
+ "url": "https://vimeo.com/112498725",
+ "type": "vimeo",
+ "token": "112498725",
+ "title": "FW14-2H-VIDEO-V4 2",
+ "thumb": "http://i.vimeocdn.com/video/497493142_640.jpg"
+ }
},
{
"type": "pumpernickel",
diff --git a/examples/index.js b/examples/index.js
index 9c5b7b4..95d2bcf 100644
--- a/examples/index.js
+++ b/examples/index.js
@@ -15,6 +15,7 @@ var app = okcms.createApp({
title: {type: 'string'},
description: {type: 'text'},
color: {type: 'enum', options: ["red","blue","green"]},
+ video: {type: 'video'},
images: {type: 'captioned-image-list'}
}
},
diff --git a/themes/okadmin/public/css/main.css b/themes/okadmin/public/css/main.css
index d120b0a..0ba6286 100644
--- a/themes/okadmin/public/css/main.css
+++ b/themes/okadmin/public/css/main.css
@@ -1,3 +1,7 @@
+* {
+ box-sizing: border-box;
+}
+
html, body {
margin: 0;
padding: 0;
@@ -139,7 +143,7 @@ label {
.main.resource form img {
display: block;
float: left;
- width: 20em;
+ width: 25em;
font-size: 1.0em;
color: #000;
border: 1px solid #333;
@@ -147,6 +151,42 @@ label {
padding: 0 0.5em;
margin-bottom: 1em;
}
+.main.resource form .group {
+ display: block;
+ float: left;
+ width: 31em;
+}
+.main.resource form .group label {
+ width: 5em;
+ color: #777;
+ font-size: 0.9em;
+ line-height: 1.4em;
+ margin-bottom: 0;
+ margin-left: -5.8em;
+ text-align: right;
+ border: 0;
+ display: none;
+}
+.main.resource form .group.loaded input:first-child,
+.main.resource form .group input:first-child {
+ display: block;
+ width: 25em;
+}
+.main.resource form .group.loaded label {
+ display: block;
+}
+.main.resource form .group.loaded input {
+ display: block;
+ width: 20.05em;
+}
+.main.resource form .group input {
+ display: none;
+ margin-bottom: 0.1em;
+}
+.main.resource form .group.loaded input[hidden],
+.main.resource form input[hidden] {
+ display: none;
+}
.main.resource form textarea {
padding: 0.5em;
@@ -159,6 +199,14 @@ label {
float: left;
padding: 0.5em;
font-size: 1.0em;
+ margin-top: 1.0em;
+}
+
+.template {
+ display: none;
+}
+.disabled {
+ display: none;
}
.clear {
diff --git a/themes/okadmin/public/js/app.js b/themes/okadmin/public/js/app.js
index b850466..84c0f53 100644
--- a/themes/okadmin/public/js/app.js
+++ b/themes/okadmin/public/js/app.js
@@ -1,11 +1,33 @@
var OKAdmin = function(){
-
OKUpload.bind()
OKUpload.add = function(data){
+ var url = data[0].extra.location
+ var imageTemplate = $("#image-template").html()
+ var $el = $(imageTemplate)
+ $el.find("url").val(url)
+ $(".images").append($el)
console.log(data)
}
+ $(".video .url").change(function(){
+ var $el = $(this)
+ var url = $el.val()
+ Parser.parse( url, function(media){
+ console.log(url,media)
+ $el.parent().addClass("loaded")
+ $el.parent().find(".video-type").val( media.type )
+ $el.parent().find(".video-token").val( media.token )
+ $el.parent().find(".video-title").val( media.title )
+ $el.parent().find(".video-thumb").val( media.thumbnail )
+ })
+ })
+
+ $("form").submit(function(){
+ $(".template").remove()
+ })
}
-window.app = new OKAdmin ()
+$(function(){
+ window.app = new OKAdmin ()
+})
diff --git a/themes/okadmin/public/js/parser.js b/themes/okadmin/public/js/parser.js
new file mode 100644
index 0000000..411f425
--- /dev/null
+++ b/themes/okadmin/public/js/parser.js
@@ -0,0 +1,282 @@
+var Parser = {
+ integrations: [{
+ type: 'image',
+ regex: /\.(jpeg|jpg|gif|png|svg)(\?.*)?$/i,
+ fetch: function(url, done) {
+ var img = new Image ()
+ img.onload = function(){
+ if (!img) return
+ var width = img.naturalWidth, height = img.naturalHeight
+ img = null
+ done({
+ url: url,
+ type: "image",
+ token: "",
+ thumbnail: "",
+ title: "",
+ width: width,
+ height: height,
+ })
+ }
+ img.src = url
+ if (img.complete) {
+ img.onload()
+ }
+ },
+ tag: function (media) {
+ return '<img src="' + media.url + '">';
+ }
+ }, {
+ type: 'video',
+ regex: /\.(mp4|webm)(\?.*)?$/i,
+ fetch: function(url, done) {
+ var video = document.createElement("video")
+ video.addEventListener("loadedmetadata", function(){
+ var width = video.videoWidth, height = video.videoHeight
+ video = null
+ done({
+ url: url,
+ type: "video",
+ token: "",
+ thumbnail: "",
+ title: "",
+ width: width,
+ height: height,
+ })
+ })
+ video.src = url
+ video.load()
+ },
+ tag: function (media) {
+ return '<video src="' + media.url + '">';
+ }
+ }, {
+ type: 'youtube',
+ regex: /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i,
+ fetch: function(url, done) {
+ var id = (url.match(/v=([-_a-zA-Z0-9]{11})/i) || url.match(/youtu.be\/([-_a-zA-Z0-9]{11})/i) || url.match(/embed\/([-_a-zA-Z0-9]{11})/i))[1].split('&')[0];
+ var thumb = "http://i.ytimg.com/vi/" + id + "/hqdefault.jpg"
+ $.ajax({
+ type: 'GET',
+ url: 'https://www.googleapis.com/youtube/v3/videos',
+ dataType: "jsonp",
+ data: {
+ id: id,
+ key: "AIzaSyDYPKGD0-_VRBWpUYRmX8Qg6BtWmcPU_cM",
+ part: "id,contentDetails,snippet,status",
+ },
+ success: function(result){
+ var res = result.items[0]
+ done({
+ url: url,
+ type: "youtube",
+ token: id,
+ thumbnail: thumb,
+ title: res.snippet.title,
+ width: 640,
+ height: 360,
+ })
+ }
+ })
+ },
+ tag: function (media) {
+ // return '<img class="video" type="youtube" vid="'+media.token+'" src="'+media.thumbnail+'"><span class="playvid">&#9654;</span>';
+ return '<div class="video" style="width: ' + media.width + 'px; height: ' + media.height + 'px; overflow: hidden; position: relative;"><iframe frameborder="0" scrolling="no" seamless="seamless" webkitallowfullscreen="webkitAllowFullScreen" mozallowfullscreen="mozallowfullscreen" allowfullscreen="allowfullscreen" id="okplayer" width="' + media.width + '" height="' + media.height + '" src="http://youtube.com/embed/' + media.token + '?showinfo=0" style="position: absolute; top: 0px; left: 0px; width: ' + media.width + 'px; height: ' + media.height + 'px;"></iframe></div>'
+ }
+ }, {
+ type: 'vimeo',
+ regex: /vimeo.com\/\d+$/i,
+ fetch: function(url, done) {
+ var id = url.match(/\d+$/i)[0];
+ $.ajax({
+ type: 'GET',
+ url: 'http://vimeo.com/api/v2/video/' + id + '.json',
+ success: function(result){
+ if (result.length == 0) { return done(id, "", 640, 360) }
+ var res = result[0]
+ if (res.embed_privacy != "anywhere") {
+ AlertModal.alert("Sorry, the author of this video has marked it private, preventing it from being embedded.", function(){})
+ return
+ }
+ done({
+ url: url,
+ type: "vimeo",
+ token: id,
+ thumbnail: res.thumbnail_large,
+ title: res.title,
+ width: res.width,
+ height: res.height,
+ })
+ }
+ })
+ },
+ tag: function (media) {
+ // return '<img class="video" type="vimeo" vid="'+media.token+'" src="'+media.thumbnail+'"><span class="playvid">&#9654;</span>';
+ return '<div class="video" style="width: ' + media.width + 'px; height: ' + media.height + 'px; overflow: hidden; position: relative;"><iframe frameborder="0" scrolling="no" seamless="seamless" webkitallowfullscreen="webkitAllowFullScreen" mozallowfullscreen="mozallowfullscreen" allowfullscreen="allowfullscreen" id="okplayer" src="http://player.vimeo.com/video/' + media.token + '?api=1&title=0&byline=0&portrait=0&playbar=0&player_id=okplayer&loop=0&autoplay=0" width="' + media.width + '" height="' + media.height + '" style="position: absolute; top: 0px; left: 0px; width: ' + media.width + 'px; height: ' + media.height + 'px;"></iframe></div>'
+ }
+ },
+ {
+ type: 'soundcloud',
+ regex: /soundcloud.com\/[-a-zA-Z0-9]+\/[-a-zA-Z0-9]+\/?$/i,
+ fetch: function (url, done) {
+ $.ajax({
+ type: 'GET',
+ url: 'http://api.soundcloud.com/resolve.json?url='
+ + url
+ + '&client_id='
+ + '0673fbe6fc794a7750f680747e863b10',
+ success: function(result) {
+ // console.log(result)
+ done({
+ url: url,
+ type: "soundcloud",
+ token: result.id,
+ thumbnail: result.artwork_url || result.user.avatar_url,
+ title: result.user.username + " - " + result.title,
+ width: 166,
+ height: 166,
+ })
+ }
+ });
+ },
+ tag: function (media) {
+ return '<iframe width="166" height="166" scrolling="no" frameborder="no"' +
+ 'src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/' + media.token +
+ '&amp;color=ff6600&amp;auto_play=false&amp;show_artwork=true"></iframe>'
+ }
+ },
+ /*
+ {
+ type: 'link',
+ regex: /^http.+/i,
+ fetch: function(url, done) {
+ done({
+ url: url,
+ type: "link",
+ token: "",
+ thumbnail: "",
+ title: "",
+ width: 100,
+ height: 100,
+ })
+ },
+ tag: function (media) {
+ return '<a href="' + media.url + '" target="_blank">' + media.url + '</a>'
+ }
+ }
+ */
+ ],
+
+ tumblr: function(url, cb){
+ var domain = url.replace(/^https?:\/\//,"").split("/")[0]
+ if (domain.indexOf(".") == -1) {
+ domain += ".tumblr.com"
+ }
+ $.ajax({
+ type: 'GET',
+ url: "http://" + domain + "/api/read",
+ dataType: "jsonp",
+ data: {
+ format: "json",
+ },
+ success: function(data){
+ var media_list = []
+ var blog = data.tumblelog
+
+ data.posts.forEach(parse)
+ cb(media_list)
+
+ function parse(post){
+ var media, caption, url
+ switch (post.type) {
+ case 'photo':
+ caption = stripHTML(post['photo-caption'])
+ if (post.photos.length) {
+ post.photos.forEach(function(photo){
+ var media = {
+ url: photo['photo-url-1280'],
+ type: "image",
+ token: "",
+ thumbnail: photo['photo-url-500'],
+ description: caption,
+ width: parseInt(photo.width),
+ height: parseInt(photo.height),
+ }
+ media_list.push(media)
+ })
+ }
+ else {
+ media = {
+ url: post['photo-url-1280'],
+ type: "image",
+ token: "",
+ thumbnail: post['photo-url-500'],
+ description: caption,
+ width: parseInt(post.width),
+ height: parseInt(post.height),
+ }
+ media_list.push(media)
+ }
+ break
+ case 'video':
+ url = post['video-source']
+ if (url.indexOf("http") !== 0) { break }
+ if (Parser.lookup.youtube.regex.test(url)) {
+ var id = (url.match(/v=([-_a-zA-Z0-9]{11})/i) || url.match(/youtu.be\/([-_a-zA-Z0-9]{11})/i) || url.match(/embed\/([-_a-zA-Z0-9]{11})/i))[1].split('&')[0];
+ var thumb = "http://i.ytimg.com/vi/" + id + "/hqdefault.jpg"
+ media = {
+ url: post['video-source'],
+ type: "youtube",
+ token: id,
+ thumbnail: thumb,
+ title: stripHTML(post['video-caption']),
+ width: 640,
+ height: 360,
+ }
+ media_list.push(media)
+ }
+ break
+ }
+ }
+// console.log(post)
+ }
+ })
+ },
+
+ parse: function (url, cb) {
+ var matched = Parser.integrations.some(function(integration){
+ if (integration.regex.test(url)) {
+ integration.fetch(url, function(res){
+ cb(res)
+ })
+ return true
+ }
+ return false
+ })
+ if (! matched) {
+ cb(null)
+ }
+ },
+
+ tag: function (media){
+ if (media.type in Parser.lookup) {
+ return Parser.lookup[media.type].tag(media)
+ }
+ return ""
+ },
+
+ loadImage: function(url, cb, error){
+ if (Parser.lookup.image.regex.test(url)) {
+ Parser.lookup.image.fetch(url, function(media){
+ cb(media)
+ })
+ }
+ else error && error()
+ },
+
+ thumbnail: function (media) {
+ return '<img src="' + (media.thumbnail || media.url) + '" class="thumb">';
+ },
+
+};
+Parser.lookup = _.indexBy(Parser.integrations, 'type');
diff --git a/themes/okadmin/templates/partials/inputs.liquid b/themes/okadmin/templates/partials/inputs.liquid
index 8269d4e..3a33f95 100644
--- a/themes/okadmin/templates/partials/inputs.liquid
+++ b/themes/okadmin/templates/partials/inputs.liquid
@@ -28,6 +28,16 @@
<option value="{{option}}" {% if option == spec.value %}selected{% endif %}>{{option}}</option>
{% endfor %}
</select>
+ {% elsif type == 'video' %}
+ <div class="video group {% if spec.value.url %}loaded{% endif %}">
+ <input name="{{name}}[url]" type="text" value="{{spec.value.url}}" class="url" placeholder="Enter a video URL">
+ <input name="{{name}}[type]" type="text" value="{{spec.value.type}}" class="video-type" hidden>
+ <input name="{{name}}[token]" type="text" value="{{spec.value.token}}" class="video-token" hidden>
+ <label>Title</label>
+ <input name="{{name}}[title]" type="text" value="{{spec.value.title}}" class="video-title">
+ <label>Thumbnail</label>
+ <input name="{{name}}[thumb]" type="text" value="{{spec.value.thumb}}" class="video-thumb">
+ </div>
{% elsif type == 'captioned-image-list' %}
<ol>
{% for image in spec.value %}
diff --git a/themes/okadmin/templates/partials/tail.liquid b/themes/okadmin/templates/partials/tail.liquid
index 76d31b0..1c6bce5 100644
--- a/themes/okadmin/templates/partials/tail.liquid
+++ b/themes/okadmin/templates/partials/tail.liquid
@@ -1,6 +1,8 @@
</div> {% comment %} closes container tag {% endcomment %}
</body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
+ <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.6.0/lodash.min.js"></script>
<script src="/_admin/js/upload.js"></script>
+ <script src="/_admin/js/parser.js"></script>
<script src="/_admin/js/app.js"></script>
</html>