function()

in kahuna/public/js/search/query.js [48:433]


  function($rootScope, $scope, $state, $stateParams, onValChange, storage, mediaApi) {

    const ctrl = this;
    ctrl.costFilterLabel = window._clientConfig.costFilterLabel;
    ctrl.costFilterChargeable = window._clientConfig.costFilterChargeable;
    ctrl.costFilterFalseValue =  ctrl.costFilterChargeable ? undefined : "'true'";
    ctrl.costFilterTrueValue =  ctrl.costFilterChargeable ? "'true'" : undefined;
    ctrl.maybeOrgOwnedValue = window._clientConfig.maybeOrgOwnedValue;

    ctrl.canUpload = false;
    mediaApi.canUserUpload().then(canUpload => {
        ctrl.canUpload = canUpload;
    });

    ctrl.ordering = {
        orderBy: $stateParams.orderBy
    };

    ctrl.filter = {
        uploadedByMe: false
    };

    ctrl.dateFilter = {
        // filled in by the watcher below
    };

    ctrl.usePermissionsFilter = window._clientConfig.usePermissionsFilter;
    ctrl.filterMyUploads = false;
    ctrl.initialShowPaidEvent = ($stateParams.nonFree === undefined && ctrl.usePermissionsFilter) ? false : true;

    //--react - angular interop events--
    function raisePayableImagesEvent(showPaid) {
      const boolShowPaid = (showPaid === true || showPaid === "true") ? true : false;
      const customEvent = new CustomEvent('setPayableImages', {
        detail: {showPaid: boolShowPaid},
        bubbles: true
      });
      window.dispatchEvent(customEvent);
    }

    function raiseQueryChangeEvent(query) {
      const customEvent = new CustomEvent('queryChangeEvent', {
        detail: {query: query},
        bubbles: true
      });
      window.dispatchEvent(customEvent);
    }

    function raiseFilterChangeEvent(filter) {
      const customEvent = new CustomEvent('filterChangeEvent', {
        detail: {filter: filter},
        bubbles: true
      });
      window.dispatchEvent(customEvent);
    }

    function raiseUploadedByCheckEvent() {
      if (ctrl.user) {
        const customEvent = new CustomEvent('uploadedByEvent', {
          detail: { userEmail: ctrl.user.email, uploadedBy: $stateParams.uploadedBy },
          bubbles: true
        });
        window.dispatchEvent(customEvent);
      }
    }

    function manageUploadedBy(filter, sender) {
      // Users should be able to follow URLs with uploadedBy set to another user's name, so only
      // overwrite if:
      //   - uploadedBy is unset, or
      //   - uploadedBy is set to their email (to allow unchecking the 'My uploads' checkbox), or
      //   - 'My uploads' checkbox is checked (overwrite other user's email with theirs).
      if (!ctrl.usePermissionsFilter) {
        const myUploadsCheckbox = filter.uploadedByMe;
        const shouldOverwriteUploadedBy =
          !filter.uploadedBy || filter.uploadedBy === ctrl.user.email || myUploadsCheckbox;
        if (shouldOverwriteUploadedBy) {
          ctrl.filter.uploadedBy = filter.uploadedByMe ? ctrl.user.email : undefined;
        }
      } else {
        if (sender === "selectMyUploads") {
          const shouldOverwriteUploadedBy =
             !filter.uploadedBy ||
             filter.uploadedBy === (ctrl.user ? ctrl.user.email : undefined) ||
             ctrl.filterMyUploads;
          if (shouldOverwriteUploadedBy) {
            ctrl.filter.uploadedBy = (ctrl.user && ctrl.filterMyUploads) ? ctrl.user.email : undefined;
            ctrl.filter.uploadedByMe = ctrl.filterMyUploads;
          }
        }
        raiseUploadedByCheckEvent();
      }
      storage.setJs("isUploadedByMe", ctrl.filter.uploadedByMe, true);
    }

    function manageDefaultNonFree(filter) {
        const defaultNonFreeFilter = storage.getJs("defaultNonFreeFilter", true);
        if (defaultNonFreeFilter && defaultNonFreeFilter.isDefault === true){
          let newNonFree = defaultNonFreeFilter.isNonFree ? "true" : undefined;
          if (newNonFree !== filter.nonFree) {
            storage.setJs("isNonFree", newNonFree ? newNonFree : false, true);
            storage.setJs("defaultIsNonFree", newNonFree ? newNonFree : false, true);
            storage.setJs("isUploadedByMe", false, true);
            storage.setJs("defaultNonFreeFilter", {isDefault: false, isNonFree: false}, true);
            ctrl.filter.orgOwned = false;
          }
          Object.assign(ctrl.filter, {nonFree: newNonFree, uploadedByMe: false, uploadedBy: undefined});
          raiseFilterChangeEvent(ctrl.filter);
        }
    }

    function manageOrgOwnedSetting(filter) {
        const structuredQuery = structureQuery(filter.query) || [];
        const orgOwnedIndexInQuery = structuredQuery.findIndex(item => item.value === ctrl.maybeOrgOwnedValue);
        const queryHasOrgOwned = orgOwnedIndexInQuery >= 0;
        if (ctrl.filter.orgOwned && !queryHasOrgOwned){
          // If the checkbox is ticked, ensure the chip is part of the search bar
          const orgOwnedChip = {
            type: "filter",
            filterType: "inclusion",
            key : "is",
            value: ctrl.maybeOrgOwnedValue
          };
          ctrl.filter.query = renderQuery([
            ...structuredQuery,
            orgOwnedChip
          ]);
        } else if (!ctrl.filter.orgOwned && queryHasOrgOwned && !ctrl.usePermissionsFilter) {
          // If the checkbox is unticked, ensure chip is no longer in the search bar
          structuredQuery.splice(orgOwnedIndexInQuery, 1);
          ctrl.filter.query = renderQuery(structuredQuery);
        }
    }

    function resetQuery() {
        ctrl.filter.query = undefined;
        ctrl.filter.orgOwned = false;
    }

    // eslint-disable-next-line complexity
    function watchSearchChange(newFilter, sender) {
      const showPaid = newFilter.nonFree ? newFilter.nonFree : false;
      storage.setJs("isNonFree", showPaid, true);

      ctrl.collectionSearch = newFilter.query ? newFilter.query.indexOf('~') === 0 : false;

      //--update filter elements--
      manageUploadedBy(newFilter, sender);
      manageDefaultNonFree(newFilter);
      manageOrgOwnedSetting(newFilter);

      const { nonFree, uploadedByMe } = ctrl.filter;
      let nonFreeCheck = nonFree;
      if (ctrl.usePermissionsFilter && nonFreeCheck === undefined) {
        const defaultShowPaid = storage.getJs("defaultIsNonFree", true);
        nonFreeCheck = defaultShowPaid;
      } else if (!ctrl.usePermissionsFilter && (nonFreeCheck === 'false' || nonFreeCheck === false)) {
        nonFreeCheck = undefined;
      }
      ctrl.filter.nonFree = nonFreeCheck;
      raiseQueryChangeEvent(ctrl.filter.query);

      sendTelemetryForQuery(ctrl.filter.query, nonFreeCheck, uploadedByMe);
      $state.go('search.results', ctrl.filter);
    }

    //-my uploads-
    function selectMyUploads(myUploadsChecked) {
      ctrl.filterMyUploads = myUploadsChecked;
      watchSearchChange(ctrl.filter, "selectMyUploads");
    }

    ctrl.myUploadsProps = {
      myUploads: ctrl.filterMyUploads,
      onChange: selectMyUploads
    };
    //-end my uploads

    //-sort control-
    function updateSortChips (sortSel) {
      ctrl.sortProps.selectedOption = sortSel;
      ctrl.ordering['orderBy'] = manageSortSelection(sortSel.value);
      watchSearchChange(ctrl.filter, "sorting");
    }

    ctrl.sortProps = {
      options: SortOptions,
      selectedOption: DefaultSortOption,
      onSelect: updateSortChips,
      query: ctrl.filter.query,
      orderBy: ctrl.ordering ? ctrl.ordering.orderBy : ""
    };
    //-end sort control-

    //-permissions filter-
    function updatePermissionsChips (permissionsSel, showChargeable) {
      ctrl.permissionsProps.selectedOption = permissionsSel;
      ctrl.filter.query = updateFilterChips(permissionsSel, ctrl.filter.query);
      ctrl.filter.nonFree = showChargeable;
      watchSearchChange(ctrl.filter, "updatePermissionsChips");
    }

    function chargeableChange (showChargeable) {
      ctrl.filter.nonFree = showChargeable;
      watchSearchChange(ctrl.filter, "chargeableChange");
    }

    let pfOpts = PermissionsConf.permissionsOptions();
    let defOptVal = PermissionsConf.permissionsDefaultOpt();
    let pfDefPerm = pfOpts.filter(opt => opt.value == defOptVal)[0];
    ctrl.permissionsProps = { options: pfOpts,
                              selectedOption: pfDefPerm,
                              onSelect: updatePermissionsChips,
                              onChargeable: chargeableChange,
                              chargeable: ctrl.filter.nonFree ? ctrl.filter.nonFree : ($stateParams.nonFree == "true"),
                              query: ctrl.filter.query
                            };
    //-end permissions filter-

    ctrl.resetQuery = resetQuery;

    // Note that this correctly uses local datetime and returns
    // midnight for the local user
    const lastMidnight  = moment().startOf('day').toISOString();
    const past24Hours   = moment().subtract(24, 'hours').toISOString();
    const pastWeek      = moment().subtract(7, 'days').toISOString();
    const past6Months   = moment().subtract(6, 'months').toISOString();
    const pastYear      = moment().subtract(1, 'years').toISOString();

    ctrl.payTypeOptions = [
        {label: 'Free', value: 'free'},
        {label: 'Free and No Rights', value: 'maybe-free'},
        {label: 'All (inc. paid)', value: 'all'}
    ];

    ctrl.sinceOptions = [
        {label: 'Anytime'},   // value: undefined
        {label: 'Today',         value: lastMidnight},
        {label: 'Past 24 hours', value: past24Hours},
        {label: 'Past week',     value: pastWeek},
        {label: 'Past 6 months', value: past6Months},
        {label: 'Past year',     value: pastYear}
    ];

    ctrl.filterDateFieldsOptions = [
        {label: 'Upload time',   name: 'uploaded'}, // value: undefined
        {label: 'Date taken',    name: 'taken',        value: 'taken'},
        {label: 'Last modified', name: 'modified',     value: 'modified'}
    ];

    const dateFilterParams = [
        'dateField', 'since', 'until', 'takenSince', 'takenUntil',
        'modifiedSince', 'modifiedUntil'
    ];

    Object.keys($stateParams).
        // Exclude date-related filters, managed separately in dateFilter
        filter(key => dateFilterParams.indexOf(key) === -1).
        forEach(setAndWatchParam);

    // URL parameters are not decoded when taken out of the params.
    // Might be fixed with: https://github.com/angular-ui/ui-router/issues/1759
    // Pass undefined to the state on empty to remove the QueryString
    function valOrUndefined(str) { return str ? str : undefined; }

    function setAndWatchParam(key) {
        //this value has been set on ctrl.order
        if (key !== 'orderBy') {
            ctrl.filter[key] = valOrUndefined($stateParams[key]);
        }

        ctrl.collectionSearch = ctrl.filter.query ?  ctrl.filter.query.indexOf('~') === 0 : false;

        $scope.$watch(() => $stateParams[key], onValChange(newVal => {
            // FIXME: broken for 'your uploads'
            // FIXME: + they triggers filter $watch and $state.go (breaks history)
            if (key === 'orderBy') {
                ctrl.ordering[key] = valOrUndefined(newVal);
            } else {
                ctrl.filter[key] = valOrUndefined(newVal);
            }

            // don't track changes to `query` as it would trigger on every keypress
            if (key !== 'query') {
                $rootScope.$emit(
                  'track:event', 'Query', 'Change', 'Success', null, { field: key, value: newVal }
                );
            }
        }));
    }

    // Init and apply date-related changes in $stateParams to ctrl.dateFilter
    $scope.$watchCollection(() => $stateParams, () => {
        switch ($stateParams.dateField) {
        case 'taken':
            ctrl.dateFilter.since = $stateParams.takenSince;
            ctrl.dateFilter.until = $stateParams.takenUntil;
            ctrl.dateFilter.field = 'taken';
            break;
        case 'modified':
            ctrl.dateFilter.since = $stateParams.modifiedSince;
            ctrl.dateFilter.until = $stateParams.modifiedUntil;
            ctrl.dateFilter.field = 'modified';
            break;
        default: // uploaded (default so represented as `undefined`)
            ctrl.dateFilter.since = $stateParams.since;
            ctrl.dateFilter.until = $stateParams.until;
            ctrl.dateFilter.field = undefined;
            break;
        }
    });

    $scope.$watchCollection(() => ctrl.filter, onValChange(newFilter => {
      watchSearchChange(newFilter, "filterChange");
    }));

    $scope.$watch(() => ctrl.ordering.orderBy, onValChange(newVal => {
        $state.go('search.results', {...ctrl.filter, ...{orderBy: newVal}});
    }));

    $scope.$watchCollection(() => ctrl.dateFilter, onValChange(({field, since, until}) => {
        // Translate dateFilter to actual state and query params
        $state.go('search.results', {...ctrl.filter, ...{
            since:         field === undefined  ? since : null,
            until:         field === undefined  ? until : null,
            takenSince:    field === 'taken'    ? since : null,
            takenUntil:    field === 'taken'    ? until : null,
            modifiedSince: field === 'modified' ? since : null,
            modifiedUntil: field === 'modified' ? until : null,
            dateField:     field
        }});
    }));

    // we can't user dynamic values in the ng:true-value see:
    // https://docs.angularjs.org/error/ngModel/constexpr
    mediaApi.getSession().then(session => {
        //-uploaded by me-
        const isUploadedByMe = storage.getJs("isUploadedByMe", true);
        ctrl.user = session.user;
        if (isUploadedByMe === null) {
          ctrl.filter.uploadedByMe = ctrl.filter.uploadedBy === ctrl.user.email;
          ctrl.filterMyUploads = ctrl.filter.uploadedByMe;
          storage.setJs("isUploadedByMe",ctrl.filter.uploadedByMe);
        } else {
          if ((ctrl.filter.uploadedBy === ctrl.user.email) && !isUploadedByMe ) {
            ctrl.filter.uploadedByMe = true;
            ctrl.filterMyUploads = ctrl.filter.uploadedByMe;
            storage.setJs("isUploadedByMe",ctrl.filter.uploadedByMe);
          } else {
            ctrl.filter.uploadedByMe = isUploadedByMe;
            ctrl.filterMyUploads = isUploadedByMe;
          }
        }

        //-default non free-
        const defNonFree = session.user.permissions ? session.user.permissions.showPaid : undefined;
        storage.setJs("defaultIsNonFree", defNonFree ? defNonFree : false, true);
        if (!ctrl.initialShowPaidEvent && (defNonFree === true || defNonFree === "true")) {
          ctrl.initialShowPaidEvent = true;
          raisePayableImagesEvent(defNonFree);
        }

        const isNonFree = storage.getJs("isNonFree", true);
        if (isNonFree === null) {
          ctrl.filter.nonFree = $stateParams.nonFree;
          storage.setJs("isNonFree", ctrl.filter.nonFree ? ctrl.filter.nonFree : (ctrl.usePermissionsFilter ? "false" : undefined), true);
        }
        else if (isNonFree === true || isNonFree === "true") {
          ctrl.filter.nonFree = "true";
        } else {
          ctrl.filter.nonFree = (ctrl.usePermissionsFilter ? "false" : undefined);
        }

        //-org owned-
        const structuredQuery = structureQuery(ctrl.filter.query);
        const orgOwned = (structuredQuery.some(item => item.value === ctrl.maybeOrgOwnedValue));
        ctrl.filter.orgOwned = orgOwned;

        watchSearchChange(ctrl.filter, "userPermissions");
    });



    const { nonFree, uploadedByMe } = ctrl.filter;
    sendTelemetryForQuery(ctrl.filter.query, nonFree, uploadedByMe);
}]);