Load inserted text in dialog - javascript

I am using summernote 0.8 and jquery 3.5.
I have created a dialog that inputs synonyms for example, when inputing test1, test2, test3 in the dialog a special tag is filled into the editor like the following:
<span data-function="addSynonym" data-options="[test2, test3]"><span style="background-color: yellow;">test1</span></span>
I would like to load the dialog with these values, edit them and add the updated values to the editor's text field.
Find below my minimum viable example:
$(document).ready(function() {
$('.summernote').summernote({
height: 300,
tabsize: 2,
toolbar: [
['insert', ['synonym', 'codeview']]
],
});
});
(function(factory) {
/* global define */
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(window.jQuery);
}
}(function($) {
$.extend($.summernote.plugins, {
'synonym': function(context) {
var self = this;
var ui = $.summernote.ui;
var $editor = context.layoutInfo.editor;
var options = context.options;
context.memo('button.synonym', function() {
return ui.button({
contents: '<i class="fa fa-snowflake-o">',
tooltip: 'Create Synonym',
click: context.createInvokeHandler('synonym.showDialog')
}).render();
});
self.initialize = function() {
var $container = options.dialogsInBody ? $(document.body) : $editor;
var body = '<div class="form-group">' +
'<label>Add Synonyms (comma - , - seperated</label>' +
'<input id="input-synonym" class="form-control" type="text" placeholder="Insert your synonym" />'
'</div>'
var footer = '<button href="#" class="btn btn-primary ext-synonym-btn">OK</button>';
self.$dialog = ui.dialog({
title: 'Create Synonym',
fade: options.dialogsFade,
body: body,
footer: footer
}).render().appendTo($container);
};
// You should remove elements on `initialize`.
self.destroy = function() {
self.$dialog.remove();
self.$dialog = null;
};
self.showDialog = function() {
self
.openDialog()
.then(function(data) {
ui.hideDialog(self.$dialog);
context.invoke('editor.restoreRange');
self.insertToEditor(data);
console.log("dialog returned: ", data)
})
.fail(function() {
context.invoke('editor.restoreRange');
});
};
self.openDialog = function() {
return $.Deferred(function(deferred) {
var $dialogBtn = self.$dialog.find('.ext-synonym-btn');
var $synonymInput = self.$dialog.find('#input-synonym')[0];
ui.onDialogShown(self.$dialog, function() {
context.triggerEvent('dialog.shown');
$dialogBtn
.click(function(event) {
event.preventDefault();
deferred.resolve({
synonym: $synonymInput.value
});
});
});
ui.onDialogHidden(self.$dialog, function() {
$dialogBtn.off('click');
if (deferred.state() === 'pending') {
deferred.reject();
}
});
ui.showDialog(self.$dialog);
});
};
this.insertToEditor = function(data) {
console.log("synonym: " + data.synonym)
var dataArr = data.synonym.split(',');
var restArr = dataArr.slice(1);
var $elem = $('<span>', {
'data-function': "addSynonym",
'data-options': '[' + restArr.join(',').trim() + ']',
'html': $('<span>', {
'text': dataArr[0],
'css': {
backgroundColor: 'yellow'
}
})
});
context.invoke('editor.insertNode', $elem[0]);
};
}
});
}));
<head>
<meta charset="UTF-8">
<title>Summernote with Bootstrap 4</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/summernote#0.8.15/dist/summernote-bs4.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote#0.8.15/dist/summernote-bs4.min.js"></script>
</head>
<body style="
padding-top: 50px;
border-left-width: 50px;
padding-left: 50px;
border-right-width: 50px;
padding-right: 150px;
">
<div class="container">
<div class="summernote">
<p>Hello World!</p>
This text should be replaced by the dialog. </div>
</div>
</body>
Any suggestions how to do add this update functionality to my yellow text?
I appreciate your replies!

