Vuejs-pdf print - vue.js

I'm using vuejs-pdf to print some pages of my pdf and the print is not show the characters :
that's the code i'm using :
<button #click="$refs.myPdfComponent.print(100,pages)">Print </button>
<pdf v-for="i in pages" :key="i" ref="newpdf" :src="'pdf/'+src" :page="i" class="rounded border
border-info mb-4" :rotate="rotate" #progress="loadedRatio = $event" #error="error" #num-pages="numPages = $event" #link-clicked="page = $event" > </pdf>
and the pdf i'm printing is myPdfComponent the newpdf is the only the pages i need :
<pdf v-if="show" ref="myPdfComponent" class="rounded border border-info mb-4" :src="'pdf/'+src"
:page="page" :rotate="rotate" #progress="loadedRatio = $event" #error="error" #num-pages="numPages =
$event" #link-clicked="page = $event"></pdf>

Open the vue-pdf plugin directory node_modules/vue-pdf/src/pdfjsWrapper.js
and replace
import { PDFLinkService } from 'pdfjs-dist/es5/web/pdf_viewer';
var pendingOperation = Promise.resolve();
export default function(PDFJS) {
function isPDFDocumentLoadingTask(obj) {
return typeof(obj) === 'object' && obj !== null && obj.__PDFDocumentLoadingTask === true;
// or: return obj.constructor.name === 'PDFDocumentLoadingTask';
}
function createLoadingTask(src, options) {
var source;
if ( typeof(src) === 'string' )
source = { url: src };
else if ( src instanceof Uint8Array )
source = { data: src };
else if ( typeof(src) === 'object' && src !== null )
source = Object.assign({}, src);
else
throw new TypeError('invalid src type');
// source.verbosity = PDFJS.VerbosityLevel.INFOS;
// source.pdfBug = true;
// source.stopAtErrors = true;
if ( options && options.withCredentials )
source.withCredentials = options.withCredentials;
var loadingTask = PDFJS.getDocument(source);
loadingTask.__PDFDocumentLoadingTask = true; // since PDFDocumentLoadingTask is not public
if ( options && options.onPassword )
loadingTask.onPassword = options.onPassword;
if ( options && options.onProgress )
loadingTask.onProgress = options.onProgress;
return loadingTask;
}
function PDFJSWrapper(canvasElt, annotationLayerElt, emitEvent) {
var pdfDoc = null;
var pdfPage = null;
var pdfRender = null;
var canceling = false;
canvasElt.getContext('2d').save();
function clearCanvas() {
canvasElt.getContext('2d').clearRect(0, 0, canvasElt.width, canvasElt.height);
}
function clearAnnotations() {
while ( annotationLayerElt.firstChild )
annotationLayerElt.removeChild(annotationLayerElt.firstChild);
}
this.destroy = function() {
if ( pdfDoc === null )
return;
// Aborts all network requests and destroys worker.
pendingOperation = pdfDoc.destroy();
pdfDoc = null;
}
this.getResolutionScale = function() {
return canvasElt.offsetWidth / canvasElt.width;
}
this.printPage = function(dpi, pageNumberOnly) {
if ( pdfPage === null )
return;
// 1in == 72pt
// 1in == 96px
var PRINT_RESOLUTION = dpi === undefined ? 150 : dpi;
var PRINT_UNITS = PRINT_RESOLUTION / 72.0;
var CSS_UNITS = 96.0 / 72.0;
/*var iframeElt = document.createElement('iframe');
function removeIframe() {
iframeElt.parentNode.removeChild(iframeElt);
}*/
var printContainerElement = document.createElement('div');
printContainerElement.setAttribute('id', 'print-container')
function removePrintContainer() {
printContainerElement.parentNode.removeChild(printContainerElement);
}
new Promise(function(resolve, reject) {
/*
iframeElt.frameBorder = '0';
iframeElt.scrolling = 'no';
iframeElt.width = '0px;'
iframeElt.height = '0px;'
iframeElt.style.cssText = 'position: absolute; top: 0; left: 0';
iframeElt.onload = function() {
resolve(this.contentWindow);
}
window.document.body.appendChild(iframeElt);*/
printContainerElement.frameBorder = '0';
printContainerElement.scrolling = 'no';
printContainerElement.width = '0px;'
printContainerElement.height = '0px;'
printContainerElement.style.cssText = 'position: absolute; top: 0; left: 0';
window.document.body.appendChild(printContainerElement);
resolve(window)
})
.then(function(win) {
win.document.title = '';
return pdfDoc.getPage(1)
.then(function(page) {
var viewport = page.getViewport({ scale: 1 });
//win.document.head.appendChild(win.document.createElement('style')).textContent =
printContainerElement.appendChild(win.document.createElement('style')).textContent =
'#supports ((size:A4) and (size:1pt 1pt)) {' +
'#page { margin: 1pt; size: ' + ((viewport.width * PRINT_UNITS) / CSS_UNITS) + 'pt ' + ((viewport.height * PRINT_UNITS) / CSS_UNITS) + 'pt; }' +
'}' +
'#print-canvas { display: none }' +
'#media print {' +
'body { margin: 0 }' +
'canvas { page-break-before: avoid; page-break-after: always; page-break-inside: avoid }' +
'#print-canvas { page-break-before: avoid; page-break-after: always; page-break-inside: avoid; display: block }' +
'body > *:not(#print-container) { display: none; }' +
'}'+
'#media screen {' +
'body { margin: 0 }' +
'}'+
''
return win;
})
})
.then(function(win) {
var allPages = [];
for ( var pageNumber = 1; pageNumber <= pdfDoc.numPages; ++pageNumber ) {
if ( pageNumberOnly !== undefined && pageNumberOnly.indexOf(pageNumber) === -1 )
continue;
allPages.push(
pdfDoc.getPage(pageNumber)
.then(function(page) {
var viewport = page.getViewport({ scale: 1 });
//var printCanvasElt = win.document.body.appendChild(win.document.createElement('canvas'));
var printCanvasElt = printContainerElement.appendChild(win.document.createElement('canvas'));
printCanvasElt.setAttribute('id', 'print-canvas')
printCanvasElt.width = (viewport.width * PRINT_UNITS);
printCanvasElt.height = (viewport.height * PRINT_UNITS);
return page.render({
canvasContext: printCanvasElt.getContext('2d'),
transform: [ // Additional transform, applied just before viewport transform.
PRINT_UNITS, 0, 0,
PRINT_UNITS, 0, 0
],
viewport: viewport,
intent: 'print'
}).promise;
})
);
}
Promise.all(allPages)
.then(function() {
win.focus(); // Required for IE
if (win.document.queryCommandSupported('print')) {
win.document.execCommand('print', false, null);
} else {
win.print();
}
removePrintContainer();
})
.catch(function(err) {
removePrintContainer();
emitEvent('error', err);
})
})
}
this.renderPage = function(rotate) {
if ( pdfRender !== null ) {
if ( canceling )
return;
canceling = true;
pdfRender.cancel();
return;
}
if ( pdfPage === null )
return;
var pageRotate = (pdfPage.rotate === undefined ? 0 : pdfPage.rotate) + (rotate === undefined ? 0 : rotate);
var scale = canvasElt.offsetWidth / pdfPage.getViewport({ scale: 1 }).width * (window.devicePixelRatio || 1);
var viewport = pdfPage.getViewport({ scale: scale, rotation:pageRotate });
emitEvent('page-size', viewport.width, viewport.height, scale);
canvasElt.width = viewport.width;
canvasElt.height = viewport.height;
pdfRender = pdfPage.render({
canvasContext: canvasElt.getContext('2d'),
viewport: viewport
});
annotationLayerElt.style.visibility = 'hidden';
clearAnnotations();
var viewer = {
scrollPageIntoView: function(params) {
emitEvent('link-clicked', params.pageNumber)
},
};
var linkService = new PDFLinkService();
linkService.setDocument(pdfDoc);
linkService.setViewer(viewer);
pendingOperation = pendingOperation.then(function() {
var getAnnotationsOperation =
pdfPage.getAnnotations({ intent: 'display' })
.then(function(annotations) {
PDFJS.AnnotationLayer.render({
viewport: viewport.clone({ dontFlip: true }),
div: annotationLayerElt,
annotations: annotations,
page: pdfPage,
linkService: linkService,
renderInteractiveForms: false
});
});
var pdfRenderOperation =
pdfRender.promise
.then(function() {
annotationLayerElt.style.visibility = '';
canceling = false;
pdfRender = null;
})
.catch(function(err) {
pdfRender = null;
if ( err instanceof PDFJS.RenderingCancelledException ) {
canceling = false;
this.renderPage(rotate);
return;
}
emitEvent('error', err);
}.bind(this))
return Promise.all([getAnnotationsOperation, pdfRenderOperation]);
}.bind(this));
}
this.forEachPage = function(pageCallback) {
var numPages = pdfDoc.numPages;
(function next(pageNum) {
pdfDoc.getPage(pageNum)
.then(pageCallback)
.then(function() {
if ( ++pageNum <= numPages )
next(pageNum);
})
})(1);
}
this.loadPage = function(pageNumber, rotate) {
pdfPage = null;
if ( pdfDoc === null )
return;
pendingOperation = pendingOperation.then(function() {
return pdfDoc.getPage(pageNumber);
})
.then(function(page) {
pdfPage = page;
this.renderPage(rotate);
emitEvent('page-loaded', page.pageNumber);
}.bind(this))
.catch(function(err) {
clearCanvas();
clearAnnotations();
emitEvent('error', err);
});
}
this.loadDocument = function(src) {
pdfDoc = null;
pdfPage = null;
emitEvent('num-pages', undefined);
if ( !src ) {
canvasElt.removeAttribute('width');
canvasElt.removeAttribute('height');
clearAnnotations();
return;
}
// wait for pending operation ends
pendingOperation = pendingOperation.then(function() {
var loadingTask;
if ( isPDFDocumentLoadingTask(src) ) {
if ( src.destroyed ) {
emitEvent('error', new Error('loadingTask has been destroyed'));
return
}
loadingTask = src;
} else {
loadingTask = createLoadingTask(src, {
onPassword: function(updatePassword, reason) {
var reasonStr;
switch (reason) {
case PDFJS.PasswordResponses.NEED_PASSWORD:
reasonStr = 'NEED_PASSWORD';
break;
case PDFJS.PasswordResponses.INCORRECT_PASSWORD:
reasonStr = 'INCORRECT_PASSWORD';
break;
}
emitEvent('password', updatePassword, reasonStr);
},
onProgress: function(status) {
var ratio = status.loaded / status.total;
emitEvent('progress', Math.min(ratio, 1));
}
});
}
return loadingTask.promise;
})
.then(function(pdf) {
pdfDoc = pdf;
emitEvent('num-pages', pdf.numPages);
emitEvent('loaded');
})
.catch(function(err) {
clearCanvas();
clearAnnotations();
emitEvent('error', err);
})
}
annotationLayerElt.style.transformOrigin = '0 0';
}
return {
createLoadingTask: createLoadingTask,
PDFJSWrapper: PDFJSWrapper,
}
}

