<commit_before>(function(){
    'use strict';

    angular
        .module('doi_cms_app')
        .controller('mainCtrl', mainCtrl)
    ;

    function mainCtrl(APIDOIService, client, $scope, $location, $log, $sce) {
        var vm = this;
        vm.tab = "list";
        $scope.base_url = apps_url;
        $scope.real_base_url = base_url;
        vm.newdoixml = "";
        vm.pp = 50;

        var app_id = "";
        app_id = $location.search().app_id;
        if (!app_id) app_id = $location.search().app_id_select;

        if ($location.search().tab) vm.tab = $location.search().tab;

        vm.client = client.data.client;

        $scope.$watch('vm.tab', function(newv){
            vm.changeTab(newv);
        });

        vm.changeTab = function(tab) {
            switch (tab) {
                case 'list':
                    vm.refreshDOIs();
                    break;
                case 'log':
                    APIDOIService.getLog(vm.client.app_id).then(function(data){
                        vm.logs = data.data.activities;
                    });
                    break;
                case 'mint':
                    if(vm.client.mode == "test"){vm.client.datacite_prefix="10.5072";}
                    if(vm.client.datacite_prefix == "10.5072"){
                        var test_str = "TEST_DOI_";
                    }else{
                        var test_str = "";
                    }
                    vm.editxml = false;
                    vm.response = false;
                    vm.newdoi_url = '';
                    vm.newdoi_id = vm.client.datacite_test_prefix +'/'+ test_str + vm.uniqid();
                    vm.newdoixml = APIDOIService.getBlankDataciteXML(vm.newdoi_id);
                    break;
            }
        }

        vm.refreshDOIs = function(search) {
            if (!search) search = false;
                APIDOIService.getDOIList(vm.client.app_id, vm.pp, 0, search, vm.client.mode).then(function(data){
                vm.dois = data.data.dois;
                vm.total = data.data.total;
                vm.offset = vm.pp;
            });
        }

        vm.doisListNext = function(offset) {
            APIDOIService.getDOIList(vm.client.app_id, vm.pp, offset).then(function(data){
                vm.dois = vm.dois.concat(data.data.dois);
                vm.total = data.data.total;
                vm.offset += vm.pp;
            });
        }

        vm.view = function(doi, keep) {
            if (!keep) {
                vm.response = false;
            }
            vm.editxml = false;
            vm.tab = 'view';
            APIDOIService.getDOI(doi, vm.client.app_id).then(function(data){
                vm.readonly = true;
                $scope.$broadcast('readonly', vm.readonly);
                vm.viewdoi = data.data;
            });
        }

        vm.update = function(doi) {
            vm.editxml = false;
            vm.tab = 'view';
            vm.response = false;
            APIDOIService.getDOI(doi, vm.client.app_id).then(function(data){
                vm.readonly = false;
                $scope.$broadcast('readonly', vm.readonly);
                vm.viewdoi = data.data;
            });
        }
        // vm.update("10.5072/00/563978d704714");

        vm.mint = function() {
            $scope.$broadcast('update');
            if(vm.client.mode == 'test'){
                var data = {
                    xml : vm.stripBlankElements(vm.newdoixml),
                    app_id : vm.client.test_app_id,
                    url : vm.newdoi_url,
                    doi : vm.newdoi_id,
                    client_id: vm.client.client_id
                };

            }else {
                var data = {
                    xml: vm.stripBlankElements(vm.newdoixml),
                    app_id: vm.client.app_id,
                    url : vm.newdoi_url,
                    doi : vm.newdoi_id,
                    client_id: vm.client.client_id
                };
            }
            vm.loading = true;
            vm.response = false;
            APIDOIService.mint(data).then(function(response){
                vm.loading = false;
                vm.response = response.response;
                if (vm.response.doi && vm.response.type!="failure") {
                    vm.view(vm.response.doi, true);
                }
            });
        }

        vm.cancel = function() {
            vm.viewdoi = false;
            vm.response = false;
            vm.tab = 'list';
        }

        vm.doupdate = function() {
            $scope.$broadcast('update');
            if(vm.client.mode == 'test'){
                var data = {
                    xml : vm.stripBlankElements(vm.viewdoi.datacite_xml),
                    app_id : vm.client.test_app_id,
                    url : vm.viewdoi.url,
                    doi : vm.viewdoi.doi_id,
                    client_id: vm.client.client_id
                };

            }else {
                var data = {
                    xml: vm.stripBlankElements(vm.viewdoi.datacite_xml),
                    app_id: vm.client.app_id,
                    url: vm.viewdoi.url,
                    doi: vm.viewdoi.doi_id,
                    client_id: vm.client.client_id
                };
            }
            vm.loading = true;
            vm.response = false;
            APIDOIService.update(data).then(function(response){
                vm.loading = false;
                vm.response = response.response;
                if (vm.response.type!='failure' && vm.response.doi) {
                    vm.view(vm.response.doi, true);
                }
            });
        }

        vm.dodeactivate = function(doi_id) {
            if(vm.client.mode == 'test') {
                var data = {
                    app_id: vm.client.test_app_id,
                    doi: doi_id,
                    client_id: vm.client.client_id
                };
            }else{
                var data = {
                    app_id: vm.client.app_id,
                    doi: doi_id,
                    client_id: vm.client.client_id
                };
            }
            vm.response = {};
            APIDOIService.deactivate(data).then(function(response){
                alert(response.response.message);
                vm.refreshDOIs();
            });
        }

        vm.doactivate = function(doi_id) {
            if(vm.client.mode == 'test') {
                var data = {
                    app_id: vm.client.test_app_id,
                    doi: doi_id,
                    client_id: vm.client.client_id
                };
            }else{
                var data = {
                    app_id: vm.client.app_id,
                    doi: doi_id,
                    client_id: vm.client.client_id
                };
            }
            vm.response = {};
            APIDOIService.activate(data).then(function(response){
                alert(response.response.message);
                vm.refreshDOIs();
            });
        }

        vm.dolinkcheck = function() {
            vm.linkchecking = true;
            APIDOIService.checkLinks(vm.client.app_id).then(function(response){
                vm.linkchecking = false;
                vm.link_checker_result = $sce.trustAsHtml(response.message);
            });
        }

        vm.uniqid = function(prefix, more_entropy) {
          //  discuss at: http://phpjs.org/functions/uniqid/
          // original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
          //  revised by: Kankrelune (http://www.webfaktory.info/)
          //        note: Uses an internal counter (in php_js global) to avoid collision
          //        test: skip
          //   example 1: uniqid();
          //   returns 1: 'a30285b160c14'
          //   example 2: uniqid('foo');
          //   returns 2: 'fooa30285b1cd361'
          //   example 3: uniqid('bar', true);
          //   returns 3: 'bara20285b23dfd1.31879087'

          if (typeof prefix === 'undefined') {
            prefix = '';
          }

          var retId;
          var formatSeed = function(seed, reqWidth) {
            seed = parseInt(seed, 10)
              .toString(16); // to hex str
            if (reqWidth < seed.length) { // so long we split
              return seed.slice(seed.length - reqWidth);
            }
            if (reqWidth > seed.length) { // so short we pad
              return Array(1 + (reqWidth - seed.length))
                .join('0') + seed;
            }
            return seed;
          };

          // BEGIN REDUNDANT
          if (!this.php_js) {
            this.php_js = {};
          }
          // END REDUNDANT
          if (!this.php_js.uniqidSeed) { // init seed with big random int
            this.php_js.uniqidSeed = Math.floor(Math.random() * 0x75bcd15);
          }
          this.php_js.uniqidSeed++;

          retId = prefix; // start with prefix, add current milliseconds hex string
          retId += formatSeed(parseInt(new Date()
            .getTime() / 1000, 10), 8);
          retId += formatSeed(this.php_js.uniqidSeed, 5); // add seed hex string
          if (more_entropy) {
            // for more entropy we add a float lower to 10
            retId += (Math.random() * 10)
              .toFixed(8)
              .toString();
          }

          return retId;
        }

        vm.formatXml = function(xml) {
            var reg = /(>)\s*(<)(\/*)/g; // updated Mar 30, 2015
            var wsexp = / *(.*) +\n/g;
            var contexp = /(<.+>)(.+\n)/g;
            xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2');
            var pad = 0;
            var formatted = '';
            var lines = xml.split('\n');
            var indent = 0;
            var lastType = 'other';
            // 4 types of tags - single, closing, opening, other (text, doctype, comment) - 4*4 = 16 transitions
            var transitions = {
                'single->single': 0,
                'single->closing': -1,
                'single->opening': 0,
                'single->other': 0,
                'closing->single': 0,
                'closing->closing': -1,
                'closing->opening': 0,
                'closing->other': 0,
                'opening->single': 1,
                'opening->closing': 0,
                'opening->opening': 1,
                'opening->other': 1,
                'other->single': 0,
                'other->closing': -1,
                'other->opening': 0,
                'other->other': 0
            };

            for (var i = 0; i < lines.length; i++) {
                var ln = lines[i];
                var single = Boolean(ln.match(/<.+\/>/)); // is this line a single tag? ex. <br />
                var closing = Boolean(ln.match(/<\/.+>/)); // is this a closing tag? ex. </a>
                var opening = Boolean(ln.match(/<[^!].*>/)); // is this even a tag (that's not <!something>)
                var type = single ? 'single' : closing ? 'closing' : opening ? 'opening' : 'other';
                var fromTo = lastType + '->' + type;
                lastType = type;
                var padding = '';

                indent += transitions[fromTo];
                for (var j = 0; j < indent; j++) {
                    padding += '\t';
                }
                if (fromTo == 'opening->closing')
                    formatted = formatted.substr(0, formatted.length - 1) + ln + '\n'; // substr removes line break (\n) from prev loop
                else
                    formatted += padding + ln + '\n';
            }

            return formatted;
        }

        vm.stripBlankElements = function(xml) {
            try {
                var dom = $.parseXML(xml);
                //$('*:empty', dom).remove();
                $("*", dom).filter(function(){
                    var tagName = $( this ).prop( "tagName" );
                    if (tagName !== "resourceType") {
                        return $.trim(this.textContent) === "";
                    }
                }).remove();
                return (new XMLSerializer()).serializeToString(dom);
            } catch (e) {
                return xml;
            }

        }

        // BULK Operation
        vm.bulk_types = [{'id':'url', 'label':'URL'}];
        vm.bulk_type = 'url';

        vm.bulkPreview = function() {
            var data = {
                app_id : vm.client.app_id,
                type : vm.bulk_type,
                from: vm.bulk_from,
                to: vm.bulk_to,
                preview: true
            }
            APIDOIService.bulkRequest(data).then(function(response){
                vm.bulkPreviewResponse = response.data;
                console.log( vm.bulkPreviewResponse );
            });
        };

        vm.sendBulkRequest = function() {
            if (!confirm('Are you sure you want to send a bulk request update?' +
                    ' This will affect ' + vm.bulkPreviewResponse.total + ' DOI(s)')
            ) {
                return;
            }
            var data = {
                app_id : vm.client.app_id,
                type : vm.bulk_type,
                from: vm.bulk_from,
                to: vm.bulk_to
            }
            APIDOIService.bulkRequest(data).then(function(response){
                vm.bulkRequestedResponse = response.data;
                vm.getBulkRequests();
                delete vm.bulkPreviewResponse;
            });
        }

        vm.getBulkRequests = function () {
            delete vm.bulkRequests;
            APIDOIService.bulk({
                client_id: vm.client.client_id,
                app_id: vm.client.app_id
            }).then(function (response) {
                vm.bulkRequests = response.data;
                angular.forEach(vm.bulkRequests, function (bulkRequest) {
                    bulkRequest.params = JSON.parse(bulkRequest.params);
                    bulkRequest.paramsString = JSON.stringify(bulkRequest.params, null, 2);
                    if (bulkRequest.counts.ERROR > 0) {
                        vm.setActiveStatus(bulkRequest, 'ERROR');
                    } else {
                        vm.setActiveStatus(bulkRequest, 'PENDING');
                    }
                });
            });
        }
        vm.getBulkRequests();

        vm.setActiveStatus = function (bulkRequest, status) {
            bulkRequest.activeStatus = status;
            bulkRequest.activeStatusList = bulkRequest[status];
        }

        vm.removeBulk = function(bulkRequest) {
            if (!confirm('Are you sure you want to delete this bulk request? ' +
                    'The bulk request log is available in the activity log')
            ) {
                return;
            }
            bulkRequest.deleting = true;
            APIDOIService.bulkRequest({
                app_id: vm.client.app_id,
                'delete': bulkRequest.id
            }).then(function () {
                vm.getBulkRequests();
            });
        }

    }

})();<commit_msg>fixed bug when generating the new doi for the mint form where the test prefix was alsways being used<commit_after>(function(){
    'use strict';

    angular
        .module('doi_cms_app')
        .controller('mainCtrl', mainCtrl)
    ;

    function mainCtrl(APIDOIService, client, $scope, $location, $log, $sce) {
        var vm = this;
        vm.tab = "list";
        $scope.base_url = apps_url;
        $scope.real_base_url = base_url;
        vm.newdoixml = "";
        vm.pp = 50;

        var app_id = "";
        app_id = $location.search().app_id;
        if (!app_id) app_id = $location.search().app_id_select;

        if ($location.search().tab) vm.tab = $location.search().tab;

        vm.client = client.data.client;

        $scope.$watch('vm.tab', function(newv){
            vm.changeTab(newv);
        });

        vm.changeTab = function(tab) {
            switch (tab) {
                case 'list':
                    vm.refreshDOIs();
                    break;
                case 'log':
                    APIDOIService.getLog(vm.client.app_id).then(function(data){
                        vm.logs = data.data.activities;
                    });
                    break;
                case 'mint':
                    if(vm.client.mode == "test"){
                        vm.client.datacite_prefix=vm.client.datacite_test_prefix;
                        var test_str = "TEST_DOI_";
                    }else{
                        var test_str = "";
                    }
                    vm.editxml = false;
                    vm.response = false;
                    vm.newdoi_url = '';
                    vm.newdoi_id = vm.client.datacite_prefix +'/'+ test_str + vm.uniqid();
                    vm.newdoixml = APIDOIService.getBlankDataciteXML(vm.newdoi_id);
                    break;
            }
        }

        vm.refreshDOIs = function(search) {
            if (!search) search = false;
                APIDOIService.getDOIList(vm.client.app_id, vm.pp, 0, search, vm.client.mode).then(function(data){
                vm.dois = data.data.dois;
                vm.total = data.data.total;
                vm.offset = vm.pp;
            });
        }

        vm.doisListNext = function(offset) {
            APIDOIService.getDOIList(vm.client.app_id, vm.pp, offset).then(function(data){
                vm.dois = vm.dois.concat(data.data.dois);
                vm.total = data.data.total;
                vm.offset += vm.pp;
            });
        }

        vm.view = function(doi, keep) {
            if (!keep) {
                vm.response = false;
            }
            vm.editxml = false;
            vm.tab = 'view';
            APIDOIService.getDOI(doi, vm.client.app_id).then(function(data){
                vm.readonly = true;
                $scope.$broadcast('readonly', vm.readonly);
                vm.viewdoi = data.data;
            });
        }

        vm.update = function(doi) {
            vm.editxml = false;
            vm.tab = 'view';
            vm.response = false;
            APIDOIService.getDOI(doi, vm.client.app_id).then(function(data){
                vm.readonly = false;
                $scope.$broadcast('readonly', vm.readonly);
                vm.viewdoi = data.data;
            });
        }
        // vm.update("10.5072/00/563978d704714");

        vm.mint = function() {
            $scope.$broadcast('update');
            if(vm.client.mode == 'test'){
                var data = {
                    xml : vm.stripBlankElements(vm.newdoixml),
                    app_id : vm.client.test_app_id,
                    url : vm.newdoi_url,
                    doi : vm.newdoi_id,
                    client_id: vm.client.client_id
                };

            }else {
                var data = {
                    xml: vm.stripBlankElements(vm.newdoixml),
                    app_id: vm.client.app_id,
                    url : vm.newdoi_url,
                    doi : vm.newdoi_id,
                    client_id: vm.client.client_id
                };
            }
            vm.loading = true;
            vm.response = false;
            APIDOIService.mint(data).then(function(response){
                vm.loading = false;
                vm.response = response.response;
                if (vm.response.doi && vm.response.type!="failure") {
                    vm.view(vm.response.doi, true);
                }
            });
        }

        vm.cancel = function() {
            vm.viewdoi = false;
            vm.response = false;
            vm.tab = 'list';
        }

        vm.doupdate = function() {
            $scope.$broadcast('update');
            if(vm.client.mode == 'test'){
                var data = {
                    xml : vm.stripBlankElements(vm.viewdoi.datacite_xml),
                    app_id : vm.client.test_app_id,
                    url : vm.viewdoi.url,
                    doi : vm.viewdoi.doi_id,
                    client_id: vm.client.client_id
                };

            }else {
                var data = {
                    xml: vm.stripBlankElements(vm.viewdoi.datacite_xml),
                    app_id: vm.client.app_id,
                    url: vm.viewdoi.url,
                    doi: vm.viewdoi.doi_id,
                    client_id: vm.client.client_id
                };
            }
            vm.loading = true;
            vm.response = false;
            APIDOIService.update(data).then(function(response){
                vm.loading = false;
                vm.response = response.response;
                if (vm.response.type!='failure' && vm.response.doi) {
                    vm.view(vm.response.doi, true);
                }
            });
        }

        vm.dodeactivate = function(doi_id) {
            if(vm.client.mode == 'test') {
                var data = {
                    app_id: vm.client.test_app_id,
                    doi: doi_id,
                    client_id: vm.client.client_id
                };
            }else{
                var data = {
                    app_id: vm.client.app_id,
                    doi: doi_id,
                    client_id: vm.client.client_id
                };
            }
            vm.response = {};
            APIDOIService.deactivate(data).then(function(response){
                alert(response.response.message);
                vm.refreshDOIs();
            });
        }

        vm.doactivate = function(doi_id) {
            if(vm.client.mode == 'test') {
                var data = {
                    app_id: vm.client.test_app_id,
                    doi: doi_id,
                    client_id: vm.client.client_id
                };
            }else{
                var data = {
                    app_id: vm.client.app_id,
                    doi: doi_id,
                    client_id: vm.client.client_id
                };
            }
            vm.response = {};
            APIDOIService.activate(data).then(function(response){
                alert(response.response.message);
                vm.refreshDOIs();
            });
        }

        vm.dolinkcheck = function() {
            vm.linkchecking = true;
            APIDOIService.checkLinks(vm.client.app_id).then(function(response){
                vm.linkchecking = false;
                vm.link_checker_result = $sce.trustAsHtml(response.message);
            });
        }

        vm.uniqid = function(prefix, more_entropy) {
          //  discuss at: http://phpjs.org/functions/uniqid/
          // original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
          //  revised by: Kankrelune (http://www.webfaktory.info/)
          //        note: Uses an internal counter (in php_js global) to avoid collision
          //        test: skip
          //   example 1: uniqid();
          //   returns 1: 'a30285b160c14'
          //   example 2: uniqid('foo');
          //   returns 2: 'fooa30285b1cd361'
          //   example 3: uniqid('bar', true);
          //   returns 3: 'bara20285b23dfd1.31879087'

          if (typeof prefix === 'undefined') {
            prefix = '';
          }

          var retId;
          var formatSeed = function(seed, reqWidth) {
            seed = parseInt(seed, 10)
              .toString(16); // to hex str
            if (reqWidth < seed.length) { // so long we split
              return seed.slice(seed.length - reqWidth);
            }
            if (reqWidth > seed.length) { // so short we pad
              return Array(1 + (reqWidth - seed.length))
                .join('0') + seed;
            }
            return seed;
          };

          // BEGIN REDUNDANT
          if (!this.php_js) {
            this.php_js = {};
          }
          // END REDUNDANT
          if (!this.php_js.uniqidSeed) { // init seed with big random int
            this.php_js.uniqidSeed = Math.floor(Math.random() * 0x75bcd15);
          }
          this.php_js.uniqidSeed++;

          retId = prefix; // start with prefix, add current milliseconds hex string
          retId += formatSeed(parseInt(new Date()
            .getTime() / 1000, 10), 8);
          retId += formatSeed(this.php_js.uniqidSeed, 5); // add seed hex string
          if (more_entropy) {
            // for more entropy we add a float lower to 10
            retId += (Math.random() * 10)
              .toFixed(8)
              .toString();
          }

          return retId;
        }

        vm.formatXml = function(xml) {
            var reg = /(>)\s*(<)(\/*)/g; // updated Mar 30, 2015
            var wsexp = / *(.*) +\n/g;
            var contexp = /(<.+>)(.+\n)/g;
            xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2');
            var pad = 0;
            var formatted = '';
            var lines = xml.split('\n');
            var indent = 0;
            var lastType = 'other';
            // 4 types of tags - single, closing, opening, other (text, doctype, comment) - 4*4 = 16 transitions
            var transitions = {
                'single->single': 0,
                'single->closing': -1,
                'single->opening': 0,
                'single->other': 0,
                'closing->single': 0,
                'closing->closing': -1,
                'closing->opening': 0,
                'closing->other': 0,
                'opening->single': 1,
                'opening->closing': 0,
                'opening->opening': 1,
                'opening->other': 1,
                'other->single': 0,
                'other->closing': -1,
                'other->opening': 0,
                'other->other': 0
            };

            for (var i = 0; i < lines.length; i++) {
                var ln = lines[i];
                var single = Boolean(ln.match(/<.+\/>/)); // is this line a single tag? ex. <br />
                var closing = Boolean(ln.match(/<\/.+>/)); // is this a closing tag? ex. </a>
                var opening = Boolean(ln.match(/<[^!].*>/)); // is this even a tag (that's not <!something>)
                var type = single ? 'single' : closing ? 'closing' : opening ? 'opening' : 'other';
                var fromTo = lastType + '->' + type;
                lastType = type;
                var padding = '';

                indent += transitions[fromTo];
                for (var j = 0; j < indent; j++) {
                    padding += '\t';
                }
                if (fromTo == 'opening->closing')
                    formatted = formatted.substr(0, formatted.length - 1) + ln + '\n'; // substr removes line break (\n) from prev loop
                else
                    formatted += padding + ln + '\n';
            }

            return formatted;
        }

        vm.stripBlankElements = function(xml) {
            try {
                var dom = $.parseXML(xml);
                //$('*:empty', dom).remove();
                $("*", dom).filter(function(){
                    var tagName = $( this ).prop( "tagName" );
                    if (tagName !== "resourceType") {
                        return $.trim(this.textContent) === "";
                    }
                }).remove();
                return (new XMLSerializer()).serializeToString(dom);
            } catch (e) {
                return xml;
            }

        }

        // BULK Operation
        vm.bulk_types = [{'id':'url', 'label':'URL'}];
        vm.bulk_type = 'url';

        vm.bulkPreview = function() {
            var data = {
                app_id : vm.client.app_id,
                type : vm.bulk_type,
                from: vm.bulk_from,
                to: vm.bulk_to,
                preview: true
            }
            APIDOIService.bulkRequest(data).then(function(response){
                vm.bulkPreviewResponse = response.data;
                console.log( vm.bulkPreviewResponse );
            });
        };

        vm.sendBulkRequest = function() {
            if (!confirm('Are you sure you want to send a bulk request update?' +
                    ' This will affect ' + vm.bulkPreviewResponse.total + ' DOI(s)')
            ) {
                return;
            }
            var data = {
                app_id : vm.client.app_id,
                type : vm.bulk_type,
                from: vm.bulk_from,
                to: vm.bulk_to
            }
            APIDOIService.bulkRequest(data).then(function(response){
                vm.bulkRequestedResponse = response.data;
                vm.getBulkRequests();
                delete vm.bulkPreviewResponse;
            });
        }

        vm.getBulkRequests = function () {
            delete vm.bulkRequests;
            APIDOIService.bulk({
                client_id: vm.client.client_id,
                app_id: vm.client.app_id
            }).then(function (response) {
                vm.bulkRequests = response.data;
                angular.forEach(vm.bulkRequests, function (bulkRequest) {
                    bulkRequest.params = JSON.parse(bulkRequest.params);
                    bulkRequest.paramsString = JSON.stringify(bulkRequest.params, null, 2);
                    if (bulkRequest.counts.ERROR > 0) {
                        vm.setActiveStatus(bulkRequest, 'ERROR');
                    } else {
                        vm.setActiveStatus(bulkRequest, 'PENDING');
                    }
                });
            });
        }
        vm.getBulkRequests();

        vm.setActiveStatus = function (bulkRequest, status) {
            bulkRequest.activeStatus = status;
            bulkRequest.activeStatusList = bulkRequest[status];
        }

        vm.removeBulk = function(bulkRequest) {
            if (!confirm('Are you sure you want to delete this bulk request? ' +
                    'The bulk request log is available in the activity log')
            ) {
                return;
            }
            bulkRequest.deleting = true;
            APIDOIService.bulkRequest({
                app_id: vm.client.app_id,
                'delete': bulkRequest.id
            }).then(function () {
                vm.getBulkRequests();
            });
        }

    }

})();<|endoftext|>


<commit_before>/**
 * An observable object.
 * @constructor
 * @since 1.0alpha1
 */
Webos.Observable = function WObservable() {
	this._observers = [];
};
Webos.Observable.prototype = {
	/**
	 * A list of all observers.
	 * @type {Array}
	 * @private
	 */
	_observers: [],
	/**
	 * Listen to an event.
	 * @param   {String}   event The event's name. Multiple events can be listened if a space-separated list of events is provided. Namespaces are supported too.
	 * @param   {Function} fn    The callback which will be called when the event will be triggered.
	 * @returns {Number}         The callback's ID.
	 */
	on: function (event, fn) {
		var namespace = event;
		var events = event.split(' '), eventsNames = [];
		for (var i = 0; i < events.length; i++) {
			eventsNames.push(events[i].split('.')[0]);
		}

		return this._observers.push({
			fn: fn,
			eventsNames: eventsNames,
			events: events
		}) - 1;
	},
	/**
	 * @deprecated Use Observable#on() instead.
	 */
	bind: function (event, fn) {
		return this.on(event, fn);
	},
	/**
	 * Listen once to an event.
	 * @param   {String}   event The event's name.
	 * @param   {Function} fn    The callback which will be called when the event will be triggered.
	 * @returns {Number}         The callback's ID.
	 * @see Webos.Observable#on()
	 */
	once: function (event, fn) {
		var that = this;

		var callbackId = this.bind(event, function(data) {
			that.unbind(callbackId);
			fn.call(this, data);
		});

		return callbackId;
	},
	/**
	 * @deprecated Use Observable#once() instead.
	 */
	one: function (event, fn) {
		return this.once(event, fn);
	},
	/**
	 * Stop listening to an event.
	 * @param  {Number|String}   key   The callback's ID or the event's name.
	 * @param  {Function}        [fn]  The callback.
	 */
	off: function (key, fn) {
		var observers = [];
		if (typeof key == 'number') {
			for (var i = 0; i < this._observers.length; i++) {
				var el = this._observers[i];
				if (key != i) {
					observers.push(el);
				}
			}
		} else {
			key = String(key);
			var events = key.split(' ');
			for (var i = 0; i < this._observers.length; i++) {
				var el = this._observers[i], keep = true;

				if (fn && el.fn === fn) {
					keep = false;
				}

				for (var j = 0; j < events.length; j++) {
					if (key && (jQuery.inArray(events[j], el.eventsNames) != -1 || jQuery.inArray(events[j], el.events) != -1)) {
						keep = false;
					}
				}

				if (keep) {
					observers.push(el);
				}
			}
		}
		this._observers = observers;
	},
	/**
	 * @deprecated Use Observable#off() instead.
	 */
	unbind: function (key, fn) {
		return this.off(key, fn);
	},
	/**
	 * Trigger an event.
	 * @param  {String} event     The event's name.
	 * @param  {Object} [data]    Data to provide to callbacks.
	 * @param  {Object} [thisObj] Scope in which callbacks will be executed.
	 */
	trigger: function (event, data, thisObj) {
		data = data || {};
		var scope = thisObj || this, events = event.split(' ');

		for (var i = 0; i < this._observers.length; i++) {
			var el = this._observers[i];

			for (var j = 0; j < events.length; j++) {
				if (jQuery.inArray(events[j], el.eventsNames) != -1 || jQuery.inArray(events[j], el.events) != -1) {
					el.fn.call(scope, data);
				}
			}
		}
	},
	/**
	 * @deprecated Use Observable#trigger() instead.
	 */
	notify: function (event, data, thisObj) {
		return this.trigger(event, data, thisObj);
	}
};

/**
 * Build an observable from an existing object.
 * @param  {Object} object The original object.
 * @returns {Object}        The modified object.
 * @static
 */
Webos.Observable.build = function (object) {
	for (var attr in Webos.Observable.prototype) {
		object[attr] = Webos.Observable.prototype[attr];
	}

	object._observers = [];

	return object;
};

/**
 * A group of observable objects.
 * @param {Array|Webos.Observable} observables Observable(s).
 * @constructor
 * @borrows Webos.Observable#bind as #bind
 * @borrows Webos.Observable#one as #one
 * @since  1.0beta1
 */
Webos.Observable.Group = function WObservableGroup(observables) {
	var list = [];
	if (observables instanceof Array) {
		for (var i = 0; i < observables.length; i++) {
			if (Webos.isInstanceOf(observables[i], Webos.Observable)) {
				list.push(observables[i]);
			}
		}
	} else if (Webos.isInstanceOf(observables, Webos.Observable)) {
		list = [observables];
	}

	this._observables = list;

	// xxxEach() methods
	var that = this;
	for (var method in Webos.Observable.prototype) {
		(function(method) {
			var thisMethodName = method + 'Each';
			that[thisMethodName] = function() {
				var args = Array.prototype.slice.call(arguments);
				return this._eachObservable(method, args);
			};
		})(method);
	}
};
Webos.Observable.Group.prototype = {
	/**
	 * Apply a method of each observable.
	 * @param  {String} method The method's name.
	 * @param  {Array}  [args] Arguments to provide to the method.
	 * @returns {Array}         Values returned by each observable.
	 */
	_eachObservable: function $_WObservableGroup__eachObserver(method, args) {
		var returnValues = [];

		for (var i = 0; i < this._observables.length; i++) {
			if (!this._observables[i][method]) {
				continue;
			}

			var result = this._observables[i][method].apply(this._observables[i], args);
			returnValues.push(result);
		}

		return returnValues;
	},
	on: function (event, fn) {
		var that = this;
		var nbrNotifications = 0;
		var notifsData = [];

		this._eachObservable('on', [event, function(data) {
			nbrNotifications++;
			notifsData.push(data);

			if (nbrNotifications >= that._observables.length) {
				fn.call(that, notifsData);

				nbrNotifications = 0;
				notifsData = [];
			}
		}]);
	},
	bind: function (event, fn) {
		return this.on(event, fn);
	},
	once: function (event, fn) {
		var that = this;
		var nbrNotifications = 0;
		var notifsData = [];

		this._eachObservable('once', [event, function(data) {
			nbrNotifications++;
			notifsData.push(data);

			if (nbrNotifications >= that._observables.length) {
				fn.call(that, notifsData);
			}
		}]);
	},
	one: function (event, fn) {
		return this.once(event, fn);
	},
	/**
	 * Add an observable to the group.
	 * @param {Webos.Observable} observable The observable.
	 */
	addObservable: function (observable) {
		if (!Webos.isInstanceOf(observable, Webos.Observable)) {
			return false;
		}

		this._observables.push(observable);
	},
	/**
	 * Remove an observable from the group.
	 * @param {Webos.Observable} observable The observable.
	 */
	removeObservable: function (observable) {
		if (!Webos.isInstanceOf(observable, Webos.Observable)) {
			return false;
		}

		var list = [];

		for (var i = 0; i < this._observables.length; i++) {
			if (this._observables[i] !== observable) {
				list.push(this._observables[i]);
			}
		}

		this._observables = list;
	},
	/**
	 * Get a list of obseravbles in the group.
	 * @returns {Array} The list of observables.
	 */
	observables: function () {
		return this._observables;
	}
};

/**
 * Put observables in a group.
 * @param   {Array|Webos.Observable} observables Observable(s).
 * @returns {Webos.Observable.Group}             The group.
 * @static
 */
Webos.Observable.group = function $_WObservable_group(observables) {
	return new Webos.Observable.Group(observables);
};
<commit_msg>Added a garbage collector for processes. Fixes #290.<commit_after>/**
 * An observable object.
 * @constructor
 * @since 1.0alpha1
 */
Webos.Observable = function WObservable() {
	this._observers = [];
};
Webos.Observable.prototype = {
	/**
	 * A list of all observers.
	 * @type {Array}
	 * @private
	 */
	_observers: [],
	/**
	 * Listen to an event.
	 * @param   {String}   event The event's name. Multiple events can be listened if a space-separated list of events is provided. Namespaces are supported too.
	 * @param   {Function} fn    The callback which will be called when the event will be triggered.
	 * @returns {Number}         The callback's ID.
	 */
	on: function (event, fn) {
		var that = this;

		var namespace = event;
		var events = event.split(' '), eventsNames = [];
		for (var i = 0; i < events.length; i++) {
			eventsNames.push(events[i].split('.')[0]);
		}

		var listenerId = this._observers.push({
			fn: fn,
			eventsNames: eventsNames,
			events: events
		}) - 1;

		//Garbage collector
		var garbageCollectorStopEvent = 'stop.garbagecollector.observable.webos';
		if (Webos.Process && Webos.Process.current() && event != garbageCollectorStopEvent) {
			Webos.Process.current().once(garbageCollectorStopEvent, function() {
				that.off(event, fn);
			});
		}

		return listenerId;
	},
	/**
	 * @deprecated Use Observable#on() instead.
	 */
	bind: function (event, fn) {
		return this.on(event, fn);
	},
	/**
	 * Listen once to an event.
	 * @param   {String}   event The event's name.
	 * @param   {Function} fn    The callback which will be called when the event will be triggered.
	 * @returns {Number}         The callback's ID.
	 * @see Webos.Observable#on()
	 */
	once: function (event, fn) {
		var that = this;

		var callbackId = this.bind(event, function(data) {
			that.unbind(callbackId);
			fn.call(this, data);
		});

		return callbackId;
	},
	/**
	 * @deprecated Use Observable#once() instead.
	 */
	one: function (event, fn) {
		return this.once(event, fn);
	},
	/**
	 * Stop listening to an event.
	 * @param  {Number|String}   key   The callback's ID or the event's name.
	 * @param  {Function}        [fn]  The callback.
	 */
	off: function (key, fn) {
		var observers = [];
		if (typeof key == 'number') {
			for (var i = 0; i < this._observers.length; i++) {
				var el = this._observers[i];
				if (key != i) {
					observers.push(el);
				}
			}
		} else {
			key = String(key);
			var events = key.split(' ');
			for (var i = 0; i < this._observers.length; i++) {
				var el = this._observers[i], keep = true;

				if (fn && el.fn === fn) {
					keep = false;
				}

				for (var j = 0; j < events.length; j++) {
					if (key && (jQuery.inArray(events[j], el.eventsNames) != -1 || jQuery.inArray(events[j], el.events) != -1)) {
						keep = false;
					}
				}

				if (keep) {
					observers.push(el);
				}
			}
		}
		this._observers = observers;
	},
	/**
	 * @deprecated Use Observable#off() instead.
	 */
	unbind: function (key, fn) {
		return this.off(key, fn);
	},
	/**
	 * Trigger an event.
	 * @param  {String} event     The event's name.
	 * @param  {Object} [data]    Data to provide to callbacks.
	 * @param  {Object} [thisObj] Scope in which callbacks will be executed.
	 */
	trigger: function (event, data, thisObj) {
		data = data || {};
		var scope = thisObj || this, events = event.split(' ');

		for (var i = 0; i < this._observers.length; i++) {
			var el = this._observers[i];

			for (var j = 0; j < events.length; j++) {
				if (jQuery.inArray(events[j], el.eventsNames) != -1 || jQuery.inArray(events[j], el.events) != -1) {
					el.fn.call(scope, data);
				}
			}
		}
	},
	/**
	 * @deprecated Use Observable#trigger() instead.
	 */
	notify: function (event, data, thisObj) {
		return this.trigger(event, data, thisObj);
	}
};

/**
 * Build an observable from an existing object.
 * @param  {Object} object The original object.
 * @returns {Object}        The modified object.
 * @static
 */
Webos.Observable.build = function (object) {
	for (var attr in Webos.Observable.prototype) {
		object[attr] = Webos.Observable.prototype[attr];
	}

	object._observers = [];

	return object;
};

/**
 * A group of observable objects.
 * @param {Array|Webos.Observable} observables Observable(s).
 * @constructor
 * @borrows Webos.Observable#bind as #bind
 * @borrows Webos.Observable#one as #one
 * @since  1.0beta1
 */
Webos.Observable.Group = function WObservableGroup(observables) {
	var list = [];
	if (observables instanceof Array) {
		for (var i = 0; i < observables.length; i++) {
			if (Webos.isInstanceOf(observables[i], Webos.Observable)) {
				list.push(observables[i]);
			}
		}
	} else if (Webos.isInstanceOf(observables, Webos.Observable)) {
		list = [observables];
	}

	this._observables = list;

	// xxxEach() methods
	var that = this;
	for (var method in Webos.Observable.prototype) {
		(function(method) {
			var thisMethodName = method + 'Each';
			that[thisMethodName] = function() {
				var args = Array.prototype.slice.call(arguments);
				return this._eachObservable(method, args);
			};
		})(method);
	}
};
Webos.Observable.Group.prototype = {
	/**
	 * Apply a method of each observable.
	 * @param  {String} method The method's name.
	 * @param  {Array}  [args] Arguments to provide to the method.
	 * @returns {Array}         Values returned by each observable.
	 */
	_eachObservable: function $_WObservableGroup__eachObserver(method, args) {
		var returnValues = [];

		for (var i = 0; i < this._observables.length; i++) {
			if (!this._observables[i][method]) {
				continue;
			}

			var result = this._observables[i][method].apply(this._observables[i], args);
			returnValues.push(result);
		}

		return returnValues;
	},
	on: function (event, fn) {
		var that = this;
		var nbrNotifications = 0;
		var notifsData = [];

		this._eachObservable('on', [event, function(data) {
			nbrNotifications++;
			notifsData.push(data);

			if (nbrNotifications >= that._observables.length) {
				fn.call(that, notifsData);

				nbrNotifications = 0;
				notifsData = [];
			}
		}]);
	},
	bind: function (event, fn) {
		return this.on(event, fn);
	},
	once: function (event, fn) {
		var that = this;
		var nbrNotifications = 0;
		var notifsData = [];

		this._eachObservable('once', [event, function(data) {
			nbrNotifications++;
			notifsData.push(data);

			if (nbrNotifications >= that._observables.length) {
				fn.call(that, notifsData);
			}
		}]);
	},
	one: function (event, fn) {
		return this.once(event, fn);
	},
	/**
	 * Add an observable to the group.
	 * @param {Webos.Observable} observable The observable.
	 */
	addObservable: function (observable) {
		if (!Webos.isInstanceOf(observable, Webos.Observable)) {
			return false;
		}

		this._observables.push(observable);
	},
	/**
	 * Remove an observable from the group.
	 * @param {Webos.Observable} observable The observable.
	 */
	removeObservable: function (observable) {
		if (!Webos.isInstanceOf(observable, Webos.Observable)) {
			return false;
		}

		var list = [];

		for (var i = 0; i < this._observables.length; i++) {
			if (this._observables[i] !== observable) {
				list.push(this._observables[i]);
			}
		}

		this._observables = list;
	},
	/**
	 * Get a list of obseravbles in the group.
	 * @returns {Array} The list of observables.
	 */
	observables: function () {
		return this._observables;
	}
};

/**
 * Put observables in a group.
 * @param   {Array|Webos.Observable} observables Observable(s).
 * @returns {Webos.Observable.Group}             The group.
 * @static
 */
Webos.Observable.group = function $_WObservable_group(observables) {
	return new Webos.Observable.Group(observables);
};
<|endoftext|>


<commit_before>'use strict';

var Changelog = function (request) {
    this.request = request;
};

// https://github.com/GleSYS/API/wiki/functions_changelog#changelogapi
Changelog.prototype.api = function () {
    return this.request.get('/changelog/api');
};

// https://github.com/GleSYS/API/wiki/functions_changelog#changelogcontrolpanel
Changelog.prototype.controlPanel = function () {
    return this.request.get('/changelog/controlpanel');
};

module.exports = Changelog;
<commit_msg>Rewrite Changelog to ES2015<commit_after>'use strict';

class Changelog {
    constructor (request) {
        this.request = request;
    }

    // https://github.com/GleSYS/API/wiki/functions_changelog#changelogapi
    api () {
        return this.request.get('/changelog/api');
    }

    // https://github.com/GleSYS/API/wiki/functions_changelog#changelogcontrolpanel
    controlPanel () {
        return this.request.get('/changelog/controlpanel');
    }
}

module.exports = Changelog;
<|endoftext|>


<commit_before>var m = require('mithril');
var $osf = require('js/osfHelpers');
var waterbutler = require('js/waterbutler');
var AddProject = require('js/addProjectPlugin');
var dropzonePreviewTemplate = require('js/home-page/dropzonePreviewTemplate');

require('css/dropzone-plugin.css');
require('css/quick-project-search-plugin.css');
require('loaders.css/loaders.min.css');

var Dropzone = require('dropzone');

var ZeroClipboard = require('zeroclipboard');
var fileURL = '';
var fileURLArray = [];
var clip = '';

// Don't show dropped content if user drags outside dropzone
window.ondragover = function (e) {
    e.preventDefault();
};
window.ondrop = function (e) {
    e.preventDefault();
};

var PublicFilesDropzone = {
    controller: function () {
        var dangerCount = 0;

        var checkIfSameName = function(file){
            var files;
            var url = $osf.apiV2Url('nodes/' + window.contextVars.publicFilesId + '/files/osfstorage/');
            return $osf.ajaxJSON('GET', url, { isCors: true}).done(function (response) {
                var files = response;

                files.forEach(function(nodeFile){
                    if(nodeFile.attributes['name'] == file.name) return true;
                });

                return false;

            });
        };

        Dropzone.options.publicFilesDropzone = {
            // Dropzone is setup to upload multiple files in one request this configuration forces it to do upload file-by-
            //file, one request at a time.
            clickable: '#publicFilesDropzone',
            // number of files to process in parallel
            parallelUploads: 1,
            // prevents default uploading; call processQueue() to upload
            autoProcessQueue: false,
            withCredentials: true,
            method: 'put',
            // in MB; lower to test errors. Default is 256 MB.
            maxFilesize: 1,
            maxFiles: 1,
            // checks if file is valid; if so, then adds to queue
            init: function () {
                // When user clicks close button on top right, reset the number of files
                var _this = this;
                $('button.close').on('click', function () {
                    _this.files.length = 0;
                });

            },
            accept: function (file, done) {
                if(checkIfSameName(file)){
                    alert("file has same name.")
                }

                if (this.files.length <= this.options.maxFiles) {
                    this.options.url = waterbutler.buildUploadUrl(false, 'osfstorage', window.contextVars.publicFilesId, file, {});
                    this.processFile(file);
                }
                else {
                    dangerCount = document.getElementsByClassName('alert-danger').length;
                    if (dangerCount === 0)
                        $osf.growl("Error", "You can upload a maximum of " + this.options.maxFiles + " files at once. " +
                            "
 To upload more files, refresh the page or click X on the top right. " +
                            "
 Want to share more files? Create a new project.", "danger", 5000);

                    return this.emit("error", file);
                }
            },

            sending: function (file, xhr) {
                //Hack to remove webkitheaders
                var _send = xhr.send;
                xhr.send = function () {
                    _send.call(xhr, file);
                };
                $('.drop-zone-format').css({'padding-bottom': '10px'});
            },

            success: function (file, xhr) {
                var link = waterbutler.buildDownloadUrl(file.xhr.response['path'], 'osfstorage', window.contextVars.publicFilesId, file.name, {});
                $osf.mergeMithrilwithDOM(file.previewElement, dropzonePreviewTemplate.shareButton(link));

                this.processQueue();
                file.previewElement.classList.add("dz-success");
                file.previewElement.classList.add("dz-preview-background-success");
                if (this.getQueuedFiles().length === 0 && this.getUploadingFiles().length === 0) {
                    if (this.files.length === 1)
                        $osf.growl("Upload Successful", this.files.length + " file was successfully uploaded to your public files project.", "success", 5000);
                    else
                        $osf.growl("Upload Successful", this.files.length + " files were successfully uploaded to your public files project.", "success", 5000);

                }
            },

            error: function (file, message) {
                this.files.length--;
                // Keeping the old behavior in case we want to revert it some time
                file.previewElement.classList.add("dz-error");
                file.previewElement.classList.add("dz-preview-background-error");
                file.previewElement.remove(); // Doesn't show the preview
                // Need the padding change twice because the padding doesn't resize when there is an error
                // get file size in MB, rounded to 1 decimal place
                var fileSizeMB = Math.round(file.size / (1000 * 1000) * 10) / 10;
                if (fileSizeMB > this.options.maxFilesize) {
                    $osf.growl("Upload Failed", file.name + " could not be uploaded.
 The file is " + fileSizeMB + " MB," +
                        " which exceeds the max file size of " + this.options.maxFilesize + " MB", "danger", 5000);
                }
            },

        };

        var $publicFiles = $('#publicFilesDropzone');

        $publicFiles.on("click", "div.dz-share", function (e) {
            var infoCount = document.getElementsByClassName('alert-info').length;
            if (infoCount === 0) {
                $.growl({
                    icon: 'fa fa-clipboard',
                    message: ' Link copied to clipboard'
                }, {
                    type: 'info',
                    allow_dismiss: false,
                    mouse_over: 'pause',
                    placement: {
                        from: "top",
                        align: "center"
                    },
                    animate: {
                        enter: 'animated fadeInDown',
                        exit: 'animated fadeOut'
                    }
                });
            }
        });

        $publicFiles.dropzone({
            url: 'placeholder',
            previewTemplate: $osf.mithrilToStr(dropzonePreviewTemplate.dropzonePreviewTemplate())
        });

        $('#ShareButton').click(function () {
                $publicFiles.stop().slideToggle();
                $publicFiles.css('display', 'inline-block');
                $('#glyphchevron').toggleClass('glyphicon glyphicon-chevron-down glyphicon glyphicon-chevron-up');
            }
        );

    },

    view: function (ctrl, args) {
        function headerTemplate() {
            return [
                m('h2.col-xs-6', 'Dashboard'), m('m-b-lg.pull-right',
                    m('button.btn.btn-primary.m-t-md.f-w-xl #ShareButton',
                        m('span.glyphicon.glyphicon-chevron-down #glyphchevron'), ' Upload Public Files'), m.component(AddProject, {
                            buttonTemplate: m('button.btn.btn-success.btn-success-high-contrast.m-t-md.f-w-xl.pull-right[data-toggle="modal"][data-target="#addProjectFromHome"]',
                                {
                                    onclick: function () {
                                        $osf.trackClick('quickSearch', 'add-project', 'open-add-project-modal');
                                    }
                                }, 'Create new project'),
                            modalID: 'addProjectFromHome',
                            stayCallback: function _stayCallback_inPanel() {
                                document.location.reload(true);
                            },
                            trackingCategory: 'quickSearch',
                            trackingAction: 'add-project',
                            templatesFetcher: ctrl.templateNodes
                        }
                    )
                )
            ];
        }

        function closeButton() {
            return [
                m('button.close[aria-label="Close"].pull-right', {
                        onclick: function () {
                            $('#publicFilesDropzone').hide();
                            $('div.dz-preview').remove();
                            $('#glyphchevron').toggleClass('glyphicon glyphicon-chevron-up glyphicon glyphicon-chevron-down');
                            $('.drop-zone-format').css({'padding-bottom': '175px'});
                        }
                    }, m('.drop-zone-close', '×')
                )
            ]
        }

        function publicFilesHelpButton() {
            return [
                m('button.btn.fa.fa-question.text-muted.close.dz-font[aria-label="Drag-and-Drop Help"][data-toggle="modal"][data-target="#dropZoneHelpModal"]'),
                m('.modal.fade #dropZoneHelpModal',
                    m('.modal-dialog',
                        m('.modal-content',
                            m('.modal-header',
                                m('button.close[data-dismiss="modal"]', '×'),
                                m('h4.modal-title', 'Public Files Drag-and-Drop Help')),
                            m('.modal-body', m('p', 'Files uploaded here will be automatically added to your public files. Additionally: '),
                                m('ul',
                                    m('li', 'You may upload one file at a time.'),
                                    m('li', 'File uploads may be up to 256 MB.'),
                                    m('li','To upload more files, refresh the page or click the close button.'),
                                    m('li','Click ', m('span.i.fa.fa-share-alt'), ' to copy a download link for that file to your clipboard. Share this link with others!'))
                            ),
                            m('.modal-footer', m('button.btn.btn-default[data-dismiss="modal"]', 'Close'))
                        )
                    )
                )
            ]
        }

        // Activate Public Files tooltip info
        $('[data-toggle="tooltip"]').tooltip();
        // unexplainable large margin between dashboard and quick search projects
        return m('.row', m('.col-xs-12.m-b-sm', headerTemplate()),
            m('div.p-v-xs.drop-zone-format.drop-zone-invis .pointer .panel #publicFilesDropzone', closeButton(),
                publicFilesHelpButton(),
                m('h1.dz-p.text-center #publicFilesDropzone', 'Drop files to upload',
                    m('h5', 'Click the box to upload files. Files are automatically uploaded to your ',
                        m('a', {
                            href: '/public_files/', onclick: function (e) {
                                // Prevent clicking of link from opening file uploader
                                e.stopImmediatePropagation();
                            }
                        }, 'Public Files'), ' ', m('i.fa.fa-question-circle.text-muted', {
                            'data-toggle': 'tooltip',
                            'title': 'The Public Files Project allows you to easily collaborate and share your files with anybody.',
                            'data-placement': 'bottom'
                        }, '')
                    )
                )
            )
        );
    }
};

module.exports = PublicFilesDropzone;<commit_msg>housecleaning<commit_after>var m = require('mithril');
var $osf = require('js/osfHelpers');
var waterbutler = require('js/waterbutler');
var AddProject = require('js/addProjectPlugin');
var dropzonePreviewTemplate = require('js/home-page/dropzonePreviewTemplate');

require('css/dropzone-plugin.css');
require('css/quick-project-search-plugin.css');
require('loaders.css/loaders.min.css');

var Dropzone = require('dropzone');

// Don't show dropped content if user drags outside dropzone
window.ondragover = function (e) {
    e.preventDefault();
};
window.ondrop = function (e) {
    e.preventDefault();
};

var PublicFilesDropzone = {
    controller: function () {
        var dangerCount = 0;

        var checkIfSameName = function(file){
            var files;
            var url = $osf.apiV2Url('nodes/' + window.contextVars.publicFilesId + '/files/osfstorage/');
            return $osf.ajaxJSON('GET', url, { isCors: true}).done(function (response) {
                var files = response;

                files.forEach(function(nodeFile){
                    if(nodeFile.attributes['name'] == file.name) return true;
                });

                return false;

            });
        };

        Dropzone.options.publicFilesDropzone = {
            // Dropzone is setup to upload multiple files in one request this configuration forces it to do upload file-by-
            //file, one request at a time.
            clickable: '#publicFilesDropzone',
            // number of files to process in parallel
            parallelUploads: 1,
            // prevents default uploading; call processQueue() to upload
            autoProcessQueue: false,
            withCredentials: true,
            method: 'put',
            // in MB; lower to test errors. Default is 256 MB.
            maxFilesize: 1,
            maxFiles: 1,
            // checks if file is valid; if so, then adds to queue
            init: function () {
                // When user clicks close button on top right, reset the number of files
                var _this = this;
                $('button.close').on('click', function () {
                    _this.files = [];
                });

            },
            accept: function (file, done) {
                if(checkIfSameName(file)){
                    alert("file has same name.")
                }

                if (this.files.length <= this.options.maxFiles) {
                    this.options.url = waterbutler.buildUploadUrl(false, 'osfstorage', window.contextVars.publicFilesId, file, {});
                    this.processFile(file);
                }
                else {
                    dangerCount = document.getElementsByClassName('alert-danger').length;
                    if (dangerCount === 0)
                        $osf.growl("Error", "You can upload a maximum of " + this.options.maxFiles + " files at once. " +
                            "
 To upload more files, refresh the page or click X on the top right. " +
                            "
 Want to share more files? Create a new project.", "danger", 5000);

                    return this.emit("error", file);
                }
            },

            sending: function (file, xhr) {
                //Hack to remove webkitheaders
                var _send = xhr.send;
                xhr.send = function () {
                    _send.call(xhr, file);
                };
                $('.drop-zone-format').css({'padding-bottom': '10px'});
            },

            success: function (file, xhr) {
                var link = waterbutler.buildDownloadUrl(file.xhr.response['path'], 'osfstorage', window.contextVars.publicFilesId, file.name, {});
                $osf.mergeMithrilwithDOM(file.previewElement, dropzonePreviewTemplate.shareButton(link));

                this.processQueue();
                file.previewElement.classList.add("dz-success");
                file.previewElement.classList.add("dz-preview-background-success");
                if (this.getQueuedFiles().length === 0 && this.getUploadingFiles().length === 0) {
                    if (this.files.length === 1)
                        $osf.growl("Upload Successful this file was successfully uploaded to your public files project.", "success", 5000);
                    else
                        $osf.growl("Upload Successful", this.files.length + " files were successfully uploaded to your public files project.", "success", 5000);
                }
            },

            error: function (file, message) {
                this.files.pop();
                // Keeping the old behavior in case we want to revert it some time
                file.previewElement.classList.add("dz-error");
                file.previewElement.classList.add("dz-preview-background-error");
                file.previewElement.remove(); // Doesn't show the preview
                // Need the padding change twice because the padding doesn't resize when there is an error
                // get file size in MB, rounded to 1 decimal place
                var fileSizeMB = Math.round(file.size / (1000 * 1000) * 10) / 10;
                if (fileSizeMB > this.options.maxFilesize) {
                    $osf.growl("Upload Failed", file.name + " could not be uploaded.
 The file is " + fileSizeMB + " MB," +
                        " which exceeds the max file size of " + this.options.maxFilesize + " MB", "danger", 5000);
                }
            },

        };

        var $publicFiles = $('#publicFilesDropzone');

        $publicFiles.on("click", "div.dz-share", function (e) {
            var infoCount = document.getElementsByClassName('alert-info').length;
            if (infoCount === 0) {
                $.growl({
                    icon: 'fa fa-clipboard',
                    message: ' Link copied to clipboard'
                }, {
                    type: 'info',
                    allow_dismiss: false,
                    mouse_over: 'pause',
                    placement: {
                        from: "top",
                        align: "center"
                    },
                    animate: {
                        enter: 'animated fadeInDown',
                        exit: 'animated fadeOut'
                    }
                });
            }
        });

        $publicFiles.dropzone({
            url: 'placeholder',
            previewTemplate: $osf.mithrilToStr(dropzonePreviewTemplate.dropzonePreviewTemplate())
        });

        $('#ShareButton').click(function () {
                $publicFiles.stop().slideToggle();
                $publicFiles.css('display', 'inline-block');
                $('#glyphchevron').toggleClass('glyphicon glyphicon-chevron-down glyphicon glyphicon-chevron-up');
            }
        );

    },

    view: function (ctrl, args) {
        function headerTemplate() {
            return [
                m('h2.col-xs-6', 'Dashboard'), m('m-b-lg.pull-right',
                    m('button.btn.btn-primary #ShareButton',
                        m('span.glyphicon.glyphicon-chevron-down #glyphchevron'), ' Upload Public Files'), m.component(AddProject, {
                            buttonTemplate: m('button.btn.btn-success.pull-right[data-toggle="modal"][data-target="#addProjectFromHome"]',
                                {
                                    onclick: function () {
                                        $osf.trackClick('quickSearch', 'add-project', 'open-add-project-modal');
                                    }
                                }, 'Create new project'),
                            modalID: 'addProjectFromHome',
                            stayCallback: function _stayCallback_inPanel() {
                                document.location.reload(true);
                            },
                            trackingCategory: 'quickSearch',
                            trackingAction: 'add-project',
                            templatesFetcher: ctrl.templateNodes
                        }
                    )
                )
            ];
        }

        function closeButton() {
            return [
                m('button.close[aria-label="Close"].pull-right', {
                        onclick: function () {
                            $('#publicFilesDropzone').hide();
                            $('div.dz-preview').remove();
                            $('#glyphchevron').toggleClass('glyphicon glyphicon-chevron-up glyphicon glyphicon-chevron-down');
                            $('.drop-zone-format').css({'padding-bottom': '175px'});
                        }
                    }, m('.drop-zone-close', '×')
                )
            ]
        }

        function publicFilesHelpButton() {
            return [
                m('button.btn.fa.fa-question.text-muted.close.dz-font[aria-label="Drag-and-Drop Help"][data-toggle="modal"][data-target="#dropZoneHelpModal"]'),
                m('.modal.fade #dropZoneHelpModal',
                    m('.modal-dialog',
                        m('.modal-content',
                            m('.modal-header',
                                m('button.close[data-dismiss="modal"]', '×'),
                                m('h4.modal-title', 'Public Files Drag-and-Drop Help')),
                            m('.modal-body', m('p', 'Files uploaded here will be automatically added to your public files. Additionally: '),
                                m('ul',
                                    m('li', 'You may upload one file at a time.'),
                                    m('li', 'File uploads may be up to 256 MB.'),
                                    m('li','To upload more files, refresh the page or click the close button.'),
                                    m('li','Click ', m('span.i.fa.fa-share-alt'), ' to copy a download link for that file to your clipboard. Share this link with others!'))
                            ),
                            m('.modal-footer', m('button.btn.btn-default[data-dismiss="modal"]', 'Close'))
                        )
                    )
                )
            ]
        }

        // Activate Public Files tooltip info
        $('[data-toggle="tooltip"]').tooltip();
        // unexplainable large margin between dashboard and quick search projects
        return m('.row', m('.col-xs-12.m-b-sm', headerTemplate()),
            m('div.p-v-xs.drop-zone-format.drop-zone-invis .pointer .panel #publicFilesDropzone', closeButton(),
                publicFilesHelpButton(),
                m('h1.dz-p.text-center #publicFilesDropzone', 'Drop files to upload',
                    m('h5', 'Click the box to upload files. Files are automatically uploaded to your ',
                        m('a', {
                            href: '/public_files/', onclick: function (e) {
                                // Prevent clicking of link from opening file uploader
                                e.stopImmediatePropagation();
                            }
                        }, 'Public Files'), ' ', m('i.fa.fa-question-circle.text-muted', {
                            'data-toggle': 'tooltip',
                            'title': 'The Public Files Project allows you to easily collaborate and share your files with anybody.',
                            'data-placement': 'bottom'
                        }, '')
                    )
                )
            )
        );
    }
};

module.exports = PublicFilesDropzone;<|endoftext|>


<commit_before>import React from 'react';
import { Resolver } from './Resolver.js';
import { getScript, getScriptData, isClient } from './script.js';

/*
  - Handles passing of data down the tree and re-hydration between server and client
  - Wraps child with <Resolver> which mediates getting data from this component via context or fetching it directly if not available ...
  - Or if child is React Router it adds the createElement hook to Router so that route components always get wrapped with <Resolver>
  - When rendered on the server:
    - Saves props.data to state and makes it available via context for <Resolver> components
    - Renders a


<commit_before>require('jquery');

module.exports = function() {
  var $selectableInputs = $('label[class*=block-label]');

  $selectableInputs
    .find('input[type=radio], input[type=checkbox]')
    .map(function (index, input) {

      var $input = $(input);

      if ($input.is(':checked')) {
        $input.closest('label').addClass('selected');
      }
      return input;
    })
    .on('focus click', function(event) {

      var $label = $(event.target).closest('label');

      $label.addClass('add-focus');
      $selectableInputs.not($label).removeClass('add-focus');
    })
    .on('change', function(event) {

      var $input = $(event.target);

      if ($input.attr('type') === 'radio') {
        $("input[name='" + $input.prop('name') + "']").map(function (index, inputWithSameName) {
            $(inputWithSameName).closest('label').removeClass('selected');
        });
      }

      $input.closest('label').toggleClass('selected', $input.prop('checked'));
    })
    .on('focusout', function(event) {
      $(event.target).closest('label').removeClass('add-focus');
    });
};
<commit_msg>IHT-1887: change to blur to provide better cross browser support<commit_after>require('jquery');

module.exports = function() {
  var $selectableInputs = $('label[class*=block-label]');

  $selectableInputs
    .find('input[type=radio], input[type=checkbox]')
    .map(function (index, input) {

      var $input = $(input);

      if ($input.is(':checked')) {
        $input.closest('label').addClass('selected');
      }
      return input;
    })
    .on('focus click', function(event) {

      var $label = $(event.target).closest('label');

      $label.addClass('add-focus');
      $selectableInputs.not($label).removeClass('add-focus');
    })
    .on('change', function(event) {

      var $input = $(event.target);

      if ($input.attr('type') === 'radio') {
        $("input[name='" + $input.prop('name') + "']").map(function (index, inputWithSameName) {
            $(inputWithSameName).closest('label').removeClass('selected');
        });
      }

      $input.closest('label').toggleClass('selected', $input.prop('checked'));
    })
    .on('blur', function(event) {
      $(event.target).closest('label').removeClass('add-focus');
    });
};
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * External dependencies
 */
import { useEffect, useRef, useState } from 'react';

/**
 * Internal dependencies
 */
import { TransformProvider } from '../../../../edit-story/components/transform';
import { UnitsProvider } from '../../../../edit-story/units';
import {
  InfiniteScroller,
  Layout,
  StandardViewContentGutter,
} from '../../../components';
import {
  DASHBOARD_VIEWS,
  SAVED_TEMPLATES_STATUSES,
  STORY_SORT_MENU_ITEMS,
  TEMPLATES_GALLERY_ITEM_CENTER_ACTION_LABELS,
} from '../../../constants';
import useDashboardResultsLabel from '../../../utils/useDashboardResultsLabel';
import useStoryView, {
  FilterPropTypes,
  PagePropTypes,
  SearchPropTypes,
  SortPropTypes,
  ViewPropTypes,
} from '../../../utils/useStoryView';
import getAllTemplates from '../../../templates';
import { StoriesPropType } from '../../../types';
import { reshapeTemplateObject } from '../../api/useTemplateApi';
import { useConfig } from '../../config';
import FontProvider from '../../font/fontProvider';
import { BodyViewOptions, PageHeading, StoryGridView } from '../shared';

function Header({ filter, search, sort, stories, view }) {
  const resultsLabel = useDashboardResultsLabel({
    isActiveSearch: Boolean(search.keyword),
    currentFilter: filter.value,
    totalResults: stories.length,
    view: DASHBOARD_VIEWS.SAVED_TEMPLATES,
  });

  return (
    <Layout.Squishable>
      <PageHeading
        defaultTitle={__('Saved Templates', 'web-stories')}
        searchPlaceholder={__('Search Templates', 'web-stories')}
        stories={stories}
        handleTypeaheadChange={search.setKeyword}
        typeaheadValue={search.keyword}
      />
      <BodyViewOptions
        resultsLabel={resultsLabel}
        layoutStyle={view.style}
        currentSort={sort.value}
        pageSortOptions={STORY_SORT_MENU_ITEMS}
        handleSortChange={sort.set}
        sortDropdownAriaLabel={__(
          'Choose sort option for display',
          'web-stories'
        )}
      />
    </Layout.Squishable>
  );
}

function Content({ stories, view, page }) {
  return (
    <Layout.Scrollable>
      <FontProvider>
        <TransformProvider>
          <UnitsProvider pageSize={view.pageSize}>
            <StandardViewContentGutter>
              <StoryGridView
                stories={stories}
                centerActionLabelByStatus={
                  TEMPLATES_GALLERY_ITEM_CENTER_ACTION_LABELS
                }
                bottomActionLabel={__('Use template', 'web-stories')}
                isSavedTemplate
              />
              <InfiniteScroller
                allDataLoadedMessage={__('No more templates.', 'web-stories')}
                isLoading={false}
                canLoadMore={false}
                onLoadMore={page.requestNextPage}
              />
            </StandardViewContentGutter>
          </UnitsProvider>
        </TransformProvider>
      </FontProvider>
    </Layout.Scrollable>
  );
}

function SavedTemplates() {
  const config = useConfig();
  const { filter, page, sort, search, view } = useStoryView({
    filters: SAVED_TEMPLATES_STATUSES,
    totalPages: 1,
  });

  const [mockTemplates, setMockTemplates] = useState([]);

  useEffect(() => {
    const templates = getAllTemplates(config).map(reshapeTemplateObject(false));
    setMockTemplates(templates);
  }, [config]);

  return (
    <Layout.Provider>
      <Header
        filter={filter}
        view={view}
        search={search}
        stories={mockTemplates}
        sort={sort}
      />
      <Content view={view} page={page} sort={sort} stories={mockTemplates} />
    </Layout.Provider>
  );
}

Header.propTypes = {
  filter: FilterPropTypes.isRequired,
  view: ViewPropTypes.isRequired,
  search: SearchPropTypes.isRequired,
  sort: SortPropTypes.isRequired,
  stories: StoriesPropType,
};

Content.propTypes = {
  view: ViewPropTypes.isRequired,
  page: PagePropTypes.isRequired,
  stories: StoriesPropType,
};

export default SavedTemplates;
export { Header as SavedTemplatesHeader, Content as SavedTemplatesContent };
<commit_msg>Remove unused import<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * External dependencies
 */
import { useEffect, useState } from 'react';

/**
 * Internal dependencies
 */
import { TransformProvider } from '../../../../edit-story/components/transform';
import { UnitsProvider } from '../../../../edit-story/units';
import {
  InfiniteScroller,
  Layout,
  StandardViewContentGutter,
} from '../../../components';
import {
  DASHBOARD_VIEWS,
  SAVED_TEMPLATES_STATUSES,
  STORY_SORT_MENU_ITEMS,
  TEMPLATES_GALLERY_ITEM_CENTER_ACTION_LABELS,
} from '../../../constants';
import useDashboardResultsLabel from '../../../utils/useDashboardResultsLabel';
import useStoryView, {
  FilterPropTypes,
  PagePropTypes,
  SearchPropTypes,
  SortPropTypes,
  ViewPropTypes,
} from '../../../utils/useStoryView';
import getAllTemplates from '../../../templates';
import { StoriesPropType } from '../../../types';
import { reshapeTemplateObject } from '../../api/useTemplateApi';
import { useConfig } from '../../config';
import FontProvider from '../../font/fontProvider';
import { BodyViewOptions, PageHeading, StoryGridView } from '../shared';

function Header({ filter, search, sort, stories, view }) {
  const resultsLabel = useDashboardResultsLabel({
    isActiveSearch: Boolean(search.keyword),
    currentFilter: filter.value,
    totalResults: stories.length,
    view: DASHBOARD_VIEWS.SAVED_TEMPLATES,
  });

  return (
    <Layout.Squishable>
      <PageHeading
        defaultTitle={__('Saved Templates', 'web-stories')}
        searchPlaceholder={__('Search Templates', 'web-stories')}
        stories={stories}
        handleTypeaheadChange={search.setKeyword}
        typeaheadValue={search.keyword}
      />
      <BodyViewOptions
        resultsLabel={resultsLabel}
        layoutStyle={view.style}
        currentSort={sort.value}
        pageSortOptions={STORY_SORT_MENU_ITEMS}
        handleSortChange={sort.set}
        sortDropdownAriaLabel={__(
          'Choose sort option for display',
          'web-stories'
        )}
      />
    </Layout.Squishable>
  );
}

function Content({ stories, view, page }) {
  return (
    <Layout.Scrollable>
      <FontProvider>
        <TransformProvider>
          <UnitsProvider pageSize={view.pageSize}>
            <StandardViewContentGutter>
              <StoryGridView
                stories={stories}
                centerActionLabelByStatus={
                  TEMPLATES_GALLERY_ITEM_CENTER_ACTION_LABELS
                }
                bottomActionLabel={__('Use template', 'web-stories')}
                isSavedTemplate
              />
              <InfiniteScroller
                allDataLoadedMessage={__('No more templates.', 'web-stories')}
                isLoading={false}
                canLoadMore={false}
                onLoadMore={page.requestNextPage}
              />
            </StandardViewContentGutter>
          </UnitsProvider>
        </TransformProvider>
      </FontProvider>
    </Layout.Scrollable>
  );
}

function SavedTemplates() {
  const config = useConfig();
  const { filter, page, sort, search, view } = useStoryView({
    filters: SAVED_TEMPLATES_STATUSES,
    totalPages: 1,
  });

  const [mockTemplates, setMockTemplates] = useState([]);

  useEffect(() => {
    const templates = getAllTemplates(config).map(reshapeTemplateObject(false));
    setMockTemplates(templates);
  }, [config]);

  return (
    <Layout.Provider>
      <Header
        filter={filter}
        view={view}
        search={search}
        stories={mockTemplates}
        sort={sort}
      />
      <Content view={view} page={page} sort={sort} stories={mockTemplates} />
    </Layout.Provider>
  );
}

Header.propTypes = {
  filter: FilterPropTypes.isRequired,
  view: ViewPropTypes.isRequired,
  search: SearchPropTypes.isRequired,
  sort: SortPropTypes.isRequired,
  stories: StoriesPropType,
};

Content.propTypes = {
  view: ViewPropTypes.isRequired,
  page: PagePropTypes.isRequired,
  stories: StoriesPropType,
};

export default SavedTemplates;
export { Header as SavedTemplatesHeader, Content as SavedTemplatesContent };
<|endoftext|>