Using the oninit callback, we can easily use jquery methods to select that embedded text and trigger a click on that button you added in your plugin.
It's the first time I use Summernote. So to bring a clear code and a similar syntax in the [UPDATE], I added jquery-ui dialogBox that would be used to update the clicked span.
And for this I used updateSpan() function that receives the (targeted) current span object and it's new value as arguments.
var i=0;
function updateSpan(object,value){
object.text(value.split(',', 1));
object.attr('data-options',value.split(',', 1));
object.attr('data-all','['+value+']');
object.css('backgroundColor','yellow');
object.parent().append(" ");
}
$(document).ready(function() {
$('.summernote').summernote({
height: 300,
tabsize: 2,
toolbar: [
['insert', ['synonym', 'codeview']]
],
callbacks: {
onInit: function() {
$(".note-editable").on('click','span[data-function="addSynonym"]', function (e) {
var spanvalue=($(this).attr('data-all')).replace(/[\[\]']+/g,'');
var targetSpan=$(this);
//console.log(spanvalue);
$('#upDialog').dialog({
open : function (event, ui) {
$('#upDialog #input-synonym').empty().val(spanvalue);
//console.log(spanvalue);
},
modal: true,
title: 'Dialog',
show: {
effect: "scale",
duration: 200
},
resizable: false,
buttons: [{
text: "ok",
click: function () {
updateSpan(targetSpan,$('#upDialog #input-synonym').val());
$(this).dialog("close");
targetSpan.focus();
}
}]
});
});
}
}
});
});
(function(factory) {
/* global define */
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(window.jQuery);
}
}(function($) {
$.extend($.summernote.plugins, {
'synonym': function(context) {
var self = this;
var ui = $.summernote.ui;
var $editor = context.layoutInfo.editor;
var options = context.options;
context.memo('button.synonym', function() {
return ui.button({
contents: '<i class="fa fa-snowflake-o">',
tooltip: 'Create Synonym',
click: context.createInvokeHandler('synonym.showDialog')
}).render();
});
self.initialize = function() {
var $container = options.dialogsInBody ? $(document.body) : $editor;
var body = '<div class="form-group">' +
'<label>Add Synonyms (comma - , - seperated</label>' +
'<input id="input-synonym" class="form-control" type="text" placeholder="Insert your synonym" />'
'</div>'
var footer = '<button href="#" class="btn btn-primary ext-synonym-btn">OK</button>';
self.$dialog = ui.dialog({
title: 'Create Synonym',
fade: options.dialogsFade,
body: body,
footer: footer
}).render().appendTo($container);
};
// You should remove elements on `initialize`.
self.destroy = function() {
self.$dialog.remove();
self.$dialog = null;
};
self.showDialog = function() {
self
.openDialog()
.then(function(data) {
ui.hideDialog(self.$dialog);
context.invoke('editor.restoreRange');
self.insertToEditor(data);
//console.log("dialog returned: ", data)
})
.fail(function() {
context.invoke('editor.restoreRange');
});
};
self.openDialog = function() {
return $.Deferred(function(deferred) {
var $dialogBtn = self.$dialog.find('.ext-synonym-btn');
var $synonymInput = self.$dialog.find('#input-synonym')[0];
ui.onDialogShown(self.$dialog, function() {
context.triggerEvent('dialog.shown');
$dialogBtn
.click(function(event) {
event.preventDefault();
deferred.resolve({
synonym: $synonymInput.value
});
});
});
ui.onDialogHidden(self.$dialog, function() {
$dialogBtn.off('click');
if (deferred.state() === 'pending') {
deferred.reject();
}
});
ui.showDialog(self.$dialog);
});
};
this.insertToEditor = function(data) {
i++;
//console.log("synonym: " + data.synonym)
var dataArr = data.synonym.split(',');
var restArr = dataArr.slice(1);
var $elem = $('<span>', {
'data-function': "addSynonym",
'data-id': i,
'data-options': '[' + restArr.join(',').trim() + ']',
'data-all': '[' + dataArr.join(',').trim() + ']',
'html': $('<span>', {
'text': dataArr[0],
'css': {
backgroundColor: 'yellow'
}
})
});
context.invoke('editor.insertNode', $elem[0]);
context.invoke('editor.insertText', ' ');
//context.invoke('editor.restoreRange');
//Still a bug : https://github.com/summernote/summernote/issues/3249
$('.summernote').summernote('editor.insertText', ' ');
context.invoke('editor.focus');
}
}
});
}));
#upDialog{
display:none;
}
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha256-KM512VNnjElC30ehFwehXjx1YCHPiQkOPmqnrWtpccM=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/summernote#0.8.15/dist/summernote-bs4.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote#0.8.15/dist/summernote-bs4.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" integrity="sha256-rByPlHULObEjJ6XQxW/flG2r+22R5dKiAoef+aXWfik=" crossorigin="anonymous" />
<body style="
padding-top: 50px;
border-left-width: 50px;
padding-left: 50px;
border-right-width: 50px;
padding-right: 150px;
">
<div class="container">
<div class="summernote">
<p>Hello World!</p>
This text should be replaced by the dialog.
</div>
<div id="upDialog" title="Update Value"><input id="input-synonym" class="form-control" type="text" placeholder="Insert your synonym" /></div>
</div>
</body>
You can replace this dialog by a modal to look identical or adapt the Dialog design to the old one.

