diff options
| -rw-r--r-- | app/node_modules/okschema/index.js | 5 | ||||
| -rw-r--r-- | examples/db.json | 24 | ||||
| -rw-r--r-- | examples/index.js | 1 | ||||
| -rw-r--r-- | themes/okadmin/public/css/main.css | 50 | ||||
| -rw-r--r-- | themes/okadmin/public/js/app.js | 26 | ||||
| -rw-r--r-- | themes/okadmin/public/js/parser.js | 282 | ||||
| -rw-r--r-- | themes/okadmin/templates/partials/inputs.liquid | 10 | ||||
| -rw-r--r-- | themes/okadmin/templates/partials/tail.liquid | 2 |
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">▶</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">▶</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 + + '&color=ff6600&auto_play=false&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> |
