SharePoint 2016: как заставить JS выполняться на каждой странице сайта, несмотря на Ajax и / или MDS?

Я реализую очень простой вариант использования, и все же я не только не нахожу решения, но и не могу найти ни одной статьи, в которой говорится об этом, как если бы я был единственным.

Я хочу, чтобы мой пользовательский Javascript выполнялся на каждой странице определенного сайта SharePoint.

Вы скажете, что это просто. Ну нет. Совсем не так, как всегда с SharePoint.

Действия по воспроизведению :

  • Создайте готовый сайт публикации
  • Включите пользовательский javascript ниже, используя любой из способов, которые я описываю ниже.
  • Заходим на сайт, на домашнюю страницу. Это сайт публикации, поэтому по умолчанию у вас должна быть левая панель навигации с как минимум «Главная» и «Документы».
  • При первой загрузке страницы выполняется javascript. Теперь нажмите «документы». Страница изменяется, но Javascript не выполняется.

Это потому, что SharePoint использует Ajax. Даже если MDS отключен. Он использует Ajax через хэш (#) в URL-адресе.

Например, он преобразует очень безобидную ссылку вроде этой:

‹A href src =" / SitePages / Home.aspx ">

в этот URL-адрес, когда вы щелкнете по нему:

https://your-url/sites/your-site/_layouts/15/start.aspx#/SitePages/Home.aspx

Вот мой Javascript:

if (ExecuteOrDelayUntilScriptLoaded && _spBodyOnLoadFunctionNames) {
    _spBodyOnLoadFunctionNames.push(ExecuteOrDelayUntilScriptLoaded(
        function () {
            alert("It's working!");
        }, "sp.js"));
} 

Итак, я пробовал следующие способы включения Javascript:

  1. С помощью настраиваемого действия пользователя. Я использовал эту очень удобную страницу, чтобы добавить ее, но это не имеет отношения к делу. Действие добавлено на сайт, и я вижу JS в DOM при первой загрузке. Но затем, когда я нажимаю ссылку на странице и после того, как SP использует Ajax, он не выполняет его снова.
  2. Изменив главную страницу, а именно: seattle.html. сначала включил вот так, просто под другими родными включениями:

‹Голова runat = server›

...

‹! - SPM:‹ SharePoint: ScriptLink language = javascript name = suitelinks.js OnDemand = true runat = server Localizable = false / ›-›

‹! - SPM:‹ SharePoint: ScriptLink language = javascript Name = ~ sitecollection / SiteAssets / MYJAVASCRIPT.js runat = server / ›-›

Но потом я прочитал об AjaxDelta (здесь: https://msdn.microsoft.com/fr-fr/library/office/dn456543.aspx), и я переместил свое включение (все еще в заголовке) в ‹AjaxDelta>, например:

‹Голова runat = server›

...

‹! - SPM:‹ SharePoint: AjaxDelta id = DeltaPlaceHolderAdditionalPageHead Container = false runat = server ›-›

‹! - SPM:‹ asp: ContentPlaceHolder id = PlaceHolderAdditionalPageHead runat = server / ›-›

‹! - SPM:‹ SharePoint: DelegateControl runat = server ControlId = AdditionalPageHead AllowMultipleControls = true / ›-›

‹! - SPM:‹ SharePoint: ScriptLink language = javascript Name = ~ sitecollection / SiteAssets / MYJAVASCRIPT.js runat = server / ›-›

‹! - SPM:‹ / SharePoint: AjaxDelta ›-›

... и пока ничего не работает. Javascript никогда не выполняется при переключении между страницами одного и того же сайта при нажатии на «управляемые» ссылки SharePoint.

Я ищу решение, которое элегантно обрабатывает Ajax SharePoint, а не что-то тяжелое и рискованное, которое перехватывает каждую гиперссылку на странице. Например, я пытался привязать свой код к методам ajaxNavigate (например: addNavigate), но я не уверен, что понимаю, что на самом деле там происходит, и можно ли Помогите мне.

РЕДАКТИРОВАТЬ:

  • Кажется, есть консенсус (например, здесь в самом низу), что настраиваемые действия пользователя выполняются несмотря ни на что - потому что SharePoint якобы по какой-то причине помещает свою ScriptLink в AjaxDelta. Я был свидетелем не этого.

  • Есть еще одно мнение, что эту проблему можно решить с помощью RegisterModuleInit. У меня это тоже не работает.

Я очень озадачен. Я думаю, что эти два решения действительно решают проблемы с навигацией, когда пользователь нажимает на ссылку, а затем нажимает «назад». Но он НЕ обращается к умным "управляемым" гиперссылкам SharePoint, пронизанным Ajax.


person jeancallisti    schedule 05.03.2018    source источник


Ответы (1)


Я наконец нашел решение, которое, кажется, никогда не подводило. Это настоящее облегчение.

Краткий ответ: используйте asyncDeltaManager.add_endRequest

В этом обсуждении MSDN предлагается простой способ его реализации: https://social.msdn.microsoft.com/Forums/office/en-US/1ae292b4-3589-46f6-bedc-7bd9dc741f1b/javascript-code-выполнить-после-все-элементы-и-css-загружены?forum=appsforsharepoint

$(function () {
  ExecuteOrDelayUntilScriptLoaded(function () {
      if (typeof asyncDeltaManager != "undefined")
           asyncDeltaManager.add_endRequest(MYCUSTOMCODE); //execute it after any ajax event
      else 
           MYCUSTOMCODE(); //execute it at first load
  }, "start.js");
});

Здесь показано, как правильно включить его в цикл SharePoint (с помощью ExecuteOrDelayUntilScriptLoaded) https://sharepoint.stackexchange.com/questions/171490/javacript-only-executed-on-first-page-load

Полноценное решение (объект "LefeCycleHelper") от Mx https://sharepoint.stackexchange.com/questions/192974/where-to-place-a-js-script-with-whom-i-need-to-get-an-div-id/193009#193009

//use an IIFE to create a scope and dont dirty the global scope
(function (_) {

// use strict to ensure we dont code stupid
'use strict';

var initHandlers = [];
var initMDSHandlers = [];

var ensureSharePoint = function (handler) {
    var sodLoaded = typeof (_v_dictSod) !== 'undefined' && _v_dictSod['sp.js'] != null && _v_dictSod['sp.js'].state === Sods.loaded;

    if (sodLoaded) {
        handler();
    } else {
        SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () { });
        SP.SOD.executeOrDelayUntilScriptLoaded(handler, 'sp.js');
    }
};

var initMDS = function () {
    for (var i = 0; i < initMDSHandlers.length; i++) {
        initMDSHandlers[i]();
    }
};

var init = function () {
    // Register MDS handler
    if ('undefined' != typeof g_MinimalDownload && g_MinimalDownload && (window.location.pathname.toLowerCase()).endsWith('/_layouts/15/start.aspx') && 'undefined' != typeof asyncDeltaManager) {
        asyncDeltaManager.add_endRequest(initMDS);
    } else {
        for (var i = 0; i < initHandlers.length; i++) {
            initHandlers[i]();
        }
    }
};

var registerInit = function (handler) {
    initHandlers.push(handler);
};

var registerInitMDS = function (handler) {
    initMDSHandlers.push(handler);
};

var domReady = (function (handler) {
    var fns = [];
    var listener;
    var loaded = (document.documentElement.doScroll ? /^loaded|^c/ : /^loaded|^i|^c/).test(document.readyState);

    if (!loaded) {
        document.addEventListener('DOMContentLoaded', listener = function () {
            document.removeEventListener('DOMContentLoaded', listener);
            loaded = 1;
            while (listener = fns.shift()) listener();
        });
    }

    return function (fn) {
        loaded ? setTimeout(fn, 0) : fns.push(fn);
    };
})();


var attachToLoad = function (functionToAttach) {
    registerInit(functionToAttach);
    registerInitMDS(functionToAttach);
   domReady(function () {
       init();
    });
};

_.AttachToLoad = attachToLoad;

// THIS WILL PROTECT YOUR GLOBAL VAR FROM THE GARBAGE COLLECTOR
window.LifeCycleHelper = _;
if (window.Function != 'undefined' && typeof (Function.registerNamespace) == 'function') {
    Function.registerNamespace('LifeCycleHelper');
}
})({});

var theCodeYouWantToRun = function () {
    alert('theCodeYouWantToRun');
};

window.LifeCycleHelper.AttachToLoad(theCodeYouWantToRun); 
person jeancallisti    schedule 06.03.2018