Related

Filter by value in checkbox popup in Mapbox GL

I have changed my mind about how I want to use the Checkbox filter in Mapbox. I am using CSV2Geojson to map Google Sheets data in my map and then filter by values in one column. I know there is this https://labs.mapbox.com/education/impact-tools/finder-with-filters/ but I want to stick to my layout instead of using a config file to define options. My original spreadsheet had a function that looked at column headers and only returned cells with "Y" in them when checked. Now, I have 1 column where I need to look for 4 specific values. Below is the code and codepen for debugging. The code in question is at the bottom of the code block.
https://codepen.io/bearcats6001/project/editor/AjrPPP
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>CodePen - project map 2</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.7.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.7.0/mapbox-gl.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
<script src='https://npmcdn.com/csv2geojson#latest/csv2geojson.js'></script>
<script src='https://npmcdn.com/#turf/turf/turf.min.js'></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.7.2/mapbox-gl-geocoder.min.js"></script>
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.7.2/mapbox-gl-geocoder.css" type="text/css">-->
<div id="map">
<div id="filterMenu">
<h3>Programs</h3>
<input type="checkbox" id="Nathan" name="srBox" value="SustainableRecreation">
<label for="Nathan"> Nathan Shock Centers of Excellence in the Basic Biology of Aging</label><br>
<input type="checkbox" id="Pepper" name="hlBox" value="HealthyLandscapes">
<label for="Pepper"> Claude D. Pepper Older Americans Independence Centers</label><br>
<input type="checkbox" id="Aging" name="ovBox" value="Overnight">
<label for="Aging"> Centers on the Demography and Economics of Aging</label><br>
<input type="checkbox" id="Minority" name="ovBox" value="Overnight">
<label for="Minority"> Resource Centers for Minority Aging Research</label><br>
</div>
</div>
<!-- partial -->
<script src="./script.js"></script>
</body>
</html>
var transformRequest = (url, resourceType) => {
var isMapboxRequest =
url.slice(8, 22) === "api.mapbox.com" ||
url.slice(10, 26) === "tiles.mapbox.com";
return {
url: isMapboxRequest
? url.replace("?", "?pluginName=sheetMapper&")
: url,
};
};
mapboxgl.accessToken = 'pk.eyJ1IjoiYWZhcm9yZyIsImEiOiJjbDIwajV3YTUwMGc3M2xwNDdiYWJiMjUzIn0.Pjt9AndPk1Axv99wez-5TA';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v10',
center: [-102.182698, 37.131563],
zoom: 3,
//left, bottom, right, top
});
var nav = new mapboxgl.NavigationControl({
showCompass: true,
showZoom: true,
visualizePitch: true
});
map.addControl(nav, "bottom-right");
$(document).ready(function () {
$.ajax({
type: "GET",
url: 'https://docs.google.com/spreadsheets/d/1umfhXq5WEPLEABV81-tZUayAw7WZrmqe/gviz/tq?tqx=out:csv&sheet=Sheet1',
dataType: "text",
success: function (csvData) { makeGeoJSON(csvData); }
});
function makeGeoJSON(csvData) {
csv2geojson.csv2geojson(csvData, {
latfield: 'Latitude',
lonfield: 'Longitude',
delimiter: ','
}, function (err, data) {
map.on('load', function () {
map.addLayer({
'id': 'rfovProjects',
'type': 'circle',
'source': {
'type': 'geojson',
'data': data
},
'paint': {
'circle-radius': 7,
'circle-color': "blue",
'circle-opacity': 0.5,
}
});
});
});
};
});
map.on('mouseenter', 'rfovProjects', function () {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'rfovProjects', function () {
map.getCanvas().style.cursor = '';
});
map.on('click', function(e) {
if(!e.originalEvent.defaultPrevented) {
e.originalEvent.preventDefault();
}
var features = map.queryRenderedFeatures(e.point, {
layers: ['rfovProjects']
});
if (!features.length) {
return;
}
var feature = features[0];
var popupContent = '<h3 style="display:inline">' + feature.properties.Name + '</h3><br><p style="display:inline"><b>'
/*popupContent += feature.properties.time ? '</b>, ' + feature.properties.time : '</b>'*/
popupContent += '<br> Website Link </p>'
var popup = new mapboxgl.Popup({ offset: [0, 0] })
.setLngLat(e.lngLat)
.setHTML(popupContent)
.addTo(map);
});
//basemap toggles
/*
var tRadio = document.getElementById('topoRadio');
tRadio.addEventListener('change', function() {
if (this.checked) {
map.setLayoutProperty('mapbox-satellite', 'visibility', 'none');
}
});
var iRadio = document.getElementById('imageryRadio');
iRadio.addEventListener('change', function() {
if (this.checked) {
map.setLayoutProperty('mapbox-satellite', 'visibility', 'visible');
}
});*/
//
map.doubleClickZoom.enable();
map.on('dblclick', function(e) {
map.getZoom() +10;
});
map.addControl(
new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl,
flyTo: {
zoom: 12,
easing: function(t) {
return t;
}
},
marker: false
})
);
map.addControl(new mapboxgl.NavigationControl());
var filters = {};
function updateFilters() {
var compositeFilter = ['all'];
for (let filterValue in filters) {
if (filters[filterValue]) {
compositeFilter.push(['==', ['get', filterValue], 'Y']);
}
}
if (compositeFilter.length > 1)
map.setFilter('rfovProjects', compositeFilter);
else {
map.setFilter('rfovProjects', null);
}
}
var checkbox = document.getElementById('Nathan');
checkbox.addEventListener('change', function() {
filters['Program'] = this.checked;
updateFilters();
});
var checkbox = document.getElementById('Pepper');
checkbox.addEventListener('change', function() {
filters['Program'] = this.checked;
updateFilters();
});
var checkbox = document.getElementById('Aging');
checkbox.addEventListener('change', function() {
filters['Program'] = this.checked;
updateFilters();
});
var checkbox = document.getElementById('Minority');
checkbox.addEventListener('change', function() {
filters['Program'] = this.checked;
updateFilters();
});

