Arquivo da Categoría: jQuery e SharePoint

Superar problema chat URLs relativos na SharePoint Quick Launch

I wanted to add a link to the quick launch navigation the other day and SharePoint told me:

image

Pure text version of that is:

Ensure that the URL is valid and begins with either a valid character (a number sign (#) or forward slash (/)) or a valid supported protocol (por exemplo, ‘http://', ‘https://', ‘file://', ‘ftp://', ‘mailto:', ‘news:').

“Blech and pox!” I said.

A workaround to this is to use JavaScript to find a known link in the quick launch and override its behavior.

To test this, add a new link to your test site thusly:

image

I used jQuery. Para resolver-lo, get some JavaScript and jQuery onto the page using your favorite technique and with a line of code like this:

 

$(documento).preparado( función () {

    $("un:contains('Test URL replacement')").clic(función () { alertar("changed click behavior!"); volver teito;});

});

And Bob’s your uncle.

The jQuery selector finds every <un> tag that has “Test URL replacement” in its name. You may want to find-tune that depending on your link and such.

The .click(función() overrides whatever SharePoint would have done when the user clicked. Make sure you “return false” or else it will do your stuff and then try to the href thing too, which is almost certainly not your goal.

This was done and test in a SharePoint online environment but should work well in 2010 and earlier too.

</final>

undefinedRexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin

Rápido e sinxelo: Solve "Parámetro URL non válido” problema con UpdateListItems en lists.asmx

When working with UpdateListItems via lists.asmx, it’s easy to generate the error:

Invalid URL Parameter.

The URL provided contains an invalid Command or Value. Please check the URL again.

You can get this error when you forget to include ID in the the list of fields to update.  Este, like a lot of these SP web services, is a bit counterintuitive since you need to include the ID in the ID attribute of the <Method> element.  And you’re not updated ID and probably never want to in the first place.

This SOAP envelope works:

<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'>
  <soapenv:Corpo>                      
    <UpdateListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'>                     
      <listName>{C712E2EA-54E1-47AD-9D99-1848C7773E2F}</listName>                     
        <updates>                     
         <Batch OnError="Continue">
          <Method ID="1" Cmd="Update">
            <Field Name="CooperativeLock">locked!</Campo>
            <Field Name="ID">1</Campo>
          </Method>
        </Batch>                     
        </updates>                
      </UpdateListItems>             
  </soapenv:Corpo>         
</soapenv:Sobre>

If you strip out the ID field reference then you’ll get the annoying “Invalid URL parameter” message.

</final>

undefinedRexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin

 

Caching pobre home en JavaScript

[TL;DR version: use cookies to store the results of async calls; render the results of past async calls immediately and then validate them after page-load.]

I’ve been working on SharePoint intranet site for a client that features, entre outras cousas, a stylized secondary navigation whose menu options are managed via a regular old custom list.  The idea is that the client gets to control “their” site’s menu without affecting or being affected by the global navigation put out by IT.

(there is something incredibly subversive about adding a CEWP that points to an HTML file that loads some CSS and JS to fundamentally alter almost everything about a site’s behavior… but that’s for another post)

The code for this pretty simple:

The sore spot here is that every time anyone hits one of the site’s pages, that user’s web browser is reaching out to get items from the list.  Once dev is complete and testing has proven things to be stable and complete, this call is unnecessary more than 99% of the time since the menu rarely changes.  It also has a weird UI affect which is common in this brave new world of hyper-ajaxy web sites – the page renders and only then does the menu render.  It’s jittery and distracting in my view.  And jittery. Así, caching. 

I modified the logic thusly:

  • Look for a cookie in the browser that contains the menu as I last read it
    • If found, render it immediately.  Don’t wait for the page to finish loading.  (You need to make sure your HTML is strategically placed here, but it’s not hard to do).
  • Wait for the page to finish loading and make an async call to load up menu items from a list using REST or lists.asmx or whatever
  • Compare what I got against the cookie
    • If it matches, STOP
    • En caso contrario, using jQuery, dynamically populate a bunch if <li>’s in a <ª>
  • Use CSS to do all the formatting
  • Profit!

Some of you are going to say, “hey! there’s no real caching going on here since you’re reading the menu anyway every single time."  And you’re right – I’m not giving the server any kind of break.  But because the call is async and happens after the page’s initial HTML payload fully renders, it “feels” more responsive to the user.  The menu renders pretty much as the page draws.  If the menu happens to the change, the user is subjected to a jittery re-draw of the menu, but only that one time.

There are some ways to make this caching more effective and help out the server at the same time:

  • Put in a rule that the “cookie cache” is valid for a minimum of 24 hours or some other timeframe. As long as there is no expired cookie, use the cookie’s menu snapshot and never hit the server.

Well … that’s all that come to mind right now :). 

If anyone has any clever ideas here I’d love to know them.

And lastly – this technique can be used for other stuff.  This client’s page has a number of data-driven things on various pages, many of them changing relatively rarely (like once a week or once a month).  If you target specific areas of functionality, you can give a more responsive UI by pulling content from the local cookie store and rendering immediately.  It feels faster to the user even if you’re not saving the server any cycles.  Vostede lata save the server cycles by deciding on some conditions and triggers to invalidate this local cookie cache.  That’s all situational and artsy stuff and really the most fun :). 

</final>

undefinedRexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin

XSLT e mostras jQuery

Teño benvida a facer unha chea de XSLT e jQuery e pensei en compartir algúns tramos que os outros poden ser útiles no futuro.

Exemplo 1: Emit JavaScript simple / jQuery en XSLT:

<XSL:template match="something" xml:space = "preserve">

  <!– En branco a filtros agradable campo oculto consulta –>
  <script type="text/javascript">
    $(documento).preparado(función(){
      $("#QueryFriendlyFilters").val("empty");
    });
  </guión>

</XSL:modelo>

Este bit emite algún JavaScript que agarda a páxina para completar a carga (por mor da $(documento).preparado(...)) e, a continuación, define o valor dun campo oculto chamado QueryFriendlyFilters ao valor literal "baleiro".

Exemplo 2: Usar <XSL:se> para comprobar a "maior que",  "Less than", etc.

<XSL:template match="something" xml:space = "preserve">

  <div id="fdcAllFilters">
 
    <XSL:if test="@Count>0">
      <span class="fdcFilterLabel">Filtros actuais:</van>
    </XSL:se>

    <!– máis cousas acontece aquí. –>

</XSL:modelo>

O tramo anterior para saber se un atributo chamado "Count" do elemento "algo" é maior que cero.  O XML detrás diso sería algo como:"

<algo Count = "5" />

Exemplo 3: Percorrer todos os elementos, intercalando chamadas jQuery.

<!– Percorrer todos os filtros e amosar o correcto  Ligazóns. –>
<XSL:for-each select="UserFilter">

  <a class="FilterHref" href="javascript:mySubmitPage(‘RemoveUserFilter’,'{@ ID}')">[X]</un>

  <span class="fdcFilterLabel"><XSL:value-of select="@FilterValue"/></van>

  <script type="text/javascript">

    $(documento).preparado(función(){
        <XSL:texto><![CDATA[$("#QueryFriendlyFilters").val( ($("#QueryFriendlyFilters").val() + " ]]></XSL:texto>\"<XSL:value-of select="@FilterValue"/>\"<XSL:texto><![CDATA["));]]></XSL:texto>
    });

  </guión>

</XSL:a-cada>

O tramo anterior é o máis complexo e pode haber formas máis fáciles de facer isto.

O XML detrás desa aparencia máis ou menos así:

<UserFilter ID = "123" FilterValue = "xyzzy" />

Este fragmento é iterado <Filtro de usuario> nodos. 

En primeiro lugar, el emite unha marca de referencia que, cando premendo chama unha función JavaScript que xa está na páxina, "MySubmitPage" e pasa o valor dun atributo no <Filtro de usuario> no chamado "ID". 

A continuación, el emite algúns jQuery que espera a páxina cargar.  Que as actualizacións jQuery un campo oculto chamado "QueryFriendlyFilters", engadindo o valor do atributo FilterValue.  Teña en conta todo o tolo <XSL:texto> e <![CDATA[ ... ]]> cousas.

É iso aí, espero que axude!

</final>

Rexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin

Lists.asmx, GetListItems e carpetas

Eu estaba facendo unha investigación para alguén hoxe en todo o servizo web list.asmx seleccionado como parte do SharePoint 2010 (e máis cedo).  Ela foi capaz de obter os elementos da lista no cartafol raíz (incluíndo os nomes dos subcartafoles), pero non podía elementos en subcartafoles.  I did some looking around on the internets and it’s a surprisingly common question.  Aínda, I couldn’t get a good answer to the simple question, “if I know the folder, how do I get the items in the folder?"  To be honest, I didn’t try all that hard since I’ve wanted to figure this one out on my own for a while sorriso.

To set this up, I created a site named “Blogging Scenarios” and a custom list named “Custom List with Sub Folders”.  I then created folders named:

  • Year 2005
  • Year 2006
  • Year 2007

I added a few items to the folder “Year 2006”.  Isto é o que parece:

image

My friend isn’t writing C# code but rather using Java, so the SOAP envelope was what she really needed.  To get that, I wrote a bit of jQuery and then used fiddler to get the actual HTTP conversation.

Here’s the relevant jQuery (I copied the code down below if you want to copy/paste):

image

They first key is to include both a <queryOptions> e <QueryOptions> node.  The second key is that the <Folder> node is a URL to which the client has access.

There may be other ways to get this, but this worked well for me when using jQuery.

Here is the SOAP envelope for the above:

<soapenv:Envelope xmlns:soapenv=’http://schemas.xmlsoap.org / xabón / Sobre /’>                
  <soapenv:Corpo>
    <GetListItems xmlns=’
http://schemas.microsoft.com / SharePoint / xabón /’>
      <listName>Custom List with Sub Folders</listName>
      <viewFields>  
        <ViewFields>
          <FieldRef Name=’Title’ />
          <FieldRef Name=’EncodedAbsUrl’ />
        </ViewFields>
      </viewFields>
      <queryOptions>
        <QueryOptions>
          <Folder>
http://demoserver1/Blogging Scenarios/lists/Custom List with Sub Folders/Year 2006</Folder>
        </QueryOptions>
      </queryOptions>
   
</GetListItems>
  </soapenv:Corpo>
</soapenv:Sobre>

A lot of examples and discussion around this led me to believe that all I need was <QueryOptions> and specify a folder name.  Para min, I need to both wrap it inside <queryOptions> as well as specify a fully qualified URL for the <Folder> node.

Here’s the jQuery AJAX setup:

$(documento).preparado(función() {
       var soapEnv =
           "<soapenv:Envelope xmlns:soapenv=’http://schemas.xmlsoap.org / xabón / Sobre /’> \
               <soapenv:Corpo> \
                    <GetListItems xmlns=’http://schemas.microsoft.com / SharePoint / xabón /’> \
                       <listName>Custom List with Sub Folders</listName> \
                       <viewFields> \
                           <ViewFields> \
                              <FieldRef Name=’Title’ /> \
                              <FieldRef Name=’EncodedAbsUrl’ /> \
                          </ViewFields> \
                       </viewFields> \
                       <queryOptions> \
                         <QueryOptions> \
                           <Folder>http://demoserver1/Blogging Scenarios/lists/Custom List with Sub Folders/Year 2006</Folder> \
                         </QueryOptions> \
                       </queryOptions> \
                   </GetListItems> \
               </soapenv:Corpo> \
           </soapenv:Sobre>";

</final>

Rexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin

Lists.asmx, GetList e "Valor non pode ser nulo”

Descubrín onte que o GetList() método lists.asmx servizo web ten que ser chamado con moito coidado ou é propenso a lanzar un misterioso "Valor non pode ser nulo" excepción (e iso supoñendo que pode pasar a mensaxe de erro aínda peor xenérico, “Exception of type ‘Microsoft.SharePoint.SoapServer.SoapServerException’ foi lanzada. ")  Especificamente, Eu penso que non pode fornecer calquera tipo de prefixo do método GetList.  O tramo a continuación ilustra o punto jQuery:

image

Se fai iso, o servizo web responde con "Valor non pode ser nulo", segundo este violinista-indicado transcrición HTTP:

<?xml version="1.0" encoding="utf-8"?>
  <xabón:Sobre
     xmlns:xabón ="
http://schemas.xmlsoap.org / xabón / Sobre /"    
     xmlns:xsi = "
http://www.w3.org/2001/XMLSchema-instance"
     xmlns:XSD ="
http://www.w3.org/2001/XMLSchema">

  <xabón:Corpo>
    <xabón:Culpa>
      <FaultCode>xabón:Servidor</FaultCode>
      <faultstring>
        Exception of type ‘Microsoft.SharePoint.SoapServer.SoapServerException’ foi lanzado.
      </faultstring>
      <detalle>
        <xmlns cadea de erro ="
http://schemas.microsoft.com / SharePoint / xabón /">
O valor non pode ser nulo.
        </errorString>
      </detalle>
    </xabón:Culpa>
  </xabón:Corpo>
</xabón:Sobre>

Por suposto, probablemente non quere engadir que o prefixo "S0" no seu propio país, pero algunhas ferramentas son propensos a facelo (como Eclipse).

Isto é aínda máis confuso / frustrante, porque outros métodos tolerar prefixos.  Por exemplo, o GetListCollection método non lle importa se foi precedido, mesmo con prefixos sen sentido como "xyzzy":

image

Este "valor non pode ser nulo" parece bastante común con lists.asmx polo que espera que isto vai axudar a alguén no futuro.

</final>

Rexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin

Endlessly Nesting <p> Etiquetas e jQuery

Este semella ser un excéntrico como tema, Eu non estou seguro se é realmente paga a pena blog sobre, pero iso nunca me impediu antes de, entón aquí imos nós sorriso

Eu estou a traballar nun proxecto onde estou tirando algúns datos dunha investigación, embalaxe-lo nunha mensaxe XML e logo, que o XML é finalmente transformada HTML vía XSLT.  Hai unha morea de jQuery implicados, un pouco do que aplica algunhas funcións tabulación.  Cando fai clic nunha guía (realmente, un <p>), jQuery invoca. ocultar() e. espectáculo() en varios divs (a cargar a páxina de inicio traslada todo o contido para que non haxa mensaxes neste caso).

Unha banda de horas, a lóxica de conmutación guía comezou a comportarse de forma irregular e que non ía amosar un dos meus guías.  Eu finalmente Rastrexar-lo para o feito de que a Internet Explorer (polo menos) pensado que o <p> tags noutras citas lonxe, moito máis profundo do que Developer Toolbar intended.The mostraría:

-<div id = "Tab1Content">
  -<p>
    -<p>
      -<div id = "Tab2Content">
        -<p>
           ..............................
                   </p>  <-Por último mostrando que estaba pechado todo o camiño ata aquí!

Así, se eu fixese un $("# Tab1Content").agochar(), Gustaríame tamén de ocultar Tab2 e eu nunca podería mostrar Tab2 se eu non mostran tamén Tab1.  Copiei e colei o código en Visual Studio e mostrou toda a mucosa da div-se ben, exactamente como se supón que deberían estar facendo, dese xeito:

-<div id = "Tab1Content">
  +<p>
  +<p>
-<div id = "Tab2Content">
  +<p>
  +<p>

Eu bati miña cabeza contra a parede por un tempo e notei que o código HTML real estaba xerando unha chea de baleiro <p> Tag, como:

<corpo>

  <div id = "Tab1Content">

    <div id = "linha1" />
    <div id = "row2" />

  </p>

  <div id = "Tab2Content">

    <div id = "linha1" />
    <div id = "row2" />

  </p>

</corpo>

(A descrición anterior é waaaaaaaaaaaay simplificado.  As etiquetas div baleiros son totalmente válido. Algúns dos meus <p> marcas estaban cheos de contido, pero moitos outros non eran.  Cheguei á conclusión de que a miña <XSL:a-cada> directivas emitían as etiquetas div de forma curta, cando o XSL:for-each non "atopa algunha datos.  Forcei un comentario HTML na saída, como se mostra:

image

 

Despois de que eu fixen, toda div está aliñado ben e meu guía cambio comezou a traballar.

Como sempre, Espero que isto axude alguén nunha pitada.

</final>

Rexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin

JQuery aínda máis–Redimensionar un exemplo de imaxe

Eu herdei unha parte web do antigo provedor de un cliente e el ten un problema de tamaño da imaxe.  As imaxes deben ser de 60×50 pero por algún motivo estraño, o provedor orixinal forzado los 42×42, para que queden esmagados:

 

Boa Imaxe

Bad Image

Aquí está o marcado (tanto simplificada):

<mesa class = "extended-Outlook '>
  <thead>
    <tr>
      <º  width = '100′>3 Martes</º>
    </tr>
  </thead>

  <tbody>
    <tr class = 'previsión'>
      <td width = '100′>
        <ª>
          <li class = "alto">Alto: 72&ti;F</li>
          <li class = 'baixa'>Baixo: 44&ti;F</li>
          <li class = 'condición'>Soleado
            <img src =’
http://deskwx.weatherbug.com/images/Forecast/icons/localized/60×50/en/trans/cond007.png’ width = '42’ height = '42’ alt =” />
          </li>
        </ª>
      </td>
    </tr>

  </tbody>

</mesa>

Vai notar que, aínda que o camiño cara á propia imaxe amosa a dimensión axeitada (60×50) o provedor orixinal forzado en 42×42.  ¿Por que?  Tolo.

De calquera xeito, Eu quería unha solución rápida e fácil a esta cuestión e eu me virei para jQuery.  O truco era localizar as apropiado <img> etiquetas.  Eu non quería muck sobre con calquera outras etiquetas img (de que son moitos).  Este pouco de jQuery fixo o truco:

<script type="text/javascript" src ="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></guión>

<script type="text/javascript">
     $(documento).preparado(función () {

         $(‘li.condition > img ').cada(función (índice, elemento)
           
{
             $(elemento).css("width", "60"); 
             $(elemento).css("height", "50");
            });
     }); // na carga documento
</guión>

Este anaco de código atopa a colección <li> marcas cuxa clase é "condición" e <img> nenos.  A continuación, el percorre todo isto.  Traballou como un encanto.

Eu probablemente podería acelerar isto, pero eu nunca fun un tipo de unix cara que resolveu π para 18 díxitos de precisión usando sed e awk, e eu non son ese tipo cara jQuery ou sorriso.

</final>

Rexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin

Implantar un Sistema de Notificación Emerxente global

Eu escribín un artigo para www.sharepoint.briefing.com titulado "Implantar un Sistema de Notificación Emerxente global."  Esta función foi aplicada a un colexio da comunidade para comunicar o peche de escolas debido á neve e así por diante. 

Usa unha lista personalizada, fóra da caixa de servizos web do SharePoint e algúns jQuery para facer o traballo.

Aquí está o teaser:

image

Ler todo aquí: http://www.sharepointbriefing.com/features/article.php/3918471/Implement-a-Global-Pop-up-Notification-System.htm

</final>

Rexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin

Asuma o control da súa botóns Aceptar e Cancelar

Escribín Neste artigo un tempo, pero parece que non conectar a el do meu blog no momento, entón aquí vai:

image

Este artigo describe como facer NewForm.aspx para redireccionar a unha páxina cando o usuario fai clic en Aceptar e unha páxina diferente, cando fai clic en Cancelar.

</final>

Rexístrate para o meu blog.

Siga-me no Twitter http://www.twitter.com/pagalvin