Related

Fabric JS 2.4.1 ClipPath Crop Not Working with a Dynamically Created rect Mask

I am making a editor using fabric js 2.4.1 and have completed all functionality except for the dynamic image cropping. The functionality involves creating a rectangle with the mouse over an image and clicking a crop button.
I have successfully done a proof of concept with a rectangle that was created statically but can't get it to render in my dynamic code. I don't think that the problem has to do with the dynamically created rect but I can't seem to isolate the problem. It has to be something simple that I'm overlooking and I think the problem might be in my crop button code.
document.getElementById("crop").addEventListener("click", function() {
if (target !== null && mask !== null) {
mask.setCoords();
target.clipPath = mask; // THIS LINE IS NOT WORKING!!!
//target.selectable = true;
target.setCoords();
console.log(target);
canvas.renderAll();
//canvas.remove(mask);
}
});
Here is a fiddle to the dynamic code that has the problem:
https://jsfiddle.net/Larry_Robertson/mqrv5fnt/
Here is a fiddle to the static code that I gained proof of concept from:
https://jsfiddle.net/Larry_Robertson/f34q67op/
Source code of Dynamic Version:
HTML
<canvas id="c" width="500" height="500" style="border:1px solid #ccc"></canvas>
<button id="crop">Crop</button>
JS
var canvas = new fabric.Canvas('c', {
selection: true
});
var rect, isDown, origX, origY, done, object, mask, target;
var src = "http://fabricjs.com/lib/pug.jpg";
fabric.Image.fromURL(src, function(img) {
img.selectable = false;
img.id = 'image';
object = img;
canvas.add(img);
});
canvas.on('object:added', function(e) {
target = null;
mask = null;
canvas.forEachObject(function(obj) {
//alert(obj.get('id'));
var id = obj.get('id');
if (id === 'image') {
target = obj;
}
if (id === 'mask') {
//alert('mask');
mask = obj;
}
});
});
document.getElementById("crop").addEventListener("click", function() {
if (target !== null && mask !== null) {
mask.setCoords();
target.clipPath = mask; // THIS LINE IS NOT WORKING!!!
//target.selectable = true;
target.setCoords();
console.log(target);
canvas.renderAll();
//canvas.remove(mask);
}
});
canvas.on('mouse:down', function(o) {
if (done) {
canvas.renderAll();
return;
}
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
rect = new fabric.Rect({
left: origX,
top: origY,
//originX: 'left',
//originY: 'top',
width: pointer.x - origX,
height: pointer.y - origY,
//angle: 0,
fill: 'rgba(255,0,0,0.3)',
transparentCorners: false,
//selectable: true,
id: 'mask'
});
canvas.add(rect);
canvas.renderAll();
});
canvas.on('mouse:move', function(o) {
if (done) {
canvas.renderAll();
return;
}
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
rect.set({
left: Math.abs(pointer.x)
});
}
if (origY > pointer.y) {
rect.set({
top: Math.abs(pointer.y)
});
}
rect.set({
width: Math.abs(origX - pointer.x)
});
rect.set({
height: Math.abs(origY - pointer.y)
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
if (done) {
canvas.renderAll();
return;
}
isDown = false;
//rect.selectable = true;
rect.set({
selectable: true
});
rect.setCoords();
canvas.setActiveObject(rect);
canvas.bringToFront(rect);
canvas.renderAll();
//alert(rect);
rect.setCoords();
object.clipPath = rect;
object.selectable = true;
object.setCoords();
canvas.renderAll();
//canvas.remove(rect);
done = true;
});
You need to set the dirty parameter on image on true, so object's cache will be rerendered next render call.
Here is the fiddle:
https://jsfiddle.net/mqrv5fnt/115/
var canvas = new fabric.Canvas('c', {
selection: true
});
var rect, isDown, origX, origY, done, object, mask, target;
var src = "http://fabricjs.com/lib/pug.jpg";
fabric.Image.fromURL(src, function(img) {
img.selectable = false;
img.id = 'image';
object = img;
canvas.add(img);
});
canvas.on('object:added', function(e) {
target = null;
mask = null;
canvas.forEachObject(function(obj) {
//alert(obj.get('id'));
var id = obj.get('id');
if (id === 'image') {
target = obj;
}
if (id === 'mask') {
//alert('mask');
mask = obj;
}
});
});
document.getElementById("crop").addEventListener("click", function() {
if (target !== null && mask !== null) {
mask.setCoords();
target.clipPath = mask; // THIS LINE IS NOT WORKING!!!
target.dirty=true;
//target.selectable = true;
target.setCoords();
canvas.remove(mask);
canvas.renderAll();
//canvas.remove(mask);
}
});
canvas.on('mouse:down', function(o) {
if (done) {
canvas.renderAll();
return;
}
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
rect = new fabric.Rect({
left: origX,
top: origY,
//originX: 'left',
//originY: 'top',
width: pointer.x - origX,
height: pointer.y - origY,
//angle: 0,
fill: 'rgba(255,0,0,0.3)',
transparentCorners: false,
//selectable: true,
id: 'mask'
});
canvas.add(rect);
canvas.renderAll();
});
canvas.on('mouse:move', function(o) {
if (done) {
canvas.renderAll();
return;
}
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
rect.set({
left: Math.abs(pointer.x)
});
}
if (origY > pointer.y) {
rect.set({
top: Math.abs(pointer.y)
});
}
rect.set({
width: Math.abs(origX - pointer.x)
});
rect.set({
height: Math.abs(origY - pointer.y)
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
if (done) {
canvas.renderAll();
return;
}
isDown = false;
//rect.selectable = true;
rect.set({
selectable: true
});
rect.setCoords();
canvas.setActiveObject(rect);
canvas.bringToFront(rect);
canvas.renderAll();
//alert(rect);
rect.setCoords();
object.clipPath = rect;
object.selectable = true;
object.setCoords();
canvas.renderAll();
//canvas.remove(rect);
done = true;
});

Webrtc video chat not working in different networks

I am trying to implement video chat with webrtc using code from google code labs . It works fine on same network but does not work on different network. i have installed coturn on my server. I am not sure if it is working correctly.
Any one used google codelabs code and made it working?
This is the modified main.js file
'use strict';
var isChannelReady = false;
var isInitiator = false;
var isStarted = false;
var localStream;
var pc;
var remoteStream;
var turnReady;
var pcConfig = {
"iceServers":[
{'urls': 'stun:stun.l.google.com:19302'},
{"urls":["turn:78.129.167.90"],"username":"wyzturner1","credential":"wyzturnp2ss"}]
};
// Set up audio and video regardless of what devices are present.
var sdpConstraints = {
offerToReceiveAudio: true,
offerToReceiveVideo: true
};
/////////////////////////////////////////////
var room = 'foo';
// Could prompt for room name:
// room = prompt('Enter room name:');
var socket = io.connect('https://www.samplesite.com:8080');
if (room !== '') {
socket.emit('create or join', room);
console.log('Attempted to create or join room', room);
}
socket.on('created', function(room) {
console.log('Created room ' + room);
isInitiator = true;
});
socket.on('full', function(room) {
console.log('Room ' + room + ' is full');
});
socket.on('join', function (room){
console.log('Another peer made a request to join room ' + room);
console.log('This peer is the initiator of room ' + room + '!');
isChannelReady = true;
});
socket.on('joined', function(room) {
console.log('joined: ' + room);
isChannelReady = true;
});
socket.on('log', function(array) {
console.log.apply(console, array);
});
////////////////////////////////////////////////
function sendMessage(message) {
console.log('Client sending message: ', message);
socket.emit('message', message);
}
// This client receives a message
socket.on('message', function(message) {
console.log('Client received message:', message);
if (message === 'got user media') {
maybeStart();
} else if (message.type === 'offer') {
if (!isInitiator && !isStarted) {
maybeStart();
}
pc.setRemoteDescription(new RTCSessionDescription(message));
doAnswer();
} else if (message.type === 'answer' && isStarted) {
pc.setRemoteDescription(new RTCSessionDescription(message));
} else if (message.type === 'candidate' && isStarted) {
var candidate = new RTCIceCandidate({
sdpMLineIndex: message.label,
candidate: message.candidate
});
pc.addIceCandidate(candidate);
} else if (message === 'bye' && isStarted) {
handleRemoteHangup();
}
});
////////////////////////////////////////////////////
var localVideo = document.querySelector('#localVideo');
var remoteVideo = document.querySelector('#remoteVideo');
navigator.mediaDevices.getUserMedia({
audio: false,
video: true
})
.then(gotStream)
.catch(function(e) {
alert('getUserMedia() error: ' + e.name);
});
function gotStream(stream) {
console.log('Adding local stream.');
localVideo.src = window.URL.createObjectURL(stream);
localStream = stream;
sendMessage('got user media');
if (isInitiator) {
maybeStart();
}
}
var constraints = {
video: true
};
console.log('Getting user media with constraints', constraints);
//if (location.hostname !== 'localhost') {
// requestTurn(
// 'https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913'
// );
//}
function maybeStart() {
console.log('>>>>>>> maybeStart() ', isStarted, localStream, isChannelReady);
if (!isStarted && typeof localStream !== 'undefined' && isChannelReady) {
console.log('>>>>>> creating peer connection');
createPeerConnection();
isStarted = true;
console.log('isInitiator', isInitiator);
if (isInitiator) {
doCall();
}
}
}
window.onbeforeunload = function() {
sendMessage('bye');
};
/////////////////////////////////////////////////////////
function createPeerConnection() {
try {
pc = new RTCPeerConnection(pcConfig);
pc.addStream(localStream);
pc.onicecandidate = handleIceCandidate;
pc.onaddstream = handleRemoteStreamAdded;
pc.oniceconnectionstatechange = function(){
console.log('ICE state: ',pc.iceConnectionState);
}
pc.onremovestream = handleRemoteStreamRemoved;
console.log('Created RTCPeerConnnection');
} catch (e) {
console.log('Failed to create PeerConnection, exception: ' + e.message);
alert('Cannot create RTCPeerConnection object.');
return;
}
}
function handleIceCandidate(event) {
console.log('icecandidate event: ', event);
if (event.candidate) {
sendMessage({
type: 'candidate',
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate
});
} else {
console.log('End of candidates.');
}
}
function handleRemoteStreamAdded(event) {
console.log('Remote stream added.');
remoteVideo.src = window.URL.createObjectURL(event.stream);
remoteStream = event.stream;
}
function handleCreateOfferError(event) {
console.log('createOffer() error: ', event);
}
function doCall() {
console.log('Sending offer to peer');
pc.createOffer(setLocalAndSendMessage, handleCreateOfferError);
}
function doAnswer() {
console.log('Sending answer to peer.');
pc.createAnswer().then(
setLocalAndSendMessage,
onCreateSessionDescriptionError
);
}
function setLocalAndSendMessage(sessionDescription) {
// Set Opus as the preferred codec in SDP if Opus is present.
// sessionDescription.sdp = preferOpus(sessionDescription.sdp);
pc.setLocalDescription(sessionDescription);
console.log('setLocalAndSendMessage sending message', sessionDescription);
sendMessage(sessionDescription);
}
function onCreateSessionDescriptionError(error) {
trace('Failed to create session description: ' + error.toString());
}
function requestTurn(turnURL) {
var turnExists = false;
for (var i in pcConfig.iceServers) {
if (pcConfig.iceServers[i].urls.substr(0, 5) === 'turn:') {
turnExists = true;
turnReady = true;
break;
}
}
// if (!turnExists) {
// console.log('Getting TURN server from ', turnURL);
// // No TURN server. Get one from computeengineondemand.appspot.com:
// var xhr = new XMLHttpRequest();
// xhr.onreadystatechange = function() {
// if (xhr.readyState === 4 && xhr.status === 200) {
// var turnServer = JSON.parse(xhr.responseText);
// console.log('Got TURN server: ', turnServer);
// pcConfig.iceServers.push({
// 'url': 'turn:' + turnServer.username + '#' + turnServer.turn,
// 'credential': turnServer.password
// });
// turnReady = true;
// }
// };
// xhr.open('GET', turnURL, true);
// xhr.send();
// }
}
function handleRemoteStreamAdded(event) {
console.log('Remote stream added.');
remoteVideo.src = window.URL.createObjectURL(event.stream);
remoteStream = event.stream;
}
function handleRemoteStreamRemoved(event) {
console.log('Remote stream removed. Event: ', event);
}
function hangup() {
console.log('Hanging up.');
stop();
sendMessage('bye');
}
function handleRemoteHangup() {
console.log('Session terminated.');
stop();
isInitiator = false;
}
function stop() {
isStarted = false;
// isAudioMuted = false;
// isVideoMuted = false;
pc.close();
pc = null;
}
///////////////////////////////////////////
// Set Opus as the default audio codec if it's present.
function preferOpus(sdp) {
var sdpLines = sdp.split('\r\n');
var mLineIndex;
// Search for m line.
for (var i = 0; i < sdpLines.length; i++) {
if (sdpLines[i].search('m=audio') !== -1) {
mLineIndex = i;
break;
}
}
if (mLineIndex === null) {
return sdp;
}
// If Opus is available, set it as the default in m line.
for (i = 0; i < sdpLines.length; i++) {
if (sdpLines[i].search('opus/48000') !== -1) {
var opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i);
if (opusPayload) {
sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex],
opusPayload);
}
break;
}
}
// Remove CN in m line and sdp.
sdpLines = removeCN(sdpLines, mLineIndex);
sdp = sdpLines.join('\r\n');
return sdp;
}
function extractSdp(sdpLine, pattern) {
var result = sdpLine.match(pattern);
return result && result.length === 2 ? result[1] : null;
}
// Set the selected codec to the first in m line.
function setDefaultCodec(mLine, payload) {
var elements = mLine.split(' ');
var newLine = [];
var index = 0;
for (var i = 0; i < elements.length; i++) {
if (index === 3) { // Format of media starts from the fourth.
newLine[index++] = payload; // Put target payload to the first.
}
if (elements[i] !== payload) {
newLine[index++] = elements[i];
}
}
return newLine.join(' ');
}
// Strip CN from sdp before CN constraints is ready.
function removeCN(sdpLines, mLineIndex) {
var mLineElements = sdpLines[mLineIndex].split(' ');
// Scan from end for the convenience of removing an item.
for (var i = sdpLines.length - 1; i >= 0; i--) {
var payload = extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i);
if (payload) {
var cnPos = mLineElements.indexOf(payload);
if (cnPos !== -1) {
// Remove CN payload from m line.
mLineElements.splice(cnPos, 1);
}
// Remove CN line in sdp
sdpLines.splice(i, 1);
}
}
sdpLines[mLineIndex] = mLineElements.join(' ');
return sdpLines;
}