Issue using angularjs/ngDialog modal with Bitmovin player

I am trying to use an angularjs/ngDialog modal to display a Bitmovin video player dialog. The sample code below loads and plays the video fine. The issue comes when I close the dialog using either the close button or clicking the background area and then try to reopen the dialog/player. The player doesn't load and play. Ideally I would like the player to pickup where it left off. When I use JWPlayer with the same angularjs/ngDialog code the video plays the 2nd, 3rd, ... times around.
I'm new to angularjs. Any help is greatly appreciated.
<!DOCTYPE html>
<html lang="en">
<head>
<title>** Bitmovin AngularJS Modal Player</title>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel='stylesheet' href='css/ngDialog.css' type='text/css' media='all' />
<link rel='stylesheet' href='css/ngDialog-theme-default.css' type='text/css' media='all' />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js?ver=1.5.8'></script>
<script type='text/javascript' src='http://cdnjs.cloudflare.com/ajax/libs/ng-dialog/0.6.4/js/ngDialog.min.js?ver=0.6.4'></script>
<script type="text/javascript" src="https://bitmovin-a.akamaihd.net/bitmovin-player/stable/6.1.7/bitmovinplayer.min.js"></script>
</head>
<body>
<div class="container">
<div class="content">
<div ng-app="myApp" ng-controller="myModalController">
<button ng-click="showVideoPlayerPopup()" class="btmv-button">WATCH</button>
</div>
</div>
</div>
<script type="text/javascript">
function playVideo() {
//var createPlayer = function () {
var config = {
key: "0b3b8038-7b11-4aa0-8717-1f848c76e436",
source: {
dash: 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd'
},
style: {
width: '50vw',
aspectratio: '16/9'
},
playback : {
autoplay : true,
muted : false
},
events: {
onReady: function(data) {
console.log('Video duration: ' + this.getDuration() + "s" );
console.log(data);
},
onPlay : function(data) {
console.log(data);
},
onPause : function(data) {
console.log(data);
},
onSeek : function(data) {
//updateTime();
console.log(data);
},
onPlaybackFinished: function(data) {
console.log('Video onPlaybackFinished: ' + this.getCurrentTime() + "s", data );
player.seek(0);
console.log('Video onPlaybackFinished seek(0) time: ' + this.getCurrentTime() + "s" );
// player.destroy();
// console.log('TGC Video onPlaybackFinished player destroyed! ');
},
onError : function(data) {
console.error("Bitmovin Player error: " + data.code + ": " + data.message);
}
} // end events
};
var player = bitmovin.player('btmv-player');
player.setup(config).then(function(value) {
console.log('Successfully created Bitmovin Player instance');
}, function(reason) {
console.log('Error while creating Bitmovin Player instance: ${error.message}');
});
function updateTime(time) {
document.getElementById("event").innerHTML ="The video has been seeked to "+JSON.stringify(player.getCurrentTime())+"s";
}
player.addEventHandler('onSeeked', function(timestamp) {
updateTime( JSON.stringify( player.getCurrentTime() ) );
});
};
function playbackFinished() {
console.log('playbackFinished fired! ');
}
function killPlayer() {
if ( confirm('Close the player?') ) {
player.destroy();
return true;
}
return false;
}
var app = angular.module('myApp',['ngDialog']);
app.controller('myModalController', function($scope, ngDialog) {
$scope.ngDialog = ngDialog;
$scope.showVideoPlayerPopup = function(video_path) {
ngDialog.open({
//animation : true,
disableAnimation: true,
scope : $scope,
template: '<div id="btmv-player"></div>' +
'<br />' +
'<div id="event"></div>',
plain : true,
className : 'ngdialog-theme-default',
closeByDocument: true,
width : 670,
height : 390,
preCloseCallback: function(value) {
//killPlayer();
return true;
}
});
$scope.$on('ngDialog.opened', function (e, $dialog) {
playVideo();
//createPlayer();
console.log('ngDialog opened: ' + $dialog.attr('id'));
});
$scope.$on('ngDialog.closing', function (e, $dialog) {
//killPlayer();
console.log('ngDialog closing: ' + $dialog.attr('id'));
});
$scope.$on('ngDialog.closed', function (e, $dialog) {
//killPlayer();
console.log('ngDialog closed: ' + $dialog.attr('id'));
});
}
});
</script>
</body>
</html>
It seems that the problem is that the player <div> does not exist any more when calling bitmovin.player("btmv-player") in killPlayer.
The following code should work. It uses the short cut bitmovin.player() instead of accessing via ID, which returns the last created player.
<html lang="en">
<head>
<title>** Bitmovin AngularJS Modal Player</title>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/ng-dialog/0.6.4/css/ngDialog.css' type='text/css' media='all' />
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/ng-dialog/0.6.4/css/ngDialog-theme-default.css' type='text/css' media='all' />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js?ver=1.5.8'></script>
<script type='text/javascript' src='http://cdnjs.cloudflare.com/ajax/libs/ng-dialog/0.6.4/js/ngDialog.min.js?ver=0.6.4'></script>
<script type="text/javascript" src="https://bitmovin-a.akamaihd.net/bitmovin-player/stable/7/bitmovinplayer.js"></script>
</head>
<body>
<div class="container">
<div class="content">
<div ng-app="myApp" ng-controller="myModalController">
<button ng-click="showVideoPlayerPopup()" class="btmv-button">WATCH</button>
</div>
</div>
</div>
<script type="text/javascript">
function playVideo() {
var config = {
key: "YOUR-PLAYER-KEY",
source: {
dash: 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd'
},
style: {
width: '50vw',
aspectratio: '16/9'
},
playback : {
autoplay : true,
muted : false
},
events: {
onReady: function(data) {
console.log('Video duration: ' + this.getDuration() + "s" );
console.log(data);
},
onPlay: function(data) {
console.log(data);
},
onPaused: function(data) {
console.log(data);
},
onSeek : function(data) {
console.log(data);
},
onPlaybackFinished: function(data) {
console.log('Video onPlaybackFinished: ' + this.getCurrentTime() + "s", data );
player.seek(0);
console.log('Video onPlaybackFinished seek(0) time: ' + this.getCurrentTime() + "s" );
},
onError : function(data) {
console.error("Bitmovin Player error: " + data.code + ": " + data.message);
}
} // end events
};
var player = bitmovin.player('btmv-player');
player.setup(config).then(function(value) {
console.log('Successfully created Bitmovin Player instance');
}, function(reason) {
console.log('Error while creating Bitmovin Player instance: ${error.message}');
});
function updateTime(time) {
document.getElementById("event").innerHTML ="The video has been seeked to "+JSON.stringify(player.getCurrentTime())+"s";
}
player.addEventHandler('onSeeked', function(timestamp) {
updateTime( JSON.stringify( player.getCurrentTime() ) );
});
};
function playbackFinished() {
console.log('playbackFinished fired! ');
}
function killPlayer() {
if ( confirm('Close the player?') ) {
var player = bitmovin.player();
if (player) {
player.destroy();
}
return true;
}
return false;
}
var app = angular.module('myApp',['ngDialog']);
app.controller('myModalController', function($scope, ngDialog) {
$scope.ngDialog = ngDialog;
$scope.showVideoPlayerPopup = function(video_path) {
ngDialog.open({
disableAnimation: true,
scope : $scope,
template: '<div id="btmv-player"></div>' +
'<br />' +
'<div id="event"></div>',
plain : true,
className : 'ngdialog-theme-default',
closeByDocument: true,
width : 670,
height : 390
});
}
$scope.$on('ngDialog.opened', function (e, $dialog) {
playVideo();
console.log('ngDialog opened: ' + $dialog.attr('id'));
});
$scope.$on('ngDialog.closed', function (e, $dialog) {
killPlayer();
console.log('ngDialog closed: ' + $dialog.attr('id'));
});
});
</script>
</body>
</html>
Furthermore I suggest not mixing AngularJS and plain JavaScript as weird things can happen, especially if the project grows. You should consider to add all the JavaScript code into the app / controllers.
There's also a Github project to use the Bitmovin Player in Angular (maintained by MovingImage24 and not by Bitmovin): https://github.com/MovingImage24/mi-angular-bitdash-player
I'm not sure how up to date it is kept, though.

