From e450c52ce06f48859024c2efa9ccee0e4cd6c457 Mon Sep 17 00:00:00 2001 From: Brandon Hundt Date: Mon, 26 Jun 2017 10:31:42 -0500 Subject: [PATCH 1/3] created Opinary embed container --- src/html/modal/modal_opinary.html | 19 +++++++++++ src/js/demo.js | 2 +- src/js/embedModal.js | 3 +- src/js/embeds/opinaryEmbed.js | 55 +++++++++++++++++++++++++++++++ src/js/templateCache.js | 3 +- 5 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 src/html/modal/modal_opinary.html create mode 100644 src/js/embeds/opinaryEmbed.js mode change 100755 => 100644 src/js/templateCache.js diff --git a/src/html/modal/modal_opinary.html b/src/html/modal/modal_opinary.html new file mode 100644 index 0000000..f757a8e --- /dev/null +++ b/src/html/modal/modal_opinary.html @@ -0,0 +1,19 @@ +
+
+
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+
\ No newline at end of file diff --git a/src/js/demo.js b/src/js/demo.js index 64ac107..62e61d3 100644 --- a/src/js/demo.js +++ b/src/js/demo.js @@ -184,7 +184,7 @@ $(document).ready(function(){ domainName: 'https://test-services.pri.org', // it is configured in the entity embed addon, but this is modalOptions: { addOnly: true, - embedTypeStr: ['image', 'audio', 'slideshow'] + embedTypeStr: ['image', 'audio', 'slideshow', 'opinary'] } }) // a good example that configuration can be done like so .done(function(scope){ diff --git a/src/js/embedModal.js b/src/js/embedModal.js index 47efe4b..baea967 100644 --- a/src/js/embedModal.js +++ b/src/js/embedModal.js @@ -35,7 +35,8 @@ var EntityEmbed = EntityEmbed || {}; externalLink:{}, newsletterSubscribe:{}, iframe:{}, - customText:{} + customText:{}, + opinary:{}, } }; var embedTypes = []; diff --git a/src/js/embeds/opinaryEmbed.js b/src/js/embeds/opinaryEmbed.js new file mode 100644 index 0000000..2c2f2f6 --- /dev/null +++ b/src/js/embeds/opinaryEmbed.js @@ -0,0 +1,55 @@ +var EntityEmbed = EntityEmbed || {}; + +(function(){ + + 'use strict'; + + // PRIVATE + var embedName = 'opinary', + defaults = { + viewPath: 'modal_opinary.html', + displayName: 'Opinary', + object_type: 'opinary', + validationOptions: { + rules: { + title: 'required', + url: 'required', + } + } + }; + + // CONSTRUCTOR + function opinaryEmbed(options){ + var self = this; + self.parent.constructor(options, defaults, embedName, self); + }; + + opinaryEmbed.inherits(EntityEmbed.embedTypes.genericEmbed); + EntityEmbed.embedTypes[embedName] = opinaryEmbed; + + + // PUBLIC + opinaryEmbed.prototype.orderIndex = 14; + + opinaryEmbed.prototype.cleanModel = function(){ + return { + title: null, + url: null, + object_type: defaults.object_type + }; + }; + + opinaryEmbed.prototype.parseForEditor = function(){ + var html = [ + '
', + '
', + '', + '
', + '
', + '' + ].join(''); + + return html; + }; + +})(); \ No newline at end of file diff --git a/src/js/templateCache.js b/src/js/templateCache.js old mode 100755 new mode 100644 index 7b72644..a9242bb --- a/src/js/templateCache.js +++ b/src/js/templateCache.js @@ -6,10 +6,11 @@ templateCache["modal/modal_customText.html"] = "

"; templateCache["modal/modal_facebook.html"] = "
"; templateCache["modal/modal_iframe.html"] = "
px
px
"; -templateCache["modal/modal_image.html"] = "
"; +templateCache["modal/modal_image.html"] = "
"; templateCache["modal/modal_instagram.html"] = "
"; templateCache["modal/modal_main.html"] = "

"; templateCache["modal/modal_newsletterSubscribe.html"] = "

"; +templateCache["modal/modal_opinary.html"] = "
"; templateCache["modal/modal_relatedLink.html"] = "

"; templateCache["modal/modal_slideshow.html"] = "

"; templateCache["modal/modal_twitter.html"] = "
"; From 553e49f86fa6a89425149f99e6844c96bb99db53 Mon Sep 17 00:00:00 2001 From: Brandon Hundt Date: Mon, 26 Jun 2017 10:34:24 -0500 Subject: [PATCH 2/3] removing comma at end of array --- src/js/embedModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/embedModal.js b/src/js/embedModal.js index baea967..902256d 100644 --- a/src/js/embedModal.js +++ b/src/js/embedModal.js @@ -36,7 +36,7 @@ var EntityEmbed = EntityEmbed || {}; newsletterSubscribe:{}, iframe:{}, customText:{}, - opinary:{}, + opinary:{} } }; var embedTypes = []; From acdb8246809790ca1c7a530166053ff7fef64f19 Mon Sep 17 00:00:00 2001 From: Rick Peterman Date: Mon, 26 Jun 2017 16:46:14 -0400 Subject: [PATCH 3/3] Updated Opinary embed modal Issue #367 - Updated Opinary embed modal to fuction similar to social and video embed modals. Provides URL validation, embed preview, and URL duplication checks. - Added `.social_editor-blocker` style to provide element to prevent embed interaction to `.social_editor-preview` as needed. - Fixed social embeds validation error messages to refer to the correct service, not just Facebook. --- src/contents/less/embed-containers.less | 4 +- src/contents/less/priEmbeds/opinaryEmbed.less | 4 + .../less/priEmbeds/priEntityEmbeds.less | 4 +- src/contents/less/social_editor.less | 12 + src/html/modal/modal_opinary.html | 37 ++- src/html/modal/modal_twitter.html | 88 +++---- src/js/embeds/facebookEmbed.js | 2 +- src/js/embeds/instagramEmbed.js | 4 +- src/js/embeds/opinaryEmbed.js | 218 +++++++++++++++++- src/js/embeds/twitterEmbed.js | 4 +- src/js/embeds/videoEmbed.js | 2 +- src/js/templateCache.js | 4 +- 12 files changed, 326 insertions(+), 57 deletions(-) create mode 100644 src/contents/less/priEmbeds/opinaryEmbed.less diff --git a/src/contents/less/embed-containers.less b/src/contents/less/embed-containers.less index b7db3a5..136d57d 100644 --- a/src/contents/less/embed-containers.less +++ b/src/contents/less/embed-containers.less @@ -32,4 +32,6 @@ @import "priEmbeds/twitterEmbed.less"; -@import "priEmbeds/slideshow.less"; \ No newline at end of file +@import "priEmbeds/slideshow.less"; + +@import "priEmbeds/opinaryEmbed.less"; \ No newline at end of file diff --git a/src/contents/less/priEmbeds/opinaryEmbed.less b/src/contents/less/priEmbeds/opinaryEmbed.less new file mode 100644 index 0000000..3ae1217 --- /dev/null +++ b/src/contents/less/priEmbeds/opinaryEmbed.less @@ -0,0 +1,4 @@ +.opinary-widget +{ + background-color: @body-bg; +} \ No newline at end of file diff --git a/src/contents/less/priEmbeds/priEntityEmbeds.less b/src/contents/less/priEmbeds/priEntityEmbeds.less index f66dfd0..a35ffa7 100644 --- a/src/contents/less/priEmbeds/priEntityEmbeds.less +++ b/src/contents/less/priEmbeds/priEntityEmbeds.less @@ -22,4 +22,6 @@ @import "twitterEmbed.less"; -@import "slideshow.less"; \ No newline at end of file +@import "slideshow.less"; + +@import "opinaryEmbed.less"; \ No newline at end of file diff --git a/src/contents/less/social_editor.less b/src/contents/less/social_editor.less index d539aef..b860e75 100644 --- a/src/contents/less/social_editor.less +++ b/src/contents/less/social_editor.less @@ -81,6 +81,8 @@ .social_editor-preview_inner { + position: relative; + > * { & + * { margin-left: 20px; @@ -152,4 +154,14 @@ color: @btn-primary-color; text-decoration: none; } +} + +.social_editor-blocker +{ + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; } \ No newline at end of file diff --git a/src/html/modal/modal_opinary.html b/src/html/modal/modal_opinary.html index f757a8e..ab9b360 100644 --- a/src/html/modal/modal_opinary.html +++ b/src/html/modal/modal_opinary.html @@ -12,7 +12,42 @@
- + + +
diff --git a/src/html/modal/modal_twitter.html b/src/html/modal/modal_twitter.html index c09604a..74ac762 100644 --- a/src/html/modal/modal_twitter.html +++ b/src/html/modal/modal_twitter.html @@ -1,52 +1,52 @@
-
-
-
- - -
-
-
-
-
-
- +
+
+
+ + +
+
+
+
+
+
+ - -
-
-
+
+
+
\ No newline at end of file diff --git a/src/js/embeds/facebookEmbed.js b/src/js/embeds/facebookEmbed.js index ffd8f87..dc23b33 100644 --- a/src/js/embeds/facebookEmbed.js +++ b/src/js/embeds/facebookEmbed.js @@ -355,7 +355,7 @@ var EntityEmbed = EntityEmbed || {}; } else { - // Get Video embeds that have matching URL + // Get Facebook embeds that have matching URL EntityEmbed.apiService.get({ path: self.options.httpPaths.getAll, data: { diff --git a/src/js/embeds/instagramEmbed.js b/src/js/embeds/instagramEmbed.js index 73b2351..e2945bd 100644 --- a/src/js/embeds/instagramEmbed.js +++ b/src/js/embeds/instagramEmbed.js @@ -210,7 +210,7 @@ var EntityEmbed = EntityEmbed || {}; $.validator.addMethod('validInstagramUrl', function(value, element, params) { var isValid = isValidUrl(value); return this.optional(element) || isValid; - }, 'The URL must be to a valid Facebook post or video.'); + }, 'The URL must be to a valid Instagram post.'); $ui.previewBtn.on('click', function(evt) { @@ -320,7 +320,7 @@ var EntityEmbed = EntityEmbed || {}; } else { - // Get Video embeds that have matching URL + // Get Instagram embeds that have matching URL EntityEmbed.apiService.get({ path: self.options.httpPaths.getAll, data: { diff --git a/src/js/embeds/opinaryEmbed.js b/src/js/embeds/opinaryEmbed.js index 2c2f2f6..36c3f5a 100644 --- a/src/js/embeds/opinaryEmbed.js +++ b/src/js/embeds/opinaryEmbed.js @@ -13,11 +13,78 @@ var EntityEmbed = EntityEmbed || {}; validationOptions: { rules: { title: 'required', - url: 'required', + url: { + required: true, + validOpinaryPollUrl: true + } } } + }, + uiElements = { + intro: '.social_editor-intro', + previewBtn: '.js-btn-preview', + preview: '.social_editor-preview', + previewPost: '.social_editor-preview_post', + titleInput: '.js-input-title', + urlInput: '.js-input-url', + editBtn: '.js-btn-edit', + cancelBtn: '.js-btn-cancel', + dropTarget: '.social_editor-intro_inner' }; + function registerUiElements(scope, $el) { + scope.$ui = scope.$ui || {}; + + for(var key in uiElements) + { + if(uiElements.hasOwnProperty(key)) + { + scope.$ui[key] = $(uiElements[key], $el); + } + } + + return scope.$ui; + } + + function showIntro(scope) { + var $ui = scope.$ui; + + // Show cancel button as needed + $ui.cancelBtn.toggle(!!scope.modalCtrl.isAdd); + + // Show intro + $ui.intro.show(); + + // Hide preview related elements + $ui.preview.hide(); + $ui.editBtn.hide(); + } + + function showPreview(scope) { + var $ui = scope.$ui; + + // Append embed html code + $ui.previewPost.html(scope.parseForEditor()); + + // Set title text + $ui.titleInput.val(scope.model.title); + + // Show edit btn as needed + $ui.editBtn.toggle(!!scope.modalCtrl.isAdd); + + // Show preview container + $ui.preview.show(); + + // Hide intro related elements + $ui.intro.hide(); + $ui.cancelBtn.hide(); + } + + function isValidUrl(url) { + var rgxOpinaryPollUrl = /^(?:https:)?\/\/compass.pressekompass.net\/compasses/i; + return rgxOpinaryPollUrl.test(url); + } + // CONSTRUCTOR function opinaryEmbed(options){ var self = this; @@ -27,10 +94,87 @@ var EntityEmbed = EntityEmbed || {}; opinaryEmbed.inherits(EntityEmbed.embedTypes.genericEmbed); EntityEmbed.embedTypes[embedName] = opinaryEmbed; - // PUBLIC opinaryEmbed.prototype.orderIndex = 14; + // function to initialize the modal view + // called after the modal view has loaded + // $el: a jQuery element for the modal view + opinaryEmbed.prototype.initModal = function($el, modalCtrl) { + var self = this; + var $ui; + + self.parent.initModal($el, modalCtrl, self); + + $ui = registerUiElements(self, $el); + + $.validator.addMethod('validOpinaryPollUrl', function(value, element, params) { + var isValid = isValidUrl(value); + return this.optional(element) || isValid; + }, 'The URL must be to a valid Opinary poll.'); + + $ui.previewBtn.on('click', function(evt) { + + evt.preventDefault(); + + self.getModelFromForm($el); + + if(isValidUrl(self.model.url)) + { + showPreview(self); + } + }); + + $ui.editBtn.on('click', function(evt) { + evt.preventDefault(); + showIntro(self); + }); + + $ui.cancelBtn.on('click', function(evt) { + evt.preventDefault(); + showPreview(self); + }); + + $ui.dropTarget + .on('dragenter dragover', function() { + $(this).addClass('js-dragover'); + }) + .on('dragleave drop', function() { + $(this).removeClass('js-dragover'); + }) + .on('drop', function(evt) { + + evt.stopPropagation(); + evt.preventDefault(); + + var droppedString = evt.originalEvent.dataTransfer.getData('text/plain'); + var droppedHtml = evt.originalEvent.dataTransfer.getData('text/html'); + var $droppedElm = $( droppedHtml ); + var $context = $('
'); + var droppedUrl; + + if(!!droppedString) + { + droppedUrl = droppedString; + } + else if(!!$droppedElm.length) + { + $context.append($droppedElm); + droppedUrl = $context.find('[href]').attr('href'); + } + + if(!!droppedUrl && isValidUrl(droppedUrl)) + { + $ui.urlInput.val(droppedUrl); + $ui.previewBtn.click(); + } + }); + + $(document).on('dragover drop', function(event) { + event.preventDefault(); + }); + }; + opinaryEmbed.prototype.cleanModel = function(){ return { title: null, @@ -39,6 +183,76 @@ var EntityEmbed = EntityEmbed || {}; }; }; + opinaryEmbed.prototype.clearForm = function($el) { + var self = this; + + self.parent.clearForm($el, self); + + showIntro(self); + + self.$ui.previewPost.empty(); + }; + + opinaryEmbed.prototype.getModelFromForm = function($form) { + var self = this; + var promise = $.Deferred(); + + // Gather fields data + self.parent.getModelFromForm($form.find('form').first(), self); + + if(!!self.model.object_id) + { + // Not a new embed. Don't need to check for duplication when editing. + promise.resolve(self.model); + } + else + { + // Get Opinary embeds that have matching URL + EntityEmbed.apiService.get({ + path: self.options.httpPaths.getAll, + data: { + url: self.model.url, + object_type: self.options.object_type + } + }) + .done(function(resp) { + var items = resp.response && resp.response.data || []; + + if(!!items.length && items[0].url === self.model.url) + { + // Use object_id from first item + self.model.object_id = items[0].object_id; + // Make sure original title is used + self.model.title = items[0].title; + self.$ui.titleInput.val(self.model.title); + } + }) + .always(function() { + // Always resolve to keep things moving. + promise.resolve(self.model); + }); + } + + return promise; + }; + + opinaryEmbed.prototype.populateFormWithModel = function($form) { + var self = this; + var $ui = self.$ui; + + self.parent.populateFormWithModel($form.find('form').first(), self); + + // Show video player and title + if(!self.model.object_id) + { + showIntro(self); + } + else + { + showPreview(self); + } + }; + opinaryEmbed.prototype.parseForEditor = function(){ var html = [ '
', diff --git a/src/js/embeds/twitterEmbed.js b/src/js/embeds/twitterEmbed.js index a8d10cf..6cb571e 100644 --- a/src/js/embeds/twitterEmbed.js +++ b/src/js/embeds/twitterEmbed.js @@ -199,7 +199,7 @@ var EntityEmbed = EntityEmbed || {}; $.validator.addMethod('validTwitterUrl', function(value, element, params) { var isValid = isValidUrl(value); return this.optional(element) || isValid; - }, 'The URL must be to a valid Facebook post or video.'); + }, 'The URL must be to a valid Twitter status.'); $ui.previewBtn.on('click', function(evt) { @@ -304,7 +304,7 @@ var EntityEmbed = EntityEmbed || {}; } else { - // Get Video embeds that have matching URL + // Get Twitter embeds that have matching URL EntityEmbed.apiService.get({ path: self.options.httpPaths.getAll, data: { diff --git a/src/js/embeds/videoEmbed.js b/src/js/embeds/videoEmbed.js index 3d0195b..84a77ac 100644 --- a/src/js/embeds/videoEmbed.js +++ b/src/js/embeds/videoEmbed.js @@ -296,7 +296,7 @@ var EntityEmbed = EntityEmbed || {}; $.validator.addMethod('validVideoDomain', function(value, element, params) { var isValid = value.indexOf('youtube.com') != -1 || value.indexOf('vimeo.com') != -1; return this.optional(element) || isValid; - }, 'The video must be from YouTube or Vimeo'); + }, 'The video must be from YouTube or Vimeo.'); $ui.previewBtn.on('click', function(e) { diff --git a/src/js/templateCache.js b/src/js/templateCache.js index a9242bb..c5c14e5 100644 --- a/src/js/templateCache.js +++ b/src/js/templateCache.js @@ -6,11 +6,11 @@ templateCache["modal/modal_customText.html"] = "

"; templateCache["modal/modal_facebook.html"] = "
"; templateCache["modal/modal_iframe.html"] = "
px
px
"; -templateCache["modal/modal_image.html"] = "
"; +templateCache["modal/modal_image.html"] = "
"; templateCache["modal/modal_instagram.html"] = "
"; templateCache["modal/modal_main.html"] = "

"; templateCache["modal/modal_newsletterSubscribe.html"] = "

"; -templateCache["modal/modal_opinary.html"] = "
"; +templateCache["modal/modal_opinary.html"] = "
"; templateCache["modal/modal_relatedLink.html"] = "

"; templateCache["modal/modal_slideshow.html"] = "

"; templateCache["modal/modal_twitter.html"] = "
";