Trello API add base64 data image as an attachement

I'd like to send base64 image as an attachment to a trello card through the API
POST /1/cards/[card id or shortlink]/attachments
There's a file field but it does not specify how should look the data there.
Refs: https://developers.trello.com/advanced-reference/card#post-1-cards-card-id-or-shortlink-attachments
Any idea?
Short answer: Trello's API only works to attach binary data via multipart/form-data. Examples below.
Long answer:
The Trello API to add attachments and images is frustratingly under-documented. They do have a coffeescript Client.js for those of us using Javascript to simplify all the basic operations: https://trello.com/1/client.coffee
Using the vanilla Client.js file I have been able to attach links and text files. While the CURL example shows pulling a binary file in from a hard drive, that doesn't work for those of us completely on a server or client where we don't have permissions to create a file.
From a LOT of trial and error, I've determined all binary data (images, documents, etc.) must be attached using multipart/form-data. Here is a jQuery snippet that will take a URL to an item, get it into memory, and then send it to Trello.
var opts = {'key': 'YOUR TRELLO KEY', 'token': 'YOUR TRELLO TOKEN'};
var xhr = new XMLHttpRequest();
xhr.open('get', params); // params is a URL to a file to grab
xhr.responseType = 'blob'; // Use blob to get the file's mimetype
xhr.onload = function() {
var fileReader = new FileReader();
fileReader.onload = function() {
var filename = (params.split('/').pop().split('#')[0].split('?')[0]) || params || '?'; // Removes # or ? after filename
var file = new File([this.result], filename);
var form = new FormData(); // this is the formdata Trello needs
form.append("file", file);
$.each(['key', 'token'], function(iter, item) {
form.append(item, opts.data[item] || 'ERROR! Missing "' + item + '"');
});
$.extend(opts, {
method: "POST",
data: form,
cache: false,
contentType: false,
processData: false
});
return $.ajax(opts);
};
fileReader.readAsArrayBuffer(xhr.response); // Use filereader on blob to get content
};
xhr.send();
I have submitted a new coffeescript for Trello developer support to consider uploading to replace Client.js. It adds a "Trello.upload(url)" that does this work.
I've also attached here for convenience in JS form.
// Generated by CoffeeScript 1.12.4
(function() {
var opts={"version":1,"apiEndpoint":"https://api.trello.com","authEndpoint":"https://trello.com"};
var deferred, isFunction, isReady, ready, waitUntil, wrapper,
slice = [].slice;
wrapper = function(window, jQuery, opts) {
var $, Trello, apiEndpoint, authEndpoint, authorizeURL, baseURL, collection, fn, fn1, i, intentEndpoint, j, key, len, len1, localStorage, location, parseRestArgs, readStorage, ref, ref1, storagePrefix, token, type, version, writeStorage;
$ = jQuery;
key = opts.key, token = opts.token, apiEndpoint = opts.apiEndpoint, authEndpoint = opts.authEndpoint, intentEndpoint = opts.intentEndpoint, version = opts.version;
baseURL = apiEndpoint + "/" + version + "/";
location = window.location;
Trello = {
version: function() {
return version;
},
key: function() {
return key;
},
setKey: function(newKey) {
key = newKey;
},
token: function() {
return token;
},
setToken: function(newToken) {
token = newToken;
},
rest: function() {
var args, error, method, params, path, ref, success;
method = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
ref = parseRestArgs(args), path = ref[0], params = ref[1], success = ref[2], error = ref[3];
opts = {
url: "" + baseURL + path,
type: method,
data: {},
dataType: "json",
success: success,
error: error
};
if (!$.support.cors) {
opts.dataType = "jsonp";
if (method !== "GET") {
opts.type = "GET";
$.extend(opts.data, {
_method: method
});
}
}
if (key) {
opts.data.key = key;
}
if (token) {
opts.data.token = token;
}
if (params != null) {
$.extend(opts.data, params);
}
if (method === 'UPLOAD' && typeof (params) === "string" && params.length > 5) {
var xhr = new XMLHttpRequest();
xhr.open('get', params);
xhr.responseType = 'blob'; // Use blob to get the mimetype
xhr.onload = function() {
var fileReader = new FileReader();
fileReader.onload = function() {
var filename = (params.split('/').pop().split('#')[0].split('?')[0]) || params || '?'; // Removes # or ? after filename
var file = new File([this.result], filename);
var form = new FormData();
form.append("file", file);
$.each(['key', 'token'], function(iter, item) {
form.append(item, opts.data[item] || 'ERROR! Missing "' + item + '"');
});
$.extend(opts, {
method: "POST",
data: form,
cache: false,
contentType: false,
processData: false
});
return $.ajax(opts);
};
fileReader.readAsArrayBuffer(xhr.response); // Use filereader on blob to get content
};
xhr.send();
} else {
return $.ajax(opts);
}
},
authorized: function() {
return token != null;
},
deauthorize: function() {
token = null;
writeStorage("token", token);
},
authorize: function(userOpts) {
var k, persistToken, ref, regexToken, scope, v;
opts = $.extend(true, {
type: "redirect",
persist: true,
interactive: true,
scope: {
read: true,
write: false,
account: false
},
expiration: "30days"
}, userOpts);
regexToken = /[&#]?token=([0-9a-f]{64})/;
persistToken = function() {
if (opts.persist && (token != null)) {
return writeStorage("token", token);
}
};
if (opts.persist) {
if (token == null) {
token = readStorage("token");
}
}
if (token == null) {
token = (ref = regexToken.exec(location.hash)) != null ? ref[1] : void 0;
}
if (this.authorized()) {
persistToken();
location.hash = location.hash.replace(regexToken, "");
return typeof opts.success === "function" ? opts.success() : void 0;
}
if (!opts.interactive) {
return typeof opts.error === "function" ? opts.error() : void 0;
}
scope = ((function() {
var ref1, results;
ref1 = opts.scope;
results = [];
for (k in ref1) {
v = ref1[k];
if (v) {
results.push(k);
}
}
return results;
})()).join(",");
switch (opts.type) {
case "popup":
(function() {
var authWindow, height, left, origin, receiveMessage, ref1, top, width;
waitUntil("authorized", (function(_this) {
return function(isAuthorized) {
if (isAuthorized) {
persistToken();
return typeof opts.success === "function" ? opts.success() : void 0;
} else {
return typeof opts.error === "function" ? opts.error() : void 0;
}
};
})(this));
width = 420;
height = 470;
left = window.screenX + (window.innerWidth - width) / 2;
top = window.screenY + (window.innerHeight - height) / 2;
origin = (ref1 = /^[a-z]+:\/\/[^\/]*/.exec(location)) != null ? ref1[0] : void 0;
authWindow = window.open(authorizeURL({
return_url: origin,
callback_method: "postMessage",
scope: scope,
expiration: opts.expiration,
name: opts.name
}), "trello", "width=" + width + ",height=" + height + ",left=" + left + ",top=" + top);
receiveMessage = function(event) {
var ref2;
if (event.origin !== authEndpoint || event.source !== authWindow) {
return;
}
if ((ref2 = event.source) != null) {
ref2.close();
}
if ((event.data != null) && /[0-9a-f]{64}/.test(event.data)) {
token = event.data;
} else {
token = null;
}
if (typeof window.removeEventListener === "function") {
window.removeEventListener("message", receiveMessage, false);
}
isReady("authorized", Trello.authorized());
};
return typeof window.addEventListener === "function" ? window.addEventListener("message", receiveMessage, false) : void 0;
})();
break;
default:
window.location = authorizeURL({
redirect_uri: location.href,
callback_method: "fragment",
scope: scope,
expiration: opts.expiration,
name: opts.name
});
}
},
addCard: function(options, next) {
var baseArgs, getCard;
baseArgs = {
mode: 'popup',
source: key || window.location.host
};
getCard = function(callback) {
var height, left, returnUrl, top, width;
returnUrl = function(e) {
var data;
window.removeEventListener('message', returnUrl);
try {
data = JSON.parse(e.data);
if (data.success) {
return callback(null, data.card);
} else {
return callback(new Error(data.error));
}
} catch (error1) {}
};
if (typeof window.addEventListener === "function") {
window.addEventListener('message', returnUrl, false);
}
width = 500;
height = 600;
left = window.screenX + (window.outerWidth - width) / 2;
top = window.screenY + (window.outerHeight - height) / 2;
return window.open(intentEndpoint + "/add-card?" + $.param($.extend(baseArgs, options)), "trello", "width=" + width + ",height=" + height + ",left=" + left + ",top=" + top);
};
if (next != null) {
return getCard(next);
} else if (window.Promise) {
return new Promise(function(resolve, reject) {
return getCard(function(err, card) {
if (err) {
return reject(err);
} else {
return resolve(card);
}
});
});
} else {
return getCard(function() {});
}
}
};
ref = ["GET", "PUT", "POST", "DELETE", "UPLOAD"];
fn = function(type) {
return Trello[type.toLowerCase()] = function() {
return this.rest.apply(this, [type].concat(slice.call(arguments)));
};
};
for (i = 0, len = ref.length; i < len; i++) {
type = ref[i];
fn(type);
}
Trello.del = Trello["delete"];
ref1 = ["actions", "cards", "checklists", "boards", "lists", "members", "organizations", "lists"];
fn1 = function(collection) {
return Trello[collection] = {
get: function(id, params, success, error) {
return Trello.get(collection + "/" + id, params, success, error);
}
};
};
for (j = 0, len1 = ref1.length; j < len1; j++) {
collection = ref1[j];
fn1(collection);
}
window.Trello = Trello;
authorizeURL = function(args) {
var baseArgs;
baseArgs = {
response_type: "token",
key: key
};
return authEndpoint + "/" + version + "/authorize?" + $.param($.extend(baseArgs, args));
};
parseRestArgs = function(arg) {
var error, params, path, success;
path = arg[0], params = arg[1], success = arg[2], error = arg[3];
if (isFunction(params)) {
error = success;
success = params;
params = {};
}
path = path.replace(/^\/*/, "");
return [path, params, success, error];
};
localStorage = window.localStorage;
if (localStorage != null) {
storagePrefix = "trello_";
readStorage = function(key) {
return localStorage[storagePrefix + key];
};
writeStorage = function(key, value) {
if (value === null) {
return delete localStorage[storagePrefix + key];
} else {
return localStorage[storagePrefix + key] = value;
}
};
} else {
readStorage = writeStorage = function() {};
}
};
deferred = {};
ready = {};
waitUntil = function(name, fx) {
if (ready[name] != null) {
return fx(ready[name]);
} else {
return (deferred[name] != null ? deferred[name] : deferred[name] = []).push(fx);
}
};
isReady = function(name, value) {
var fx, fxs, i, len;
ready[name] = value;
if (deferred[name]) {
fxs = deferred[name];
delete deferred[name];
for (i = 0, len = fxs.length; i < len; i++) {
fx = fxs[i];
fx(value);
}
}
};
isFunction = function(val) {
return typeof val === "function";
};
wrapper(window, jQuery, opts);
}).call(this);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

PDF export from icCube reporting with custom widget

PDF export for custom widget doesn't work from icCube reporting. Server engine version is 5.0.3 and reporting 5.0.3 (6:2163).
We didn't see any error message within the logs, the process remains stuck into the Monitoring -> Active Requests tab.
The report included is based on icCube demo Sales schema.
Widget code:
FishboneChart.js:
test = {
module : {}
}
test.module.FishboneChart = (function (_super) {
__extends(FishboneChart, _super);
function FishboneChart(container, options) {
_super.call(this, container, options);
this.options = options;
this.container = container;
var chartContainer = $("<div class='ic3w-fishbone-chart'></div>");
var contentContainer = $("<div class='ic3w-fishbone-chart-content'></div>");
var ct = $(this.container);
ct.append(chartContainer);
chartContainer.append(contentContainer);
};
$.extend(FishboneChart.prototype, {
buildInHtml : function (gviTable) {
var chartData = buildChartDataJson(gviTable);
renderFishboneChart(chartData);
}
});
return FishboneChart;
})(viz.GviChartBase);
test.module.FishboneChartAdapterFactory = (function (_super) {
__extends(FishboneChartAdapterFactory, _super);
function FishboneChartAdapterFactory() {
_super.call(this, "test.module.FishboneChartAdapter");
}
FishboneChartAdapterFactory.prototype.getId = function () {
return 'testFishboneChart';
};
FishboneChartAdapterFactory.prototype.getMenuGroupName = function () {
return "testMenu"
};
FishboneChartAdapterFactory.prototype.getTag = function () {
return "testFishboneChart"
};
return FishboneChartAdapterFactory;
})(ic3.WidgetAdapterFactory);
test.module.FishboneChartAdapter = (function (_super) {
__extends(FishboneChartAdapter, _super);
function FishboneChartAdapter(context) {
_super.call(this, context);
this.classID = "test.module.FishboneChartAdapter";
}
FishboneChartAdapter.prototype.reportTypeName = function () {
return 'Test fishbone-chart';
};
FishboneChartAdapter.prototype.getWidgetGroupName = function() {
return 'chart';
};
FishboneChartAdapter.prototype.getNameForCssClass = function() {
return 'test-chart';
};
FishboneChartAdapter.prototype.gutsMeta = function () {
return [
{
name: 'title',
type: 'text'
}
]
};
FishboneChartAdapter.prototype.createWidget = function (options, container) {
return new test.module.FishboneChart(container, options);
};
return FishboneChartAdapter;
})(ic3.ChartAdapter);
var initializeFishbone = function(d3){
"use strict";
d3.fishbone = function(){
var _margin = 50,
_marginRoot = 20,
_marginTail = 100,
_marginTop = 30,
_nodes,
_links,
_node,
_link,
_root,
_arrowId = function(d){ return "arrow"; },
_children = function(d){ return d.children; },
_label = function(d){ return d.name; },
_perNodeTick = function(d){},
_linkScale = d3.scale.log()
.domain([1, 5])
.range([20, 10]),
_chartSize = getChartSize(),
_force = d3.layout.force()
.gravity(0)
.size([
_chartSize.width,
_chartSize.height
])
.linkDistance(_linkDistance)
.chargeDistance([10])
.on("tick", _tick);
var fb1 = function($){
_links = [];
_nodes = [];
_build_nodes($.datum());
_force
.nodes(_nodes)
.links(_links);
_link = $.selectAll(".link")
.data(_links);
_link.enter().append("line");
_link
.attr({
"class": function(d){ return "link link-" + d.depth; },
"marker-end": function(d){
return d.arrow ? "url(#" + _arrowId(d) + ")" : null;
}
});
_link.exit().remove();
_node = $.selectAll(".node").data(_nodes);
_node.enter().append("g")
.attr({
"class": function(d){ return "node" + (d.root ? " root" : ""); }
})
.append("text");
_node.select("text")
.attr({
"class": function(d){ return "label-" + d.depth; },
"text-anchor": function(d){
return !d.depth ? "start" : d.horizontal ? "end" : "middle";
},
dy: function(d){
return d.horizontal ? ".35em" : d.region === 1 ? "1em" : "-.2em";
}
})
.text(_label);
_node.exit().remove();
_node
.call(_force.drag)
.on("mousedown", function(){ d3.event.stopPropagation(); });
_root = $.select(".root").node();
};
function _arrow($){
var defs = $.selectAll("defs").data([1]);
defs.enter().append("defs");
defs.selectAll("marker#" + _arrowId())
.data([1])
.enter().append("marker")
.attr({
id: _arrowId(),
viewBox: "0 -5 10 10",
refX: 10,
refY: 0,
markerWidth: 10,
markerHeight: 10,
orient: "auto"
})
.append("path")
.attr({d: "M0,-5L10,0L0,5"});
}
function _build_nodes(node){
_nodes.push(node);
var cx = 0;
var between = [node, node.connector],
nodeLinks = [{
source: node,
target: node.connector,
arrow: true,
depth: node.depth || 0
}],
prev,
childLinkCount;
if(!node.parent){
_nodes.push(prev = {tail: true});
between = [prev, node];
nodeLinks[0].source = prev;
nodeLinks[0].target = node;
node.horizontal = true;
node.vertical = false;
node.depth = 0;
node.root = true;
node.totalLinks = []
}else{
node.connector.maxChildIdx = 0;
node.connector.totalLinks = [];
}
node.linkCount = 1;
(_children(node) || []).forEach(function(child, idx){
child.parent = node;
child.depth = (node.depth || 0) + 1;
child.childIdx = idx;
child.region = node.region ? node.region : (idx & 1 ? 1 : -1);
child.horizontal = !node.horizontal;
child.vertical = !node.vertical;
if(node.root && prev && !prev.tail){
_nodes.push(child.connector = {
between: between,
childIdx: prev.childIdx
})
prev = null;
}else{
_nodes.push(prev = child.connector = {between: between, childIdx: cx++});
}
nodeLinks.push({
source: child,
target: child.connector,
depth: child.depth
});
childLinkCount = _build_nodes(child);
node.linkCount += childLinkCount;
between[1].totalLinks.push(childLinkCount);
});
between[1].maxChildIdx = cx;
Array.prototype.unshift.apply(_links, nodeLinks);
return node.linkCount;
}
function _linePosition($){
$.attr({
x1: function(d){ return d.source.x; },
y1: function(d){ return d.source.y; },
x2: function(d){ return d.target.x; },
y2: function(d){ return d.target.y; }
})
}
function _nodePosition($){
$.attr("transform", function(d){
return "translate(" + d.x + "," + d.y + ")";
})
}
function _linkDistance(d){
return (d.target.maxChildIdx + 1) * _linkScale(d.depth === 0 ? 1 : d.depth);
}
function _tick(e){
var k = 6 * e.alpha,
size = _force.size(),
width = size[0],
height = size[1],
a,
b;
_nodes.forEach(function(d){
if(d.root){ d.x = width - (_marginRoot + _root.getBBox().width); }
if(d.tail){ d.x = _marginTail; d.y = height / 2; }
if(d.depth === 1){
d.y = d.region === -1 ? _marginTop : (height - _marginTop);
d.x -= 10 * k;
}
if(d.vertical){ d.y += k * d.region; }
if(d.depth){ d.x -= k; }
if(d.between){
a = d.between[0];
b = d.between[1];
d.x = b.x - (1 + d.childIdx) * (b.x - a.x) / (b.maxChildIdx + 1);
d.y = b.y - (1 + d.childIdx) * (b.y - a.y) / (b.maxChildIdx + 1);
}
_perNodeTick(d);
});
_node.call(_nodePosition);
_link.call(_linePosition);
}
fb1.links = function(){ return _links; };
fb1.nodes = function(){ return _nodes; };
fb1.force = function(){ return _force; };
fb1.defaultArrow = _arrow;
fb1.margin = function(_){
if(!arguments.length){ return _margin; }
_margin = _;
return my;
};
fb1.children = function(_){
if(!arguments.length){ return _children; }
_children = _;
return my;
};
fb1.label = function(_){
if(!arguments.length){ return _label; }
_label = _;
return my;
};
fb1.perNodeTick = function(_){
if(!arguments.length){ return _perNodeTick; }
_perNodeTick = _;
return my;
};
return fb1;
};
};
var getChartSize = function() {
var chart = $('.ic3w-fishbone-chart');
return {
width : chart.width() || 0,
height : chart.height() || 0
};
};
var renderFishboneChart = function(chartData) {
if (!d3.fishbone) {
initializeFishbone(d3);
}
d3.selectAll('.ic3w-fishbone-chart-content svg').remove();
var fishbone = d3.fishbone();
d3.select('.ic3w-fishbone-chart-content')
.append("svg")
.attr(getChartSize())
.datum(chartData)
.call(fishbone.defaultArrow)
.call(fishbone);
fishbone.force().start();
};
var buildChartDataJson = function(gviTable) {
var rowCount = gviTable.getRowCount();
var colCount = gviTable.getColumnCount();
var currentLevel, levelDepthStr;
var currentBranch = [];
for (var i = 0; i < colCount; i++) {
levelDepthStr = gviTable.getPropertyForColumnHeader(i, 0, "a_ld");
currentLevel = parseInt(levelDepthStr);
if (!isNaN(currentLevel)) {
var currentEl = {
name: gviTable.getColumnLabel(i),
children: []
};
if (currentLevel <= currentBranch.length - 1) {
removeElements(currentBranch, currentLevel);
}
currentBranch[currentLevel] = currentEl;
if (currentLevel != 0) {
var parent = currentBranch[currentLevel - 1];
parent.children.push(currentEl);
}
}
}
return currentBranch.length > 0 ? currentBranch[0] : {};
};
var removeElements = function(array, targetLength) {
if (array) {
while (array.length > targetLength) {
array.pop();
}
}
};
FishBonePlugin.js:
ic3globals.plugins.push(
{
name: "Fishbone Chart",
loadCSS: function (options) {
var root = options.rootLocal + "plugins/";
ic3css(root + 'Fishbone.css');
},
loadJS: function (options) {
var root = options.rootLocal + "plugins/";
var deps = ['FishboneChart'];
$script(root + 'FishboneChart.js', deps[0]);
$script.ready(deps, function () { /* asynchronous callback */
options.callback && options.callback();
});
},
registerWidgetFactories: function (manager) {
manager.addWidgetFactory(new test.module.FishboneChartAdapterFactory());
},
registerBabylonTags: function (babylon) {
}
});
Fishbone.css:
.ic3w-fishbone-chart {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.ic3w-fishbone-chart-content *{
font-family: "Gill Sans", "Gill Sans MT";
}
.ic3w-fishbone-chart-content .label-0 {
font-size: 2em;
}
.ic3w-fishbone-chart-content .label-1 {
font-size: 1.5em;
fill: #111;
}
.ic3w-fishbone-chart-content .label-2 {
font-size: 1em;
fill: #444;
}
.ic3w-fishbone-chart-content .label-3 {
font-size: .9em;
fill: #888;
}
.ic3w-fishbone-chart-content .label-4 {
font-size: .8em;
fill: #aaa;
}
.ic3w-fishbone-chart-content .link-0 {
stroke: #000;
stroke-width: 2px;
}
.ic3w-fishbone-chart-content .link-1 {
stroke: #333;
stroke-width: 1px;
}
.ic3w-fishbone-chart-content .link-2, .ic3w-fishbone-chart-content .link-3, .ic3w-fishbone-chart-content .link-4 {
stroke: #666;
stroke-width: .5px;
}
Report code:
{"classID":"ic3.ReportGuts","guts_":{"ic3Version":13,"schemaName":"Sales","cubeName":"Sales","layout":{"classID":"ic3.FixedLayout","guts_":{"ic3Version":13,"grid":10,"boxes":[{"classID":"ic3.FixedLayoutBox","guts_":{"ic3Version":13,"header":"widget-0 ( widgetGroup.testMenu/testFishboneChart )","behaviour":"Fixed Box","noPrint":false,"position":{"top":0,"left":170,"width":1380,"height":820},"widgetAdapterUid":"w1","zIndex":2001,"ic3_uid":"ic3-164"}}]}},"widgetMgr":{"classID":"ic3.WidgetAdapterContainerMgr","guts_":{"ic3Version":13,"items":[{"classID":"test.module.FishboneChartAdapter","guts_":{"ic3Version":13,"navigationGuts":{"classID":"ic3.NavigationStrategy","guts_":{"ic3Version":13,"menuVisibility":{"back":true,"axisXChange":"All","axisYChange":"All","filter":"All","reset":true,"widget":true,"others":"All"},"maxAxisMemberCount":25}},"ic3_name":"widget-0","ic3_uid":"w1","ic3_eventMapper":{"classID":"ic3.EventWidgetMapper","guts_":{"__ic3_widgetEventsDescription":{}}},"ic3_mdxBuilderUid":"m1","__ic3_widgetTypeName":"widgetGroup.testMenu/testFishboneChart"}}]}},"constantMgr":{"classID":"ic3.ConstantsMgr","guts_":{"ic3Version":13}},"cssMgr":{"classID":"ic3.CssMgr","guts_":{}},"javascriptMgr":{"classID":"ic3.ReportJavascriptMgr","guts_":{"ic3Version":13,"js":"/** \n * A function called each time an event is generated. \n * \n * #param context the same object is passed between consumeEvent calls. \n * Can be used to store information. \n * { \n * $report : jQuery context of the report container \n * fireEvent : a function( name, value ) triggering an event \n * } \n * \n * #param event the event information \n * \n { \n * name : as specified in the 'Events' tab \n * value : (optional) actual event value \n * type : (optional) e.g., ic3selection \n * } \n * \n * Check the 'Report Event Names' menu for the list of available events. \n */ \n \nfunction consumeEvent( context, event ) { \n if (event.name == 'ic3-report-init') { \n \n ic3globals.plugins.push(\n {\n name: \"Fishbone Chart\",\n\n loadCSS: function (options) {\n },\n\n loadJS: function (options) {\n },\n\n registerWidgetFactories: function (manager) {\n console.log('korte1');\n manager.addWidgetFactory(new test.module.FishboneChartAdapterFactory());\n },\n\n registerBabylonTags: function (babylon) {\n }\n });\n } \n}"}},"calcMeasureMgr":{"classID":"ic3.CalcMeasureMgr","guts_":{"measures":[]}},"mdxQueriesMgr":{"classID":"ic3.MdxQueriesContainerMgr","guts_":{"mdxQueries":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[{"classID":"ic3.QueryBuilderWidget","guts_":{"mdxWizard":{"classID":"ic3.QueryBuilderWizardForm","guts_":{"rows":[],"cols":[{"classID":"ic3.QueryBuilderHierarchyForm","guts_":{"hierarchy":{"name":"Geography","uniqueName":"[Customers].[Geography]"},"type":"membersOf","membersOf":"all members"}}],"filters":[],"nonEmptyOnRows":false,"nonEmptyOnColumns":false}},"mdxFlat":{"classID":"ic3.QueryBuilderFlatMdxForm","guts_":{"useMdxStatement":false}},"ic3_name":"mdx Query-0","ic3_uid":"m1"}}]}},"mdxFilter":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[]}},"actionBuilders":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[]}}}}}}
Thanks,
Balint Ruzsa
Widget adapter code needs two extra functions(workaround for internal bug):
FishboneChartAdapter.prototype.hasNavigation = function()
{
return false;
};
FishboneChartAdapter.prototype.getNavigationMenuItems = function()
{
return [];
};
isRendered method should be modified, because layout for chart computed dynamicaly. I suggest to use simple setTimeout to with heuristic timeout, but you may implement custom check.
FishboneChart:
test.module.FishboneChart = (function (_super) {
__extends(FishboneChart, _super);
function FishboneChart(container, options) {
_super.call(this, container, options);
this.options = options;
this.container = container;
this.rendered = false;
var chartContainer = $("<div class='ic3w-fishbone-chart'></div>");
var contentContainer = $("<div class='ic3w-fishbone-chart-content'></div>");
var ct = $(this.container);
ct.append(chartContainer);
chartContainer.append(contentContainer);
};
$.extend(FishboneChart.prototype, {
buildInHtml: function (gviTable) {
var chartData = buildChartDataJson(gviTable);
renderFishboneChart(chartData);
var self = this;
// wait until layout is stabilized
setTimeout(function(){self.rendered = true;}, 10000);
},
isRendered: function () {
return this.rendered;
}
});
return FishboneChart;
})(viz.GviChartBase);