Bootstrap x-editable. Change data type programmatically (Remove select2 data-type)

I'm, using bootstrap x-editable https://vitalets.github.io/x-editable/index.html
This is my html code:
<a href="#" data-name="category" class="addon" data-value="{{$cat->id}}"
data-pk="{{$cat->id}}" data-type="select2" data-title="Favor llenar los campos"></a>
javascript code:
$('.addon').editable({
placement: 'bottom',
mode: 'inline',
showbuttons: false,
source: categories,
select2: {
width: 200
},
display: function (value) {
var elem = $.grep(categories, function (o) {
return o.id == value;
});
$(this).attr('data-value', value);
$(this).parent().parent().find('.btnEdit').attr('href', '/wizard_product/' + product_id + '/category/' + value + '/edit');
return $(this).text(elem[0].text);
}
});
But. I want to change programmatically to normal x-editable element without the select2 options.
I have tried with jquery to change the data-type attribute of the a element to text, but it does not work.
$('a.addon').attr('data-type', 'text');
Also tried:
$('a.addon').select2('destroy');
Also tried:
$('a.addon').editable({type: 'text'});
But neither options work. select2 is still active.
How can I remove select2 options of x-editable?
Can you help me please
You will have to combine the things that you've tried - destroy the default X-editable instance, change the data-type value, and reinstate X-editable on that element.
The most simple implementation/example would be:
$('.addon').editable('destroy').data('type', 'text').editable({type: 'text'});
In practice, you'll have to put your other settings back when you re-apply X-editable as text:
$('.addon').editable('destroy');
$('.addon').data('type', 'text');
$('.addon').editable({
placement: 'bottom',
mode: 'inline',
showbuttons: false,
source: categories,
type: 'text',
display: function (value) {
var elem = $.grep(categories, function (o) {
return o.id == value;
});
$(this).attr('data-value', value);
$(this).parent().parent().find('.btnEdit').attr('href', '/wizard_product/' + product_id + '/category/' + value + '/edit');
return $(this).text(elem[0].text);
}
});
Edit:
I've put together a demo that mirrors your setup as best I could tell and it seems to work:
var categories = [{
id: 'html',
value: 'html',
text: 'html'
}, {
id: 'javascript',
value: 'javascript',
text: 'javascript'
}];
setupSelect2();
$('#useSelect2').click(function() {
$('.addon')
.data('type', 'select2')
.editable('destroy');
setupSelect2();
});
$('#useText').click(function() {
$('.addon')
.data('type', 'text')
.editable('destroy');
setupText();
});
function setupSelect2() {
$('.addon').editable({
mode: 'inline',
placement: 'bottom',
showbuttons: false,
source: categories,
select2: {
width: 200
},
display: function(value) {
var elem = $.grep(categories, function(o) {
return o.id == value;
});
$(this).attr('data-value', value);
if (elem[0])
return $(this).text(elem[0].text);
}
});
}
function setupText() {
$('.addon').editable({
mode: 'inline',
placement: 'bottom',
type: 'text',
showbuttons: false,
source: categories,
display: function(value) {
var elem = $.grep(categories, function(o) {
return o.id == value;
});
$(this).attr('data-value', value);
if (elem[0])
return $(this).text(elem[0].text);
}
});
}
<script src="https://vitalets.github.io/x-editable/assets/jquery/jquery-1.9.1.min.js"></script>
<link href="https://vitalets.github.io/x-editable/assets/select2/select2.css" rel="stylesheet" />
<script src="https://vitalets.github.io/x-editable/assets/select2/select2.js"></script>
<link href="https://vitalets.github.io/x-editable/assets/bootstrap300/css/bootstrap.css" rel="stylesheet" />
<script src="https://vitalets.github.io/x-editable/assets/bootstrap300/js/bootstrap.js"></script>
<link href="https://vitalets.github.io/x-editable/assets/x-editable/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet" />
<script src="https://vitalets.github.io/x-editable/assets/x-editable/bootstrap3-editable/js/bootstrap-editable.js"></script>
<link href="https://vitalets.github.io/x-editable/assets/select2/select2-bootstrap.css" rel="stylesheet" />
<h3>Select 2</h3>
<br>
<br>
<button id="useSelect2" class="btn btn-default">Use Select2</button>
<button id="useText" class="btn btn-default">Use Text</button>

