diff options
Diffstat (limited to 'themes/okadmin/public/js')
| -rw-r--r-- | themes/okadmin/public/js/app.js | 346 | ||||
| -rw-r--r-- | themes/okadmin/public/js/parser.js | 49 | ||||
| -rw-r--r-- | themes/okadmin/public/js/upload.js | 225 |
3 files changed, 529 insertions, 91 deletions
diff --git a/themes/okadmin/public/js/app.js b/themes/okadmin/public/js/app.js index 4b8d98f..9891298 100644 --- a/themes/okadmin/public/js/app.js +++ b/themes/okadmin/public/js/app.js @@ -1,61 +1,333 @@ var OKAdmin = function(){ - - OKUpload.bind() - OKUpload.add = function(data){ - var url = data[0].extra.Location - add_image(url) - } - function add_image(url){ - var imageTemplate = $("#captioned-image-template").html() - var $el = $(imageTemplate) - $el.find(".uri").val(url) - $el.find("img").attr("src", url) - $(".captioned-image-list ol").append($el) - } - $(".captioned-image-list ol").sortable() - $(".captioned-image-list ol").disableSelection() - - $("#add-image-url").keydown(pressEnter(function(e){ - var url = $(this).val() - $(this).val("") - add_image(url) - })}) - - $(document).on("click", ".remove-image", function(){ - if (confirm("Delete this image?")) { + + // initialize our multi-image uploader with an element and a template + $(".group.image-list").each(function(){ + var parent = this + var uploader = new OKUpload () + uploader.bind( this ) + uploader.add = function(media){ + var url = media.url + var imageTemplate = $(".image-template", parent).html() + var $el = $(imageTemplate) + $el.find(".uri").val(media.url) + $el.find(".image-width").val(media.width) + $el.find(".image-height").val(media.height) + $el.find("img").attr("src", media.url) + $("ol", parent).prepend($el) + } + }) + // delete image from gallery + $(document).on("mousedown", ".image-list .remove", function(){ + if (confirm("Remove this image?")) { $(this).parent().remove() } }) - - $(".video .url").keydown(pressEnter(function(){ + + // Add default date + $('.date input').each(function(i, el){ + var value = el.getAttribute('value') + if (!value) { + el.setAttribute('value', toDateInputValue(new Date)) + } + + function toDateInputValue (date) { + var local = new Date(date); + local.setMinutes(date.getMinutes() - date.getTimezoneOffset()); + return local.toJSON().slice(0,10); + } + }) + + // initialize our multimedia uploader with an element and a template + $(".group.media-list").each(function(){ + var parent = this + var uploader = new OKUpload () + uploader.bind( this ) + uploader.add = function(media){ + var url = media.url + var imageTemplate = $(".image-template", parent).html() + var $el = $(imageTemplate) + $el.find(".uri").val(media.url) + $el.find(".image-width").val(media.width) + $el.find(".image-height").val(media.height) + $el.find("img").attr("src", media.url) + $("ol", parent).prepend($el) + } + uploader.addMedia = function(media){ + switch (media.type) { + case 'youtube': + case 'vimeo': + case 'video': + var videoTemplate = $(".video-template", parent).html() + var $el = $(videoTemplate) + $el.addClass("loaded") + $el.find(".video-type").val( media.type ) + $el.find(".video-token").val( media.token ) + $el.find(".video-uri").val( media.uri ) + $el.find(".video-title").val( media.title ) + $el.find(".video-thumb").val( media.thumbnail ) + $el.find(".video-width").val( media.width ) + $el.find(".video-height").val( media.height ) + $el.find("img").attr("src", media.thumbnail ) + $("ol", parent).prepend($el) + break + case 'audio': + var audioTemplate = $(".audio-template", parent).html() + var $el = $(audioTemplate) + $el.addClass("loaded") + $el.find(".audio-type").val( media.type ) + $el.find(".audio-token").val( media.token ) + $el.find(".audio-uri").val( media.uri ) + $el.find(".audio-title").val( media.title ) + $el.find(".audio-thumb").val( media.thumbnail ) + $el.find(".audio-duration").val( media.duration ) + $el.find("img").attr("src", media.thumbnail ) + $("ol", parent).prepend($el) + break + case 'link': + var linkTemplate = $(".link-template", parent).html() + var $el = $(linkTemplate) + $el.addClass("loaded") + $el.find(".uri").val( media.url ) + $("ol", parent).prepend($el) + break + default: + alert("Unsupported link type!") + } + } + }) + // delete image from gallery + $(document).on("mousedown", ".media-list .remove", function(){ + if (confirm("Remove this media?")) { + $(this).parent().remove() + } + }) + + // initialize our single image uploader with existing DOM + $(".group.image").each(function(){ + var $el = $(this) + var uploader = new OKUpload () + uploader.bind( this ) + uploader.add = function(media){ + console.log(media) + $el.find(".uri").val(media.url) + $el.find(".caption").val("") + $el.find(".image-width").val(media.width) + $el.find(".image-height").val(media.height) + $el.find("img").attr("src", media.url).show() + $el.addClass("loaded") + } + }) + // delete image from single image entry + $(document).on("mousedown", ".image .remove", function(){ + if (confirm("Remove this image?")) { + var $el = $(this).closest(".image") + $el.removeClass('loaded') + $el.find(".uri").val("") + $el.find(".image-width").val("") + $el.find(".image-height").val("") + $el.find(".caption").val("") + $el.find("img").attr("src", "") + } + }) + + // make the region sortable with drag-and-drop + $(".media-list ol, .image-list ol, .link-list .links").sortable() + $(".media-list ol, .image-list ol").disableSelection() + + // populate a video field with info from our url parser + var last_url + $(".video .url").on("focus", function(){ + var $el = $(this) + last_url = $el.val() + }) + $(".video .url").on("keydown blur", pressEnter(function(){ var $el = $(this) var url = $el.val() + if (url == last_url) { return } 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-uri").val( media.url ) $el.parent().find(".video-title").val( media.title ) $el.parent().find(".video-thumb").val( media.thumbnail ) + $el.parent().find(".video-width").val( media.width ) + $el.parent().find(".video-height").val( media.height ) }) - }})) - - $("form").submit(function(){ - $(".image-element").each(function(index){ - $(this).find("input,textarea").each(function(){ - var field = $(this).attr("name").replace(/\[\]/, "[" + index + "]") - $(this).attr("name", field) + })) + + // Add a new link to the list + $('.link-list').on('click', '.add-link-btn', function addNewLink (e) { + e.preventDefault && e.preventDefault() + e.stopPropagation && e.stopPropagation() + var $delegate = $(e.delegateTarget) + var $list = $delegate.find('.links') + var linkCount = $list.find("li").length + + var $linkText = $delegate.find(".link-input-new.link-text") + var $linkURI = $delegate.find(".link-input-new.link-uri") + + var template = $delegate.find(".link-template").html() + template = template.replace(/\[\]/g, "[" + linkCount + "]") + var $el = $(template) + $el.find(".link-text").val( $linkText.val() ) + $el.find(".link-uri").val( $linkURI.val() ) + $list.append($el) + $linkText.val("") + $linkURI.val("") + }) + + // Remove a link from the list + $('.link-list').on('click', '.remove-link-btn', function(e) { + e.preventDefault() + e.stopPropagation() + var $target = $(e.target) + $target.closest("li").remove() + }) + + // fix post indexing in list-driven inputs + $(".main.resource form").submit(function(e){ + var $id = $("[name=id]"), $title = $("[name=title]"), $menu = $("[name=menu]"), $section = $(".resource.main") + var id = $section.data("id"), type = $section.data("type") + + if ($title.length && ! $title.val()) { + $title.focus() + alert("Please enter a title") + e.preventDefault() + return + } + + if ($menu.length && ! $menu.val()) { + $menu.val( $title.val() ) + } + + // TODO: pass through whether this page is static + if (type === "page" && (id == "contact" || id == "about")) { + ; + } + else { + var slug = slugify( $title.val() ) + $id.val( slug ) + } + + // Parse date input + $('.property .date').each(function(i, el) { + var name = $(el).parent('.property').data('name') + var $input = $(el).find('input') + var date = new Date($input.val()) + // Set to middle of day so it is the same date + // for all locales + date.setUTCHours(12) + var dateString = date.toUTCString() + var normalizedInput = document.createElement('input') + $(normalizedInput).attr({ + name: name, + type: 'text', + value: dateString + }) + $input.remove() + $(el).append(normalizedInput) + }) + + // Modify flags checkboxes such that unchecked ones return "false" + // instead of nothing + $('.property input[type=checkbox]').each(function(i, el) { + var checked = !!el.checked + if (!checked) { + el.value = 'false' + el.setAttribute('checked', true) + } + }) + + $(".link-list").each(function(){ + var $inputs = $(this).find(".link-input-new") + if ($inputs.eq(0).val() && $inputs.eq(1).val()) { + $(this).find(".add-link-btn").trigger("click") + } + }) + + $("ol").each(function(){ + $("li", this).each(function(index){ + $(this).find("input,textarea").each(function(){ + var field = $(this).attr("name").replace(/\[[0-9]*\]/, "[" + index + "]") + $(this).attr("name", field) + }) }) }) }) + + // delete individual records + $("#delete_form").submit(function(e){ + if (confirm("Are you sure you want to delete this record?")) { + return + } + else { + e.preventDefault() + } + }) + + // reorder items in categories + $(".resource-category:not(.grouped)").on("click", ".edit-btn", function(e) { + e.preventDefault(); + var $parent = $(e.delegateTarget) + var $editBtn = $parent.find(".edit-btn"); + var $cancelBtn = $parent.find(".cancel-btn"); + var $saveBtn = $parent.find(".save-btn"); + var $ol = $parent.find("ol"); + var toggles = [$parent, $cancelBtn, $saveBtn, $editBtn]; + + $ol.sortable(); + $ol.disableSelection(); + toggle(); + + $cancelBtn.one("click", function(e) { + $ol.sortable("cancel"); + $ol.enableSelection(); + toggle(); + }); + + $saveBtn.one("click", function(e) { + $ol.sortable(); + toggle(); + }); + + function toggle() { + toggles.forEach(function($el) { + $el.toggleClass('active'); + }) + } + }); + + // save new category order + $(".resource-category.root").on("submit", "form", function(e) { + var $parent = $(e.delegateTarget); + var $resources = $parent.find(".resource-input") + var isDescending = $parent.hasClass("descending") + $resources.each(function(index) { + var $input = $(this); + var parsed = JSON.parse($input.val()); + if (isDescending) { + parsed.__index = $resources.length - index; + } + else { + parsed.__index = index; + } + $input.val(JSON.stringify(parsed)); + }) + }); - function pressEnter(fn){ - return function(e){ - if (e.keyCode !== 13) return + $(window).on('keydown', function(e){ + if ( (e.ctrlKey || e.altKey || e.metaKey) && e.keyCode == 83 ) { e.preventDefault() + $("#resource_form").submit() } - } + }) +} $(function(){ window.app = new OKAdmin () }) + + +function slugify (s){ return (s || "").toLowerCase().replace(/\s/g,"-").replace(/[^-_a-zA-Z0-9]/g, '-').replace(/-+/g, "-") } diff --git a/themes/okadmin/public/js/parser.js b/themes/okadmin/public/js/parser.js index 411f425..81bba2d 100644 --- a/themes/okadmin/public/js/parser.js +++ b/themes/okadmin/public/js/parser.js @@ -31,15 +31,17 @@ var Parser = { regex: /\.(mp4|webm)(\?.*)?$/i, fetch: function(url, done) { var video = document.createElement("video") + var url_parts = url.replace(/\?.*$/, "").split("/") + var filename = url_parts[ url_parts.length-1 ] video.addEventListener("loadedmetadata", function(){ var width = video.videoWidth, height = video.videoHeight video = null done({ url: url, type: "video", - token: "", - thumbnail: "", - title: "", + token: url, + thumbnail: "http://okfocus.s3.amazonaws.com/misc/okcms/video.png", + title: filename, width: width, height: height, }) @@ -51,6 +53,31 @@ var Parser = { return '<video src="' + media.url + '">'; } }, { + type: 'audio', + regex: /\.(wav|mp3)(\?.*)?$/i, + fetch: function(url, done) { + var audio = document.createElement("audio") + var url_parts = url.replace(/\?.*$/, "").split("/") + var filename = url_parts[ url_parts.length-1 ] + audio.addEventListener("loadedmetadata", function(){ + var duration = audio.duration + audio = null + done({ + url: url, + type: "audio", + token: url, + thumbnail: "http://okfocus.s3.amazonaws.com/misc/okcms/audio.png", + title: filename, + duration: duration, + }) + }) + audio.src = url + audio.load() + }, + tag: function (media) { + return '<audio src="' + media.url + '">'; + } + }, { type: 'youtube', regex: /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i, fetch: function(url, done) { @@ -73,6 +100,8 @@ var Parser = { token: id, thumbnail: thumb, title: res.snippet.title, + autoplay: false, + loop: false, width: 640, height: 360, }) @@ -106,6 +135,8 @@ var Parser = { title: res.title, width: res.width, height: res.height, + autoplay: false, + loop: false, }) } }) @@ -114,8 +145,7 @@ var Parser = { // 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) { @@ -126,13 +156,14 @@ var Parser = { + '&client_id=' + '0673fbe6fc794a7750f680747e863b10', success: function(result) { - // console.log(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, + duration: result.duration, width: 166, height: 166, }) @@ -145,7 +176,6 @@ var Parser = { '&color=ff6600&auto_play=false&show_artwork=true"></iframe>' } }, - /* { type: 'link', regex: /^http.+/i, @@ -163,8 +193,7 @@ var Parser = { tag: function (media) { return '<a href="' + media.url + '" target="_blank">' + media.url + '</a>' } - } - */ + }, ], tumblr: function(url, cb){ @@ -232,6 +261,8 @@ var Parser = { title: stripHTML(post['video-caption']), width: 640, height: 360, + autoplay: false, + loop: false, } media_list.push(media) } diff --git a/themes/okadmin/public/js/upload.js b/themes/okadmin/public/js/upload.js index d9fd5ed..6ff7ac9 100644 --- a/themes/okadmin/public/js/upload.js +++ b/themes/okadmin/public/js/upload.js @@ -1,56 +1,191 @@ -var OKUpload = { - action: "/_services/image", - - bind: function(){ - var el = document.getElementById("file") - if (! el) return - el.addEventListener("change", OKUpload.handleFileSelect) - }, +var OKUpload = function(){ + this.config = $("#uploadConfig").data() + this.imageAction = "/_services/s3/image" + this.videoAction = "/_services/s3/video" + this.audioAction = "/_services/s3/audio" +} +OKUpload.prototype.bind = function(rapper){ + var uploader = this + this.rapper = rapper + this.$progress = $("<div class='progress'>") + this.xhrCount = 0 + this.loadCount = 0 + + $(this.rapper).append(this.$progress) + $(".add-image-button input", rapper).change( uploader.handleFileSelect.bind(uploader) ) + $(".add-url", rapper).on("keydown blur", pressEnter( function(e){ + var url = $(this).val() + $(this).val("") + uploader.parse(url) + })) +} +OKUpload.prototype.parse = function(url){ + if (! url) return + var uploader = this + Parser.parse( url, function(media){ + console.log(url, media) + if (! media) { + alert("Not a valid link") + } + else if (media.type == "image") { + uploader.add(media) + } + else { + uploader.addMedia(media) + } + }) +} +OKUpload.prototype.handleFileSelect = function(e) { + e.stopPropagation(); + e.preventDefault(); - handleFileSelect: function(e) { - e.stopPropagation(); - e.preventDefault(); + var files = e.dataTransfer ? e.dataTransfer.files : e.target.files; - var files = e.dataTransfer ? e.dataTransfer.files : e.target.files; + for (var i = 0, f; f = files[i]; i++) { + this.upload(f) + } +} +OKUpload.prototype.largeFileError = function(file, maxSize) { + var your_bytes = bytesToString(file.size) + var max_bytes = bytesToString(maxSize) + alert("Sorry, your file is too big.\n\n" + file.name + "\n\nYour file: " + your_bytes + "\nMax size: " + max_bytes) + function bytesToString (n) { + if (n < 1024) return n + " bytes" + n /= 1024 + if (n < 1024) return n.toFixed(1) + " kb" + n /= 1024 + if (n < 1024) return n.toFixed(1) + " mb" + } +} +OKUpload.prototype.upload = function(f){ - for (var i = 0, f; f = files[i]; i++) { - if ( ! f.type.match('image.*')) { - continue; - } - OKUpload.upload(f) + var field, action + + if ( f.type.match('video.*') ) { + if (this.config.videoMaxbytes && f.size > this.config.videoMaxbytes) { + return this.largeFileError(f, this.config.videoMaxbytes) + } + field = 'video' + action = this.videoAction + } + else if ( f.type.match('audio.*') ) { + if (this.config.audioMaxbytes && f.size > this.config.audioMaxbytes) { + return this.largeFileError(f, this.config.audioMaxbytes) } - }, + field = 'audio' + action = this.audioAction + } + else { + if (this.config.imageMaxbytes && f.size > this.config.imageMaxbytes) { + return this.largeFileError(f, this.config.imageMaxbytes) + } + field = 'image' + action = this.imageAction || this.action + } + + this.xhrCount += 1 - upload: function(f){ - var fd = new FormData() - fd.append('image', f) + this.$progress.addClass("loading") - var request = $.ajax({ - url: OKUpload.action, - type: "post", - data: fd, - dataType: "json", - processData: false, - contentType: false, - }) - request.done(OKUpload.success) - }, + var $loader = $("<div class='xhr'>") + var $loading_bar = $("<div>") + $loading_bar.css("width", "0%") + $loader.append( $loading_bar ) + this.$progress.append($loader) - success: function(media){ - if (media.error) { - console.log(media.error) - return + var fd = new FormData() + fd.append(field, f) + + var request = new XMLHttpRequest() + request.open("POST", action, true) + + request.addEventListener("progress", updateProgress.bind(this)); + request.addEventListener("load", transferComplete.bind(this)); + request.addEventListener("error", transferError.bind(this)); + request.addEventListener("abort", transferAbort.bind(this)); + + function updateProgress (e) { + if (e.lengthComputable) { + var percentComplete = Math.round( 100 * e.loaded / e.total ) + $loading_bar.css("width", percentComplete + "%") } - OKUpload.add(media) - }, - - add: function(media){ - console.log(media) - }, - - error: function(error){ - throw error - }, + } + function transferComplete (data) { + this.loadCount += 1 + this.hideUploadBars() + if (request.readyState == 4 && request.status == 200) { + var responseData + try { + responseData = JSON.parse( request.responseText ) + this.success( responseData ) + } + catch (e) { + console.log(request.responseText) + console.log("ERROR PARSING JSON") + } + } + console.log(arguments, request) + } + function transferError (data) { + console.log("Transfer error") + this.loadCount += 1 + this.hideUploadBars() + console.log(arguments) + } + function transferAbort (data) { + console.log("Transfer aborted") + this.loadCount += 1 + this.hideUploadBars() + console.log(arguments) + } + request.send(fd) + +/* + var request = $.ajax({ + url: this.action, + type: "post", + data: fd, + dataType: "json", + processData: false, + contentType: false, + }) + request.done(this.success.bind(this)) +*/ } +OKUpload.prototype.hideUploadBars = function () { + if (this.xhrCount == this.loadCount) { + this.$progress.removeClass("loading") + setTimeout(function(){ + this.$progress.empty() + }.bind(this), 300) + } +} +OKUpload.prototype.success = function(data){ + if (data.error) { + console.log(data.error) + return + } + var url = data.url + console.log(url) + this.parse(url) +} +OKUpload.prototype.add = function(media){ + console.log(media) +} +OKUpload.prototype.addMedia = function(media){ + console.log(media) +} +OKUpload.prototype.error = function(error){ + throw error +} + + +function pressEnter(fn){ + return function(e){ + if (e.keyCode && e.keyCode !== 13) return + e.preventDefault() + fn.apply(this) + } +}
\ No newline at end of file |
