Кастомизация
30
Авг
49

MS CRM и jQuery

jQuery — библиотека JavaScript, фокусирующаяся на взаимодействии JavaScript и HTML. Библиотека jQuery помогает легко получать доступ к любому элементу DOM, обращаться к атрибутам и содержимому элементов DOM, манипулировать ими. Также библиотека jQuery предоставляет удобный API по работе с Ajax.

Спрашиваете, что она может? Например, вращать планеты вокруг Солнца 🙂

Рассмотрим пару примеров, как ее можно применить вместе с MS CRM…

Подключение jQuery

Скачайте jQuery (качайте последнюю лайт-версию, на данный момент это jquery-1.3.2.min.js) и поместите js-файл в папку <сайт CRM>/ISV/ на сервере CRM. Далее, добавьте следующий код на событие onLoad формы (каждой формы CRM, где Вы хотите задействовать jQuery):

function load_script (url) {
	var x = new ActiveXObject("Msxml2.XMLHTTP");
	x.open('GET', url, false);
	x.send('');
	eval(x.responseText);
	var s = x.responseText.split(/\n/);
	var r = /^(?:function|var)\s*([a-zA-Z_]+)/i;
	for (var i = 0; i < s.length; i++) {
		var m = r.exec(s[i]);
		if (m != null) {
			window[m[1]] = eval(m[1]);
		}
	}
}

load_script("/ISV/jquery-1.3.2.min.js");

Этот код подгружает JavaScript-код находящийся в js-файле данной библиотеки в текущую форму CRM (кстати, использование внешних файлов является ансапортом, чтобы избежать этого можете полностью сопировать содержимое js-файла на онлоад).


А теперь несколько примеров…

Подсветка элементов обязательных для заполнения

Поместите на онлоад такой скрипт (конечно после вышеупомянутого кода) – он выделяет обязательные для заполнения поля красной рамкой:

//для простых текстовых полей
$("input[req=2]").css("border","1px solid red");

//для лукапов
$("img[req=2]").each(
	function() {
		$(this).parents("tr:first").find("td > div").css("border","1px solid red");
	}
);

//для полей даты/времени
$("table[req=2] tbody > tr > td > input").css("border","1px solid red");

Как Вы можете заметить мы используем разные строчки для разных типов полей в MS CRM. Это потому что все они имеют разныю HTML-структуру. Поэтому требуют индивидуального подхода 🙂 Этот код читается так (по пордяку):


  1. Выделить все теги input (именно им кодируются простые текстовые поля), у которых есть атрибут RequiredLevel (отображается как rec в списке атрибутов) и он равен 2, затем для каждого элемента добавить css-параметр border, отрисовывающий красную границу в один пиксель.
  2. Находим все теги img (этот тег отображает иконку лупы для лукап поля), у которых есть атрибут RequiredLevel и он равен 2, затем для кажого из них находим первый родительский элемент tr, для которого в свою очередь найдем элемент div входящий в тег td. И к тэгу div применяем далее css-параметр border, отрисовывающий красную границу в один пиксель.
  3. Выделяем теги input входящие в тег td, которые в свою очередь входят в тег tr, которые входят в тег table у которых есть атрибут RequiredLevel и он равен 2. И для этих тэогов input применяем css-параметр border, отрисовывающий красную границу в один пиксель.

Изменение фона метки для всех обязательныхполей

По аналогии с предыдущем примером закрасим фон меток всех полей требующих обязательного заполнения желтым цветом!

$("*[req=2]").each( 
   function() { 
      $("label[for=" + this.id + "]") 
         .css("background-color", "yellow"); 
   }
);

Что мы делаем: находим все еслементы у которых есть атрибут RequiredLevel и он равен 2, затем для каждого из них мы находим HTML-тэг label, который имеет атрибут for с id равным id элемента с атрибутом rec=2. Ну, и устанавливаем фон метки (т.е. для label) в желтый.


Сокрытие всей строки формы CRM