jquery ui autocomplete with multiple fields

this code works just fine, but the second input field does not show images appearing with the text suggestions. I would appreciate if someone could take a look and let me know what needs to be changed in the js for it to work.
Example queries: clinton, bush
you can see the script here http://predcast.com/include/autoc/jqui/test2.php
<!DOCTYPE html>
<html>
<head>
<title>jQuery UI Autocomplete: Custom HTML in Dropdown</title>
<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/smoothness/jquery-ui.min.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"> </script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script>
<style>
.loading {
display: none;
width: 16px;
height: 16px;
background-image: url(/img/loading.gif);
vertical-align: text-bottom;
}
#autocomplete.ui-autocomplete-loading ~ .loading {
display: inline-block;
}
.ui-menu-item {
padding:1px;
margin:1px;
}
.ac-m {
height:block;
overflow:auto;
padding:2px 2px 2px 2px;
}
.ac-img {
max-width:30px;
float:left;
margin:2px 2px 2px 2px;
}
.ac-title {
margin:1px;
font-size:14px;
}
.ui-autocomplete {
margin:1px;
}
</style>
</head>
<body>
<form action="http://www.test.com/">
<input class="autocomplete" type="text" placeholder="Option 1" name="e1">
<input class="autocomplete" type="text" placeholder="Option 2" name="e2">
<span class="loading"></span>
</form>
<script>
/*
* jQuery UI Autocomplete: Custom HTML in Dropdown
* http://salman-w.blogspot.com/2013/12/jquery-ui-autocomplete-examples.html
*/
$(function () {
$('.autocomplete').autocomplete({
delay: 500,
minLength: 3,
source: function (request, response) {
$.getJSON("http://predcast.com/include/autoc/jqui/jsond.php", {
q: request.term,
}, function (data) {
var array = data.error ? [] : $.map(data.movies, function (m) {
return {
label: m.title,
year: m.year,
img: m.img,
};
});
response(array);
});
},
focus: function (event, ui) {
event.preventDefault();
},
}).data("ui-autocomplete")._renderItem = function (ul, item) {
var $a = $("<div class='ac-m'></div>");
if (item.img) {
$("<span></span>").addClass(item.icon).appendTo($a).append("<img src='" + item.img + "' border='0' class='ac-img' />");
}
$("<span class='ac-title'></span>").text(item.label).appendTo($a);
return $("<li></li>").append($a).appendTo(ul);
};
});
</script>
</body>
</html>
The problem is related to the way you are defining the _renderItem extension point.
In your code, you are redefining the jquery-ui autocomplete _renderItem function only for your first widget instance, so the _renderItem for your second autocomplete instance is the default one defined in the jquery-ui code.
You are initializating the autocomplete for your 2 inputs with this $('.autocomplete').autocomplete({ ...}) then you get the first widget instance with this instruction .data("ui-autocomplete") and then redefine the _renderItem function for this instance only.
You can define it for all your instances like this:
// Create your widget instances
$('.autocomplete').autocomplete({
delay: 500,
minLength: 3,
source: function (request, response) {
$.getJSON("http://predcast.com/include/autoc/jqui/jsond.php", {
q: request.term,
}, function (data) {
var array = data.error ? [] : $.map(data.movies, function (m) {
return {
label: m.title,
year: m.year,
img: m.img,
};
});
response(array);
});
},
focus: function (event, ui) {
event.preventDefault();
}
});
// Then redefine the _renderItem for each instance
$('.autocomplete').each(function() {
$(this).data('ui-autocomplete')._renderItem = function (ul, item) {
var $a = $("<div class='ac-m'></div>");
if (item.img) {
$("<span></span>").addClass(item.icon).appendTo($a).append("<img src='" + item.img + "' border='0' class='ac-img' />");
}
$("<span class='ac-title'></span>").text(item.label).appendTo($a);
return $("<li></li>").append($a).appendTo(ul);
};
});

