There is an API for getting ink stroke objects in OneNote. Per the examples/documentation you can run code that gets the InkStroke object. My understanding is that Highlighter strokes are FloatingInk in the OneNote object model. Is it possible to get information about the stroke itself? Something like:
if(inkObject.getType() == "Highlighter") {
var width = inkObject.getStroke().width;
var height = inkObject.getStroke().height;
}
The documentation shows an example below, but it only appears to make the "id" property available.
OneNote.run(function(context) {
// Gets the active page.
var page = context.application.getActivePage();
var contents = page.contents;
// Load page contents and their types.
page.load('contents/type');
return context.sync()
.then(function(){
// Load every ink content.
$.each(contents.items, function(i, content) {
if (content.type == "Ink"){
content.load('ink/id');
}
})
return context.sync();
})
.then(function(){
// Log ID of every ink content.
$.each(contents.items, function(i, content) {
if (content.type == "Ink"){
console.log(content.ink.id);
}
})
});
})
.catch(function(error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
EDIT: While not ideal, you could obtain the RestApiId and then make an API call to retrieve the InkML document, which will contain this information.
https://blogs.msdn.microsoft.com/onenotedev/2017/07/07/onenote-ink-beta-apis/
Unfortunately, there is no way of getting ink stroke coordinate information from OneNote Add-ins. I encourage you to file a uservoice item and link it here.
https://onenote.uservoice.com/forums/245490-onenote-developer-apis/
Related
Hello so I'm trying to combine data retrieved from 3 different locations in my firebase. The data is structured as follows:
dashboard.data.post
dashboard.data.post.image
dashboard.data.post.audio
dashboard.data.post.text
When any user posts they are able to make a post underneath one of those blocks.
I would like to be able to search underneath that block for all of the users posts and retrieve that information, combine it all, ordered by the data it was post and display it to the user.
So far My method i feel is rudimentary and would appreciate as much help an advice as possible, even if it means restructuring my data.
info.block = $firebaseArray of the id's which the users have of their post
info.text is $firebaseArray of the texts post
info.image is $firebaseArray of the image post
info.audio is $firebaseArray of the audio post
var storage = function(text, image, audio, value, listStore) {
var postkey = value.postid;
angular.forEach(info.text, function(curr, key) {
if (postkey === curr.$id) {
listStore.push(curr);
return true;
}
});
angular.forEach(info.image, function(curr, key) {
if (postkey === curr.$id) {
listStore.push(curr);
return true;
}
});
angular.forEach(info.audio, function(curr, key) {
if (postkey === curr.$id) {
listStore.push(curr);
return true;
}
});
};
info.blog.$loaded().then(function() {
info.text.$loaded().then(function() {
info.image.$loaded().then(function() {
info.audio.$loaded().then(function() {
angular.forEach(info.blog, function(value, key) {
storage(info.text,info.image,info.audio,value,this);
}, $scope.randomObj);
});
});
});
});
I'm new to titanium. I've been having some problems on this for a while now. Help would be greatly appreciated.
I have a array loop that cycles through a database to retrieve images and labels. These are all stored in a view. I am adding an event listener to the the view and then adding fire event to the listener to open the selected image in a new window with the id of that video acting as a reference point to play the selected video in the new window. Hope my code makes more sense.
The problem is that the even listener will only return the value of the last row in the database, not the info of the video image that the user clicks on
function getChannelVideos(){
// create an empty data array
var video = [];
// create the httpRequest
var xhr = Titanium.Network.createHTTPClient();
xhr.open('GET','getVideoFeed.php?chid='+channelView.channelId);
// this method will be called when the request is complete
xhr.onload = function()
{
// parse json coming from the server
var json = JSON.parse(this.responseText);
// if Channel Videos are returned
if(json.channelVideos)
{
for (var i = 0; i < json.channelVideos.length; i++){
var video = Ti.UI.createView({ // creates video view
width:'60%', // sets height
backgroundColor: 'transparent',
});
var videoThumb = Ti.UI.createImageView({ // creates thumb
image:json.channelVideos[i].vThumb,
width:'100%', // sets height
top:150 + i*200, // positions from top
backgroundColor: '#000'
});
video.add(videoThumb); // adds thumb to video view
var videoTitle = Ti.UI.createLabel({ // creates label
text:json.channelVideos[i].vTitle,
font:{
fontSize:12
},
color:'#fff',
backgroundColor:'#000',
textAlign:'center',
width:'100%',
height:20,
top:140 + i*200, // positions from top
});
video.add(videoTitle); // adds video title to video view
var videoSpeaker = Ti.UI.createLabel({ // creates Label
text:json.channelVideos[i].vSpeaker,
font:{
fontSize:12
},
color:'#fff',
backgroundColor:'#000',
textAlign:'center',
width:'100%',
height:20,
top:295 + i*200, // positions from top
});
video.add(videoSpeaker); // adds speaker name to video view
var videoPlay = Ti.UI.createImageView({
image:'/images/light_play.png',
top:215 + i*200, // positions from top
});
video.add(videoPlay); // adds playbutton to videoview
chContentAreaView.add(video); // adds video view to scrollview
var vId=json.channelVideos[i].vId;
video.vId = vId; // Here vId is custom property of video
video.addEventListener('click', function(e){
alert(e.source.vId);
Ti.App.fireEvent('videoPlay',{
videoId:e.source.vId
});
});
}
}
};
// this method will be called if there is an error
xhr.onerror = function(){
alert(this.error + ': ' + this.statusText);
return false;
};
// open the httpRequest
xhr.setRequestHeader("contentType","application/json; charset=utf-8");
xhr.send();
}
try some things:
give video.vId = json.channelVideos[i].vId directly in the property of video like :
var video = Ti.UI.createView({ // creates video view
width:'60%', // sets height
backgroundColor: 'transparent',
vId : json.channelVideos[i].vId
});
use property touchEnabled : false in other views and labels for videoThumb, videoTitle, videoSpeaker, videoPlay etc.
I think by doing this all things will work fine.
I am trying to use store.loadData(data, true) to append data to an existing store but for some reason it is clearing the store and replacing it with the new data which should only happen if the boolean is set to false which it is not. Is there something I am missing that I need to do to make sure the data is appended to the old data and not replacing it entirely?
Edit Additional code. Currently I am pulling a row from a grid and creating a new window with additional information for that object that is pulled from a database. The idea is that all the possible data for the rows is stored in one store and then when the window appears the store has a filter added so that you only see data that pertains to that particular object. At some point I iterate every single object in the grid and check to see if it has data that was edited. Which is an issue if I only have data from the last object that was edited.
editSelectedNode: function(grid, rowIndex, colIndex){
var store = Ext.getStore('EditStore');
var win = Ext.create('BOMGeneratorSencha.view.EditMenu', {});
var item = grid.getStore().getAt(rowIndex).get('original');
console.debug(item);
win.show();
var el = win.getEl();
store.clearFilter(true);
console.debug(store.getCount());
if(store.getCount() == 0){
el.mask('Loading Values');
console.debug(store.getCount());
Ext.Ajax.request({
url : 'EditPart.jsp',
timeout: 300000,
params : {
item: item
},
success: function (response, opt) {
el.unmask();
var res = Ext.JSON.decode(response.responseText);
if (res.success) {
console.debug(res.results);
store.loadData(res.results,true);
console.debug(store);
}
else {
console.debug("JSON failure");
Ext.Msg.alert('Error', 'Invalid part number');
}
},
failure: function(response,options){
console.debug("major failure");
el.unmask();
Ext.Msg.alert('Error', 'Connection failed<br>' + response.responseText);
}
});
}
}
I have a code that is similat to your one. But when i get response, I dont use
store.loadData(someData)
instead I am using following steps to load data(piece of my code placed here):
success: function(response, opts){
var obj = Ext.decode(response.responseText)
,data = obj.data
,$ = Ext.ComponentQuery;
var store = Ext.create('MyApp.store.SomeStore',{
data : data
});
$.query('SomeGrid')[0].bindStore(store);
$.query('SomeGrid')[0].refresh();
}
I am writing a Google Chrome extension.
I want to pass a small array from a content script to background page in a message. Can I simply reference the array name or need I construct a JSON object from it first?
Here is the code:
IN THE CONTENT SCRIPT
var req;
var detailWin;
//drag off the f_foto class
var searchResult = document.getElementsByClassName("f_foto");
alert("Found Class f_foto "+searchResult.length+" times.");
//collect profile links
for (var i = 0; i<searchResult.length; ++i)
{
var profileLink=searchResult[i].getElementsByTagName("a");
profileLinks[i]=profileLink[0].href;
// alert(i+1+" of "+searchResult.length+" "+profileLinks[i]+" length of "+profileLinks[i].length);
}
for (var i = 0; i<searchResult.length; ++i)
{
//tell bkgd page to open link
chrome.extension.sendRequest({cmd: "openProfile", url: profileLinks[i]});
//BETTER TO SEND WHOLE ARRAY.
//LIKE THIS? chrome.extension.sendRequest({cmd: "openProfile", urlList: profileLinks});
//OR SHOULD I MAKE A JSON OBJECT OUT OF IT?
}
//IN THE BACKGROUND PAGE
var detailTabId = null;
var profileLinks = new Array();
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if(request.cmd == "openProfile") {
//IF RECEIVING AN ARRAY, PROCESS IT LIKE THIS?
// profileLinks= request.urlList;
// console.log=("Received "+ urlList.length + " links.");
chrome.tabs.create({url: request.url}, function(tab){
//save tab id so we can close this tab later
detailTabId = tab.id;
//profile tab is created, inject profile script
chrome.tabs.executeScript(tab.id, {file: "profile.js"});
});
}
});
An Array is a construct of a JSON object so there is no need to do anything other than what you are doing now.
I'm loading an external script (that creates a new window component) into a panel, which works fine.
Now, I want to access the created window from a callback function to register a closed event handler. I've tried the following:
panel.load({
scripts: true,
url: '/createWindow',
callback: function(el, success, response, options) {
panel.findByType("window")[0].on("close", function { alert("Closed"); });
}
});
However, the panel seems to be empty all the time, the findByType method keeps returning an empty collection. I've tried adding events handlers for events like added to the panel but none of them got fired.
I don't want to include the handler in the window config because the window is created from several places, all needing a different refresh strategy.
So the question is: how do I access the window in the panel to register my close event handler on it?
The simplest solution would be to simply include your close handler in the window config that comes back from the server using the listeners config so that you could avoid having a callback altogether, but I'm assuming there's some reason you can't do that?
It's likely a timing issue between the callback being called (response completed) and the component actually getting created by the ComponentManager. You might have to "wait" for it to be created before you can attach your listener, something like this (totally untested):
panel.load({
scripts: true,
url: '/createWindow',
callback: function(el, success, response, options) {
var attachCloseHandler = function(){
var win = panel.findByType("window")[0];
if(win){
win.on("close", function { alert("Closed"); });
}
else{
// if there's a possibility that the window may not show
// up maybe add a counter var and exit after X tries?
attachCloseHandler.defer(10, this);
}
};
}
});
I got it to work using a different approach. I generate a unique key, register a callback function bound to the generated key. Then I load the window passing the key to it and have the window register itself so that a match can be made between the key and the window object.
This solution takes some plumbing but I think its more elegant and more reliable than relying on timings.
var _windowCloseHandlers = [];
var _windowCounter = 0;
var registerWindow = function(key, window) {
var i;
for (i = 0; i < _windowCounter; i++) {
if (_windowCloseHandlers[i].key == key) {
window.on("close", _windowCloseHandlers[i].closeHandler);
}
}
};
var loadWindow = function(windowPanel, url, params, callback) {
if (params == undefined) {
params = { };
}
windowPanel.removeAll(true);
if (callback != undefined) {
_windowCloseHandlers[_windowCounter] = {
key: _windowCounter,
closeHandler: function() {
callback();
}
};
}
Ext.apply(params, { windowKey: _windowCounter++ });
Ext.apply(params, { containerId: windowPanel.id });
windowPanel.load({
scripts: true,
params: params,
url: url,
callback: function(el, success, response, options) {
#{LoadingWindow}.hide();
}
});
};
Then, in the partial view (note these are Coolite (Ext.Net) controls which generate ExtJs code):
<ext:Window runat="server" ID="DetailsWindow">
<Listeners>
<AfterRender AutoDataBind="true" Handler='<%# "registerWindow(" + Request["WindowKey"] + ", " + Detailswindow.ClientID + ");" %>' />
</Listeners>
</ext:Window>
And finally, the window caller:
loadWindow(#{ModalWindowPanel}, '/Customers/Details', {customerId: id },
function() {
#{MainStore}.reload(); \\ This is the callback function that is called when the window is closed.
});