getting the error while copying feature ""Requested type name "feature" is unknown.""

This is code what I wrote for this...
Feature Deep Copy
rally.PortfolioItemDeepCopy = function (rallyDataSource, config) {
var portfolioitemBuffer = [];
var firstPortfolioItem = null;
var firstStory = null;
var finishedCallback;
var that = this;
//dojo.connect(obj, event, context, method, dontFix);
this._fireEvent = function(eventName, eventArgs) {
if (config && config.eventListeners[eventName] && dojo.isFunction(config.eventListeners[eventName])) {
config.eventListeners[eventName](that, eventArgs);
}
};
// removes private and read only fields to keep from pushing them up.
this.filterObject = function (object) {
return object;
};
this._addObject = function(object, typeName, callback) {
var item = dojo.clone(object);
item = this.filterObject(item);
function errorFunctionWrapper(error) {
if (dojo.isArray(error.Errors)) {
var errorMessage = error.Errors.pop();
if (errorMessage.indexOf("Not authorized to create:") >= 0) {
errorMessage = "Unable to create an object. This can happen due to a child or task being in a project you do not have write permissions to.";
}
rally.sdk.ui.AppHeader.showMessage("error", errorMessage, 10000);
}
else if(dojo.isObject(error)&&error.message){
rally.sdk.ui.AppHeader.showMessage("error", error.message, 10000);
error = [error.message];
}
if (dojo.isFunction(config.onError)) {
config.onError(error);
}
}
rallyDataSource.create(typeName, item, callback, errorFunctionWrapper);
};
this._copyAllFromBuffer = function() {
if (portfolioitemBuffer.length > 0) {
var portfolioitem = portfolioitemBuffer.pop();
that._copyPortfolioItem(portfolioitem.ref, portfolioitem.parent, that._copyAllFromBuffer);
}
else {
if (finishedCallback) {
finishedCallback(firstPortfolioItem);
}
}
};
this._addPortfolioItemsToBuffer = function(portfolioitemArray, parentRef) {
dojo.forEach(portfolioitemArray, function (portfolioitem) {
portfolioitemBuffer.push({
ref: portfolioitem._ref,
parent: parentRef
});
});
};
this._copyPortfolioItem = function(ref, parentRef, callback) {
rallyDataSource.getRallyObject(ref, function (foundObject) {
var type = "feature"
that._fireEvent("portfolioitemPreAdd", {portfolioitem:foundObject});
if (parentRef) {
foundObject.Parent = parentRef;
}
else {
foundObject.Name = "(Copy of) " + foundObject.Name;
}
that._addObject(foundObject, type, function (portfolioitemRef) {
if (!firstPortfolioItem) {
firstPortfolioItem = portfolioitemRef;
}
that._fireEvent("portfolioitemPostAdd", {});
that._addPortfolioItemsToBuffer(foundObject.Children, portfolioitemRef);
that._copyStoriesToPortfolioItem(foundObject.Stories, portfolioitemRef, callback);
that._copyTasksToStory(foundObject.Tasks, portfolioitemRef, callback);
}, null);
});
};
this._copyTasksToStory = function(tasks, storyRef, callback) {
//Copy the array
var localTasks = tasks.slice(0);
if (localTasks.length > 0) {
var task = localTasks.pop();
that._copyTask(task._ref, storyRef, function () {
that._copyTasksToStory(localTasks, storyRef, callback);
});
}
else {
callback();
}
};
this._copyStoriesToPortfolioItem = function(stories, portfolioitemRef, callback) {
//Copy the array
var localStories = stories.slice(0);
if (localStories.length > 0) {
var task = localStories.pop();
that._copyStory(story._ref, portfolioitemRef, function () {
that._copyStoriesToPortfolioItem(localStories, portfolioitemRef, callback);
});
}
else {
callback();
}
};
this._copyStory = function(ref, portfolioitemRef, callback) {
rallyDataSource.getRallyObject(ref, function (foundObject) {
var type = "hierarchicalrequirement";
foundObject.WorkProduct = portfolioitemRef;
that._fireEvent("storyPreAdd", {story:foundObject});
that._addObject(foundObject, type, function (ref, warnings) {
if (callback) {
that._fireEvent("storyPostAdd", [ref]);
callback();
}
}, null);
});
};
this._copyTask = function(ref, storyRef, callback) {
alert('helooooddddddddddddd task', ref);
rallyDataSource.getRallyObject(ref, function (foundObject) {
var type = "task";
foundObject.WorkProduct = storyRef;
that._fireEvent("taskPreAdd", {task:foundObject});
that._addObject(foundObject, type, function (ref, warnings) {
if (callback) {
that._fireEvent("taskPostAdd", [ref]);
callback();
}
}, null);
});
};
this.copyPortfolioItem = function (ref, callback) {
alert('hello');
that._copyPortfolioItem(ref, undefined, that._copyAllFromBuffer);
finishedCallback = callback;
};
};
</script>
<style type="text/css">
/* Add app styles here */
</style>
<script type="text/javascript">
rally.addOnLoad(function() {
var selectedValue = null;
var tasksAdded = 0;
var storiesAdded = 0;
var portfolioitemAdded = 0;
var searchPortfolioItem;
var searchStories;
var goButton, chooseButton;
var chooser;
var waiter;
var dataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
function taskPostAdd(object, args) {
tasksAdded = tasksAdded + 1;
displayTasksAdded(tasksAdded);
}
function taskPreAdd(object, args) {
dojo.byId("currentInfo").innerHTML = "Adding Task " + args.task.FormattedID + " - " + args.task.Name;
}
function storyPreAdd(object, args) {
dojo.byId("currentInfo").innerHTML = "Adding User Story " + args.story.FormattedID + " - " + args.story.Name;
}
function storyPostAdd(object, args) {
storiesAdded = storiesAdded + 1;
displayStoriesAdded(storiesAdded);
}
function displayStoriesAdded(count) {
dojo.byId("storyResult").innerHTML = "Stories added: " + count;
}
function portfolioitemPreAdd(object, args) {
dojo.byId("currentInfo").innerHTML = "Adding PortfolioItem " + args.story.FormattedID + " - " ;
}
function portfolioitemPostAdd(object, args) {
portfolioitemsAdded = portfolioitemsAdded + 1;
displayPortfolioItemsAdded(portfolioitemsAdded);
}
function displayPortfolioItemsAdded(count) {
dojo.byId("portfolioitemResult").innerHTML = "PortfolioItems added: " + count;
}
function displayTasksAdded(count) {
dojo.byId("taskResult").innerHTML = "Tasks added: " + tasksAdded;
}
function portfolioitemCopied(portfolioitem) {
dojo.byId("currentInfo").innerHTML = "Copy complete: ";
var link = new rally.sdk.ui.basic.Link({
item: portfolioitem,
text: portfolioitem._refObjectName
});
link.display('currentInfo');
goButton.setEnabled(true);
chooseButton.setEnabled(true);
if(waiter) {
waiter.hide();
waiter = null;
}
}
function buttonPressed() {
if (selectedValue) {
var config = {
eventListeners:{
portfolioitemPreAdd:portfolioitemPreAdd,
portfolioitemPostAdd:portfolioitemPostAdd,
storyPreAdd:storyPreAdd,
storyPostAdd:storyPostAdd,
taskPreAdd:taskPreAdd,
taskPostAdd:taskPostAdd
}
};
portfolioitemsAdded = 0;
displayPortfolioItemsAdded(portfolioitemsAdded);
tasksAdded = 0;
displayTasksAdded(tasksAdded);
storiesAdded = 0;
displayStoriesAdded(storiesAdded);
dojo.byId("currentInfo").innerHTML = "";
var copy = new rally.PortfolioItemDeepCopy(dataSource, config);
goButton.setEnabled(false);
chooseButton.setEnabled(false);
waiter = new rally.sdk.ui.basic.Wait({});
waiter.display('wait');
copy.copyPortfolioItem(rally.sdk.util.Ref.getRelativeRef(selectedValue), portfolioitemCopied);
}
}
function onChooserClose(chooser, args) {
if (args.selectedItem) {
selectedValue = args.selectedItem;
goButton.setEnabled(true);
dojo.byId('portfolioitemBox').innerHTML = args.selectedItem.FormattedID + ' - ' + args.selectedItem.Name;
}
}
function showChooser() {
var chooserConfig = {
fetch:"FormattedID,Name,Description",
type: "PortfolioItem",
title: "Feature Chooser"
};
chooser = new rally.sdk.ui.Chooser(chooserConfig, dataSource);
chooser.addEventListener('onClose', onChooserClose);
chooser.display();
}
rally.addOnLoad(function () {
goButton = new rally.sdk.ui.basic.Button({
text: "Copy",
enabled: false
});
goButton.addEventListener('onClick', buttonPressed);
goButton.display('goButton');
chooseButton = new rally.sdk.ui.basic.Button({
text: "Choose"
});
chooseButton.addEventListener('onClick', showChooser);
chooseButton.display('chooseButton');
showChooser();
rally.sdk.ui.AppHeader.setHelpTopic("252");
});
});
</script>
</head>
<body>
<div id="container">
<div style="float:left">
<span id="chooseButton"></span>
<span id="portfolioitemBox" style="line-height:18px;vertical-align:middle">[No feature selected]</span>
<span id="goButton"></span>
</div>
<div id="wait" style="float:left; height: 16px; width: 24px;"></div>
<div style="margin-left:5px;padding-top:10px;clear:both">
<div id="currentInfo" style="height:16px"></div>
<div id="portfolioitemResult" style="margin-top:10px"></div>
<div id="storyResult"></div>
<div id="taskResult"></div>
</div>
</div>
</body>
</html>
In WS API there is no object "feature". Please try either portfolioitem/feature or portfolioitem and then filter out by _type, e.g.
if(results.pi[i]._type == "PortfolioItem/Feature"){ //...
as shown here.
Since you are using a legacy AppSDK1 I assume you are setting a version to 1.43 as mentioned in this post.