Equivalent of SPContet.Current.ListItem in Client Object Model (ECMAScript) - javascript

I'm integrating an external application to SharePoint 2010 by developing custom ribbon tabs, groups, controls and commands that are made available to editors of a SharePoint 2010 site. The ribbon commands use the dialog framework to open dialogs with custom application pages.
In order to pass a number of query string parameters to the custom applications pages, I'm therefore looking for the equivalent of SPContext.Current.ListItem in the Client Object Model (ECMAScript).
Regarding available tokens (i.e. {ListItemId} or {SelectedItemId}) that can be used in the declarative XML, I already emitting all tokens, but unfortunately the desired tokens are not either not parsed or simply null, while in the context of a Publishing Page (i.e. http://domain/pages/page.aspx). Thus, none of the tokes that do render, are of use to establishing the context of the calling SPListItem in the application page.
Looking at the SP.ClientContext.get_current() provides a lot of information about the current SPSite, SPWeb etc. but nothing about the current SPListItem I'm currently positioned at (again, having the page rendered in the context of a Publishing Page).
What I've come up with so far is the idea of passing in the url of the current page (i.e. document.location.href) and parse that in the application page - however, it feels like I'm going in the wrong direction, and SharePoint surely should be able to provide this information.

I'm not sure this is a great answer, or even fully on-topic, but is basically something I originally intended to blog about - anyway:
It is indeed a pain that the Client OM does not seem to provide a method/property with details of the current SPListItem. However, I'd venture to say that this is a simple concept, but actually has quite wide-ranging implications in SharePoint which aren't apparent until you stop to think about it.
Consider:
Although a redirect exists, a discussion post can be surfaced on 2 or 3 different URLs (e.g. Threaded.aspx/Flat.aspx)
Similarly, a blog post can exist on a couple (Post.aspx/EditPost.aspx, maybe one other)
A list item obviously has DispForm.aspx/EditForm.aspx and (sort of) NewForm.aspx
Also for even for items with an associated SPFile (e.g. document, publishing page), consider that these URLs represent the same item:
http://mydomain/sites/someSite/someLib/Forms/DispForm.aspx?ID=x, http://mydomain/sites/someSite/someLib/Filename.aspx
Also, there could be other content types outside of this set which have a similar deal
In our case, we wanted to 'hang' data off internal and external items (e.g. likes, comments). We thought "well everything in SharePoint has a URL, so that could be a sensible way to identify an item". Big mistake, and I'm still kicking myself for falling into it. It's almost like we need some kind of 'normalizeUrl' method in the API if we wanted to use URLs in this way.
Did you ever notice the PageUrlNormalization class in Microsoft.SharePoint.Utilities? Sounds promising doesn't it? Unfortunately that appears to do something which isn't what I describe above - it doesn't work across the variations of content types etc (but does deal with extended web apps, HTTP/HTTPS etc).
To cut a long story short, we decided the best approach was to make the server emit details which allowed us to identify the current SPListItem when passed back to the server (e.g. in an AJAX request). We hide the 'canonical' list item ID in a JavaScript variable or hidden input field (whatever really), and these are evaluated when back at the server to re-obtain the list item. Not as efficient as obtaining everything from context, but for us it's OK because we only need to resolve when the user clicks something, not on every page load. By canonical, I mean:
SiteID|WebID|ListID|ListItemID
IIRC, one of the key objects has a CanonicalId property (or maybe it's internal), which may help you build such a string.
So in terms of using the window.location.href, I'd avoid that if you're in vaguely the same situation as us. Suggest considering an approach similar to the one we used, but do remember that there are some locations (e.g. certain forms) where even on the server SPContext.Current.ListItem is null, despite the fact that SPContext.Current.Web (and possibly SPContext.Current.List) are populated.
In summary - IDs are your friend, URLs are not.

Related

Should I use one publish per collection or several?

I am working on a user group system. Each group has several features and I want to make the interaction with the group collection as secure and simple as it can be since it is still at an early stage.
Right now, I have a group section in my website where I use several nested pages. The purpose of the section is to allow the user to get in a group, request membership if the group is private, browse one group objects, etc.
For example, within my group section, I can load in the yield a "see all groups" page, a "create a new group" page or "see only my groups" (the ones I am member of) or a "view group" to get a group details.
My first approach was to create one controller.js file for each subpage, which call one subscription tailored for the subpage needs. For instance, I have an 'all_group' publication/subscription for the "see all groups" subpage and a "my_groups" one for the "see only my groups" subpage.
But this is becoming really messy. Additionally, I declared my "group" collection in the both folder, so I am not sure to follow where the data available to the client comes from.
Now that I explained the situation, here are my questions:
when I do a console.table(Groups.find().fetch()); on client, I see fields that shouldn't be there (i.e. not returned by my current publication or any other). Is that because I declared the "group" collection on client side? How to fix that?
Should I get rid of all these publications and create only one with everything the client is allowed to see? I would then subscribe to it from the group section page controller and work with a single set of data.
Should I simply block any insert/update/remove from client with allow/deny rules and make these using methods only?
Would it be safe/advised to put my methods in both folder so I don't lose the latency compensation feature?
EDIT
Ok, I was freaking out because I had all my collection data on client-side but it was just a bad query in the publish (I was using both field:1 and field:0 projections).
Two questions remain:
If I use methods, I assume I don't have to deny everything in the native driver, I just have to be more restrictive than what method allow, right?
If I put my methods in the both folder, it will be executed both on client and server, so in "client offline" context, even if the client mess with my methods, the server should roll back the changes if the client result is different than his (assuming that the changes couldn't be done using the allow-deny rules)? And I will have latency compensation working even with the methods?
To better control and visualize your subscriptions, you can use msavin:mongol.
Creating one catch-all publication is not a good idea performance-wise (sending all data to all clients will be a pain to everyone involved).
If you use methods and have removed autopublish, then yes everything is denied... Except for updates on the user's own profile. You may want to manually deny that too.
With methods and collection rules you should share the validation code. This way, client and server validate the same way (and should always come up with the same results), so unless your client is screwing up with the console there should be no issue and lag compensation should remain.
If your server method does something the client should not know about, you can also define the method once on the server, and once on the client. Same effect.

"Null" HTML DOM Element?

I'm writing a framework which uses javascript/html as the client and it-doesn't-matter as the back end.
From time to time I have a need to store data in the HTML DOM. Ideally I'd like to store the data against a DOM element, but I want this element to have no UI impact.
At the moment I'm thinking I'll use a <span> with no text content and decorate it with attribution so that my framework can pick up that it is a data container and behave appropriately.
Is there a better choice? (For the avoidance of doubt, I know there are other ways I could do things - I'm not interested in these, purely in what the best HTML element to use to contain data without having a UI impact).
Edit (explanation of architecture):
I've created a server-side technology which is based on top of a generic reporting engine I've previously created. This server-side thing essentially works as a web-server - this might seem like an unusual choice to make but, given organisational constraints, it's the best choice - for the sake of argument, assume this is true. One of the things I need this system to do is to generate dynamic forms to capture data which is in a tree-like form. This has been fine and has worked well - my question is because when a sub-form is hidden (for example, the user has made all required decisions in a given sub-section of the data), I destroy the data capture elements - if the form is embedded within a parent form which needs access to the data captured in a destroyed sub-form, I need a way of embedding the data into the DOM so it can be collected to be passed back to the server. The requirements are a lot more complicated that this, but it'll take far too long to detail them all.
Well (and for the avoidance of doubt), the HTML elements are not supposed to store data. If you really want to, use the <input type="hidden"> element.
For your purpose, I recommend (in that order) using localstorage or cookie or web database.
here are some resources :
localstorage : http://diveintohtml5.info/storage.html
cookie : http://www.the-art-of-web.com/javascript/setcookie/
web database : http://www.tutorialspoint.com/html5/html5_web_sql.htm
As JLRishe pointed out, if you need, for whatever reason, a text node storage, then span is a good choice as div is (and as lot of elements are as long as you display: none them).
You could just create javascript objects...
var myData ={
property1:"aaaaa",
property2:500,
property3:{morestuff1:"AAA", ... },
property3:["list1", "list2", ... ],
....
}
Easy to access and easy to manipulte within the DOM if you need.
No UI impact.... (no render)
The obvious choice here is to use HTML data attribute. If you have a table and want to store info about the table that is not shown to the user - you could just:
<table id="mytable" data-id="2000" data-rows="20" data-whatever="whatever">
You could then get it with jQuery easely with:
$("#mytable").data('rows');
Which would give you 20.
It's not good practice to store data in the DOM, if you're not actually using it for the purpose of layout. Yikes!
To better suit your needs, HTML5 provides a JavaScript API for handling client side storage. Depending on your circumstances, you have 2 options to choose from. The APIs are exactly the same, the only difference is the lifetime of the storage.
They are:
localStorage: Local storage is persistent; data stored in local storage is even available to the webpage after the user closes the browser completely and reopens it.
sessionStorage: As the name says, this data is only available for the current session.
Here's a link that will help you better understand these APIs so you can solve your particular problem: http://www.w3schools.com/html/html5_webstorage.asp

How to store documents like google docs?

I'm interested how does google docs store documents on server side because I need to create similar application.
Does it use pure RTF/ODF files or own database?
How do they make possible versioning and undo/redo feature?
If anybody have knowing according this question please share with me.
To answer you question specifically to how Google Docs works. They use a technology called
Operational Transformation
You may be able to use one of operational transformation engines listed on: https://en.wikipedia.org/wiki/Operational_transform#OT_software
The basic idea is that every operation has a context, e.g. "delete the fourth word in the fifth paragraph" or "add an input box after the button". The clients all send each other operations thru the server. The clients and server each keep their own version of the document and apply operations as they come.
When operations have overlapping contexts, there are a bunch of rules that kick in to resolve conflicts. Like you can't modify something that's been deleted, so the delete must come last in a sequence of concurrent operations on that context.
It's possible that the various clients and server will get out of sync, so you need a secondary algorithm to maintain consistency. One way would be to reload the data from the server whenever a conflict is detected.
--This is an answer I got from a professor when I asked the same thing a couple of years ago.
You should use a database. Perhaps a table storing each document revision. First, find a way to determine whether an update is significant or not. You can store minor changes client side for redo/undo, and then, either periodically or per some condition (e.g., user hits save), create a database entry per revision (you can store things like bytes changed, bytes added, bytes deleted, etc.).
Take a look at MediaWiki, which is open source, and essentially does what you're asking (i.e., take a look at their tables and code).
RTF/ODF would typically be generated, and served, when a user requests exporting the document.
Possibly, you should consider utilizing Google Drive's public API. See link for details.

Regex from another domain?

I'm trying to make an automated process to retrieve some information from a site on my work network.
var duderegex = new RegExp("Title for Mr. [^\n]+","m");
var dude = duderegex.exec(input);
So far, so good. The problem is that I'm writing this on my work computer and probably won't be able to convince anyone to store this on the same domain as the site that is hosting it. So that technically makes it XSS. And I'd rather not have to get approval to install anything seriously funky (so I can't guarantee JQuery or a powershell that's easier to copy/paste from, for example).
I don't have any problems downloading files and manipulating them via webpage after download, but that adds a step clicking Save As...
Does anyone have any workable solutions for running regex on HTML source from a different domain? I don't need to limit it to Javascript, but getting PHP to work, for example, might require more resources than I have.
A commenter asked for clarification, so here goes. Let's say I have to contact 50 copyright holders a day (it has nothing to do with intellectual property but it will work). Right now, I have a form that takes me to
(1) http://foo.bar/form.htm?action=search&type=ArtistAlbum&Artist=Beatles&Album=White
and redirects to
(2) http://foo.bar/form.htm?id=4578469
From there, I click on a dropdown (let's say track listing), and that takes me to
(3) http://foo.bar/form.htm?id=4578469&track=7
There I have an alphabetical list of everyone who worked on the track, their agents, and legal representatives. I'm only interested in three names, the name of the person who holds the copyright of the lyrics, the name of the person who holds the copyright for the melody, and the name of the person who holds the copyright of the recording. So I have to search the document three times.
Since each name has a standard title, I should be able to write a script that asks for the artist and album, generates the link to (1), either copies the param from the url for (2) or uses a regex to find it from the link to (3), loads page (3), and then generates the output for a regex on the strings
/Lyrics Copyright Holder [^\n]+/
/Melody Copyright Holder [^\n]+/
/Performance Copyright Holder [^\n]+/
I could download all the files (it would take a long time), but the information changes on occasion, and I want to make sure I'm always pulling the newest information.
But I can't seem to get around the XSS bit.
You don't say what problem you're really trying to solve so it's a little hard to know what solutions make the most sense for you, but you can write javascript that works on any web page in a browser plug-in (like in Chrome or Firefox) or by using a scripting language outside of a browser (Python, Javascript, PHP, etc...) where you load the page contents and then manipulate the contents using the language tools.

CouchDB: How to change view function via javascript?

I am playing around with CouchDB to test if it is "possible" [1] to store scientific data (simulated and experimental raw data + metadata). A big pro is the schema-less approach of CouchDB: we have to be very flexible with the metadata, as the set of parameters changes very often.
Up to now I have some code to feed raw data, plots (both as attachments), and hierarchical metadata (as JSON) into CouchDB documents, and have written some prototype Javascript for filtering and showing. But the filtering is done on the client side (a.k.a. browser): The map function simply returns everything.
How could I change the (or push a second) map function of a specific _design-document with simple browser-JS?
I do not think that a temporary view would yield any performance gain...
Thanks for your time and answers.
[1]: of course it is possible, but is it also useful? feasible? reasonable?
[added]
Ah, the jquery.couch.js (version 0.9.0) provides a saveDoc() function, which could update the _design document with the new map function.
But I also tried out the query function, which uses a temporary view. Okay, "do not use this in the real product, only during development"... But scientific research is steady development, right?
Temporary views are getting cached, as I noticed, and it works well for ~1000 documents per DB. A second plus: all users (think of 1 to 3, so a big user management is quit of an overkill) can work with their own temporary view.
Never ever use temporary views. They are really only there for dev and debugging purposes. For more information, see http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views (specifically the bold "NOTE").
And yes, because design documents are really just documents with special powers, you can run you GET/POST/PUT/DELETE methods on them. However, you will usually need admin privileges to do this. So, if you are allowing a client side piece of software to do that, you are making your entire database public for read/write access - this may be fine for your application, but is important to remember.
Ex., if you restrict access to your database, but put the username and password in client side javascript, then anyone can see that username and password.
Cheers.
I´ve written an helper functions for jquery.couch and design docs, take a look at:
https://github.com/grischaandreew/jquery.couch.js

Categories