Commit a6fbcbd7 by Zubair Afzal

Add baseview(extended from backbone view), which can further extended by other…

Add baseview(extended from backbone view), which can further extended by other views + Add fucntion to modify iframe and embed tags + add related tests
STUD-823
parent 608aaf31
......@@ -199,6 +199,8 @@ define([
"js/spec/utils/module_spec",
"js/spec/models/explicit_url_spec"
"js/spec/views/baseview_spec",
"js/spec/utils/handle_iframe_binding_spec",
# these tests are run separate in the cms-squire suite, due to process
# isolation issues with Squire.js
......
require(["domReady", "jquery", "underscore", "gettext", "js/views/feedback_notification", "js/views/feedback_prompt",
"js/utils/get_date", "js/utils/module", "jquery.ui", "jquery.leanModal", "jquery.form", "jquery.smoothScroll"],
function(domReady, $, _, gettext, NotificationView, PromptView, DateUtils, ModuleUtils) {
"js/utils/get_date", "js/utils/module", "js/utils/handle_iframe_binding", "jquery.ui", "jquery.leanModal", "jquery.form", "jquery.smoothScroll"],
function(domReady, $, _, gettext, NotificationView, PromptView, DateUtils, ModuleUtils, IframeUtils) {
var $body;
var $newComponentItem;
......@@ -113,6 +113,8 @@ domReady(function() {
$('.edit-subsection-publish-settings').on('change', '.start-date, .start-time', function() {
$('.edit-subsection-publish-settings').find('.save-button').show();
});
IframeUtils.iframeBinding();
});
function smoothScrollLink(e) {
......
define(
[
"jquery", "underscore",
"js/utils/handle_iframe_binding",
],
function ($, _, IframeBinding) {
describe("IframeBinding", function () {
var doc = document.implementation.createHTMLDocument("New Document");
var iframe_html = '<iframe src="http://www.youtube.com/embed/NHd27UvY-lw" frameborder="0" height="350" width="618"></iframe>';
iframe_html += '<iframe src="http://www.youtube.com/embed/NHd27UvY-lw?allowFullScreen=false" frameborder="0" height="350" width="618"></iframe>';
iframe_html += '<embed type="application/x-shockwave-flash" src="http://www.youtube.com/embed/NHd27UvY-lw" height="315" width="560">';
doc.body.innerHTML = iframe_html;
it("modifies src url of DOM iframe and embed elements when iframeBinding function is executed", function () {
expect($(doc).find("iframe")[0].src).toEqual("http://www.youtube.com/embed/NHd27UvY-lw");
expect($(doc).find("iframe")[1].src).toEqual("http://www.youtube.com/embed/NHd27UvY-lw?allowFullScreen=false");
expect($(doc).find("embed")[0].hasAttribute("wmode")).toBe(false);
IframeBinding.iframeBinding(doc);
//after calling iframeBinding function: src url of iframes should have "wmode=transparent" in its querystring
//and embed objects should have "wmode='transparent'" as an attribute
expect($(doc).find("iframe")[0].src).toEqual("http://www.youtube.com/embed/NHd27UvY-lw?wmode=transparent");
expect($(doc).find("iframe")[1].src).toEqual("http://www.youtube.com/embed/NHd27UvY-lw?wmode=transparent&allowFullScreen=false");
expect($(doc).find("embed")[0].hasAttribute("wmode")).toBe(true);
iframe_html = IframeBinding.iframeBindingHtml(iframe_html);
//after calling iframeBinding function: src url of iframes should have "wmode=transparent" in its querystring
//and embed objects should have "wmode='transparent'" as an attribute
expect(iframe_html).toEqual('<iframe src="http://www.youtube.com/embed/NHd27UvY-lw?wmode=transparent" frameborder="0" height="350" width="618"></iframe>' +
'<iframe src="http://www.youtube.com/embed/NHd27UvY-lw?wmode=transparent&amp;allowFullScreen=false" frameborder="0" height="350" width="618"></iframe>' +
'<embed wmode="transparent" type="application/x-shockwave-flash" src="http://www.youtube.com/embed/NHd27UvY-lw" height="315" width="560">');
});
});
});
define(
[
"jquery", "underscore",
"js/views/baseview",
"js/utils/handle_iframe_binding",
"sinon"
],
function ($, _, BaseView, IframeBinding, sinon) {
describe("BaseView check", function () {
var baseView;
var iframeBinding_spy;
beforeEach(function () {
iframeBinding_spy = sinon.spy(IframeBinding, "iframeBinding");
baseView = BaseView.prototype;
spyOn(baseView, 'initialize');
spyOn(baseView, 'beforeRender');
spyOn(baseView, 'render');
spyOn(baseView, 'afterRender').andCallThrough();
});
afterEach(function () {
iframeBinding_spy.restore();
});
it('calls before and after render functions when render of baseview is called', function () {
var baseview_temp = new BaseView()
baseview_temp.render();
expect(baseView.initialize).toHaveBeenCalled();
expect(baseView.beforeRender).toHaveBeenCalled();
expect(baseView.render).toHaveBeenCalled();
expect(baseView.afterRender).toHaveBeenCalled();
});
it('calls iframeBinding function when afterRender of baseview is called', function () {
var baseview_temp = new BaseView()
baseview_temp.render();
expect(baseView.afterRender).toHaveBeenCalled();
expect(iframeBinding_spy.called).toEqual(true);
//check calls count of iframeBinding function
expect(iframeBinding_spy.callCount).toBe(1);
IframeBinding.iframeBinding();
expect(iframeBinding_spy.callCount).toBe(2);
});
});
});
define(["jquery"], function($) {
var iframeBinding = function (e) {
var target_element = null;
if (typeof(e) == "undefined"){
target_element = $("iframe, embed");
} else {
if (typeof(e.nodeName) != 'undefined'){
target_element = $(e).find("iframe, embed");
} else{
target_element = e.$("iframe, embed");
}
}
modifyTagContent(target_element);
};
var modifyTagContent = function (target_element) {
target_element.each(function(){
if ($(this).prop('tagName') == 'IFRAME'){
var ifr_source = $(this).attr('src');
var wmode = "wmode=transparent";
if(ifr_source.indexOf('?') != -1) {
var getQString = ifr_source.split('?');
if (getQString[1].search('wmode=transparent') == -1){
var oldString = getQString[1];
var newString = getQString[0];
$(this).attr('src',newString+'?'+wmode+'&'+oldString);
}
}
else $(this).attr('src',ifr_source+'?'+wmode);
}
else{
$(this).attr('wmode', 'transparent');
}
});
};
// Modify iframe/embed tags in provided html string
// Use this method when provided data is just html sting not dom element
// This method will only modify iframe (add wmode=transparent in url querystring) and embed (add wmode=transparent as attribute)
// tags in html string so both tags will attach to dom and don't create z-index problem for other popups
// Note: embed tags should be modified before rendering as they are static objects as compared to iframes
// Note: this method can modify unintended html (invalid tags) while converting to dom object
var iframeBindingHtml = function (html_string) {
if (html_string){
var target_element = null;
var temp_content = document.createElement('div');
$(temp_content).html(html_string);
target_element = $(temp_content).find("iframe, embed");
if (target_element.length > 0){
modifyTagContent(target_element);
html_string = $(temp_content).html();
}
}
return html_string;
};
return {
iframeBinding: iframeBinding,
iframeBindingHtml: iframeBindingHtml
};
});
\ No newline at end of file
define(["backbone", "underscore"], function(Backbone, _) {
var AbstractEditor = Backbone.View.extend({
define(["js/views/baseview", "underscore"], function(BaseView, _) {
var AbstractEditor = BaseView.extend({
// Model is MetadataModel
initialize : function() {
......
define(["backbone", "underscore", "gettext", "js/views/feedback_prompt", "js/views/feedback_notification"],
function(Backbone, _, gettext, PromptView, NotificationView) {
var AssetView = Backbone.View.extend({
define(["js/views/baseview", "underscore", "gettext", "js/views/feedback_prompt", "js/views/feedback_notification"],
function(BaseView, _, gettext, PromptView, NotificationView) {
var AssetView = BaseView.extend({
initialize: function() {
this.template = _.template($("#asset-tpl").text());
this.listenTo(this.model, "change:locked", this.updateLockState);
......
define(["backbone", "js/views/asset"], function(Backbone, AssetView) {
define(["js/views/baseview", "js/views/asset"], function(BaseView, AssetView) {
var AssetsView = Backbone.View.extend({
var AssetsView = BaseView.extend({
// takes AssetCollection as model
initialize : function() {
......
define(
[
'jquery',
'underscore',
'backbone',
"js/utils/handle_iframe_binding"
],
function ($, _, Backbone, IframeUtils) {
/* This view is extended from backbone with custom functions 'beforeRender' and 'afterRender'. It allows other
views, which extend from it to access these custom functions. 'afterRender' function of BaseView calls a utility
function 'iframeBinding' which modifies iframe src urls on a page so that they are rendered as part of the DOM.
Other common functions which need to be run before/after can also be added here.
*/
var BaseView = Backbone.View.extend({
//override the constructor function
constructor: function(options) {
_.bindAll(this, 'beforeRender', 'render', 'afterRender');
var _this = this;
this.render = _.wrap(this.render, function (render) {
_this.beforeRender();
render();
_this.afterRender();
return _this;
});
//call Backbone's own constructor
Backbone.View.prototype.constructor.apply(this, arguments);
},
beforeRender: function () {
},
render: function () {
return this;
},
afterRender: function () {
IframeUtils.iframeBinding(this);
}
});
return BaseView;
});
\ No newline at end of file
define(["backbone", "underscore", "jquery"], function(Backbone, _, $) {
var ChecklistView = Backbone.View.extend({
define(["js/views/baseview", "underscore", "jquery"], function(BaseView, _, $) {
var ChecklistView = BaseView.extend({
// takes CMS.Models.Checklists as model
events : {
......
define(["backbone", "js/views/course_info_update", "js/views/course_info_handout"],
function(Backbone, CourseInfoUpdateView, CourseInfoHandoutView) {
define(["js/views/baseview", "js/views/course_info_update", "js/views/course_info_handout"],
function(BaseView, CourseInfoUpdateView, CourseInfoHandoutView) {
/* this view should own everything on the page which has controls effecting its operation
generate other views for the individual editors.
The render here adds views for each update/handout by delegating to their collections but does not
generate any html for the surrounding page.
*/
var CourseInfoEdit = Backbone.View.extend({
var CourseInfoEdit = BaseView.extend({
// takes CMS.Models.CourseInfo as model
tagName: 'div',
......
define(["backbone", "underscore", "codemirror", "js/views/feedback_notification", "js/views/course_info_helper", "js/utils/modal"],
function(Backbone, _, CodeMirror, NotificationView, CourseInfoHelper, ModalUtils) {
define(["js/views/baseview", "underscore", "codemirror", "js/views/feedback_notification", "js/views/course_info_helper", "js/utils/modal"],
function(BaseView, _, CodeMirror, NotificationView, CourseInfoHelper, ModalUtils) {
// the handouts view is dumb right now; it needs tied to a model and all that jazz
var CourseInfoHandoutsView = Backbone.View.extend({
var CourseInfoHandoutsView = BaseView.extend({
// collection is CourseUpdateCollection
events: {
"click .save-button" : "onSave",
......
define(["codemirror", "utility"],
function(CodeMirror) {
define(["codemirror", 'js/utils/handle_iframe_binding', "utility"],
function(CodeMirror, IframeBinding) {
var editWithCodeMirror = function(model, contentName, baseAssetUrl, textArea) {
var content = rewriteStaticLinks(model.get(contentName), baseAssetUrl, '/static/');
model.set(contentName, content);
......@@ -18,6 +18,11 @@ define(["codemirror", "utility"],
var changeContentToPreview = function (model, contentName, baseAssetUrl) {
var content = rewriteStaticLinks(model.get(contentName), '/static/', baseAssetUrl);
// Modify iframe (add wmode=transparent in url querystring) and embed (add wmode=transparent as attribute)
// tags in html string (content) so both tags will attach to dom and don't create z-index problem for other popups
// Note: content is modified before assigning to model because embed tags should be modified before rendering
// as they are static objects as compared to iframes
content = IframeBinding.iframeBindingHtml(content);
model.set(contentName, content);
return content;
};
......
define(["backbone", "underscore", "codemirror", "js/models/course_update",
define(["js/views/baseview", "underscore", "codemirror", "js/models/course_update",
"js/views/feedback_prompt", "js/views/feedback_notification", "js/views/course_info_helper", "js/utils/modal"],
function(Backbone, _, CodeMirror, CourseUpdateModel, PromptView, NotificationView, CourseInfoHelper, ModalUtils) {
function(BaseView, _, CodeMirror, CourseUpdateModel, PromptView, NotificationView, CourseInfoHelper, ModalUtils) {
var CourseInfoUpdateView = Backbone.View.extend({
var CourseInfoUpdateView = BaseView.extend({
// collection is CourseUpdateCollection
events: {
"click .new-update-button" : "onNew",
......
define(["backbone", "underscore", "underscore.string", "jquery", "gettext", "js/models/uploads", "js/views/uploads"],
function(Backbone, _, str, $, gettext, FileUploadModel, UploadDialogView) {
define(["js/views/baseview", "underscore", "underscore.string", "jquery", "gettext", "js/models/uploads", "js/views/uploads"],
function(BaseView, _, str, $, gettext, FileUploadModel, UploadDialogView) {
_.str = str; // used in template
var EditChapter = Backbone.View.extend({
var EditChapter = BaseView.extend({
initialize: function() {
this.template = _.template($("#edit-chapter-tpl").text());
this.listenTo(this.model, "change", this.render);
......
define(["backbone", "underscore", "jquery", "js/views/edit_chapter", "js/views/feedback_notification"],
function(Backbone, _, $, EditChapterView, NotificationView) {
var EditTextbook = Backbone.View.extend({
define(["js/views/baseview", "underscore", "jquery", "js/views/edit_chapter", "js/views/feedback_notification"],
function(BaseView, _, $, EditChapterView, NotificationView) {
var EditTextbook = BaseView.extend({
initialize: function() {
this.template = _.template($("#edit-textbook-tpl").text());
this.listenTo(this.model, "invalid", this.render);
......
define(["backbone", "underscore", "underscore.string", "jquery"], function(Backbone, _, str, $) {
var SystemFeedback = Backbone.View.extend({
define(["js/views/baseview", "underscore", "underscore.string", "jquery"], function(BaseView, _, str, $) {
var SystemFeedback = BaseView.extend({
options: {
title: "",
message: "",
......
define(["backbone", "underscore", "jquery", "js/views/edit_textbook", "js/views/show_textbook"],
function(Backbone, _, $, EditTextbookView, ShowTextbookView) {
var ListTextbooks = Backbone.View.extend({
define(["js/views/baseview", "underscore", "jquery", "js/views/edit_textbook", "js/views/show_textbook"],
function(BaseView, _, $, EditTextbookView, ShowTextbookView) {
var ListTextbooks = BaseView.extend({
initialize: function() {
this.emptyTemplate = _.template($("#no-textbooks-tpl").text());
this.listenTo(this.collection, 'all', this.render);
......
define(
[
"backbone", "underscore", "js/models/metadata", "js/views/abstract_editor",
"js/views/baseview", "underscore", "js/models/metadata", "js/views/abstract_editor",
"js/views/transcripts/metadata_videolist"
],
function(Backbone, _, MetadataModel, AbstractEditor, VideoList) {
function(BaseView, _, MetadataModel, AbstractEditor, VideoList) {
var Metadata = {};
Metadata.Editor = Backbone.View.extend({
Metadata.Editor = BaseView.extend({
// Model is CMS.Models.MetadataCollection,
initialize : function() {
......
define(["backbone", "underscore", "gettext", "js/models/assignment_grade", "js/views/feedback_notification"],
function(Backbone, _, gettext, AssignmentGrade, NotificationView) {
var OverviewAssignmentGrader = Backbone.View.extend({
define(["js/views/baseview", "underscore", "gettext", "js/models/assignment_grade", "js/views/feedback_notification"],
function(BaseView, _, gettext, AssignmentGrade, NotificationView) {
var OverviewAssignmentGrader = BaseView.extend({
// instantiate w/ { graders : CourseGraderCollection, el : <the gradable-status div> }
events : {
"click .menu-toggle" : "showGradeMenu",
......
define(["backbone", "underscore", "js/views/feedback_prompt", "js/views/section_show", "require"], function(Backbone, _, PromptView, SectionShowView, require) {
var SectionEdit = Backbone.View.extend({
define(["js/views/baseview", "underscore", "js/views/feedback_prompt", "js/views/section_show", "require"], function(BaseView, _, PromptView, SectionShowView, require) {
var SectionEdit = BaseView.extend({
render: function() {
var attrs = {
name: this.model.escape('name')
......
define(["backbone", "underscore", "gettext", "js/views/section_edit", "require"], function(Backbone, _, gettext, SectionEditView, require) {
define(["js/views/baseview", "underscore", "gettext", "js/views/section_edit", "require"], function(BaseView, _, gettext, SectionEditView, require) {
var SectionShow = Backbone.View.extend({
var SectionShow = BaseView.extend({
template: _.template('<span data-tooltip="<%= gettext("Edit this section\'s name") %>" class="section-name-span"><%= name %></span>'),
render: function() {
var attrs = {
......
define(["backbone", "underscore", "gettext", "js/views/feedback_notification", "js/views/feedback_prompt"],
function(Backbone, _, gettext, NotificationView, PromptView) {
var ShowTextbook = Backbone.View.extend({
define(["js/views/baseview", "underscore", "gettext", "js/views/feedback_notification", "js/views/feedback_prompt"],
function(BaseView, _, gettext, NotificationView, PromptView) {
var ShowTextbook = BaseView.extend({
initialize: function() {
this.template = _.template($("#show-textbook-tpl").text());
this.listenTo(this.model, "change", this.render);
......
define(["backbone", "underscore", "jquery", "jquery.form"],
function(Backbone, _, $) {
var UploadDialog = Backbone.View.extend({
define(["js/views/baseview", "underscore", "jquery", "jquery.form"],
function(BaseView, _, $) {
var UploadDialog = BaseView.extend({
options: {
shown: true,
successMessageTimeout: 2000 // 2 seconds
......
define(["backbone", "underscore", "jquery", "gettext", "js/views/feedback_notification", "js/views/feedback_alert", "jquery.smoothScroll"],
function(Backbone, _, $, gettext, NotificationView, AlertView) {
define(["js/views/baseview", "underscore", "jquery", "gettext", "js/views/feedback_notification", "js/views/feedback_alert", "js/views/baseview", "jquery.smoothScroll"],
function(BaseView, _, $, gettext, NotificationView, AlertView) {
var ValidatingView = Backbone.View.extend({
var ValidatingView = BaseView.extend({
// Intended as an abstract class which catches validation errors on the model and
// decorates the fields. Needs wiring per class, but this initialization shows how
// either have your init call this one or copy the contents
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment