I am trying to delay loading of youtube videos via javascript code as explained here.
and here is the code for that:
function optimizeYouTubeEmbeds() {
// Get all iframes
var frames = document.getElementsByTagName('iframe');
// Loop through each iframe in the page.
for (var i = 0; i < frames.length; i++) {
// Find out youtube embed iframes.
if (frames[i].src && frames[i].src.length > 0 && frames[i].src.match(/http(s)?:\/\/www\.youtube\.com/)) {
// For Youtube iframe, extract src and id.
var src = frames[i].src;
var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
var id = (src.match(p) ? RegExp.$1 : false);
if (id == false) { continue; }
// Get width and height.
var w = frames[i].width;
var h = frames[i].height;
if (src == '' || w == '' || h == '') { continue; }
// Thease are to position the play button centrally.
var pw = Math.ceil(w / 2 - 38.5);
var ph = Math.ceil(h / 2 + 38.5);
// The image+button overlay code.
var code = '<img src="http://i.ytimg.com/vi/' + id + '/hqdefault.jpg" style="" />';
// Replace the iframe with a the image+button code.
var div = document.createElement('div');
div.innerHTML = code;
div = div.firstChild;
frames[i].parentNode.replaceChild(div, frames[i]);
i--;
}
}
}
// Replace preview image of a video with it's iframe.
function LoadYoutubeVidOnPreviewClick(id, w, h) {
var code = '<iframe src="https://www.youtube.com/embed/' + id + '/? autoplay=1&autohide=1&border=0&wmode=opaque&enablejsapi=1" width="' + w + '" height="' + h + '" frameborder=0 allowfullscreen style="border:1px solid #ccc;" ></iframe>';
var iframe = document.createElement('div');
iframe.innerHTML = code;
iframe = iframe.firstChild;
var div = document.getElementById("skipser-youtubevid-" + id);
div.parentNode.replaceChild(iframe, div);
}
This code worked before switching my project to the angular way of doing things.
I initially thought I could just wrap that code in a $scope and call it, but that did not work. Here is my code that retrieves the videos:
$scope.renderHtml = function (html) {
return $sce.trustAsHtml(html);
};
$scope.Videos = [];
$scope.getVideos = function() {
// api call
$http.get('/api/Videos/AllVideos')
.success(function(data) {
$scope.Videos = data;
});
};
$scope.getVideos();
and here is the html tag where it is rendered:
<div ng-repeat="vid in Videos">
<div ng-bind-html="renderHtml(vid.url)"></div>
</div>
The vid.url includes all the iframe tag information etc. What do I need to do to make this work?
Related
this is my starter work
I just call the web API and retrieved the hotel names
(function() {
var myAPI = "https://gmgapi.azurewebsites.net/SystemParameters/Hotels/GetAll?langId=en";
$.getJSON(myAPI, {
format: "json"
})
.done(function(data) {
doSomething(data);
console.log("Load was performed.");
});
})();
function doSomething(data) {
for (var i = 0; i < data.length; i++) {
var div = $("<div>");
var label = $("<label>").text(data[i].DisplayValue);
$(div).append(label);
$('#result').append(div);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"> </div>
now i want to click on hotel name to get other data related to hotel like deescription and other data
the proplem faced me that i couldn't get the value correctely when i clicked on html to retrive the data
i tried to declare var and use it but not worked for me like showed here
(function () {
var myAPI = "http://gmgapi.azurewebsites.net/SystemParameters/Hotels/GetAll?langId=en";
$.getJSON(myAPI, {
format: "json"
})
.done(function (data) {
doSomething(data);
doSomethinginClick(data);
});
})();
function doSomething(data) {
for (var i = 0; i < data.length; i++) {
var div = $("<div>");
var h1 = $("<h1>").text(" Hotel name : " + data[i].DisplayValue);
$(div).append(h1);
$('#result').append(div);
}
}
function doSomethinginClick(data) {
// var clicked = data[this].Id;
var clicked = data[0];
$('h1').click(function () {
var divx = $("<div>");
var h1 = $("<h1>").text(" Hotel name : " + clicked.DisplayValue);
var p = $("<p>").text(" Hotel Description : " + clicked.DisplayValueDesc);
var p2 = $("<p>").text(" CurrencyTitle : " + clicked.CurrencyTitle);
var price = $("<p>").text(" PriceStart : " + clicked.PriceStart);
var rate = $("<p>").text(" Rate : " + clicked.Rate);
$(divx).append(h1, p, p2, price, rate);
$('#resultsec').append(div);
});
}
<div id="result">
</div>
<div id="resultsec">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
First of, In the method doSomethinginClick(), where you define the h1 click function, you have missed to define the div element which you are appending to.
Add the following
var div = $("<div>");
To make the solution more dynamic, you can store a identifier on the h1 tag thats connect the tag to an hotel.
I added a custom field called hotelId on the html tag for this
function doSomething(data) {
for (var i = 0; i < data.length; i++) {
var h1 = $("<h1></h1>").text(" Hotel name : " + data[i].DisplayValue);
h1.data('hotelId', i);
$("#result").append(h1);
}
}
function doSomethinginClick(data) {
$('h1').click(function () {
var id = $(this).data('hotelId');
var clicked = data[id];
var h1 = $("<p>").text(" Hotel name : " + clicked.DisplayValue);
var p = $("<p>").text(" Hotel Description : " + clicked.DisplayValueDesc);
var p2 = $("<p>").text(" CurrencyTitle : " + clicked.CurrencyTitle);
var price = $("<p>").text(" PriceStart : " + clicked.PriceStart);
var rate = $("<p>").text(" Rate : " + clicked.Rate);
var div = $("<div>");
$(div).append(h1, p, p2, price, rate);
$('#resultsec').append(div);
});
}
Here's a plunker with mocked data
I have a number of spans being created with ng-repeat:
<div class="row" id="year-1">
<span class="event" ng-repeat="(key, event) in events" event data-start={{event.date_start}} data-end={{event.date_end}} data-key={{key}} data-type={{event.role}}>
{{event.title}} - {{event.date_start}}
</span>
</div>
I have a directive for event which does a number of things to manipulate each span created accordingly. One of the things is to check is there are other spans with data-type="X".
In my directive, if I do the following, I get all the span's with class 'event':
var parentid = angular.element(document.getElementById('year-1'));
var typeExists = parentid[0].querySelectorAll('.event')[0];
But if I try to narrow it down to data-type="X" such as the following, I get undefined.
var typeExists = parentid[0].querySelectorAll('.event[data-type="' + attr.type + '"]')[0];
Am I overlooking something? Full directive:
angular.module("app").directive("event", function() {
return {
link: function(scope, element, attr) {
var getStart = attr.start.split('-'),
getEnd = attr.end.split('-'),
getKey = attr.key;
getHeight = element[0].offsetHeight;
var parentid = angular.element(document.getElementById('year-1')),
backgroundParent = angular.element(document.getElementsByClassName('year-current'));
// get the month event starts with
var monthStart = angular.element(document.querySelectorAll('[data-location="' + getStart[1] + '"]'));
// get the month event ends with
var monthEnd = angular.element(document.querySelectorAll('[data-location="' + getEnd[1] + '"]'));
// how many events do we have
var eventcount = angular.element(document.getElementsByClassName('event'));
// get width of events container
var eventsContainer = angular.element(document.getElementById('events'));
// does this type exist already, if so get its top
var typeExists = parentid[0].querySelectorAll('.event')[0];
console.log(typeExists);
if(monthStart.length > 0) {
// how many days in start month
var daysStart = getDaysInMonth(getStart[1], getStart[0]),
daysStartPercent = (getStart[2] / daysStart.length);
// how many days in end month
var daysEnd = getDaysInMonth(getEnd[1], getEnd[0]),
daysEndPercent = (getEnd[2] / daysEnd.length);
// determine left starting %
var elementLeft = ((monthStart[0].offsetLeft + (monthStart[0].clientWidth * daysStartPercent)) / eventsContainer[0].clientWidth) * 100;
// determine width in %
var elementRight = ((monthEnd[0].offsetLeft + (monthEnd[0].clientWidth * daysEndPercent)) / eventsContainer[0].clientWidth) * 100;
var width = (elementRight - elementLeft);
// get the background color for this role
var background = angular.element(document.querySelector('.role[data-type="' + attr.type + '"]'))[0].getAttribute('data-background');
element.css({
'left': elementLeft + '%',
'top' : parentid[0].offsetHeight + 'px',
'width': width + '%',
'background': background
});
element.addClass('stretchRight');
parentid.css({'height': parentid[0].offsetHeight + getHeight + 'px'});
backgroundParent.css({'height': parentid[0].offsetHeight + getHeight + 'px'});
} else {
element.css({ 'display': 'none' });
}
}
}
});
I was able to recreate the problem you saw and found that you need to change your line from this:
var typeExists = parentid[0].querySelectorAll('.event[data-type="' + attr.type + '"]')[0];
to this:
var typeExists = parentid.querySelectorAll('.event[data-type="' + attr.type + '"]')[0];
Remove the [0] from your parentid reference because you only have a single element with ID of year-1 which means it's not an array.
I have audio player directive, but in Chrome (and firefox) music mute in player and no draw spectrum. But in Opera and IE also its ok.
Help me find a Chrome (and firefox) bug...I think, i incorrect paste audio source in html.
var app = angular.module('app', []);
app.directive('spectrum', ['$document', '$timeout', function($document, $timeout) {
return function(scope, element, attr) {
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
var audioVisual = document.getElementById('player');
//console.log(wrap);
// canvas stuff
var canvas = document.getElementById('c');
canvas_context = canvas.getContext('2d');
var gradient = canvas_context.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(1, '#550000');
gradient.addColorStop(0.75, '#ff0000');
gradient.addColorStop(0.25, '#ffff00');
gradient.addColorStop(0, '#ffff00');
canvas_context.fillStyle = gradient;
// audio stuff
audio = new Audio();
var audioSrc = 'http://www.noiseaddicts.com/samples/273.mp3';
//audio.__proto__ = scope.audio;
audio.src = audioSrc;
audio.controls = true;
audio.autoplay = true;
//scope.audios.paused = true;
audio.id = 'audioplayer';
audioVisual.appendChild(audio);
scope.audiosrc = audio.src;
// analyser stuff
var context = new AudioContext();
var analyser = context.createAnalyser();
analyser.fftSize = 2048;
// connect the stuff up to eachother/*
var source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);
freqAnalyser();
// draw the analyser to the canvas
function freqAnalyser() {
window.requestAnimFrame(freqAnalyser);
var sum;
var average;
var bar_width;
var scaled_average;
var num_bars = 60;
var data = new Uint8Array(128);
analyser.getByteFrequencyData(data);
// clear canvas
canvas_context.clearRect(0, 0, canvas.width, canvas.height);
var bin_size = Math.floor(data.length / num_bars);
for (var i = 0; i < num_bars; i += 1) {
sum = 0;
for (var j = 0; j < bin_size; j += 1) {
sum += data[(i * bin_size) + j];
}
average = sum / bin_size;
bar_width = canvas.width / num_bars;
scaled_average = (average / 256) * canvas.height;
canvas_context.fillRect(i * bar_width, canvas.height, bar_width - 2, - scaled_average);
}
}
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div spectrum>
<div class="spectrum">
<canvas id="c" width="500" height="200"></canvas>
</div>
<div id="player"><div id="audio-visual">
</div>
</div>
</div>
I have created a custom directive. The controls defined in templates seem to be working fine. But, I need to append another control - image button, to a control defined in templates according to some condition. To do this I included an IF condition, created an image button and added a 'ng-click' attribute to it. However, using javascript 'append' of image button to my template control's ('html') does not seem to work as it says no 'append' is an undefined function. Hence I used 'concat()', this renders the image button but 'ng-click' does not work. The function in the controller does get hit. Please help!
<div ng-controller="pdfFormsEditController">
<split-pane id="splitPane" height="800">
<split-pane-component id="leftPane" width="50%"> <div class="form-editor boxed-section dashed" id="form">
<form-control ng-repeat="control in formDefinition.Definition.controls" control="control" />
</div></split-pane-component>
</split-pane>
</div>
This is my directive file -
"use strict";
angular.module('configurePDF.directives.noteForms', [])
.directive('formControl', ['$compile', function ($compile) {
var templates = {
"NoteLabel":'<label ng-click="onSelectNoteField(control.Name)" ng-style="control.style" style="font-style:Bold; font-size: 8.25pt; font-family:Arial">{{control.Properties.DisplayName}}</label>',
"NoteMedcinFinding":'<p ng-click="onSelectNoteField(control.Name)" ng-style="control.style"><input type="image" src="../Images/YesNo.gif" style="Width:35px; Height:17px;"><label style="font-style:Bold; font-size: 8.25pt; font-family:Arial">{{control.Properties.OriginalText}}</label></input></p>'
}
var linker = function(scope, element, attrs) {
var location = scope.control.Properties.Location.split(',');
var size=scope.control.Properties.Size.split(',');
// var font=scope.control.Properties.Font.split(',');
scope.control.style = {position: "absolute", left: (parseInt(location[0])*1.5) + "px", top: location[1] + "px" ,minWidth:425+"px",height:size[1]+"px"};
var html = templates[scope.control.Type];
debugger;
if(scope.control.Properties.DetailFormID != "00000000-0000-0000-0000-000000000000"){
var img = document.createElement('input');
img.type = "image"
img.src = "../../Images/plus.png";
img.height = 10;
img.width = 10;
img.style.position = 'absolute'
img.style.left = ((parseInt(location[0])*1.5) - 13) + "px"
img.style.top = (parseInt(location[1]) + 3)+ "px"
//img.className ="ng-scope ng-binding"
//img.onclick = "onSelectNoteField(scope.control.Properties.DetailFormID)"
var attr = document.createAttribute("data-ng-click");
attr.value = "onSelectNoteField(control.Properties.DetailFormID)";
img.attributes.setNamedItem(attr);
debugger;
html = html.concat(img.outerHTML);
//console.log(element);
}
var elem = $compile(html)(scope);
element.replaceWith(elem);
}
return {
restrict: "E",
replace: true,
link: linker,
scope: {
control:'='
}
};
}]);
UPDATE: I read that class="ng-scope ng-binding" should be created automatically in the element's html. But in my image button the class is is just "ng-scope". So, may be there is some binding issue to the scope, because I was not able to append the image button but concatenate it??
<input type="image" src="../../Images/plus.png" height="10" width="10" style="position: absolute; left: 32px; top: 83px;" data-ng-click="onSelectNoteField(control.Properties.DetailFormID)" class="ng-scope">
Controller:
/
.controller('pdfFormsEditController', ['$scope', '$routeParams', 'pdfFormsService','mastersService','$rootScope',
function pdfFormsEditController($scope, $routeParams, pdfFormsService,mastersService,$rootScope) {
var allNoteFields = [];
$scope.editMode = true;
$scope.onSelectNoteField = function(noteField) {
debugger;
$scope.formDefinition = {};
var result = pdfFormsService.getFormDefinition('3151ff0d-6c93-4c80-9182-fd05f7d6cf90');
result.success(function (formDefinition) {
console.log(formDefinition);
$scope.formDefinition = formDefinition;
var size = $scope.formDefinition.Definition.Properties.Size.split(',');
$scope.formDefinition.style = { position: 'relative', width: size[0] + "px", height: size[1] + "px" }
}
Well, I found the answer and its pretty simple! My directive had no access/link to the scope when I was calling onSelectNoteField! Hence a different approach worked.
if ((scope.control.Properties.DetailFormID != "00000000-0000-0000-0000-000000000000") && (scope.control.Properties.DetailFormID != "0") && (scope.control.Properties.DetailFormID !== undefined)) {
var img = document.createElement('input');
img.type = "image";
img.src = "../../Images/plus.png";
img.height = 10;
img.width = 10;
img.style.position = 'absolute'
img.style.left = ((parseInt(location[0]) * 1.5) - 13) + "px"
img.style.top = (parseInt(location[1]) + 3) + "px"
//img.className ="ng-scope ng-binding"
//img.onclick = "onSelectNoteField(scope.control.Properties.DetailFormID)"
var attr = document.createAttribute("data-ng-click");
attr.value = "onImageClick('" + scope.control.Properties.DetailFormID + "')";
img.attributes.setNamedItem(attr);
html = html.concat(img.outerHTML);
}
var elem1 = $compile(html)(scope);
element.replaceWith(elem1);
scope.onImageClick = function (subformID) {
var id = subformID;
scope.onImageClick = function (control) {
var scope = angular.element($("#form")).scope();
scope.onSelectNoteField(id);
}
}
I am creating a scope property- the function onImageClick and calling this in ng-click of my image. onImageClick gets the scope of my parent element, which has access to the function I want to call - onSelectNoteField!
I would like to wrap text with span tag and save the position.
I know how to do it with JS but i dont know how to do it with angularjs
Here is what i have done:
http://jsfiddle.net/ymeaL06j/1/
This function gives me the position of the text in the DIV
function getSelectionPosition() {
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(document.getElementById("code"));
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
}
};
I take the start and end positions and insert them as an attribute in the span tag
After this i would like to save all the marked positions and load it later, i have a function that select text and then i can wrap it (i hope that there is a better solution)
function setSelection(savedSel) {
var charIndex = 0, range = document.createRange();
range.setStart(document.getElementById("code"), 0);
range.collapse(true);
var nodeStack = [containerEl], node, foundStart = false, stop = false;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
You can use the same code that you illustrated above and put it inside of your angularjs controller.
Refer to my plunker code; it is a simple angularjs version of your jsfiddle code.
For example, suppose that a snippet of the index.html looks like this:
<body ng-controller="MainCtrl">
<div id="code">This is <b>some text</b> bla bla bla</div>
<br />
<input type="button" value="Mark!" ng-click="markText()" />
<input type="button" value="Remove marks!" ng-click="removeMarks()" />
</body>
Then the example angularjs controller, MainCtrl, could look like this:
app.controller('MainCtrl', function($scope) {
var getSelectionPosition = function () {
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(document.getElementById("code"));
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
}
}
$scope.markText = function() {
var currPosition = getSelectionPosition();
var selection = window.getSelection().getRangeAt(0);
var selectedText = selection.extractContents();
var span = document.createElement("span");
span.className = "Mark";
span.setAttribute("PosStart", currPosition.start);
span.setAttribute("PosEnd", currPosition.end);
span.appendChild(selectedText);
selection.insertNode(span);
};
$scope.removeMarks = function() {
$(".Mark").each(function () {
$(this).contents().unwrap();
});
};
});
Notice that the MainCtrl is the angularjs controller for the body. The ng-click on the buttons reference the markText and removeMarks functions in the controller's scope. The logic in the functions are exactly the same as you referenced in your question (and jsfiddle).
None of your JS code changed other than moving the functions inside of the controller. Again, check out the plunker above to see the actual code working.