dgrid in a custom widget

I have a custom widget to which I pass data from backend. Grid shown on the correct place but not showing data on it. I tried with hardcoded data but only the headers are shown. Grid has height and width set.
Here is the code snippet. I would appreciate any help. thanks.
define(["dojo/_base/declare", "dijit/_WidgetBase",
"dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin",
"dijit/_OnDijitClickMixin",
GridWidget.js
define(["dojo/_base/declare", "dijit/_WidgetBase",
"dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin",
"dijit/_OnDijitClickMixin", "dojo/text!./templates/GridWidget.html",
"dgrid/Grid","dgrid/Keyboard", "dgrid/Selection", "dgrid/extensions/DijitRegistry", "dstore/Memory", "dstore/Trackable"], function(declare, _WidgetBase,
_TemplatedMixin, _WidgetsInTemplateMixin,
_OnDijitClickMixin, template, Grid, Keyboard, Selection, DigitRegistry, Memory, Trackable) {
return decalare("GridWidget", [_WidgetBase, _OnDijitClickMixin, _TemplatedMixin, _WidgetsInTemplateMixin], {
widgetsInTemplate: true,
baseClass: 'GridWidget',
templateString: template,
data: null,
store: null,
grid: null,
columns: null,
constructor: function(data) {
this.data = data;
},
_setData: function(input) {
if (input) {
this._set("data", input);
}
},
getData: function() {
return this.data;
},
postCreate : function() {
this.inherited(arguments);
var StandardGrid = declare([Grid, Selection, Keyboard, DijitRegistry]);
this.store = new (declare([Trackable, Memory]))({
data : this.data,
idProperty : "isbn"
});
this.columns = {
bookTitle : "Title",
first : "First Name",
last : "Last Name",
releaseDate : "Release Date"
};
this.grid = new StandardGrid({
collection : this.store,
columns : this.columns,
cellNavigation : false,
noDataMessage : "No results.",
loadingMessage : "Loading Data...",
}, this.gridNode);
}
startup: function() {
if (this._started) return;
this.inherited(arguments);
if (this.grid) {
this.grid.startup();
}
}
});
});
GridWidget.html
<div class="${baseClass}">
<div class="${baseClass}Grid"data-dojo-attach-point="gridNode"></div>
</div>
testGridWidget.html
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test: Dgrid 0.4</title>
<link rel="stylesheet" href="style.css" media="screen">
<link rel="stylesheet" href="dojo/dijit/themes/claro/claro.css" media="screen">
<script>
//var startTime = new Date();
var CONTEXT_ROOT = 'DtossApp';
var djConfig = (function(){
var base = location.href.split("/");
base.pop();
base = base.join("/");
return {
parseOnLoad: true,
isDebug: true,
packages: [{
name: CONTEXT_ROOT,
location: base + "/widget"
}]
};
})();
</script>
</head>
<body class="claro">
<script>
function showGrid() {
require([
CONTEXT_ROOT + '/GridWidget',
'dojo/dom-construct',
'dojo/dom',
'dijit/layout/ContentPane',
], function (GridWidget, domConstruct, dom, ContentPane) {
var testWidget = new GridWidget({ data: createData()});
var cp = new ContentPane({
title : "Book List",
content : testWidget});
var ref = dom.byId('grid');
domConstruct.place(cp.domNode, ref);
testWidget.startup();
//Copied from dgrid laboratory sample..
function createData () {
var data = [];
var column;
var i;
for (i = 0; i < 50; i++) {
data.push({});
for (column in { first: 1, last: 1, bookTitle: 1, releaseDate: 1 }) {
data[i].isbn = i;
data[i][column] = column + '_' + (i + 1);
}
}
return data;
}
});
}
</script>
<h1>Test: Dgrid 0.4</h1>
<div id="buttonContainer">
<button class="action" onClick="showGrid1()">Show Grid</button>
</div>
<div id="grid"></div>
<!-- load dojo and provide config via data attribute -->
<script src="dojo/dojo/dojo.js"></script>
</body>
</html>
GridWidget.css
.GridWidgetGrid {
height: 300px;
width: 80%;
}
Dgrid tutorial shows the following note:
When using the basic Grid module, the grid will be empty until you call renderArray. The more advanced store-based implementations like OnDemandGrid will populate themselves from the store automatically.
I changed my Grid to OnDemandGrid which picks data from store automatically.
Also calling renderArray in startup method populates data for Grid.

Categories