Чтобы скрыть крыть какую-либо строку на форме MS CRM необходимо обратится сначала к полю входящему в это строку а затем по иерархии элементов добраться до все строки. Например, так:

crmForm.all.<имя_поля_входящего_в_строку>_c.parentElement.style.display = 'none';  

Но, тут есть один косячок: этот код скрывает саму строку, т.е. Вы не сможете к ней обратится через форму, но он к сожалению Вы до сих пор в состоянии добраться до дочерних полей с помощью клавиши Tab (хотя Вы и не будуту видеть куда попал Ваш курсор). Чтобы предотвратить это, необходимо также скрыть все элементы, входящие в эту строчку. То же самое справедливо и для скрытия секций. Короче, если делать все по фэн-шую одной строкой кода Вы не отделаетесь 🙂 А сейчас посмотрим, как это можно сделать с помощью jQuery.

$("#statuscode").parents("tr:first").hide(0, 
   function() { 
      $(this).find("*").hide(); 
   }
);

Разбор полетов: отбираем поле с именем statuscode, а затем обращаемся к первому его родительскому элементу tr. Далее скрываем все без исключения элементы входящие в этот tr (тегом tr в HTML кодируется строчка таблицы)!


Подправим цвет текста неактивного поля

Как то на форуме видел вопрос о необходимости изменить цвет текста тольк одного нективного поля (чтобы изменить текст всех неактивных полей откройте статью Много-много JavaScript’а на разделе «Изменение цвета заблокированных полей формы»). Сейчас подправим цвте одного такого поля используя jQuery (также будет продемонстрирована такая характерная особенность jQuery как «сцепление»).

$("#estimatedvalue").removeAttr("disabled").css("border","1px solid #c5c5c5");

Код довольно прост: находим поле с именем estimatedvalue, удаляем у него атрибут disabled (иначе нельзя будет ничего сделать с самим значением поля) и отрисовываем границу как и у обычных заблокированных олей (в противном случаи она будт как у не заблокированных полей — синего цвета).


Сохранить как завершенное

Если Вы хоть иногда почитываете SDK, то возможно знаете, что у формы CRM есть два замечательных метода: Save() и SaveAndClose(). Как следует из навания они сохраняют и сохраняют и закрывают форму соответсвенно. Но помимо этого есть еще и други возможные действия из этой серии, к которым можно добраться через форму объекта. Например, Сохранить как завершенное — вызвается по нажатью на одноименной кнопке на панели инструментов формы объекта Звонок! Чтобы произвести это действие с помощью JavaScript-кода нужно выполнить SOAP-запрос на изменение статуса, а затем повторно открыть запись — вобщем не очень изящный метод)!

Но это очень просто сделать с помощью jQuery (я поместил этот код на событие onchange поля Тема объекта Звонок, т.к. это единственное обязательное для него поле):

$("#_MBSaveAsCompleted").click();

Где _MBSaveAsCompleted это id (его можно узнасть с помощью IE Developer Toolbar) кнопки Сохранить как завершенное. Как просто, да? 🙂



P.S. можете попробовать воспользоваться для работы с jQuery инструментом jQueryPad.

