Skip to content
Extraits de code Groupes Projets
Segmentation.js 47,4 ko
Newer Older
  • Learn to ignore specific revisions
  • mattab's avatar
    mattab a validé
    /*!
     * Piwik - Web Analytics
     *
     * @link http://piwik.org
     * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
     */
    
    Segmentation = (function($) {
    
        var segmentation = function segmentation(config) {
    
            if (!config.target) {
                throw new Error("target property must be set in config to segment editor control element");
            }
    
    
    mattab's avatar
    mattab a validé
            var self = this;
    
    mattab's avatar
    mattab a validé
            self.currentSegmentStr = "";
            self.segmentAccess = "read";
    
    mattab's avatar
    mattab a validé
            self.availableSegments = [];
    
            for (var item in config) {
    
    mattab's avatar
    mattab a validé
                self[item] = config[item];
            }
    
    
            self.editorTemplate = self.editorTemplate.detach();
    
    
    mattab's avatar
    mattab a validé
            self.timer = ""; // variable for further use in timing events
            self.searchAllowed = true;
    
            self.availableMatches = [];
            self.availableMatches["metric"] = [];
    
            self.availableMatches["metric"]["=="] = self.translations['General_OperationEquals'];
            self.availableMatches["metric"]["!="] = self.translations['General_OperationNotEquals'];
            self.availableMatches["metric"]["<="] = self.translations['General_OperationAtMost'];
            self.availableMatches["metric"][">="] = self.translations['General_OperationAtLeast'];
            self.availableMatches["metric"]["<"] = self.translations['General_OperationLessThan'];
            self.availableMatches["metric"][">"] = self.translations['General_OperationGreaterThan'];
    
    mattab's avatar
    mattab a validé
            
            self.availableMatches["dimension"] = [];
    
            self.availableMatches["dimension"]["=="] = self.translations['General_OperationIs'];
            self.availableMatches["dimension"]["!="] = self.translations['General_OperationIsNot'];
            self.availableMatches["dimension"]["=@"] = self.translations['General_OperationContains'];
            self.availableMatches["dimension"]["!@"] = self.translations['General_OperationDoesNotContain'];
    
    mattab's avatar
    mattab a validé
    
            segmentation.prototype.getSegment = function(){
                var self = this;
    
    mattab's avatar
    mattab a validé
                if($.browser.mozilla) {
                    return self.currentSegmentStr;
                }
                return decodeURIComponent(self.currentSegmentStr);
    
    mattab's avatar
    mattab a validé
    
    
            segmentation.prototype.setSegment = function(segmentStr){
    
    mattab's avatar
    mattab a validé
                if(!$.browser.mozilla) {
                    segmentStr = encodeURIComponent(segmentStr);
                }
    
    mattab's avatar
    mattab a validé
    
            segmentation.prototype.shortenSegmentName = function(name, length){
    
    
                if(typeof length === "undefined") length = 16;
    
    mattab's avatar
    mattab a validé
                if(typeof name === "undefined") name = "";
                var i;
                
                if(name.length > length)
                {
                    for(i = length; i > 0; i--){
                        if(name[i] === " "){
                            break;
                        }
                    }
                    if(i == 0){ 
                        i = length-3;
                    }
                    
                    return name.slice(0,i)+"...";
                }
                return name;
    
    mattab's avatar
    mattab a validé
    
    
            segmentation.prototype.markCurrentSegment = function(){
                var current = this.getSegment();
    
    mattab's avatar
    mattab a validé
    
    
                var segmentationTitle = $(this.content).find(".segmentationTitle");
    
    mattab's avatar
    mattab a validé
                if( current != "")
                {
                    var selector = 'div.segmentList ul li[data-definition="'+current+'"]';
    
                    var title = $('<strong></strong>');
    
    mattab's avatar
    mattab a validé
                    if( foundItems.length > 0) {
                        var name = $(foundItems).first().find("span.segname").text();
    
    mattab's avatar
    mattab a validé
                    } else {
    
                        title.text("Custom Segment");
    
    mattab's avatar
    mattab a validé
                    }
    
                    segmentationTitle.html(title);
    
    mattab's avatar
    mattab a validé
                }
                else {
    
                    $(this.content).find(".segmentationTitle").text(this.translations['SegmentEditor_DefaultAllVisits']);
    
    mattab's avatar
    mattab a validé
                }
    
    mattab's avatar
    mattab a validé
    
            var getAndDiv = function(){
                if(typeof andDiv === "undefined"){
    
                    var andDiv = self.editorTemplate.find("> div.segment-and").clone();
    
    mattab's avatar
    mattab a validé
                }
                return andDiv.clone();
    
    mattab's avatar
    mattab a validé
    
            var getOrDiv = function(){
                if(typeof orDiv === "undefined"){
    
                    var orDiv = self.editorTemplate.find("> div.segment-or").clone();
    
    mattab's avatar
    mattab a validé
                }
                return orDiv.clone();
    
    mattab's avatar
    mattab a validé
    
            var getMockedInputSet = function(){
                if(typeof mockedInputSet === "undefined"){
    
                    var mockedInputSet = self.editorTemplate.find("div.segment-row-inputs").clone();
    
    mattab's avatar
    mattab a validé
                }
                return mockedInputSet.clone();
    
    mattab's avatar
    mattab a validé
    
            var getMockedInputRowHtml = function(){
                if(typeof mockedInputRow === "undefined"){
                    var mockedInputRow = '<div class="segment-row"><a class="segment-close" href="#"></a><div class="segment-row-inputs">'+getMockedInputSet().html()+'</div></div>';
                }
                return mockedInputRow;
    
    mattab's avatar
    mattab a validé
    
            var getMockedFormRow = function(){
                if(typeof mockedFormRow === "undefined")
                {
    
                    var mockedFormRow = self.editorTemplate.find("div.segment-rows").clone();
    
    mattab's avatar
    mattab a validé
                    $(mockedFormRow).find(".segment-row").append(getMockedInputSet()).after(getAddOrBlockButtonHtml).after(getOrDiv());
                }
                return mockedFormRow.clone();
    
    mattab's avatar
    mattab a validé
    
            var getInitialStateRowsHtml = function(){
                if(typeof initialStateRows === "undefined"){
    
                    var content = self.editorTemplate.find("div.initial-state-rows").html();
    
    mattab's avatar
    mattab a validé
                    var initialStateRows = $(content).clone();
                }
                return initialStateRows;
    
    mattab's avatar
    mattab a validé
    
            var revokeInitialStateRows = function(){
                $(self.form).find(".segment-add-row").remove();
                $(self.form).find(".segment-and").remove();
    
    mattab's avatar
    mattab a validé
    
            var appendSpecifiedRowHtml= function(metric) {
                $(self.form).find(".segment-content > h3").after(getMockedFormRow());
                $(self.form).find(".segment-content").append(getAndDiv());
                $(self.form).find(".segment-content").append(getAddNewBlockButtonHtml());
                doDragDropBindings();
                $(self.form).find(".metricList").val(metric).trigger("change");
    
    mattab's avatar
    mattab a validé
    
            var appendComplexRowHtml = function(block){
                var key;
                var newRow = getMockedFormRow();
    
                var x = $(newRow).find(".metricMatchBlock select");
                $(newRow).find(".metricListBlock select").val(block[0].metric);
                $(newRow).find(".metricMatchBlock select").val(block[0].match);
                $(newRow).find(".metricValueBlock input").val(block[0].value);
    
                if(block.length > 1) {
                    $(newRow).find(".segment-add-or").remove();
                    for(key = 1; key < block.length;key++) {
                        var newSubRow = $(getMockedInputRowHtml()).clone();
                        $(newSubRow).find(".metricListBlock select").val(block[key].metric);
                        $(newSubRow).find(".metricMatchBlock select").val(block[key].match);
                        $(newSubRow).find(".metricValueBlock input").val(block[key].value);
                        $(newRow).append(newSubRow).append(getOrDiv());
                    }
                    $(newRow).append(getAddOrBlockButtonHtml());
                }
                $(self.form).find(".segment-content").append(newRow).append(getAndDiv());
    
    mattab's avatar
    mattab a validé
    
            var applyInitialStateModification = function(){
                $(self.form).find(".segment-add-row").remove();
                $(self.form).find(".segment-content").append(getInitialStateRowsHtml());
                doDragDropBindings();
    
    mattab's avatar
    mattab a validé
    
            var getSegmentFromId = function (id) {
                if(self.availableSegments.length > 0) {
    
                    for(var i = 0; i < self.availableSegments.length; i++)
    
    mattab's avatar
    mattab a validé
                    {
    
                        segment = self.availableSegments[i];
    
    mattab's avatar
    mattab a validé
                        if(segment.idsegment == id) {
                            return segment;
                        }
                    }
                }
                return false;
    
    mattab's avatar
    mattab a validé
    
    
    mattab's avatar
    mattab a validé
            var getListHtml = function() {
    
                var html = self.editorTemplate.find("> .listHtml").clone();
    
    mattab's avatar
    mattab a validé
                var segment, injClass;
    
    
                var listHtml = '<li data-idsegment="" ' +
    
    mattab's avatar
    mattab a validé
                                (self.currentSegmentStr == "" ? " class='segmentSelected' " : "")
    
                                + ' data-definition=""><span class="segname">' + self.translations['SegmentEditor_DefaultAllVisits']
                                + ' ' + self.translations['General_DefaultAppended']
                                + '</span></li> ';
    
    mattab's avatar
    mattab a validé
                if(self.availableSegments.length > 0) {
    
                    for(var i = 0; i < self.availableSegments.length; i++)
    
    mattab's avatar
    mattab a validé
                    {
    
                        segment = self.availableSegments[i];
    
                        injClass = "";
    
    mattab's avatar
    mattab a validé
                        if( segment.definition == self.currentSegmentStr){
    
                            injClass = 'class="segmentSelected"';
    
    mattab's avatar
    mattab a validé
                        }
    
    mattab's avatar
    mattab a validé
                        listHtml += '<li data-idsegment="'+segment.idsegment+'" data-definition="'+ (segment.definition).replace(/"/g, '&quot;') +'" '
    
    mattab's avatar
    mattab a validé
                                    + injClass +' title="'+segment.name+'"><span class="segname">'
                                    + self.shortenSegmentName(segment.name)+'</span>';
                        if(self.segmentAccess == "write") {
    
                            listHtml += '<span class="editSegment">['+ self.translations['General_Edit'].toLocaleLowerCase() +']</span>';
    
    mattab's avatar
    mattab a validé
                        }
                        listHtml += '</li>';
                    }
                    $(html).find(".segmentList > ul").append(listHtml);
                    if(self.segmentAccess === "write"){
    
                        $(html).find(".add_new_segment").html(self.translations['SegmentEditor_AddNewSegment']);
    
    mattab's avatar
    mattab a validé
                    }
    
                        $(html).find(".add_new_segment").hide();
    
    mattab's avatar
    mattab a validé
                    }
                }
                else
                {
                    $(html).find(".segmentList > ul").append(listHtml);
                }
                return html;
    
    mattab's avatar
    mattab a validé
    
            var getFormHtml = function() {
    
                var html = self.editorTemplate.find("> .segment-element").clone();
    
    mattab's avatar
    mattab a validé
                // set left margin to center form
    
                var segmentsDropdown = $(html).find(".available_segments_select");
    
    mattab's avatar
    mattab a validé
                var segment, newOption;
    
                newOption = '<option data-idsegment="" data-definition="" title="'
                            + self.translations['SegmentEditor_AddNewSegment']
                            + '">' + self.translations['SegmentEditor_AddNewSegment']
                            + '</option>';
    
    mattab's avatar
    mattab a validé
                segmentsDropdown.append(newOption);
    
                for(var i = 0; i < self.availableSegments.length; i++)
    
    mattab's avatar
    mattab a validé
                {
    
                    segment = self.availableSegments[i];
    
    mattab's avatar
    mattab a validé
                    newOption = '<option data-idsegment="'+segment.idsegment+'" data-definition="'+(segment.definition).replace(/"/g, '&quot;')+'" title="'+segment.name+'">'+self.shortenSegmentName(segment.name)+'</option>';
    
    mattab's avatar
    mattab a validé
                    segmentsDropdown.append(newOption);
                }
                $(html).find(".segment-content > h3").after(getInitialStateRowsHtml()).show();
                return html;
    
    mattab's avatar
    mattab a validé
    
            var doListBindings = function()
            {
                self.jscroll = self.content.find(".segmentList").jScrollPane({
                    autoReinitialise: true,
                    showArrows:true
                }).data().jsp;
    
                self.content.find(".add_new_segment").unbind().on("click", function(event){
                    event.stopPropagation();
                    closeAllOpenLists();
    
                    addForm("new");
    
    mattab's avatar
    mattab a validé
                    doDragDropBindings();
                });
    
    
    mattab's avatar
    mattab a validé
    
            var closeAllOpenLists = function() {
    
                $(".segmentationContainer", self.target).each(function() {
    
                    if($(this).closest('.segmentEditorPanel').hasClass("visible"))
    
    mattab's avatar
    mattab a validé
                        $(this).trigger("click");
                });
    
    mattab's avatar
    mattab a validé
    
    
            var findAndExplodeByMatch = function(metric){
                var matches = ["==" , "!=" , "<=", ">=", "=@" , "!@","<",">"];
                var newMetric = {};
                var minPos = metric.length;
                var match, index;
                var singleChar = false;
    
                for(var key=0; key < matches.length; key++)
                {
                    match = matches[key];
                    index = metric.indexOf(match);
                    if( index != -1){
                        if(index < minPos){
                            minPos = index;
    
    mattab's avatar
    mattab a validé
                            if(match.length == 1){
    
    mattab's avatar
    mattab a validé
                                singleChar = true;
                            }
                        }
                    }
                }
    
                if(minPos < metric.length){
                    // sth found - explode
                    if(singleChar == true){
                        newMetric.metric = metric.substr(0,minPos);
                        newMetric.match = metric.substr(minPos,1);
                        newMetric.value = metric.substr(minPos+1);
    
    mattab's avatar
    mattab a validé
                        newMetric.metric = metric.substr(0,minPos);
                        newMetric.match = metric.substr(minPos,2);
                        newMetric.value = metric.substr(minPos+2);
                    }
                    // if value is only "" -> change to empty string
                    if(newMetric.value == '""')
                    {
                        newMetric.value = "";
                    }
                }
    
    mattab's avatar
    mattab a validé
    
                newMetric.value = decodeURIComponent(newMetric.value);
    
    mattab's avatar
    mattab a validé
                return newMetric;
    
    mattab's avatar
    mattab a validé
    
            var parseSegmentStr = function(segmentStr)
            {
                var blocks;
                blocks = segmentStr.split(";");
                for(var key in blocks){
                    blocks[key] = blocks[key].split(",");
                    for(var innerkey = 0; innerkey < blocks[key].length; innerkey++){
                        blocks[key][innerkey] = findAndExplodeByMatch(blocks[key][innerkey]);
                    }
                }
                return blocks;
    
    mattab's avatar
    mattab a validé
    
            var openEditForm = function(segment){
    
    mattab's avatar
    mattab a validé
                addForm("edit", segment);
    
    
    mattab's avatar
    mattab a validé
                $(self.form).find(".segment-content > h3 > span").text(segment.name);
    
                $(self.form).find('.available_segments_select > option[data-idsegment="'+segment.idsegment+'"]').prop("selected",true);
    
    mattab's avatar
    mattab a validé
    
    
                $(self.form).find('.available_segments a.dropList').html(self.shortenSegmentName(segment.name, 16));
    
    mattab's avatar
    mattab a validé
    
    
    mattab's avatar
    mattab a validé
                if(segment.definition != ""){
                    revokeInitialStateRows();
                    var blocks = parseSegmentStr(segment.definition);
                    for(var key in blocks){
                        appendComplexRowHtml(blocks[key]);
                    }
                    $(self.form).find(".segment-content").append(getAddNewBlockButtonHtml());
                }
                $(self.form).find(".metricList").each( function(){
                    $(this).trigger("change", true);
                });
                doDragDropBindings();
    
    mattab's avatar
    mattab a validé
    
            var bindListEvents = function(){
                $(self.content).off("click").on("click", function(event){
                    // hide all other modals connected with this widget
    
                    if(self.content.closest('.segmentEditorPanel').hasClass("visible")){
    
    mattab's avatar
    mattab a validé
                        if($(event.target).hasClass("jspDrag") === true)
                        {
                            event.stopPropagation();
                        }
                        else{
                            self.jscroll.destroy();
    
                            self.target.closest('.segmentEditorPanel').removeClass('visible');
    
    mattab's avatar
    mattab a validé
                        }
                    }
                    else{
                        // for each visible segmentationContainer -> trigger click event to close and kill scrollpane - very important !
                        closeAllOpenLists();
    
                        self.target.closest('.segmentEditorPanel').addClass('visible');
    
    mattab's avatar
    mattab a validé
                        doListBindings();
                    }
                });
    
                $(self.content).off("click",".editSegment").on("click", ".editSegment", function(e){
    
                    $(this).closest(".segmentationContainer").trigger("click");
    
    mattab's avatar
    mattab a validé
                    var target = $(this).parent("li");
    
    mattab's avatar
    mattab a validé
    
                    openEditFormGivenSegment(target);
    
    mattab's avatar
    mattab a validé
                    e.stopPropagation();
                    e.preventDefault();
                });
    
                $(self.content).off("click", ".segmentList li").on("click", ".segmentList li", function(e){
                    if($(e.currentTarget).hasClass("grayed") !== true){
                        var segment = {};
                        segment.idsegment = $(this).attr("data-idsegment");
    
    mattab's avatar
    mattab a validé
                        segment.definition = $(this).data("definition");
    
    mattab's avatar
    mattab a validé
                        segment.name = $(this).attr("title");
    
                        self.setSegment(segment.definition);
                        self.markCurrentSegment();
    
    mattab's avatar
    mattab a validé
                        self.segmentSelectMethod( segment.definition );
    
                        toggleLoadingMessage( segment.definition.length );
    
    mattab's avatar
    mattab a validé
                    }
                });
            };
    
            var bindChangeMetricSelectEvent = function()
            {
    
                $(".segment-content", self.target)
                    .off("change","select.metricList")
                    .on("change", "select.metricList", function(e, persist){
                        if(typeof persist === "undefined"){
                            persist = false;
                        }
                        alterMatchesList(this, persist);
    
                        doDragDropBindings();
    
                        autoSuggestValues(this, persist);
                    });
    
    mattab's avatar
    mattab a validé
    
    
    mattab's avatar
    mattab a validé
            var autoSuggestValues = function(select, persist) {
                var type = $(select).find("option:selected").attr("value");
                if(!persist) {
                    var parents = $(select).parents('.segment-row');
                    var loadingElement = parents.find(".segment-loading");
                    loadingElement.show();
    
                    var inputElement = parents.find(".metricValueBlock input");
                    var segmentName = $('option:selected',select).attr('value');
    
    mattab's avatar
    mattab a validé
    
                    var ajaxHandler = new ajaxHelper();
                    ajaxHandler.addParams({
                        module: 'API',
                        format: 'json',
                        method: 'API.getSuggestedValuesForSegment',
    
                        segmentName: segmentName
    
    mattab's avatar
    mattab a validé
                    }, 'GET');
                    ajaxHandler.setCallback(function(response) {
                        loadingElement.hide();
    
    mattab's avatar
    mattab a validé
                        inputElement.autocomplete({
                            source: response,
                            minLength: 0,
                            select: function(event, ui){
                                event.preventDefault();
                                $(inputElement).val(ui.item.value);
                            }
                        });
    
                        inputElement.click(function(e){
                            inputElement.autocomplete('search', $(inputElement).val());
                        });
    
    mattab's avatar
    mattab a validé
                    });
    
    mattab's avatar
    mattab a validé
                }
    
    mattab's avatar
    mattab a validé
    
            var alterMatchesList = function(select, persist){
                var oldMatch;
                var type = $(select).find("option:selected").attr("data-type");
                var matchSelector = $(select).parents(".segment-input").siblings(".metricMatchBlock").find("select");
                if(persist === true){
    
                    oldMatch = matchSelector.find("option:selected").val();
    
    mattab's avatar
    mattab a validé
                    oldMatch = "";
                }
    
    mattab's avatar
    mattab a validé
                if(type === "dimension" || type === "metric"){
                    matchSelector.empty();
                    var optionsHtml = "";
                    for(var key in self.availableMatches[type]){
                        optionsHtml += '<option value="'+key+'">'+self.availableMatches[type][key]+'</option>';
                    }
                }
    
    mattab's avatar
    mattab a validé
                matchSelector.append(optionsHtml);
                matchSelector.val(oldMatch);
    
    mattab's avatar
    mattab a validé
    
            var getAddNewBlockButtonHtml = function()
            {
                if(typeof addNewBlockButton === "undefined")
                {
    
                    var addNewBlockButton = self.editorTemplate.find("> div.segment-add-row").clone();
    
    mattab's avatar
    mattab a validé
                }
                return addNewBlockButton.clone();
    
    
    mattab's avatar
    mattab a validé
    
            var getAddOrBlockButtonHtml = function(){
    
                if(typeof addOrBlockButton === "undefined") {
                    var addOrBlockButton = self.editorTemplate.find("div.segment-add-or").clone();
    
    mattab's avatar
    mattab a validé
                }
                return addOrBlockButton.clone();
    
    mattab's avatar
    mattab a validé
    
            var placeSegmentationFormControls = function(){
                doDragDropBindings();
                $(self.form).find(".scrollable").jScrollPane({
                    showArrows: true,
                    autoReinitialise: true,
                    verticalArrowPositions: 'os',
                    horizontalArrowPositions: 'os'
                });
    
    mattab's avatar
    mattab a validé
    
    
    mattab's avatar
    mattab a validé
            function openEditFormGivenSegment(option) {
                var segment = {};
                segment.idsegment = option.attr("data-idsegment");
    
                var segmentExtra = getSegmentFromId(segment.idsegment);
                for(var item in segmentExtra)
                {
                    segment[item] = segmentExtra[item];
                }
    
    mattab's avatar
    mattab a validé
                segment.name = option.attr("title");
    
    mattab's avatar
    mattab a validé
                segment.definition = option.data("definition");
    
    mattab's avatar
    mattab a validé
    
                openEditForm(segment);
            }
    
    
    mattab's avatar
    mattab a validé
            var bindFormEvents = function(){
    
    
                $(self.form).on("click", "a:not(.crowdfundingLink)", function(e){
    
    mattab's avatar
    mattab a validé
                    e.preventDefault();
                });
    
                $(self.form).off("click", "a.editSegmentName").on("click", "a.editSegmentName", function(e){
                    var oldName = $(e.currentTarget).parents("h3").find("span").text();
                    $(e.currentTarget).parents("h3").find("span").hide();
                    $(e.currentTarget).hide();
    
                    $(e.currentTarget).before('<input class="edit_segment_name" type="text"/>');
                    $(e.currentTarget).siblings(".edit_segment_name").focus().val(oldName);
    
    mattab's avatar
    mattab a validé
                });
    
    
    
                $(self.form).off("click", ".segmentName").on("click", ".segmentName", function(e) {
                    $(self.form).find("a.editSegmentName").trigger('click');
                });
    
    
                $(self.form).off("blur", "input.edit_segment_name").on("blur", "input.edit_segment_name", function(e){
    
    mattab's avatar
    mattab a validé
                    var newName = $(this).val();
    
    mattab's avatar
    mattab a validé
                    if(newName.trim() != '') {
                        $(e.currentTarget).parents("h3").find("span").text(newName).show();
                        $(self.form).find("a.editSegmentName").show();
                        $(this).remove();
                    }
    
    mattab's avatar
    mattab a validé
                });
    
                $(self.form).on("click", '.segment-element', function(event) {
                    event.stopPropagation();
                    event.preventDefault();
                });
    
    
                $(self.form).find(".available_segments_select").bind("change", function(e){
    
    mattab's avatar
    mattab a validé
                    var option = $(e.currentTarget).find('option:selected');
    
    mattab's avatar
    mattab a validé
                    openEditFormGivenSegment(option);
    
    mattab's avatar
    mattab a validé
                });
    
                // attach event that shows/hides child elements of each metric category
                $(self.form).find(".segment-nav > div > ul > li > a").each( function(){
                    $(this).on("click", function(e){
                        $(e.currentTarget).siblings("ul").toggle();
                    });
                });
    
                $(self.form).off("click", ".custom_select_search a").on("click", ".custom_select_search a", function(e){
    
                    $(self.form).find(".segmentSearch").val("").trigger("keyup").val(self.translations['General_Search']);
    
    mattab's avatar
    mattab a validé
                });
    
                // attach event that will clear search input upon focus if its content is default
    
                $(self.form).find(".segmentSearch").on("focus", function(e){
    
    mattab's avatar
    mattab a validé
                    var search = $(e.currentTarget).val();
    
                    if(search == self.translations['General_Search'])
    
    mattab's avatar
    mattab a validé
                        $(e.currentTarget).val("");
                });
    
                // attach event that will set search input value upon blur if its content is not null
    
                $(self.form).find(".segmentSearch").on("blur", function(e){
    
    mattab's avatar
    mattab a validé
                    var search = $(e.currentTarget).val();
                    if(search == ""){
                        clearSearchMetricHighlight();
    
                        $(e.currentTarget).val(self.translations['General_Search']);
    
    mattab's avatar
    mattab a validé
                    }
                });
    
                // bind search action triggering - only when input text is longer than 2 chars
    
                $(self.form).find(".segmentSearch").on("keyup", function(e){
    
    mattab's avatar
    mattab a validé
                    var search = $(e.currentTarget).val();
                    if( search.length >= 2)
                    {
                        clearTimeout(self.timer);
                        self.searchAllowed = true;
                        self.timer = setTimeout(function(){
                            searchSegments(search);
                        }, 500);
                    }
                    else{
                        self.searchAllowed = false;
                        clearSearchMetricHighlight();
                    }
                });
    
                $(self.form).on("click", ".delete", function(){
                    var segmentName = $(self.form).find(".segment-content > h3 > span").text();
    
                    var segmentId = $(self.form).find(".available_segments_select option:selected").attr("data-idsegment");
    
    mattab's avatar
    mattab a validé
                    var params = {
                        "idsegment" : segmentId
                    };
    
                    $('.segment-delete-confirm', self.target).find('#name').text( segmentName );
    
    mattab's avatar
    mattab a validé
                    if(segmentId != ""){
    
                        piwikHelper.modalConfirm( '.segment-delete-confirm', {
    
    mattab's avatar
    mattab a validé
                            yes: function(){
                                self.deleteMethod(params);
                            }
                        });
                    }
                });
    
                $(self.form).on("click", "a.close", function(e){
    
                    $(".segmentListContainer", self.target).show();
    
    mattab's avatar
    mattab a validé
                    self.form.unbind().remove();
                });
    
    mattab's avatar
    mattab a validé
                $("body").on("keyup", function(e){
                    if(e.keyCode == "27"){
    
                        $(".segmentListContainer", self.target).show();
    
    mattab's avatar
    mattab a validé
                        $(self.form).remove();
                    }
                });
    
                bindChangeMetricSelectEvent();
    
                placeSegmentationFormControls();
    
    mattab's avatar
    mattab a validé
    
            var doDragDropBindings = function(){
                $(self.form).find(".segment-nav div > ul > li > ul > li").sortable({
                    cursor: 'move',
                    revert: 10,
                    revertDuration: 0,
                    snap: false,
                    helper: 'clone',
                    appendTo: 'body'
                });
    
                $(self.form).find(".metricListBlock").droppable({
                    hoverClass: "hovered",
                    drop: function( event, ui ) {
                        $(this).find("select").val(ui.draggable.parent().attr("data-metric")).trigger("change");
                    }
                });
    
                $(self.form).find(".segment-add-row > div").droppable({
                    hoverClass: "hovered",
                    drop: function( event, ui ) {
                        $(this).find("a").trigger("click", [ui.draggable.parent().attr("data-metric")]);
                        if($(this).find("a > span").length == 0){
                            revokeInitialStateRows();
                            appendSpecifiedRowHtml([ui.draggable.parent().attr("data-metric")]);
                        }
                    }
                });
    
                $(self.form).find(".segment-add-or > div").droppable({
                    hoverClass: "hovered",
                    drop: function( event, ui ) {
                        $(this).find("a").trigger("click", [ui.draggable.parent().attr("data-metric")]);
                    }
                });
    
    mattab's avatar
    mattab a validé
    
            var searchSegments = function(search){
    
                // pre-process search string to normalized form
    
    mattab's avatar
    mattab a validé
                search = normalizeSearchString(search);
    
    mattab's avatar
    mattab a validé
                // ---
                // clear all previous search highlights and hide all categories
                // to allow further showing only matching ones, while others remain invisible
                clearSearchMetricHighlight();
                $(self.form).find('.segment-nav div > ul > li').hide();
    
    mattab's avatar
    mattab a validé
                var curStr = "";
    
    mattab's avatar
    mattab a validé
                // 1 - do most obvious selection -> mark whole categories matching search string
                // also expand whole category
    
    mattab's avatar
    mattab a validé
                $(self.form).find('.segment-nav div > ul > li').each( function(){
    
                    curStr = normalizeSearchString($(this).find("a.metric_category").text());
    
                        if(curStr.indexOf(search) > -1) {
                            $(this).addClass("searchFound");
                            $(this).find("ul").show();
                            $(this).find("li").show();
                            $(this).show();
                        }
    
    mattab's avatar
    mattab a validé
                    }
    
    mattab's avatar
    mattab a validé
                // 2 - among all unselected categories find metrics which match and mark parent as search result
                $(self.form).find(".segment-nav div > ul > li:not(.searchFound)").each(function(){
                    var parent = this;
                    $(this).find("li").each( function(){
                        var curStr = normalizeSearchString($(this).text());
                        var curMetric = normalizeSearchString($(this).attr("data-metric"));
                        $(this).hide();
                        if(curStr.indexOf(search) > -1 || curMetric.indexOf(search) > -1){
                            $(this).show();
                            $(parent).find("ul").show();
                            $(parent).addClass("searchFound").show();
                        }
                    });
                });
    
    mattab's avatar
    mattab a validé
    
                if( $(self.form).find("li.searchFound").length == 0)
                {
    
                    $(self.form).find("div > ul").prepend('<li class="no_results"><a>'+self.translations['General_SearchNoResults']+'</a></li>').show();
    
    mattab's avatar
    mattab a validé
                }
                // check if search allow flag was revoked - then clear all search results
                if(self.searchAllowed == false)
                {
                    clearSearchMetricHighlight();
                    self.searchAllowed = true;
                }
    
    
    mattab's avatar
    mattab a validé
    
            var clearSearchMetricHighlight = function(){
                $(self.form).find('.no_results').remove();
                $(self.form).find('.segment-nav div > ul > li').removeClass("searchFound").show();
                $(self.form).find('.segment-nav div > ul > li').removeClass("others").show();
                $(self.form).find('.segment-nav div > ul > li > ul > li').show();
                $(self.form).find('.segment-nav div > ul > li > ul').hide();
    
    mattab's avatar
    mattab a validé
    
            var normalizeSearchString = function(search){
                search = search.replace(/^\s+|\s+$/g, ''); // trim
                search = search.toLowerCase();
                // remove accents, swap ñ for n, etc
                var from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;";
                var to   = "aaaaeeeeiiiioooouuuunc------";
                for (var i=0, l=from.length ; i<l ; i++) {
                    search = search.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
                }
    
                search = search.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
                .replace(/\s+/g, '_') // collapse whitespace and replace by underscore
                .replace(/-+/g, '-'); // collapse dashes
                return search;
    
    mattab's avatar
    mattab a validé
    
            var bindSegmentManipulationEvents = function(){
                // upon clicking - add new segment block, then bind 'x' action to newly added row
                $(self.form).on("click", ".segment-add-row a", function(event, data){
                    $(self.form).find(".segment-and:last").after(getAndDiv()).after(getMockedFormRow());
                    if(typeof data !== "undefined"){
                        $(self.form).find(".metricList:last").val(data);
                    }
    
                    $(self.form).find(".metricList:last").trigger('change');
    
    mattab's avatar
    mattab a validé
                    doDragDropBindings();
                });
    
                $(self.form).on("click", ".segment-add-row span", function(event, data){
                    if(typeof data !== "undefined") {
                        $(self.form).find(".segment-and:last").after(getAndDiv()).after(getMockedFormRow());
                        $(self.form).find(".metricList:last").val(data).trigger('change');
                        doDragDropBindings();
                    }
                });
    
    
    mattab's avatar
    mattab a validé
                $(self.form).on("click", ".segment-add-or  a", function(event, data){
                    $(event.currentTarget).parents(".segment-rows").find(".segment-or:last").after(getOrDiv()).after(getMockedInputRowHtml());
                    if(typeof data !== "undefined"){
                        $(event.currentTarget).parents(".segment-rows").find(".metricList:last").val(data);
                    }
                    $(event.currentTarget).parents(".segment-rows").find(".metricList:last").trigger('change');
                    doDragDropBindings();
                });
    
                $(self.form).on("click", ".segment-close",  function(e){
                    var target = e.currentTarget;
                    var rowCnt = $(target).parents(".segment-rows").find(".segment-row").length;
                    var globalRowCnt = $(self.form).find(".segment-close").length;
                    if(rowCnt > 1){
                        $(target).parents(".segment-row").next().remove();
                        $(target).parents(".segment-row").remove();
                    }
                    else if(rowCnt == 1){
                        $(target).parents(".segment-rows").next().remove();
                        $(target).parents(".segment-rows").remove();
                        if(globalRowCnt == 1){
                            applyInitialStateModification();
                        }
                    }
                });
    
    mattab's avatar
    mattab a validé
    
    
    mattab's avatar
    mattab a validé
            // Mode = 'new' or 'edit'
            var addForm = function(mode, segment){
    
                self.target.find(".segment-element:visible").unbind().remove();
    
    mattab's avatar
    mattab a validé
                if(typeof self.form !== "undefined")
                {
                    self.form.unbind().remove();
                }
                // remove any remaining forms
    
                self.form = getFormHtml();
    
                self.target.prepend(self.form);
    
    mattab's avatar
    mattab a validé
    
    
                // if there's enough space to the left & not enough space to the right,
                // anchor the form to the right of the selector
                if (self.form.width() + self.target.offset().left > $(window).width()
                    && self.form.width() < self.target.offset().left + self.target.width()
                ) {
                    self.form.addClass('anchorRight');
                }
    
    
    mattab's avatar
    mattab a validé
                bindFormEvents();
                bindSegmentManipulationEvents();
    
    mattab's avatar
    mattab a validé
    
                if(mode == "edit") {
    
                    $(self.form).find('.enable_all_users_select > option[value="'+segment.enable_all_users+'"]').prop("selected",true);
                    $(self.form).find('.visible_to_website_select > option[value="'+segment.enable_only_idsite+'"]').prop("selected",true);
                    $(self.form).find('.auto_archive_select > option[value="'+segment.auto_archive+'"]').prop("selected",true);
    
    mattab's avatar
    mattab a validé
    
                }
    
    
                makeDropList(".enable_all_users" , ".enable_all_users_select");
                makeDropList(".visible_to_website" , ".visible_to_website_select");
                makeDropList(".auto_archive" , ".auto_archive_select");
                makeDropList(".available_segments" , ".available_segments_select");
    
    mattab's avatar
    mattab a validé
                $(self.form).find(".saveAndApply").bind("click", function(e){
                    e.preventDefault();
                    parseFormAndSave();
                });
    
                $(self.form).find('.segment-footer').hover( function() {
    
                    $('.segmentFooterNote', self.target).fadeIn();
    
                    $('.segmentFooterNote', self.target).fadeOut();
    
                if(typeof mode !== "undefined" && mode == "new")
                {
                    $(self.form).find(".editSegmentName").trigger('click');
                }
    
                $(".segmentListContainer", self.target).hide();
    
    mattab's avatar
    mattab a validé
    
    
    mattab's avatar
    mattab a validé
    
            var parseForm = function(){
                var segmentStr = "";
                $(self.form).find(".segment-rows").each( function(){
                    var subSegmentStr = "";
    
                    $(this).find(".segment-row").each( function(){
                        if(subSegmentStr != ""){
                            subSegmentStr += ","; // OR operator
                        }
                        $(this).find(".segment-row-inputs").each( function(){
                            var metric = $(this).find(".metricList option:selected").val();
                            var match = $(this).find(".metricMatchBlock > select option:selected").val();
                            var value = $(this).find(".segment-input input").val();
                            subSegmentStr += metric + match + encodeURIComponent(value);
                        });
                    });
                    if(segmentStr != "")
                    {
                        segmentStr += ";"; // add AND operator between segment blocks
                    }
                    segmentStr += subSegmentStr;
                });
                return segmentStr
    
    mattab's avatar
    mattab a validé
    
            var parseFormAndSave = function(){
                var segmentName = $(self.form).find(".segment-content > h3 >span").text();
                var segmentStr = parseForm();
    
                var segmentId = $(self.form).find('.available_segments_select > option:selected').attr("data-idsegment");
                var user = $(self.form).find(".enable_all_users_select option:selected").val();
                var autoArchive = $(self.form).find(".auto_archive_select option:selected").val() || 0;
    
    mattab's avatar
    mattab a validé
                var params = {
                    "name": segmentName,
                    "definition": segmentStr,
                    "enabledAllUsers": user,
    
    mattab's avatar
    mattab a validé
                    "autoArchive": autoArchive,
    
                    "idSite":  $(self.form).find(".visible_to_website_select option:selected").val()
    
    mattab's avatar
    mattab a validé
                };
    
    mattab's avatar
    mattab a validé
    
    
    mattab's avatar
    mattab a validé
                // determine if save or update should be performed
                if(segmentId === ""){
                    self.addMethod(params);
                }
                else{
                    jQuery.extend(params, {
                        "idSegment": segmentId
                    });
                    self.updateMethod(params);
                }
    
    mattab's avatar
    mattab a validé
    
            var makeDropList = function(spanId, selectId){
                var select = $(self.form).find(selectId).hide();
                var dropList = $( '<a class="dropList dropdown">' )
                .insertAfter( select )
                .text( select.children(':selected').text() )
                .autocomplete({
                    delay: 0,
                    minLength: 0,
                    appendTo: "body",
                    source: function( request, response ) {
                        response( select.children( "option" ).map(function() {
                            var text = $( this ).text();
                            return {
                                label: text,
                                value: this.value,
                                option: this
                            };
                        }) );
                    },
                    select: function( event, ui ) {
    
    mattab's avatar
    mattab a validé
                        event.preventDefault();
    
    mattab's avatar
    mattab a validé
                        ui.item.option.selected = true;
    
    mattab's avatar
    mattab a validé
                        // Mark original select>option
    
                        $(spanId + ' option[value="' + ui.item.value + '"]', self.editorTemplate).prop('selected', true);
    
    mattab's avatar
    mattab a validé
                        dropList.text(ui.item.label);
                        $(self.form).find(selectId).trigger("change");
    
    mattab's avatar
    mattab a validé
                    }
                })
                .click(function() {
                    // close all other droplists made by this form
                    $("a.dropList").autocomplete("close");
                    //                 close if already visible
                    if ( $(this).autocomplete( "widget" ).is(":visible") ) {
                        $(this).autocomplete("close");
                        return;
                    }
                    // pass empty string as value to search for, displaying all results
                    $(this).autocomplete( "search", "" );
    
                });
    
                $('body').on('mouseup',function(e){
    
    mattab's avatar
    mattab a validé
                    if(!$(e.target).parents(spanId).length && !$(e.target).is(spanId) && !$(e.target).parents(spanId).length
                        && !$(e.target).parents(".ui-autocomplete").length && !$(e.target).is(".ui-autocomplete") && !$(e.target).parents(".ui-autocomplete").length
                        ) {
    
                        dropList.autocomplete().autocomplete("close");
    
    mattab's avatar
    mattab a validé
                    }
                });
    
    mattab's avatar
    mattab a validé
    
    
            function toggleLoadingMessage(segmentIsSet) {
                if (segmentIsSet) {
    
                    $('#ajaxLoadingDiv').find('.loadingSegment').show();
    
                    $('#ajaxLoadingDiv').find('.loadingSegment').hide();
    
    mattab's avatar
    mattab a validé
            var initHtml = function() {
                if(typeof self.content !== "undefined"){
                    self.content.unbind();
                }
                var html = getListHtml();
    
    mattab's avatar
    mattab a validé
                if(typeof self.content !== "undefined"){
                    self.content.html($(html).html());
                } else {
    
                    self.target.append(html);
                    self.content = self.target.find(".segmentationContainer");
    
    mattab's avatar
    mattab a validé
                }
    
                // assign content to object attribute to make it easil accesible through all widget methods
                bindListEvents();
    
    
                // Loading message
                var segmentIsSet = self.getSegment().length;
                toggleLoadingMessage(segmentIsSet);
    
    mattab's avatar
    mattab a validé
            initHtml();
        };
    
        return segmentation;
    })(jQuery);
    
    
    
    $(document).ready(function() {
        var exports = require('piwik/UI');
        var UIControl = exports.UIControl;
    
    mattab's avatar
    mattab a validé
    
    
        /**
         * Sets up and handles events for the segment selector & editor control.