Isotope
씨발 존 나 깔쌈한 라이브러리…
존네좋군
Filter 와 Sort 기능을 갖춘 반응형 레이아웃 js 플러그인 – isotope.js
http://jsfiddle.net/tahirahmed/ku2kyfow/
http://imagesloaded.desandro.com/
http://purecss.io/layouts/side-menu/#
https://codepen.io/hanlinC/pen/dJwil
"use strict"; var resolve = { delay: function($q, $timeout) { var delay = $q.defer(); return $timeout(delay.resolve, 0, !1), delay.promise } }; angular.module("dropApp", ["ngCookies", "ngResource", "ngRoute", "ngSanitize", "ngProgress", "timer", "infinite-scroll"]).config(["$compileProvider", function($compileProvider) { $compileProvider.debugInfoEnabled(!1) }]).config(["$routeProvider", "$locationProvider", "$httpProvider", function($routeProvider, $locationProvider, $httpProvider) { $routeProvider.when("/", { templateUrl: "views/main.html", controller: "MainCtrl", resolve: resolve }).when("/all", { templateUrl: "views/all.html", controller: "AllCtrl", resolve: resolve }).when("/create", { templateUrl: "views/create.html", controller: "CreateCtrl", resolve: resolve }).when("/featured", { templateUrl: "views/drop.html", controller: "DropCtrl", reloadOnSearch: !1, resolve: resolve }).when("/drop/:id", { templateUrl: "views/drop.html", controller: "DropCtrl", reloadOnSearch: !1, resolve: resolve }).otherwise({ redirectTo: "/" }), $httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8"; var param = function(obj) { var name, value, fullSubName, subName, subValue, innerObj, i, query = ""; for (name in obj) if (value = obj[name], value instanceof Array) for (i = 0; i < value.length; ++i) subValue = value[i], fullSubName = name + "[" + i + "]", innerObj = {}, innerObj[fullSubName] = subValue, query += param(innerObj) + "&"; else if (value instanceof Object) for (subName in value) subValue = value[subName], fullSubName = name + "[" + subName + "]", innerObj = {}, innerObj[fullSubName] = subValue, query += param(innerObj) + "&"; else void 0 !== value && null !== value && (query += encodeURIComponent(name) + "=" + encodeURIComponent(value) + "&"); return query.length ? query.substr(0, query.length - 1) : query }; $httpProvider.defaults.transformRequest = [function(data) { return angular.isObject(data) && "[object File]" !== String(data) ? param(data) : data }] }]).run(["$rootScope", "$location", "$route", "$timeout", "Spotify", "ngProgress", function($rootScope, $location, $route, $timeout, Spotify, ngProgress) { var token_key = "access_token=", token_index = window.location.href.indexOf(token_key); if (token_index > -1) { var token = window.location.href.substr(token_index + token_key.length).split("&")[0]; Spotify.set_access_token(token), $location.path("/create") } var oldLocation = ""; $rootScope.$on("$routeChangeStart", function(angularEvent, next) { $rootScope.view_class = "view-" + $location.path().substr(1), ngProgress.reset(); var isForwards = !0; if (next && next.$$route) { var newLocation = next.$$route.originalPath; oldLocation !== newLocation && -1 !== oldLocation.indexOf(newLocation) && (isForwards = !1), oldLocation = newLocation } }), ngProgress.color("#16e58a") }]), angular.module("dropApp").service("Image", function() { function hexToRgb(hex) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null } this.grayscale = function(pixels) { for (var d = pixels.data, i = 0; i < d.length; i += 4) { var r = d[i], g = d[i + 1], b = d[i + 2], v = .2126 * r + .7152 * g + .0722 * b; d[i] = d[i + 1] = d[i + 2] = v } return pixels }, this.duotone = function(img, tone1, tone2) { var gradient = this.gradientMap(tone1, tone2); img = this.grayscale(img); for (var d = img.data, i = 0; i < d.length; i += 4) d[i] = gradient[4 * d[i]], d[i + 1] = gradient[4 * d[i + 1] + 1], d[i + 2] = gradient[4 * d[i + 2] + 2]; return img }, this.gradientMap = function(tone1, tone2) { for (var rgb1 = hexToRgb(tone1), rgb2 = hexToRgb(tone2), gradient = [], i = 0; 1024 > i; i += 4) gradient[i] = ((256 - i / 4) * rgb1.r + i / 4 * rgb2.r) / 256, gradient[i + 1] = ((256 - i / 4) * rgb1.g + i / 4 * rgb2.g) / 256, gradient[i + 2] = ((256 - i / 4) * rgb1.b + i / 4 * rgb2.b) / 256, gradient[i + 3] = 255; return gradient }, this.flipImage = function(input) { for (var tempCtx = document.createElement("canvas").getContext("2d"), output = tempCtx.createImageData(input.width, input.height), w = input.width, h = input.height, inputData = input.data, outputData = output.data, y = 1; h - 1 > y; y += 1) for (var x = 1; w - 1 > x; x += 1) for (var i = 4 * (y * w + x), flip = 4 * (y * w + (w - x)), c = 0; 4 > c; c += 1) outputData[i + c] = inputData[flip + c]; return output } }), angular.module("dropApp").service("BlockFormatter", function() { this.format_media = function(media, parent) { var block = {}; switch (block.type = "media", block.media_type = media.drop_type, block.title = media.title ? media.title : "Check out this exclusive " + media.drop_type + "!", block.description = media.description ? media.description : "Love " + parent.name + "? Don't miss this!", block.url = "/drop/" + media.artist_id + "?media=" + media.id, media.drop_type) { case "video": block.call_to_action = "watch now"; break; case "gallery": block.call_to_action = "gallery"; break; case "playlist": block.call_to_action = "follow" } return block }, this.format_drop = function(data) { var block = {}; return block.type = "drop", block.title = data.name, block.image = data.files[data.featured_image_id].url, block.url = "/drop/" + data.id, block.call_to_action = "view drop", block } }), angular.module("dropApp").service("Spotify", ["$http", "$location", "$window", "$q", function($http, $location, $window, $q) { var access_token, user, client_id = "d8c2bf8b2663462e93004f0575f821e8", redirect_uri = "http://spotify-thedrop.com/", authorization_url = "https://accounts.spotify.com/authorize", api_base = "https://api.spotify.com/v1"; this.set_access_token = function(token) { access_token = token }, this.get_access_token = function() { return access_token }, this.authenticate = function() { var url_string = authorization_url + "?response_type=token&client_id=" + client_id + "&redirect_uri=" + redirect_uri; $window.location.href = url_string }, this.get_user = function() { var deferred = $q.defer(); return user ? deferred.resolve(user) : $http({ url: api_base + "/me", headers: { Authorization: "Bearer " + access_token } }).success(function(response) { deferred.resolve(user = response) }).error(function(response) { deferred.reject() }), deferred.promise } }]), angular.module("dropApp").service("Api", ["$http", "$q", function($http, $q) { function card_shim(raw) { for (var i = 0; i < raw.length; i++) raw[i].type = "card"; return raw } function drop_shim(data) { function get_image_url(id) { return data.files[id] ? data.files[id].url : null } function get_image_content_url(i, id) { return data.content[i].files[id] ? data.content[i].files[id].url : null } var now = (new Date).getTime(); data.type = "drop", data.featured_image = get_image_url(data.featured_image_id), data.header_image = get_image_url(data.header_image_id), data.dropped_at = moment(data.reveal_date).fromNow(), data.single_uri = "spotify:track:" + data.single, data.dropped = moment(data.release_date).isBefore(now), "i" === data.dropped_at.charAt(0) && "n" === data.dropped_at.charAt(1) ? data.dropped_at = "Dropping " + data.dropped_at : data.dropped_at = "Dropped " + data.dropped_at, data.card_images = []; var card_image_1 = get_image_url(data.artist_image1_id), card_image_2 = get_image_url(data.artist_image2_id), card_image_3 = get_image_url(data.artist_image3_id); if (card_image_1 && data.card_images.push(card_image_1), card_image_2 && data.card_images.push(card_image_2), card_image_3 && data.card_images.push(card_image_3), data.content) for (var i = 0; i < data.content.length; i++) { var content = data.content[i]; content.item_index = i, content.type = "media", content.media_type = content.content_type, content.media_index = i, content.featured_image = get_image_content_url(i, content.featured_image_id), content.dropped_at = moment(content.release_date).fromNow(), content.drop_id = data.id, content.locked = moment(content.release_date).isAfter(now) } return data } var drops, cards, ads, base = "http://api.spotify-thedrop.com"; this.get_drop = function(id) { var deferred = $q.defer(); return $http.get(base + "/drop/" + id + "/").success(function(response) { deferred.resolve(drop_shim(response)) }), deferred.promise }, this.get_all_drops = function() { var deferred = $q.defer(); return drops ? deferred.resolve(drops) : $http.get(base + "/drops").success(function(response) { for (var i = 0; i < response.length; i++) response[i] = drop_shim(response[i]); deferred.resolve(drops = response) }), deferred.promise }, this.get_featured = function() { var deferred = $q.defer(); return $http.get(base + "/drops?featured=1").success(function(response) { deferred.resolve(drop_shim(response[response.length - 1])) }), deferred.promise }, this.get_cards = function() { var deferred = $q.defer(); return cards ? deferred.resolve(cards) : $http.get(base + "/cards?featured=1/").success(function(response) { cards = card_shim(response), deferred.resolve(cards) }), deferred.promise }, this.get_single_card = function(route) { var deferred = $q.defer(); return cards ? deferred.resolve(cards) : $http.get(route).success(function(response) { deferred.resolve(response) }), deferred.promise }, this.get_ad = function() { var deferred = $q.defer(), addArray = []; return ads ? deferred.resolve(ads) : $http.get(base + "/brands").success(function(response) { if ("object" == typeof response) { var adObj = { type: "ad", image: "images/mc-ad-blue.jpg", description: "It takes two to tango with a 20 piece.", content_url: "" }, add_timestamp = function(url) { return url ? String(url).replace("[timestamp]", (new Date).getTime()) : "" }, setObj = function(responseObj) { adObj.image = responseObj.files[responseObj.image_id].url, adObj.description = responseObj.title, adObj.content_url = responseObj.content_url, adObj.ad_url = add_timestamp(responseObj.ad_url), adObj.ad_text_url = add_timestamp(responseObj.ad_text_url), adObj.ad_text_url || (adObj.ad_text_url = adObj.ad_url), adObj.tracking_pixel_url = add_timestamp(responseObj.tracking_pixel_url), addArray.push(angular.copy(adObj)) }; response = response.sort(function(a, b) { return a.id == b.id ? 0 : a.id > b.id ? -1 : 1 }); for (var i = 0; i < response.length; i++) setObj(response[i]) } deferred.resolve(addArray) }), deferred.promise }, this.save_card = function(card_data, image) { var deferred = $q.defer(), data = { drop_id: card_data.drop.id, creator_id: card_data.user.id, image: image }; return $http({ method: "POST", url: base + "/card/", data: data, headers: { "Content-Type": "application/x-www-form-urlencoded" } }).success(function(response, status, headers, config) { deferred.resolve("" + base + headers().location) }), deferred.promise } }]), angular.module("dropApp").controller("MainCtrl", ["$scope", "$timeout", "$q", "$location", "Api", "ngProgress", function($scope, $timeout, $q, $location, Api, ngProgress) { $scope.items = []; var featured = 0; $scope.selectFeature = function(setFeature) { featured = setFeature }, $scope.isFeatured = function(checkFeature) { return featured === checkFeature }, this.load_featured_drop = function() { Api.get_featured().then(function(response) { ngProgress.complete(), $scope.featured = response, $scope.$on("imageLoaded", function() { $timeout(function() { $scope.backgroundLoaded = !0, $scope.firstLoad = !0; media: for (var i = $scope.featured.content.length; i--; i >= 0) if (!$scope.featured.content[i].locked) { $scope.items.unshift($scope.featured.content[i]), $scope.items[0].name = $scope.featured.name, $timeout(function() { $scope.firstLoad = !1 }, 1e3); break media } $timeout(function() { Api.get_ad().then(function(response) { $scope.items.push(response[0]) }), $scope.ready = !0 }, 1600) }, 700) }) }) }; var random_drops, ad_blocks, counter = 0; $scope.load_random_assets = function() { ngProgress.start(), $q.all([Api.get_all_drops(), Api.get_ad()]).then(function(response) { ngProgress.complete(), random_drops = angular.copy(response[0]), ad_blocks = angular.copy(response[1]), $scope.add_random_assets() }) }, $scope.add_random_assets = function() { if (counter++, $scope.ready = !1, !random_drops || !random_drops.length) return $scope.load_random_assets(), !1; for (var random_items = [], random_index = Math.floor(Math.random() * (random_drops.length - 9)), random_range = random_drops.splice(random_index, 10), i = 0; i < random_range.length; i++) { var selected_drop = random_range[i], selected_drop_media_length = selected_drop.content ? selected_drop.content.length : 0, selected_random_index = Math.floor(Math.random() * (selected_drop_media_length + 1)); selected_random_index === selected_drop_media_length ? random_items.push(selected_drop) : (selected_drop.content[selected_random_index].name = selected_drop.name, random_items.push(selected_drop.content[selected_random_index])) } if (counter % 2 === 0) { var shuffle = function(a) { var j, x, i; for (i = a.length; i; i -= 1) j = Math.floor(Math.random() * i), x = a[i - 1], a[i - 1] = a[j], a[j] = x; return a }; random_items = shuffle(random_items); var shuffle_merge = function(source, target) { for (var sourceInds = [], result = [], i = 0; i < source.length; i++) sourceInds.push(i); sourceInds = shuffle(shuffle(sourceInds)).slice(0, target.length).sort(); for (var currentInd = sourceInds.shift(), i = 0; i < source.length; i++) i == currentInd && (result.push(target.pop()), currentInd = sourceInds.shift()), result.push(source[i]); return result }; random_items = shuffle_merge(random_items, ad_blocks) } $scope.items = $scope.items.concat(random_items), $scope.ready = !0 }, this.load_featured_drop() }]), angular.module("dropApp").controller("HeaderCtrl", ["$scope", "$location", function($scope, $location) { $scope.links = [{ title: "FEATURED", path: "/drop/featured", color: "#fae62d" }, { title: "ALL", path: "/all", color: "#9bf0e1" }], $scope.timestamp = (new Date).getTime(), $scope.visisble = !0, $scope.toggleShare = function(toggle) { var $shareButtons = $(".share-button"), buttonsNum = $shareButtons.length, buttonsMid = buttonsNum / 3, spacing = 90; $scope.visisble && "close" !== toggle ? ($shareButtons.each(function(i) { var $cur = $(this), pos = i - 1, dist = Math.abs(pos); $cur.css({ zIndex: buttonsMid - dist }), TweenMax.to($cur, 1.1 * dist, { x: pos * spacing, y: 90, scale: .95, width: 60, height: 60, ease: Elastic.easeOut, easeParams: [1.01, .5] }), TweenMax.to($cur, .8, { delay: .2 * dist - .1, scale: .95, width: 60, height: 60, ease: Elastic.easeOut, easeParams: [1.1, .6] }), TweenMax.fromTo($cur.children(".share-icon"), .2, { scale: 0 }, { delay: .2 * dist - .1, scale: 1, ease: Quad.easeInOut }) }), $scope.visisble = !$scope.visisble) : "close" === toggle ? ($shareButtons.each(function(i) { var $cur = $(this), pos = i, dist = Math.abs(pos); $cur.css({ zIndex: dist }), TweenMax.to($cur, .4 + .1 * (buttonsMid - dist), { x: 0, y: 0, scale: 0, width: 32, height: 32, ease: Quad.easeInOut }), TweenMax.to($cur.children(".share-icon"), .2, { scale: 0, ease: Quad.easeIn }) }), $scope.visisble = !0) : ($shareButtons.each(function(i) { var $cur = $(this), pos = i, dist = Math.abs(pos); $cur.css({ zIndex: dist }), TweenMax.to($cur, .4 + .1 * (buttonsMid - dist), { x: 0, y: 0, scale: 0, width: 32, height: 32, ease: Quad.easeInOut }), TweenMax.to($cur.children(".share-icon"), .2, { scale: 0, ease: Quad.easeIn }) }), $scope.visisble = !0) }, $scope.$on("$locationChangeSuccess", function(e, next) { $scope.path = $location.path(), $scope.toggleShare("close") }), $scope.path = $location.path() }]), angular.module("dropApp").controller("FeaturedCtrl", ["$scope", "$timeout", "$q", "$location", "Api", "ngProgress", function($scope, $timeout, $q, $location, Api, ngProgress) { $scope.items = [], this.load_featured_drop = function() { ngProgress.start(), Api.get_featured().then(function(response) { ngProgress.complete(), $timeout(function() { $scope.featured = response; media: for (var i = $scope.quantity; i--; i >= 0) if (!$scope.featured.content[i].locked) { $scope.items.unshift($scope.featured.content[i]); break media } Api.get_ad().then(function(response) { $scope.items.push(response[0]) }), $scope.ready = !0 }, 500) }) }; var random_drops, random_cards; $scope.load_random_assets = function() { ngProgress.start(), $q.all([Api.get_all_drops(), Api.get_cards()]).then(function(response) { ngProgress.complete(), random_drops = angular.copy(response[0]), random_cards = angular.copy(response[1]), $scope.add_random_assets() }) }, $scope.add_random_assets = function() { if ($scope.ready = !1, !random_drops || !random_drops.length) return $scope.load_random_assets(), !1; for (var random_items = [], random_index = Math.floor(Math.random() * (random_drops.length - 4)), random_range = random_drops.splice(random_index, 5), i = 0; i < random_range.length; i++) { var selected_drop = random_range[i], selected_drop_media_length = selected_drop.content ? selected_drop.content.length : 0, selected_random_index = Math.floor(Math.random() * (selected_drop_media_length + 1)); selected_random_index === selected_drop_media_length ? random_items.push(selected_drop) : random_items.push(selected_drop.content[selected_random_index]) } if (random_cards.length) { var random_card_index = Math.floor(Math.random() * (random_items.length - 1)); random_items.splice(random_card_index, 0, random_cards.pop()) } $scope.items = $scope.items.concat(random_items), $scope.ready = !0 }, this.load_featured_drop() }]), angular.module("dropApp").controller("AllCtrl", ["$scope", "$timeout", "Api", "ngProgress", function($scope, $timeout, Api, ngProgress) { $scope.limit = 6, $scope.limit_per_page = 6, $scope.visible = !1, this.load_drops = function() { ngProgress.start(), Api.get_all_drops().then(function(response) { ngProgress.complete(), $timeout(function() { $scope.drops = response.reverse(), $scope.visible = !0 }, 500) }) }, $scope.background = "/images/auth/all.jpg", $scope.next_page = function() { $scope.limit = $scope.limit + $scope.limit_per_page }, this.load_drops() }]), angular.module("dropApp").controller("CreateCtrl", ["$scope", "$q", "$timeout", "Api", "Spotify", "ngProgress", function($scope, $q, $timeout, Api, Spotify, ngProgress) { $scope.card = {}, $scope.imageUrl = "spotify-thedrop.com", $scope.auth_blocked = !Spotify.get_access_token(), $scope.auth_blocked || (ngProgress.start(), $scope.auth_blocked = !1, $q.all([Spotify.get_user(), Api.get_all_drops()]).then(function(response) { ngProgress.complete(), $scope.card.drop = response[1][0], $scope.card.track = $scope.card.drop.song_list[0], $scope.$watch("card.drop", function() { $scope.card.track = $scope.card.drop.song_list[0], $scope.randomize() }, !0), $timeout(function() { $timeout(function() { $scope.drops = response[1], $scope.card.user = response[0] }, 500) }, 500) }, function(response) { ngProgress.complete(), $scope.auth_blocked = !0, console.log("error") })), $scope.authenticate = function() { Spotify.authenticate() }, $scope.themes = [{ text: "#F59B23", foreground: "#AF2896", background: "#503750", value: 0 }, { text: "#2D46B9", foreground: "#CDF564", background: "#FF4632", value: 1 }, { text: "#F573A0", foreground: "#9BF0E1", background: "#503750", value: 2 }, { text: "#000000", foreground: "#FAE62D", background: "#F037A5", value: 3 }], $scope.background = "/images/auth/auth.png", $scope.bursts = ["/images/bursts/triangle.png", "/images/bursts/rectangle.png", "/images/bursts/circle.png"], $scope.select_type = function(type) { $scope.card.type = type }, $scope.select_burst = function(burst) { $scope.card.burst = burst }, $scope.select_image = function(image) { $scope.card.image = image }, $scope.select_theme = function(theme) { $scope.card.theme = theme }, $scope.scale_background = function() { $scope.card.scale = !$scope.card.scale }, $scope.flip_background = function() { $scope.card.flip = !$scope.card.flip }, $scope.rotate_background = function() { $scope.card.rotation = $scope.card.rotation < 3 ? ++$scope.card.rotation : 0 }, $scope.drag_background = function() { $scope.drag = !$scope.drag }, $scope.randomize = function() { $scope.card.type = Math.random() >= .5 ? "burst" : "image", $scope.card.image = $scope.card.drop ? $scope.card.drop.card_images[Math.floor(Math.random() * $scope.card.drop.card_images.length)] : "", $scope.card.burst = $scope.bursts[Math.floor(Math.random() * $scope.bursts.length)], $scope.card.theme = $scope.themes[Math.floor(Math.random() * $scope.themes.length)], $scope.card.rotation = Math.floor(3 * Math.random()), $scope.card.flip = Math.random() >= .5, $scope.card.scale = Math.random() >= .5 } }]), angular.module("dropApp").controller("DropCtrl", ["$scope", "$routeParams", "$timeout", "$location", "Api", function($scope, $routeParams, $timeout, $location, Api) { function load_drop() { isNaN($routeParams.id) ? Api.get_featured().then(render_drop) : Api.get_drop($routeParams.id).then(render_drop) } function render_drop(drop) { "i" === drop.dropped_at.charAt(0) || "i" === drop.dropped_at.charAt(5) ? drop.dropped = !1 : drop.dropped = !0, $scope.drop = drop, $scope.drop.album_uri = "spotify:album:" + $scope.drop.album_uri, $scope.drop.endpoint = "http://open.spotify.com/" + $scope.drop.album_uri.replace("spotify:", "").replace(/:/g, "/"), $scope.spotify = "/images/spotify.png"; for (var i = $scope.drop.content.length; i--; i >= 0) $scope.drop.content[i].locked ? $scope.drop.content.splice($scope.drop.content.length, 0, $scope.drop.content.splice($scope.drop.content[i], 1)[0]) : $scope.items.unshift($scope.drop.content[i]); Api.get_ad().then(function(response) { $scope.items.push(response[0]) }), $timeout(function() { $scope.$broadcast("timer-start") }, 400), $scope.$on("$routeUpdate", $scope.on_route_update), $scope.on_route_update() } $scope.items = [], $scope.clickWatch = 0, $scope.set_media = function(index) { $location.search("media", index), $scope.clickWatch++ }, $scope.clear_media = function() { $(".youtube-player iframe").remove(), $location.url($location.path()) }, $scope.on_route_update = function() { $scope.media_index = $location.search().media, $scope.media = $scope.drop.content[$scope.media_index] }, load_drop() }]), angular.module("dropApp").directive("audioPlayer", function() { return { scope: { uri: "=audioPlayerUri", albumUri: "=audioPlayerAlbumUri", revealDate: "=audioPlayerRevealDate" }, link: function(scope, element) { var base = '<iframe src="https://embed.spotify.com/?uri={uri}" width="100%" height="100%" frameborder="0" allowtransparency="true"></iframe>'; scope.afterRelease = !1, scope.$watch("revealDate", function() { if (scope.revealDate) { var revealDate = moment(scope.revealDate), currentDate = moment(), diff = currentDate.diff(revealDate, "seconds"); scope.afterRelease = diff > 0 ? !0 : !1 } }), scope.$watch("albumUri", function() { scope.afterRelease && (scope.albumUri ? (element.html(base.replace("{uri}", scope.albumUri)), setTimeout(function() { element.addClass("activated album") }, 500)) : element.removeClass("activated")) }), scope.$watch("uri", function() { scope.afterRelease || (scope.uri ? (element.html(base.replace("{uri}", scope.uri)), setTimeout(function() { element.addClass("activated") }, 500)) : element.removeClass("activated")) }) } } }), angular.module("dropApp").directive("slider", function() { return { scope: { options: "=sliderOptions", switcher: "=clickWatch" }, templateUrl: "/partials/slider.html", transclude: !0, controller: ["$scope", function($scope) { this.initialize = function() { $scope.init() } }], link: function(scope, element) { var defaults = { grabCursor: !0, pagination: $(element).find(".swiper-pagination"), nextButton: $(element).find(".swiper-button-next"), prevButton: $(element).find(".swiper-button-prev"), paginationClickable: !0, preloadImages: !1, lazyLoading: !0 }; scope.$watch("switcher", function() { $(".swiper-slide .swiper-lazy").each(function(idx) { self = $(this), $(this).attr("src") && (self.removeClass("swiper-lazy-loaded"), self.removeAttr("src"), setTimeout(function() { s.lazy.load() })) }) }); var s, options = angular.extend(defaults, scope.options); scope.init = function() { s && s.destroy(), setTimeout(function() { s = new Swiper(element[0], options) }, 100) } } } }), angular.module("dropApp").directive("sliderItem", function() { return { require: "^slider", link: function(scope, element, attrs, sliderCtrl) { scope.$last && sliderCtrl.initialize() } } }), angular.module("dropApp").directive("mediaCircle", function() { return { templateUrl: "partials/media-circle.html", link: function(scope, element) { var r = 4 * Math.random() + 2.5, t = .25 * Math.PI, labelX = r + r * Math.cos(t), labelY = r + r * Math.sin(t); scope.circleStyle = { width: 2 * r + "em", height: 2 * r + "em" }, scope.labelStyle = { top: labelY + "em", left: labelX + "em" }, setTimeout(function() { element.addClass("revealed") }, 200 * scope.$index + 1500) } } }), angular.module("dropApp").directive("imageLoader", function() { return { scope: { imageLoaderSrc: "=imageLoaderSrc" }, template: '<div class="image-loader-element" ng-style="backgroundImage"></div><div class="image-loader-progress"></div>', link: function(scope, element, attrs) { function loadImage() { image = new Image, image.onload = onImageLoaded, image.src = scope.imageLoaderSrc, element.removeClass("image-loader-complete").addClass("image-loader-loading") } function onImageLoaded() { void 0 !== attrs.backgroundImage && scope.$emit("imageLoaded"), element.removeClass("image-loader-loading").addClass("image-loader-complete").children().first().css("background-image", "url(" + scope.imageLoaderSrc + ")") } function onImageError() { element.removeClass("image-loader-loading").removeClass("image-loader-complete") } var image; scope.$watch("imageLoaderSrc", function(val) { val ? setTimeout(function() { loadImage() }, 300) : onImageError() }) } } }), angular.module("dropApp").directive("gallery", function() { return { scope: { items: "=galleryItems" }, templateUrl: "partials/gallery.html", link: function(scope, element, attrs) { scope.gallerySliderOptions = { slidesPerView: 1, pagination: ".swiper-pagination", nextButton: ".swiper-button-next", prevButton: ".swiper-button-prev", paginationClickable: !0, preloadImages: !1, lazyLoading: !0, loop: !0 } } } }), angular.module("dropApp").directive("youtubePlayer", ["$sce", "$timeout", function($sce, $timeout) { return { scope: { data: "=youtubePlayer" }, templateUrl: "partials/videoplayer.html", link: function(scope, element, attrs) { var id, base = "http://www.youtube.com/embed/{id}?autoplay=1&showinfo=0&rel=0&autohide=1&showinfo=0&enablejsapi=1&playerapiid=ytplaye"; scope.visible = !1, scope.$watch("data", function() { if (scope.data && scope.data.content) { if (!scope.data.content.url) return void scope.stop(); id = scope.data.content.url.split("watch?v=")[1], $timeout(scope.play, 500) } else scope.stop() }), scope.play = function() { scope.iframe_url = $sce.trustAsResourceUrl(base.replace("{id}", id)), scope.playing = !0 }, scope.stop = function() { scope.iframe_url = $sce.trustAsResourceUrl("about:blank"), scope.playing = !1 }, window.uploadDone = function() { scope.data && (scope.visible = !0, scope.$apply()) } } } }]), angular.module("dropApp").directive("packery", function() { return { scope: !0, controller: ["$scope", function($scope) { this.initialize = function() { $scope.init() } }], link: function(scope, element, attrs) { var p, defaults = { itemSelector: ".block-item", percentPosition: !0, masonry: { columnWidth: ".block-item-small" } }; scope.init = function() { setTimeout(function() { p = new Isotope(element[0], defaults) }, 200), setTimeout(function() { p.arrange() }, 300) } } } }), angular.module("dropApp").directive("packeryItem", function() { return { require: "^packery", link: function(scope, element, attrs, packeryCtrl) { scope.$last && packeryCtrl.initialize() } } }), angular.module("dropApp").directive("blockItem", function() { return { scope: { data: "=blockItemData" }, template: '<div ng-include="get_template_url()"></div>', link: function(scope, element, attrs) { function generate_media_cta(type) { switch (type) { case "video": return "watch now"; case "playlist": return "listen"; case "single": return "listen"; case "gallery": return "view now"; case "ad": return "watch now"; default: return "view " + type } } function get_image_url(id, files) { return files[id] ? files[id].url : null } function build_card() { switch (scope.data.type) { case "card": scope.template_url = "partials/block-item-card.html", scope.cta = "create your card", scope.image = get_image_url(scope.data.image_id, scope.data.files), element.addClass("block-item-small block-item-card"); break; case "ad": scope.template_url = "partials/block-item-ad.html", scope.cta = "", scope.ad_url = scope.data.ad_url, scope.tracking_pixel_url = scope.data.tracking_pixel_url, element.addClass("block-item-small block-item-ad"); break; case "media": scope.template_url = "partials/block-item-media.html", scope.cta = generate_media_cta(scope.data.media_type), element.addClass("video" === scope.data.media_type ? "block-item-large" : "block-item-small"); break; case "drop": scope.template_url = "partials/block-item-drop.html", scope.cta = "view drop", element.addClass("block-item-small") } if (!scope.data.image && !scope.data.featured_image) { var random_drop_style = Math.floor(5 * Math.random()); element.addClass("drop-style-" + random_drop_style) } } scope.$watch("data", function(val) { val && build_card() }), scope.get_template_url = function() { return scope.template_url }, scope.show_ad_video = function(youtube_id) { if (youtube_id) { var iframeHtml = '<iframe width="560" height="315" style="z-index: 2" src="http://www.youtube.com/embed/' + youtube_id + '?autoplay=1&showinfo=0" frameborder="0" allowfullscreen></iframe>'; $.fancybox(iframeHtml, { title: "", closeBtn: !1, closeClick: !0, width: 560, height: 300, autoSize: !1, autoHeight: !1, scrolling: !1, helpers: { overlay: { closeClick: !0, locked: !1, css: { position: "fixed", width: "100%", height: "100%", top: 0, left: 0, background: "rgba(50,50,50, 0.7)", zIndex: 0 } } } }) } }, scope.is_playing = !1, scope.toggle_music = function() { scope.is_playing ? (scope.is_playing = !1, element.removeClass("block-item-playing"), scope.audio_uri = null) : (scope.is_playing = !0, element.addClass("block-item-playing"), scope.audio_uri = "spotify:track:1XALSFY5nrFQ9NaI2XNp9t") } } } }), angular.module("dropApp").directive("dropCard", ["Image", "Api", function(Image, Api) { return { scope: !1, restrict: "A", link: function(scope, element, attrs) { function render_background() { var is_burst = "burst" === scope.card.type; background.onImageLoaded(function() { var img_data = background.getOriginalImageData(); img_data = Image.duotone(img_data, scope.card.theme.background, scope.card.theme.foreground), img_data = scope.card.flip ? Image.flipImage(img_data) : img_data, background.setImageData(img_data), background.setRotation(is_burst ? 90 * scope.card.rotation : 0), background.update(!is_burst && scope.card.scale ? { w: 900, h: 900, x: -300, y: -300 } : { w: 450, h: 450, x: -75, y: -75 }) }), card.background.update({ fill: scope.card.theme.background }), background.changeURL(is_burst ? scope.card.burst : scope.card.image) } function render_text() { return scope.card.track ? (text.song.changeText(scope.card.track), text.songxs.changeText(""), text.artist.changeText(scope.card.drop.album), text.song.w > 270 ? (text.song.changeText(""), text.songxs.changeText(scope.card.track), format_text("small"), text.songxs.w > 270 && text.songxs.truncate(270)) : format_text("normal"), void(text.artist.w > 200 && text.artist.truncate(200))) : !1 } function format_text(type) { switch (type) { case "small": text.headline.update({ y: 100 }), text.songxs.update({ y: 138 }), text.from.update({ y: 170 }), text.artist.update({ y: 170 }); break; default: text.headline.update({ y: 100 }), text.song.update({ y: 145 }), text.from.update({ y: 178 }), text.artist.update({ y: 178 }) } for (var t in text) text[t].update({ fill: scope.card.theme.text }) } function render_user() { if (scope.card.user) { var img = new window.Image; img.crossOrigin = "Anonymous", img.onload = function() { var c = document.createElement("canvas"), ctx = c.getContext("2d"); ctx.beginPath(), ctx.arc(25, 25, 25, 0, 2 * Math.PI, !0), ctx.closePath(), ctx.fill(), ctx.clip(), ctx.drawImage(this, 0, 0, 50, 50); var d = ctx.getImageData(0, 0, 50, 50); avatar.setImageData(d), avatar.update({ y: 15 }) }, img.src = scope.card.user.images[0].url, username.changeText(scope.card.user.display_name), username.update({ y: 35 }) } } function onMouseLeave() { is_dragging = !1 } function onMouseDown(x, y) { drag_position.x = x - background.x, drag_position.y = y - background.y, is_dragging = !0 } function onMouseUp() { is_dragging = !1 } function onMouseMove(x, y) { if (is_dragging) { var _x = x - drag_position.x, _y = y - drag_position.y; _x >= -1 ? _x = -1 : _x + background.w <= card.width - 1 && (_x = card.width - background.w + 1), _y >= -1 ? _y = -1 : _y + background.h <= card.height - 1 && (_y = card.height - background.h + 1), background.update({ x: _x, y: _y }) } } var card = new Postcard(element[0], { filename: "dropcard.png" }), background = card.addImage("background", ""), avatar = (card.addImage("bottomLogos", "/images/bottomlogos.png", { x: 0, y: 260, w: 300, h: 40 }), card.addImage("avatar", "/images/sample-profile.png", { x: 15, y: -45, w: 35, h: 35 })), username = card.addText("username", "", 10, { x: 58, y: -35, family: "light", size: "14px" }), text = { headline: card.addText("intro", "I'm feeling", 10, { x: 15, y: -15, family: "light", size: "20px" }), song: card.addText("song", "", 10, { x: 15, y: 128, family: "bold", size: "40px" }), songxs: card.addText("song.small", "", 10, { x: 15, y: 121, family: "bold", size: "30px" }), from: card.addText("from", "from", 10, { x: 15, y: -15, family: "light", size: "20px" }), artist: card.addText("artist", "", 10, { x: 63, y: -15, family: "bold", size: "20px" }), cta: card.addText("cta", "Album out now", 10, { x: 15, y: -15, family: "light", size: "15px" }) }; scope.refresh = function() { scope.saved = !1, render_background(), render_text(), render_user() }, scope.$watch("card", scope.refresh, !0), scope.randomize(); var is_dragging = !1, drag_position = {}; scope.$watch("drag", function() { scope.drag ? (element.css("cursor", "move").bind("mouseleave", onMouseLeave), card.onMouseDown(onMouseDown), card.onMouseUp(onMouseUp), card.onMouseMove(onMouseMove)) : (element.css("cursor", "auto"), card.clearMouseEvents()) }), scope.save = function() { Api.save_card(scope.card, card["export"]()).then(function(response) { scope.saved = !0, Api.get_single_card(response).then(function(data) { scope.imageUrl = encodeURIComponent(data.files[data.image_id].url) }) }) }, scope.download = function(event) { card.save(event) }, PostcardTextObject.prototype.truncate = function(width) { for (var t = this.text, i = 0; this.w > width;) this.changeText(t.substr(0, t.length - ++i) + "...") } } } }]), angular.module("dropApp").directive("mediaIcon", function() { return { scope: { media: "=mediaIcon" }, link: function(scope, element, attrs) { scope.$watch("media", function() { if (element.removeClass(), scope.media.locked) element.replaceWith('<div class="exlusive-video"><img src="/images/icons/Locked-white.svg"><span>Locked Content</span></div>'); else switch (scope.media.media_type) { case "video": element.replaceWith('<div class="exlusive-video"><img src="/images/icons/Video-white.svg"><span>Exclusive Video</span></div>'); break; case "playlist": element.replaceWith('<div class="exlusive-video"><img src="/images/icons/Playlist-white.svg"><span>Exclusive Playlist</span></div>'); break; case "single": element.addClass("fa fa-play"); break; case "gallery": element.replaceWith('<div class="exlusive-video"><img src="/images/icons/Gallery-white.svg"><span>Exclusive Gallery</span></div>') } }) } } });