Комментарии (49)
  • stanislav 30.08.2009

    Добрый день.
    Можно ли с помощью этого скрипта, сделать автоматическую подстановку, телефона клиента при создании события звонок?

  • slivka_83 30.08.2009

    А можете поподробнее расписать что Вам требуется и при каких условиях?

  • stanislav 30.08.2009

    создаётся событие «звонок», при добавлении «кому звонок» нужно сделать, так что бы «рабочий телефон» выбранного контакта, подставлялся в поле «телефон» созданного события «зонок». Вот как то так.

  • slivka_83 30.08.2009

    Под «кому» Вы подразумеваете поле «Получатель» при исходящем звонке (в стандартной конфигурации)?
    Если так, то у меня вопрос: поле «Получатель» это патилист, т.е. Вы в этом поле можете выбрать несколько значений 🙂 как в этом случаи быть?

  • stanislav 30.08.2009

    да «кому» это «получатель» «звонка». Получатель может быть либо «контакт», либо «организация». У обоих есть поле «основной телефон», его значение нужно подставить в форму «звонок» поле «телефон», при создани формы «звонок».

  • stanislav 30.08.2009

    и ещё при попытке выполнить выше приведённый код появляется ошибка:
    Поле: window
    Событие: onLoad
    Ошибка: object expected
    в чём может быть проблема?
    Это вопрос помимо предидущего 🙂

  • stanislav 30.08.2009

    Поправка к посту ошибка:’evalScritp’ is Undefined

  • stanislav 30.08.2009

    С ошбками разобрался! я пользовал полную библиотеку jquery-1.3.2.js. Она похоже отличается от мини jquery-1.3.2.min.js. Так что всё тепель ок! Класный пост, да и блог тоже! :):):)

    Но вопрос по звонку остался! 🙂

  • slivka_83 30.08.2009

    Вы не поняли вопроса 🙂 в «Получатель» я могу выбрать несколько организаций СРАЗУ 🙂 Что в этом случаи должно проискходить? 🙂

  • stanislav 30.08.2009

    Получатель только один, если их много, то и телефон подставлять не имеет смысла. Когда создаётся звонок из карточки клиента, телефон подставляется, а когда создаёшь звонок, а после подставляшь организаию/контакт, телефон не подставляется.
    Как то так.

  • Владимир 30.08.2009

    Очень интересные возможности,
    а вот куда «копать» если на поле ввода
    подцепить аналог ajaxToolkit:AutoCompleteExtender,
    то есть чтобы при вводе автоматом подцеплялся справочник да еще чтобы и id элемента справочника где нибудь «прятался»??
    С Уважением = Л. Владимир

  • slivka_83 30.08.2009
  • Михаил 30.08.2009

    Добрый день!
    Полдня безуспешно пытался прикрутить выделение строк в зависимости от значения ячейки по этому примеру http://blog.odynia.org/archives/14-Colourising-Microsoft-CRM-Grids.html, но так ничего и не вышло.

    Тут (http://mmcrm.ru/?p=844) прочитал, что Вы реккомендуете jQuery для решения этой задачи.

    А можно ли пример? По-моему, очень нужная штука для многих…

  • slivka_83 30.08.2009

    Добрый день 🙂

    В этом посте http://mmcrm.ru/?p=796 я привел пример как разукрасить каждую четную строку 🙂 не пробовали копать в этом направлении?

  • Михаил 30.08.2009

    Не совсем понял, куда там можно копать? В «Полосатом рейсе» работа идет просто с классом, который применяется для таблицы в целом.
    А нам необходимо реализовать именно вот это http://blog.odynia.org/archives/14-Colourising-Microsoft-CRM-Grids.html.
    То есть, чтобы в зависимости от значения в пиклисте происходила окраска. Понятно, что без Javы тут не обойтись, а с этим как раз есть проблема 🙂

    Может проще прикрутить все-таки Colourising?
    Но там я встал вот на этом моменте:
    ———————
    /**
    * Locate the «type» of the grid. We use the blue title thing for that
    **/
    var t = top.frames[0].document;
    var type = t.getElementById(‘tdStageContextBar’).innerText;

    /**
    * What type of grid are we colourising? We only support cases in this version.
    **/
    if (type == ‘Cases’)
    {
    var table = ‘cases’; // the table name, for passing to the lookup script
    var col = 5; // the column position that our status is listed in
    var highlight = ‘Not Started’; // status that we want to highlight to make it stand out
    } else
    {
    alert(‘We only support colourising Cases.’);
    return;
    }
    ————————

    Не могу понять, что в данном случае «тип» Грида и где мне посмотреть какой тип используется в моем расширении? Ну и не понятно, что в данном случае «table name»? Название самого расширения или что?

    Спасибо 🙂

  • slivka_83 30.08.2009

    1. То решение что Вы приводите работает в связке с ASP-страничкой (код которой приведен внизу по той же ссылке).
    2. Я могу попробовать написать скрипт который выделяет строки в зависимости от значения какой либо ячейки (возможно в выходные). Но учтите одну вещь: т.к. значения стилей задаваемых скриптом (т.е. на клиенте) перекрывают значения стилей CSS, то при выделении уже подсвеченной троки ее цвет не изменится 🙂 Вас это устраивает? 🙂

  • Михаил 30.08.2009

    1. Про ASP-страницу я понял, конечно, но… ладно, разбирать этот пример видимо смысла нет, т.к. есть хорошее предложение в пункте 2 🙂
    2. Конечно устраивает 🙂 Очень ждем такой полезный скрипт!

  • slivka_83 30.08.2009

    Ну, вот скрипт:

    // Проверяем, что представление сформировано для объкта Бизнес-партнер
    if (document.all.divGridParams.children["otc"].value == 1) {
    	// Отбираем все строки в представлении        
    	var allHTMLTags = document.getElementsByTagName("tr");
    	for (i = 0; i < allHTMLTags.length; i++) {
    		if (
    			(allHTMLTags[i].className == "ms-crm-List-Row" || // не выделенные строки
    			allHTMLTags[i].className == "ms-crm-List-SelectedRow") &&  // выделенные строки
    			allHTMLTags[i].childNodes[2].childNodes[0].innerHTML == "Test" // отбиаем только строку в которой первый столбец равен "Test"
    		) {
    			// закрашиваем найденную строку в светло-серый цвет
    			allHTMLTags[i].style.backgroundColor = "#eeeeee";
    		}
    	}
    }
    

    куда вешать написано здесь: http://mmcrm.ru/?p=1081

    Три уточнения:
    1. Как я уже говорил, подсвеченная строка перекрывает своим цветом выделенную строку;
    2. Данный код работает только при загрузке страницы! Если Вы поменяете представление, то перезагрузки страницы не произойдет — скрипт на onLoad не сработает и соответственно выделения не будет;
    3. Данный скрипт ищет нужный текст только для текстовых полей вынесенных в представление. Т.к. все типы полей в представлении имеют свою HTML-структуру, то соответственно, чтобы он заработал с другими типами полей его необходимо чуть-чуть подкорректировать 🙂

  • Михаил 30.08.2009

    Все работает! Большое спасибо!

  • Михаил 30.08.2009

    А можно еще вопрос? Имеется ли в CRM какая-нибудь возможность оповещать пользователей, когда им приходит электронка? Ну, чтобы как в аутлуке: пришло письмо — вылезло окошко и в трее висит…

  • slivka_83 30.08.2009

    Из бесплатных мне известно только решение Accelerators Notifications + FeedReader (у него как раз есть всплывающее окошко 🙂 )
    http://mmcrm.ru/?p=224

  • Владимир 30.08.2009

    Добрый день!
    Не так давно задавал Вам вопрос, куда копать с autocomplet-ом. Спасибо — все раскопал. Остались мелочи. На CRM форме autocomplet открывается с прозрачным фоном, что нетехнологично. Экспериментирую с функцией formatitem. Вот несложный код:

    $(function(){ $(«#nameFld»).autocomplete(«Data.ashx»,
    { width: 400,
    formatItem: function(data, i, n, value) {
    return «» + data[0] + ‘ ‘; }
    }) });

    И по этому коду два вопроса:
    1. Как в width указать ширину по родителю + 2 пикселя (по умолчанию он идет чуть уже родителя)?
    2. Какой тэг лучше использовать при выводе списка. При использовании li, как здесь, решается задача получить непрозрачный фон, НО — не работают стрелки прохода по списку и не работает мышка для выбора элемента?? У других тегов (em, p, input) что-то лучше, что-то хуже или вообще не работают? В частности у тега em у меня не получается задавать непрозрачную ширину по родителю…
    С Уважением = Л.Владимир

  • Владимир 30.08.2009

    Полная строка возврата:
    return «» + data[0] + ‘ ‘

  • Владимир 30.08.2009

    return «li style= ‘background-color: #CCFFFF; border: 1px solid #99FFFF; ‘ » + data[0] + ‘/li ‘

  • slivka_83 30.08.2009

    Боюсь мои познания в jQuery органичиваются одним маленьким экспериментам 🙂 Поэтому Вам лучше обратиться к более сведущим профессионалам в этом вопросе 🙂

  • Михаил 30.08.2009

    Добрый день!
    А можно ли в представлении заменить текст картинкой? Скажем, есть колонка «Статус», в ней бывает 4 разных значения (задаются через пиклист), хочется в представлении заменить их картинками 4 разных цветов, чтобы визуально проще все это воспринималось…

  • slivka_83 30.08.2009

    Здрастье 🙂
    Теоретически не вижу никаких проблем 🙂

  • Михаил 30.08.2009

    🙂 может тогда подскажете как это реализовать можно?

  • Владимир 30.08.2009

    Добрый день!
    Вот еще вопрос по плагинам jQuery:
    тот же autocomplete имеет свой файл стилей .css в обрамлении , и как такие файлы подключать на стандартные формы CRM??

    Это одновременно и ответ на мой предыдущий вопрос (см. выше).
    С Уважением = Л.Владимир

  • Владимир 30.08.2009

    Разобрался:
    В форму на собитие OnLoad включить код:

    setCssStyle = function() {
    var cssStyle = document.createElement(‘link’);
    cssStyle .type = «text/css»;
    cssStyle .href = «/SolverCRM/_isv/scripts/jquery.autocomplete.css»;
    cssStyle .rel = «stylesheet»;

    var heads = document.getElementsByTagName(«HEAD»);
    heads[0].appendChild(cssStyle );
    }

    setKladrStyle();

  • slivka_83 30.08.2009

    -> Михаил
    Сейчас я в отпуске — под рукой нет «инструментов» поэтому напомните в конце следующей недели 🙂 попробую реализовать 🙂

  • Михаил 30.08.2009

    Напоминаю 🙂

  • Михаил 30.08.2009

    И есть еще одна задачка 🙂
    Сделал, чтобы в форме Звонка и Электронной почты при выборе контактного лица в поле В отношении автоматом подставлялся Родительский клиент этого контакта. С этим я справился 🙂 Работает при изменении поля Кому и при загрузке формы (соответственно код висит на OnChange поля To и на OnLoad формы). Тут все понятно.

    НО! Это все прекрасно работает, если речь идет об исходящих действиях, когда в поле кому стоит Контактное лицо Бизнес-партнера. Но если мы открываем пришедшее нам письмо, то естественно валятся ошибки, т.к. в этом случае в поле Кому стоит наш Пользователь, которому пришло письмо, а у него нет Родительского контакта.

    Хотел избавиться от этого бага путем проверки на тип значения в лукапе, но выяснил, что типа бывает всего два — Контакт и Бизнес-партнер. И Пользователь приравнивается к Контакту.

    Итого: как мне отличить Пользователя от Контакта в Лукапе? 🙂
    Спасибо 🙂

  • slivka_83 30.08.2009

    Этого не может быть 🙂 Если в поле Кому (в случаи с Электропочтой) стоит Пользователь то у него тип systemuser 🙂 и никак иначе 🙂

    П.С. в поле Кому может быть указано 5 типов записей, а не 2 🙂

    Над картинкой в тексте подумаю… наверное оформлю как отдельный пост 🙂 нестесняйтесь — напоминайте (а то у меня сейчас несколько постов в разработке могу и подзабыть) 🙂

  • Михаил 30.08.2009

    Спасибо за оперативный ответ!
    Действительно, я что-то делал не так. Теперь тип лукапа правильно определяется и свой баг я успешно устранил.

    НО не совсем 🙂
    Почему-то тип лукапа От упорно не хочет определяться в пришедших письмах. В отправленных определяется, а в пришедших — нет. Упорно пишет Underfined. В чем может быть проблема?

    Запрос простой:
    var lookupFrom = new Array;
    lookupFrom = crmForm.all.from.DataValue;
    alert(lookupFrom[0].typename);

  • Михаил 30.08.2009

    И в догонку еще вопрос тогда уж 🙂
    Можно ли в представлении полученной почты вывести не только дату, но и время получения письма?

  • slivka_83 30.08.2009

    1. Определяйте тип по коду: crmForm.all.from.DataValue[0].type;

    🙂
    2. Попробуйте в настройках атрибута даты добавить Дата и время 🙂

  • Михаил 30.08.2009

    🙂
    Спасибо! Все получилось 🙂
    По первому: работает, но странно, что в отношении поля To моя конструкция работает, а в отношении поля From — нет. Разницы я так и не понял 🙂 ну да ладно 🙂
    Ну, а по второму ступил, конечно 🙂

  • Михаил 30.08.2009

    Еще вопрос возник. Как по кнопке открывать нужное представление? Точнее нужно открыть входящую элеткронную почту, то есть объект Действия, Тип Электронная почта, Моя полученная почта.
    Какой JavaScript-код нужно повесить на кнопку?

  • slivka_83 30.08.2009

    А где Вы хотите открывать это представление?

  • Михаил 30.08.2009

    Гм. В основном окне CRMа 🙂
    Задача просто ускорить процесс перехода в это представление.
    Чтобы попадать туда не в 2-3 клика мыши, а в 1…
    Нажал на кнопку — и увидел полученную почту.

  • slivka_83 30.08.2009

    Ну попробуйте скопироватья ярлык представления: меню над представлением Другие действия — Копировать ярылк — Из текущего представления

    Если не получится скопировать представление то попробуйте найти его GUID с помощью SQL запроса и подставить в URL по аналогии с предыдущим пунктом 🙂 :

    select * from dbo.SavedQueryBase
    where Name like Мои активные контакты'
    

    .. это для представления ‘Мои активные контакты

  • Михаил 30.08.2009

    URL, который нужно открыть я получил: /vss/Workplace/home_activities.aspx?type=email&viewid=%7bCC98CB1F-6552-4FD8-9E2F-39A1CAD2F710%7d

    А как заставить его открываться не в новом окне, а в общем окне CRM?

  • slivka_83 30.08.2009

    А где у Вас кнопка расположена?

  • Михаил 30.08.2009

    Наверху 🙂
    Root — ToolBar — Button

  • slivka_83 30.08.2009

    В голову приходит два варианта:
    1. Подключаем в файле Global.js jQuery и «щелкаем мышью» по ссылке Действия (при нажатии кнопки). И надейятся что нужное Вам представление является дефолтным 🙂
    2. Основное окно CRM состойит из трех фреймов

    <frameset>
       <frame1>
       <frameset>
           <frame2>
           <frame3>
    

    В 3 фрейме и отображаются представления. Ну собственно необходимо при нажатии на кнопку сменить его свойство SRC на Ваше ссылку на представление 🙂 Правда при это также придется ручками менять заголовок представления, иначе он так и останется прежним (например, Бизнес-партнеры);

  • lu 30.08.2009

    Добрый день! А как можно сделать так, чтобы в поле номер телефона автоматически вставлялся код города, после которого менеджер может ввести собственно остальные цифры номера?

  • slivka_83 30.08.2009

    Здрасте 🙂 А какой именно код? Статический или динамический? И если динамический, то какова логика его формирования? 🙂

  • lu 30.08.2009

    Что-то я так подумала, бессмысленно это. Проще вбивать полный номер ручками. Сорри, поспешила с вопросом:)

*

code