Advertisement
DAZD

Untitled

Nov 21st, 2018
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. 'use strict';
  2. angular.module('pgCore', ['ngSanitize']);
  3. ;'use strict';
  4. angular.module('pgCore').factory('config', ['$http','$q', function($http, $q) {
  5.   var configPromise;
  6.   var config = {
  7.     getConfig: function(){
  8.       if(config.loaded) return $q.when(config);
  9.       if(configPromise) return configPromise;
  10.       configPromise = $http.get('./config.json').then(function(data){
  11.         config.loaded = true;
  12.         return _.extend(config, data.data);
  13.       }).finally(function(){
  14.         configPromise = null;
  15.       });
  16.       return configPromise;
  17.     }
  18.   };
  19.   return config;
  20. }]);
  21. ;'use strict';
  22.  
  23. angular.module('pgCore').factory('events', [function () {
  24.   var events = {
  25.     register: register
  26.   };
  27.   var eventApi = {
  28.     'loggedIn': 'triggers when the user has loggedin or on first load if the user is logged in',
  29.     'loggedOut': 'triggers when the user logs out',
  30.     'currentUserReady': 'when the current user is available',
  31.     'resize': 'when the window is resized',
  32.     'menuItemsAdded': 'when a menu item is added to the header menu',
  33.     'navItemsAdded': 'when a navigation item is added to the header menu',
  34.   };
  35.  
  36.   createApi();
  37.  
  38.   function createApi() {
  39.     for (var event in eventApi) {
  40.       if (eventApi.hasOwnProperty(event)) {
  41.         events[event] = apiConstructor();
  42.       }
  43.     }
  44.   }
  45.  
  46.   function apiConstructor() {
  47.     var callbackRegistry = {};
  48.     return {
  49.       trigger: function(params) {
  50.         for (var id in callbackRegistry) {
  51.           if (callbackRegistry.hasOwnProperty(id)) {
  52.             callbackRegistry[id].apply(this, arguments);
  53.           }
  54.         }
  55.       },
  56.       on: function(on) {
  57.         var id = _.uniqueId('EVENT');
  58.         if (typeof on === 'function') {
  59.           callbackRegistry[id] = on;
  60.           return function() {
  61.             return unregister(id);
  62.           };
  63.         } else {
  64.           throw 'Must be a function passed to .on';
  65.         }
  66.       }
  67.     };
  68.  
  69.     function unregister(id) {
  70.       delete callbackRegistry[id];
  71.     }
  72.   }
  73.  
  74.   function register(registry, description){
  75.     if(typeof registry == 'string'){
  76.       eventApi[registry] = description;
  77.       events[registry] = apiConstructor();
  78.     }else if(typeof registry === 'object'){
  79.       _.extend(eventApi, registry);
  80.       for (var event in registry) {
  81.         if (registry.hasOwnProperty(event) && !events.hasOwnProperty(event)) {
  82.           events[event] = apiConstructor();
  83.         }
  84.       }
  85.     }
  86.   }
  87.  
  88.   window.onresize = function(){
  89.     events.resize.trigger();
  90.   };
  91.  
  92.   return events;
  93.  
  94. }]);
  95. ;'use strict';
  96. angular.module('pgCore').factory('features', ['$http', '$q', function ($http, $q) {
  97.   var featuresPromise;
  98.   var features = {
  99.     getFeatures: function () {
  100.       if (features.loaded) return $q.when(features);
  101.       if (featuresPromise) return featuresPromise;
  102.       featuresPromise = $http.get('./features.json').then(function (data) {
  103.         features.loaded = true;
  104.         return _.extend(features, data.data);
  105.       }).finally(function () {
  106.         featuresPromise = null;
  107.       });
  108.       return featuresPromise;
  109.     },
  110.     on: function(featureName) {
  111.       return !!features[featureName];
  112.     }
  113.   };
  114.   return features;
  115. }]);
  116. ;'use strict';
  117.  
  118. angular.module('pgCore').factory('helpers', [function() {
  119.  
  120.   var helpers ={
  121.  
  122.     getUID: function(){
  123.       //UUID generator was taken form joint.js uuid generator to match cuurent style
  124.       return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  125.         var r = Math.random() * 16|0;
  126.         var v = c == 'x' ? r : (r&0x3|0x8);
  127.         return v.toString(16);
  128.       });
  129.     },
  130.  
  131.     formatDate: function(date,increment){
  132.       if (!date) return null;
  133.       date = new Date(date);
  134.       date = new Date(date.setDate(date.getDate()+(!!increment && parseInt(increment))));
  135.       return (date.getMonth()+1)+'/'+date.getDate()+'/'+date.getFullYear();
  136.     },
  137.  
  138.     b64toBlob: function(b64Data, contentType, sliceSize) {
  139.       contentType = contentType || '';
  140.       sliceSize = sliceSize || 512;
  141.       var byteCharacters = atob(b64Data);
  142.       var byteArrays = [];
  143.  
  144.       for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
  145.         var slice = byteCharacters.slice(offset, offset + sliceSize);
  146.  
  147.         var byteNumbers = new Array(slice.length);
  148.         for (var i = 0; i < slice.length; i++) {
  149.           byteNumbers[i] = slice.charCodeAt(i);
  150.         }
  151.  
  152.         var byteArray = new Uint8Array(byteNumbers);
  153.  
  154.         byteArrays.push(byteArray);
  155.       }
  156.  
  157.       return new Blob(byteArrays, { type: contentType});
  158.     },
  159.  
  160.     blob2file: function(blob, name){
  161.       return _.extend(blob, { name: name, lastModified: new Date().getTime(), lastModifiedDate: new Date(), webkitRelativePath: '' });
  162.     },  
  163.  
  164.     b64toFile: function (b64Data, name, contentType, sliceSize){
  165.       return helpers.blob2file(helpers.b64toBlob(b64Data, contentType, sliceSize) ,name)
  166.     },
  167.  
  168.     refreshMap: function(obj,defaults){
  169.       for (var prop in obj) { if (obj.hasOwnProperty(prop)) { delete obj[prop]; } };
  170.       if(defaults) _.extend(obj,defaults);
  171.     },
  172.  
  173.     getUniqueProp: function(arr,prop){
  174.       return _.uniq(_.pluck(arr, prop));
  175.     },
  176.  
  177.     getYoutubeUrlFromText: function (text) {
  178.       var regex = /(http(s)?:\/\/)?(\w+\.)?(youtube\.com\/((watch\?v=(\S){11})|(embed\/(\S){11}))|youtu\.be\/(\S){11})/i
  179.       var url = regex.exec(text);
  180.       return url && url[0];
  181.     },
  182.  
  183.     getYoutubeIdFromUrl: function (text) {
  184.       var regexReplace = /(http(s)?:\/\/)?(\w+\.)?(youtube\.com\/((watch\?v=)|(embed\/))|youtu\.be\/)/ig
  185.       var url = helpers.getYoutubeUrlFromText(text);
  186.       if (!url || !url.length) return null;
  187.       return url.replace(regexReplace, '');
  188.     }
  189.  
  190.   }
  191.   return helpers
  192. }]);
  193. ;'use strict';
  194. angular.module('pgCore').factory('i18n', ['$rootScope', '$route', '$http', '$q', '$location', function ($rootScope, $route, $http, $q, $location) {
  195.   var promise;
  196.   var i18n = {};
  197.   var locale = ($route.current.params.lang && $route.current.params.lang.toLowerCase()) || 'en';
  198.  
  199.   var i18nFactory =  {
  200.     locale: locale,
  201.  
  202.     ready: function () {
  203.       if (i18n.loaded) return $q.when(i18nFactory);
  204.       if (promise) return promise;
  205.       promise = $http.get('./lang/'+locale+'/common.json').then(function (data) {
  206.         i18n.loaded = true;
  207.         _.extend(i18n, data.data);
  208.         return i18nFactory;
  209.       }).catch(function(error){
  210.         i18nFactory.locale = locale = 'en';
  211.         console.error(error);
  212.         return i18nFactory;
  213.       }).finally(function () {
  214.         // promise = null;
  215.       });
  216.       return promise;
  217.     },
  218.  
  219.     get: function(key){
  220.       return i18n[key];
  221.     }
  222.  
  223.   };
  224.  
  225.  
  226.   $rootScope.$on('$routeChangeStart', function(event,next,curr){
  227.       if(curr && next && curr.params.lang !== next.params.lang){
  228.         location.reload();
  229.       }
  230.   });
  231.  
  232.   return i18nFactory;
  233.  
  234. }]);
  235. ;'use strict';
  236. angular.module('pgCore').factory('logger', ['$http', '$q', function ($http, $q) {
  237.     var fakeConsole = {},
  238.     registry = (localStorage.getItem('pgConsole') && JSON.parse(localStorage.getItem('pgConsole'))) || {},
  239.     logger = {
  240.         register: function (service) {
  241.             if (registry[service]) {
  242.                 turnOn(service);
  243.             } else {
  244.                 turnOff(service);
  245.             }
  246.             return logger[service];
  247.         }
  248.     };
  249.     Object.keys(console).forEach(function (key) {
  250.         fakeConsole[key] = function () { return; };
  251.     })
  252.     registry && registry.general ? turnOn() : turnOff();
  253.  
  254.     window.pgConsole = {
  255.         on: turnOn,
  256.         off: turnOff,
  257.         isOn: function(service){
  258.             if(service){
  259.                 return !!registry[service];
  260.             }else{
  261.                 return !!registry.general;
  262.             }
  263.         },
  264.         list: function(){
  265.             return registry;
  266.         }
  267.     }  
  268.  
  269.     function turnOn(service) {
  270.         if(service && service !== 'all'){
  271.             if (!logger[service]) logger[service] = {};
  272.             Object.assign(logger[service], console);
  273.             registry[service] = true;
  274.         }else if(service && service === 'all'){
  275.             Object.assign(logger, console);
  276.             registry.all = true;
  277.             Object.keys(registry).forEach(function(key){
  278.                 if (!logger[key]) logger[key] = {};
  279.                 Object.assign(logger[key], console);
  280.                 registry[key] = true;
  281.             });
  282.         }else{
  283.             Object.assign(logger, console);
  284.             registry.general = true;
  285.         }
  286.         localStorage.setItem('pgConsole', JSON.stringify(registry));
  287.  
  288.     }
  289.  
  290.     function turnOff(service){
  291.         if (service && service !== 'all') {
  292.             if (!logger[service]) logger[service] = {};
  293.             Object.assign(logger[service], fakeConsole);
  294.             registry[service] = false;
  295.         } else if (service && service === 'all') {
  296.             Object.assign(logger, fakeConsole);
  297.             registry.all = false;
  298.             Object.keys(registry).forEach(function (key) {
  299.                 if (!logger[key]) logger[key] = {};
  300.                 Object.assign(logger[key], fakeConsole);
  301.                 registry[key] = false;
  302.             });
  303.         } else {
  304.             Object.assign(logger, fakeConsole);
  305.             registry.general = false;
  306.         }
  307.         localStorage.setItem('pgConsole', JSON.stringify(registry));
  308.     }
  309.  
  310.     return logger;
  311. }]);
  312. ;'use strict';
  313. angular.module('pgCore').factory('pgService', ['$http','$q','config', 'events','helpers', function($http, $q, config, events, helpers) {
  314.   var apiUrl = apiUrl = config && config.apiUrl || '';
  315.   var inactiveLimit = 5400000; // (90 MINS) will log you out if inactive for this long
  316.   var token = localStorage.getItem('PG_Token');
  317.   var tokenTimeout = parseInt(localStorage.getItem('PG_TokenTimeout'));
  318.   var sessionTimeout = parseInt(localStorage.getItem('PG_SessionTimeout'));
  319.  
  320.   if(token){
  321.     $http.defaults.headers.common['Authorization'] = token;
  322.   }
  323.  
  324.   config.getConfig().then(function(){
  325.     apiUrl = config && config.apiUrl || '';
  326.   });
  327.  
  328.   var service = {
  329.     //STORAGE
  330.     currentUserRole: { id: null },
  331.     currentUser: {},
  332.  
  333.     //APP HELPERS
  334.     login: login,
  335.     logout: logout,
  336.     isLoggedIn: isLoggedIn,
  337.     getApiUrl: getApiUrl,
  338.     getAuthToken: getAuthToken,
  339.  
  340.     //USERS
  341.     getCurrentUser: getCurrentUser,
  342.     getCurrentUserRole: getCurrentUserRole,
  343.     getUsers: getUsers,
  344.     getUserById: getUserById,
  345.     createUserGroup: createUserGroup,
  346.     updateUserRole: updateUserRole,
  347.  
  348.     //MEETINGS
  349.     getMeetingById: getMeetingById,
  350.     getUpcomingMeetings: getUpcomingMeetings,
  351.     getPreviousMeetings: getPreviousMeetings,
  352.     getMeetingsByDateRange: getMeetingsByDateRange,
  353.     getMeetingLite: getMeetingLite,
  354.     getMeetingContents: getMeetingContents,
  355.     getMeetingDetails: getMeetingDetails,
  356.     getMeetingTemplate: getMeetingTemplate,
  357.     getMeetingDocument: getMeetingDocument,
  358.     getMeetingSections: getMeetingSections,
  359.     getMeetingSectionItems: getMeetingSectionItems,
  360.     getMeetingSectionMotions: getMeetingSectionMotions,
  361.     getMeetingSectionMinutes: getMeetingSectionMinutes,
  362.     getMeetingSectionActions: getMeetingSectionActions,
  363.     getMeetingSectionNotes: getMeetingSectionNotes,
  364.     getMeetingItemMotions: getMeetingItemMotions,
  365.     getMeetingItemMinutes: getMeetingItemMinutes,
  366.     getMeetingItemActions: getMeetingItemActions,
  367.     getMeetingItemNotes: getMeetingItemNotes,
  368.     getMeetingItemAttachments: getMeetingItemAttachments,
  369.     getSystemItemAttachments: getSystemItemAttachments,
  370.     getMeetingAttendees: getMeetingAttendees,
  371.     getMeetingRoles: getMeetingRoles,
  372.     getMeetingTypes: getMeetingTypes,
  373.     getItemTypes: getItemTypes,
  374.     getMotionTypes: getMotionTypes,
  375.     getItemMotionById: getItemMotionById,
  376.     getSectionMotionById: getSectionMotionById,
  377.     getFormattedMotionTextbyType: getFormattedMotionTextbyType,
  378.     getSectionFormattedMotionTextbyType: getSectionFormattedMotionTextbyType,
  379.     getItemPublicSpeakers: getItemPublicSpeakers,
  380.  
  381.     createMeeting: createMeeting,
  382.     createSection: createSection,
  383.     createSystemItem: createSystemItem,
  384.     createMeetingItem: createMeetingItem,
  385.     createItemMotion: createItemMotion,
  386.     createSectionMotion: createSectionMotion,
  387.     createItemMinute: createItemMinute,
  388.     createSectionMinute: createSectionMinute,
  389.     createItemAction: createItemAction,
  390.     createSectionAction: createSectionAction,
  391.     createItemNote: createItemNote,
  392.     createSectionNote: createSectionNote,
  393.     createPublicSpeaker: createPublicSpeaker,
  394.  
  395.     addMeetingTypeAttendee: addMeetingTypeAttendee,
  396.     addAdHocAttendee: addAdHocAttendee,
  397.  
  398.     updateMeeting: updateMeeting,
  399.     updateMeetingAttendees: updateMeetingAttendees,
  400.  
  401.     deleteMeeting: deleteMeeting,
  402.     deleteSection: deleteSection,
  403.     deleteMeetingItem: deleteMeetingItem,
  404.     deleteItemMinute: deleteItemMinute,
  405.     deleteSectionMinute: deleteSectionMinute,
  406.     deleteItemAction: deleteItemAction,
  407.     deleteSectionAction: deleteSectionAction,
  408.     deleteItemNote: deleteItemNote,
  409.     deleteSectionNote: deleteSectionNote,
  410.     deleteItemMotion: deleteItemMotion,
  411.     deleteSectionMotion: deleteSectionMotion,
  412.     deletePublicSpeaker: deletePublicSpeaker,
  413.     deleteMeetingTypeUserRole: deleteMeetingTypeUserRole,
  414.  
  415.     activateSection: activateSection,
  416.     activateItem: activateItem,
  417.  
  418.     sortItems: sortItems,
  419.     sortSections: sortSections,
  420.  
  421.     compileAgenda: compileAgenda,
  422.     publishAgenda: publishAgenda,
  423.     meetingSearch: meetingSearch,
  424.  
  425.  
  426.     //ATTACHMENTS
  427.     getAttachmentViewerTemplates: getAttachmentViewerTemplates,
  428.     getAttachmentViewerRedactionReasons: getAttachmentViewerRedactionReasons,
  429.     getAttachmentViewerLanguageJson: getAttachmentViewerLanguageJson,
  430.     getAttachmentViewerSearchJson: getAttachmentViewerSearchJson,
  431.     getAttachmentViewerSessionId: getAttachmentViewerSessionId,
  432.     getDownloadItemAttachment: getDownloadItemAttachment,
  433.     getAttachmentDownloadUrl: getAttachmentDownloadUrl,
  434.     getAttachmentPDFDownloadUrl: getAttachmentPDFDownloadUrl,
  435.     uploadAttachment: uploadAttachment,
  436.     loadAttachmentAnnotations: loadAttachmentAnnotations,
  437.     saveAttachmentAnnotations: saveAttachmentAnnotations,
  438.  
  439.  
  440.     //COMMITTEES
  441.     getCommittees: getCommittees,
  442.     getCommiteePositions: getCommiteePositions,
  443.  
  444.     //FORMS
  445.     getFormById: getFormById,
  446.     getFormsByType: getFormsByType,
  447.  
  448.     //DOCUMENTS
  449.     getDocumentById: getDocumentById,
  450.     getDocumentComments: getDocumentComments,
  451.     getDocumentAttachments: getDocumentAttachments,
  452.     getDocumentAttachmentDownloadUrl: getDocumentAttachmentDownloadUrl,
  453.     downloadDocumentById: downloadDocumentById,
  454.     addDocumentComment: addDocumentComment,
  455.     updateDocumentComment: updateDocumentComment,
  456.     uploadDocumentAttachment: uploadDocumentAttachment,
  457.     convertDocumnetAttachmentToPdf: convertDocumnetAttachmentToPdf,
  458.     deleteDocumentAttachment: deleteDocumentAttachment,
  459.  
  460.     //WORKFLOW AND TASKS
  461.     getMyWorkflowTasks: getMyWorkflowTasks,
  462.     getAllWorkflowTasks: getAllWorkflowTasks,
  463.     getWorkflowTaskById: getWorkflowTaskById,
  464.     getWorkflowTaskChoices: getWorkflowTaskChoices,
  465.     completeTask: completeTask,
  466.  
  467.  
  468.     //YOUTUBE
  469.     youtubeAuthList: youtubeAuthList,
  470.     youtubeAuthById: youtubeAuthById,
  471.  
  472.     //PUBLIC APIS
  473.     getMeetingTypesPublic: getMeetingTypesPublic,
  474.     getCommitteesPublic: getCommitteesPublic,
  475.     meetingSearchPublic: meetingSearchPublic,
  476.     getUpcomingMeetingsPublic: getUpcomingMeetingsPublic,
  477.     getPreviousMeetingsPublic: getPreviousMeetingsPublic,
  478.     getMeetingsByDateRangePublic: getMeetingsByDateRangePublic,
  479.     getMeetingByDateAndTypePublic: getMeetingByDateAndTypePublic,
  480.     getPublishedDownloadUrl: getPublishedDownloadUrl,
  481.     getMeetingAgendaHtml: getMeetingAgendaHtml,
  482.     getMeetingItemAttachmentsPublic: getMeetingItemAttachmentsPublic,
  483.     getMeetingItemDocumentAttachmentsPublic: getMeetingItemDocumentAttachmentsPublic,
  484.     getPdfDownloadUrlPublic: getPdfDownloadUrlPublic,
  485.     getItemVideoLocationPublic: getItemVideoLocationPublic,
  486.     createPublicSpeakerPublic: createPublicSpeakerPublic,
  487.     getMeetingSectionItemsPublic: getMeetingSectionItemsPublic,
  488.     submitFormPublic: submitFormPublic,
  489.    
  490.   };
  491.  
  492.   return service;
  493.  
  494.  
  495.   /**
  496.    * ********* APP HELPERS  ***********************************************
  497.    */
  498.  
  499.   function login(username, password) {
  500.     return getAuthToken(username, password).then(function (token) {
  501.       if(token){
  502.         getCurrentUser();
  503.         return {success: true};
  504.       }
  505.       if(!token) return {error:'Login failed'};
  506.     }, function (error) {
  507.       return {error: error}
  508.     });
  509.   }
  510.  
  511.   function logout(){
  512.     localStorage.removeItem('PG_Token');
  513.     localStorage.removeItem('PG_TokenTimeout');
  514.     localStorage.removeItem('PG_UserName');
  515.     localStorage.removeItem('PG_SessionTimeout');
  516.     helpers.refreshMap(service.currentUser);
  517.     events.loggedOut.trigger();
  518.     return $q.when(false);
  519.   }
  520.  
  521.   function isLoggedIn(){
  522.     token = localStorage.getItem('PG_Token');
  523.     tokenTimeout = parseInt(localStorage.getItem('PG_TokenTimeout'));
  524.     sessionTimeout = parseInt(localStorage.getItem('PG_SessionTimeout'));
  525.     return !!token && !!sessionTimeout && sessionTimeout > new Date().getTime() - inactiveLimit;
  526.   }
  527.  
  528.   function getApiUrl(){
  529.     if(apiUrl && apiUrl.length){
  530.       return $q.when(apiUrl);
  531.     }else{
  532.       return config.getConfig().then(function () {
  533.         return apiUrl = config && config.apiUrl || '';
  534.       });
  535.     }
  536.    
  537.   }
  538.  
  539.   /**
  540.    * ********* USERS API  ***********************************************
  541.    */
  542.  
  543.   function getCurrentUser(){
  544.     if(service.currentUser.id){
  545.       return $q.when(service.currentUser);
  546.     }else{
  547.       return get('/api/user/getcurrent').then(function(data){
  548.         if(data) data.role = service.currentUserRole;
  549.         events.currentUserReady.trigger(data);
  550.         return _.extend(service.currentUser, data);
  551.       });
  552.     }
  553.   }
  554.  
  555.   function getCurrentUserRole(meetingTypeId) {
  556.     return get('/api/meetingTypeUserRole/ListForCurrentUser?meetingTypeId=' + meetingTypeId);
  557.   }
  558.  
  559.   function getUsers(){
  560.     return get('/api/user/list');
  561.   }
  562.  
  563.   function getUserById(id){
  564.     return get('/api/user/get?userId='+id);
  565.   }
  566.  
  567.   function createUserGroup(params){
  568.     // params: users, name, description, id
  569.     return post('/api/userGroup/post',params)
  570.   }
  571.  
  572.   function updateUserRole(id, role){
  573.     return post('/api/meetingTypeUserRole/updateUserRole?id=' + id + '&role=' + role);
  574.   }
  575.  
  576.  
  577.   /**
  578.    * ********* MEETINGS API  ***********************************************
  579.    */
  580.  
  581.   function getMeetingById(id) {
  582.     return get('/api/meeting/GetMeetingLite?Id=' + id)
  583.   }
  584.  
  585.   function getUpcomingMeetings() {
  586.     return get('/api/meeting/listupcoming');
  587.   }
  588.  
  589.   function getPreviousMeetings() {
  590.     return get('/api/meeting/listprevious');
  591.   }
  592.  
  593.   function getMeetingsByDateRange(from, to) {
  594.     return get('/api/meeting/search?from=' + from + '&to=' + to + '&_=' + new Date().getTime());
  595.   }
  596.  
  597.   function getMeetingLite(id) {
  598.     return get('/api/meeting/GetMeetingLite?Id=' + id);
  599.   }
  600.  
  601.   function getMeetingContents(id) {
  602.     return get('/api/meeting/GetMeetingContents/' + id);
  603.   }
  604.   //overloaded for legacy
  605.   function getMeetingDetails(id){
  606.     return get('/api/meeting/GetMeetingContents/'+id);
  607.   }
  608.  
  609.   function getMeetingTemplate(id){
  610.     return get('/api/meetingTemplate/list?meetingId='+id);
  611.   }
  612.  
  613.   function getMeetingDocument(id) {
  614.     return get('/api/compiledMeetingDocument/listForMeeting?meetingId=' + id);
  615.   }
  616.  
  617.   function getMeetingSections(meeting) {
  618.     return post('/api/meetingsectiontemplate/ListForPreMeetingWithFormatting', {
  619.       id: meeting.id,
  620.       numberingType: meeting.numberingType,
  621.       numberPrefixCharacter: meeting.numberPrefixCharacter,
  622.       numberTrailingCharacter: meeting.numberTrailingCharacter
  623.     });
  624.   }
  625.  
  626.   function getMeetingSectionItems(section, meetingId) {
  627.     return post('/api/meetingitem/ListForPreMeetingBySection', {
  628.       id: section.id,
  629.       itemHtml: section.itemHtml,
  630.       meetingId: meetingId,
  631.       tabIndent: section.tabIndent,
  632.       numberTrailingCharacter: section.numberTrailingCharacter,
  633.       numberingContinuous: section.numberingContinuous,
  634.       numberingType: section.numberingType,
  635.       numberPrefixCharacter: section.numberPrefixCharacter
  636.     });
  637.   }
  638.  
  639.   function getMeetingSectionMotions(id) {
  640.     return get('/api/meetingsectionmotion/GetSectionMotionsAndVotesWithFormatting?sectionId=' + id);
  641.   }
  642.  
  643.   function getMeetingSectionMinutes(id) {
  644.     return get('/api/meetingsectionminutes/GetSectionMinutesWithFormatting?sectionId=' + id);
  645.   }
  646.  
  647.   function getMeetingSectionActions(id) {
  648.     return get('/api/meetingsectionactions/GetSectionActionswithFormatting?sectionId=' + id);
  649.   }
  650.  
  651.   function getMeetingSectionNotes(id) {
  652.     return get('/api/meetingsectionnotes/list?itemid=' + id);
  653.   }
  654.  
  655.   function getMeetingItemMotions(id) {
  656.     return get('/api/meetingitemmotion/GetItemMotionsAndVotesWithFormatting?itemId=' + id);
  657.   }
  658.  
  659.   function getMeetingItemMinutes(id) {
  660.     return get('/api/meetingitemminutes/GetItemMinuteswithFormatting?itemId=' + id);
  661.   }
  662.  
  663.   function getMeetingItemActions(id) {
  664.     return get('/api/meetingitemactions/GetItemActionswithFormatting?itemId=' + id);
  665.   }
  666.  
  667.   function getMeetingItemNotes(id) {
  668.     return get('/api/meetingitemnotes/list?itemid=' + id);
  669.   }
  670.  
  671.   function getMeetingItemAttachments(id) {
  672.     return get('/api/meetingitemattachment/list?meetingitemid=' + id);
  673.   }
  674.  
  675.   function getSystemItemAttachments(id) {
  676.     return get('/api/systemitemattachment2/list?itemId=' + id)
  677.   }
  678.  
  679.   function getMeetingAttendees(id) {
  680.     return get('/api/meetingAttendee/list?meetingId=' + id);
  681.   }
  682.  
  683.   function getMeetingRoles(meetingTypeId) {
  684.     return get('/api/meetingTypeUserRole/list?meetingTypeId=' + meetingTypeId);
  685.   }
  686.  
  687.   function getMeetingTypes() {
  688.     return get('/api/meetingtype/list');
  689.   }
  690.  
  691.   function getItemTypes() {
  692.     return get('/api/systemitemtype/list');
  693.   }
  694.  
  695.   function getMotionTypes() {
  696.     return get('/api/motionType/List');
  697.   }
  698.  
  699.   function getItemMotionById(motionId) {
  700.     return get('/api/meetingitemmotion/get/' + motionId);
  701.   }
  702.  
  703.   function getSectionMotionById(motionId) {
  704.     return get('/api/meetingsectionmotion/get/' + motionId);
  705.   }
  706.  
  707.   function getFormattedMotionTextbyType(motionTypeId, meetingItemId) {
  708.     return get('/api/motionType/format/' + motionTypeId + '?meetingItemId=' + meetingItemId);
  709.   }
  710.  
  711.   function getSectionFormattedMotionTextbyType(motionTypeId, meetingSectionId, meetingItemIds) {
  712.     return post('/api/motionType/formatSection/' + motionTypeId + '?meetingSectionId=' + meetingSectionId, { meetingItemIds: meetingItemIds } );
  713.   }
  714.  
  715.   function getItemPublicSpeakers(meetingId, itemId) {
  716.     return get('/api/publicspeaker/listforitem?meetingid=' + meetingId + '&itemid=' + itemId);
  717.   }
  718.  
  719.   function createMeeting(params){
  720.     return post('/api/meeting/create', {}, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}, params:params});
  721.   }
  722.  
  723.   function createSection(params){
  724.     return post('/api/meetingsectiontemplate/create', {}, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}, params:params});
  725.   }
  726.  
  727.   function createSystemItem(params){
  728.     return post('/api/systemitem/post',params);
  729.   }
  730.  
  731.   function createMeetingItem(params){
  732.     return post('/api/meetingItem/post',params);
  733.   }
  734.  
  735.   function createItemMotion(params){
  736.     return post('/api/meetingitemmotion/postAndReturnFormatting', params);
  737.   }
  738.  
  739.   function createSectionMotion(params){
  740.     return post('/api/meetingsectionmotion/postAndReturnFormatting', params);
  741.   }
  742.  
  743.   function createItemMinute(params){
  744.     return post('/api/meetingitemminutes/post', params);
  745.   }
  746.  
  747.   function createSectionMinute(params){
  748.     return post('/api/meetingsectionminutes/post', params);
  749.   }
  750.  
  751.   function createItemAction(params) {
  752.     return post('/api/meetingitemactions/post', params);
  753.   }
  754.  
  755.   function createSectionAction(params) {
  756.     return post('/api/meetingsectionactions/post', params);
  757.   }
  758.  
  759.   function createItemNote(params) {
  760.     return post('/api/meetingitemnotes/post', params);
  761.   }
  762.  
  763.   function createSectionNote(params) {
  764.     return post('/api/meetingsectionnotes/post', params);
  765.   }
  766.  
  767.   function createPublicSpeaker(params) {
  768.     return post('/api/publicspeaker/post', params);
  769.   }
  770.  
  771.   function addMeetingTypeAttendee(params){
  772.     return post('/api/meetingTypeUserRole/post', params);
  773.   }
  774.  
  775.   function addAdHocAttendee(params) {
  776.     return post('/api/MeetingAttendee/AddAdHocAttendee', params);
  777.   }
  778.  
  779.   function updateMeeting(params){
  780.     return post('/api/meeting/post', params);
  781.   }
  782.  
  783.   function updateMeetingAttendees(params) {
  784.     return post('/api/meetingAttendee/post', params)
  785.   }
  786.  
  787.   function deleteMeeting(id){
  788.     return post('/api/meeting/delete/'+id);
  789.   }
  790.  
  791.   function deleteSection(id){
  792.     return post('/api/meetingsectiontemplate/delete/'+id);
  793.   }
  794.  
  795.   function deleteMeetingItem(params){
  796.     return post('/api/meetingitem/remove',{}, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}, params:params})
  797.   }
  798.  
  799.   function deleteItemMinute(id) {
  800.     return post('/api/meetingitemminutes/delete/' + id);
  801.   }
  802.  
  803.   function deleteSectionMinute(id) {
  804.     return post('/api/meetingsectionminutes/delete/' + id);
  805.   }
  806.  
  807.   function deleteItemAction(id) {
  808.     return post('/api/meetingitemactions/delete/' + id);
  809.   }
  810.  
  811.   function deleteSectionAction(id) {
  812.     return post('/api/meetingsectionactions/delete/' + id);
  813.   }
  814.  
  815.   function deleteSectionNote(id) {
  816.     return post('/api/meetingsectionnotes/delete/' + id)
  817.   }
  818.  
  819.   function deleteItemNote(id) {
  820.     return post('/api/meetingitemnotes/delete/' + id)
  821.   }
  822.  
  823.   function deleteItemMotion(id) {
  824.     return post('/api/meetingitemmotion/delete/' + id);
  825.   }
  826.  
  827.   function deleteSectionMotion(id) {
  828.     return post('/api/meetingsectionmotion/deletemotion/' + id);
  829.   }
  830.  
  831.   function deletePublicSpeaker(id) {
  832.     return post('/api/publicspeaker/delete?id=' + id);
  833.   }
  834.  
  835.   function deleteMeetingTypeUserRole(id){
  836.     return post('/api/meetingTypeUserRole/delete/'+id)
  837.   }
  838.  
  839.   function activateSection(id) {
  840.     return post('/api/meetingSection/activateSection/' + id);
  841.   }
  842.  
  843.   function activateItem(id) {
  844.     return post('/api/meetingItem/activate/' + id);
  845.   }
  846.  
  847.   function sortItems(params) {
  848.     return post('/api/meetingitem/sort', {}, { params: params });
  849.   }
  850.  
  851.   function sortSections(params) {
  852.     return post('/api/meetingsectiontemplate/sort', {}, { params: params });
  853.   }
  854.  
  855.   function compileAgenda(params){
  856.     return post('/api/meeting/compile',params);
  857.   }
  858.  
  859.   function publishAgenda(id){
  860.     return post('/api/compiledMeetingDocument/publish/'+id,{publish:1})
  861.   }
  862.  
  863.   function meetingSearch(params){
  864.     return get('/api/meeting/search',{params:params});
  865.   }
  866.  
  867.   /**
  868.    * ********* ATTACHMENTS API  ***********************************************
  869.    */
  870.  
  871.   function getAttachmentViewerTemplates() {
  872.     return get('/api/accusoftviewer/gettemplates');
  873.   }
  874.  
  875.   function getAttachmentViewerRedactionReasons() {
  876.     return get('/api/accusoftviewer/getredactonreasons');
  877.   }
  878.  
  879.   function getAttachmentViewerLanguageJson() {
  880.     return get('/api/accusoftviewer/getlanguagejson');
  881.   }
  882.  
  883.   function getAttachmentViewerSearchJson() {
  884.     return get('/api/accusoftviewer/GetSearchJson');
  885.   }
  886.  
  887.   function getAttachmentViewerSessionId(name) {
  888.     return post('/api/AccusoftViewer/GetSessionId?documentName=' + name + '.pdf');
  889.   }
  890.  
  891.   function getDownloadItemAttachment(attachmentId) {
  892.     return get('/api/systemItemAttachment2/DownloadItemAttachment?id=' + attachmentId);
  893.   }
  894.  
  895.   function getAttachmentDownloadUrl(id) {
  896.     return get('/api/systemitemattachment/getdownloadurl/' + id);
  897.   }
  898.  
  899.   function getAttachmentPDFDownloadUrl(id) {
  900.     return get('/api/systemitemattachment/getdownloadurlforpdf/' + id);
  901.   }
  902.  
  903.   function uploadAttachment(file, itemId) {
  904.     var deffered = $q.defer();
  905.     var flow = new Flow({ target: apiUrl + '/api/systemitemattachment/upload', query: { systemItemId: itemId }, testChunks: false, headers: { Authorization: token } });
  906.     flow.on('complete', deffered.resolve);
  907.     flow.addFile(file);
  908.     flow.upload();
  909.     return deffered.promise;
  910.   }
  911.  
  912.   function loadAttachmentAnnotations(docId, userId, id, type) {
  913.     return get('/api/accusoftviewer/loadannotations/q?SessionID=u' + docId + '&username=' + userId + '&id=' + id + '&type=' + type)
  914.   }
  915.  
  916.   function saveAttachmentAnnotations(docId, userId, id, type, params) {
  917.     return post('/api/accusoftviewer/saveannotations/q?SessionID=u' + docId + '&username=' + userId + '&id=' + id + '&type=' + type, params)
  918.   }
  919.  
  920.  
  921.  
  922.   /**
  923.    * ********* COMMITEES API  ***********************************************
  924.    */
  925.  
  926.   function getCommittees(){
  927.     return post('/api/committee/list');
  928.   }
  929.  
  930.   function getCommiteePositions(id, date) {
  931.     return get('/api/committeeposition/listfordate?committeeId=' + id + '&date=' + date);
  932.   }
  933.  
  934.  
  935.   /**
  936.    * ********* FORMS API  ***********************************************
  937.    */
  938.  
  939.   function getFormById(formId) {
  940.     return get('/api/formInstance/get/' + formId)
  941.   }
  942.  
  943.   function getFormsByType(typeId, archived){
  944.     return get('/api/formInstance/listForDefinition/?id='+typeId+'&getArchived='+!!archived) ;
  945.   }
  946.  
  947.   /**
  948.    * ********* DOCUMENTS API  ***********************************************
  949.    */
  950.  
  951.   function getDocumentById(docId){
  952.     return get('/api/systemdocument/get?id='+docId);
  953.   }
  954.  
  955.   function getDocumentComments(docId){
  956.     return get('/api/systemdocumentcomment/list?id='+docId)
  957.   }
  958.  
  959.   function getDocumentAttachments(docId){
  960.     return get('/api/systemdocumentattachment/list/'+docId);
  961.   }
  962.  
  963.   function getDocumentAttachmentDownloadUrl(id){
  964.     return get('/api/systemdocumentattachment/getdownloadurl/'+id);
  965.   }
  966.  
  967.   function getDocumentsByType(id){
  968.     return get('api/systemDocument/ListByDocumentType/'+id);
  969.   }
  970.  
  971.   function searchDocuments(term){
  972.     return get('/api/systemdocument/search/?searchTerm='+term);
  973.   }
  974.  
  975.   function downloadDocumentById(docId){
  976.     return get('/api/systemdocument/DownloadSystemDocument?id='+docId);
  977.   }
  978.  
  979.   function addDocumentComment(docId, text, type){
  980.     return post('/api/systemdocumentcomment/post', { Id: 0, CommentById: 0, SystemDocumentId: docId, Comment: text, Type: type || 0 })
  981.   }
  982.  
  983.   function updateDocumentComment(commentId, userId, docId, text, type) {
  984.     return post('/api/systemdocumentcomment/post', { Id: commentId, CommentById:userId || 0, SystemDocumentId: docId, Comment: text, Type: type || 0 })
  985.   }
  986.  
  987.   function uploadDocumentAttachment(file, docId) {
  988.     var deffered = $q.defer();
  989.     var flow = new Flow({ target: apiUrl + '/api/systemdocumentattachment/upload', query: { systemDocumentId: docId }, testChunks: false, headers:{ Authorization : token} });
  990.     flow.on('fileSuccess', function(file ,id){
  991.       deffered.resolve({file:file, id:id});
  992.     });
  993.     flow.addFile(file);
  994.     flow.upload();
  995.     return deffered.promise;
  996.   }
  997.  
  998.   function convertDocumnetAttachmentToPdf(id){
  999.     return post('/api/systemdocumentattachment/converttopdf?Id='+id)
  1000.   }
  1001.  
  1002.   function deleteDocumentAttachment(id){
  1003.     return post('/api/systemdocumentattachment/delete?Id='+id);
  1004.   }
  1005.  
  1006.  
  1007.   /**
  1008.    * ********* WORKFLOW AND TASKS API  ***********************************************
  1009.    */
  1010.  
  1011.   function getMyWorkflowTasks(completed) {
  1012.     return get('/api/workflow_Task/listActive?completed=' + !!completed + '&showAll=false');
  1013.   }
  1014.  
  1015.   function getAllWorkflowTasks(completed) {
  1016.     return get('/api/workflow_Task/listActive?completed='+!!completed+'&showAll=true');
  1017.   }
  1018.  
  1019.   function getWorkflowTaskById(id){
  1020.     return get('/api/workflow_Task/get/'+id);
  1021.   }
  1022.  
  1023.   function getWorkflowTaskChoices(id){
  1024.     return get('/api/workflow_Task/getTaskChoices/'+id);
  1025.   }
  1026.  
  1027.   function completeTask(params){
  1028.     // params: id, choice, comments
  1029.     return post('/api/workflow_Task/completeTask', params)
  1030.   }
  1031.  
  1032.   /**
  1033.    * ******** YOUTUBE API ***************************************************
  1034.    */
  1035.  
  1036.   function youtubeAuthList(){
  1037.     return get('/api/youtubeauth/list');
  1038.   }
  1039.   function youtubeAuthById(id){
  1040.     return get('/api/youtubeauth/get?id='+id);
  1041.   }
  1042.  
  1043.   /**
  1044.    * ******** PUBLIC API ***************************************************
  1045.    */
  1046.  
  1047.   function getMeetingTypesPublic() {
  1048.     return publicGet('/api/meetingtype/list');
  1049.   }
  1050.  
  1051.   function getCommitteesPublic() {
  1052.     return publicPost('/api/committee/list');
  1053.   }
  1054.  
  1055.   function meetingSearchPublic(params) {
  1056.     return publicGet('/api/meeting/search', { params: params });
  1057.   }
  1058.  
  1059.   function getUpcomingMeetingsPublic() {
  1060.     return publicGet('/api/meeting/search?from=' + helpers.formatDate(new Date()) + '&to=' + helpers.formatDate(new Date(),180) + '&_=' + new Date().getTime());
  1061.   }
  1062.  
  1063.   function getPreviousMeetingsPublic() {
  1064.     return publicGet('/api/meeting/search?from=' + helpers.formatDate(new Date()) + '&to=' + helpers.formatDate(new Date(), -180) + '&_=' + new Date().getTime());
  1065.   }
  1066.  
  1067.   function getMeetingsByDateRangePublic(from, to) {
  1068.     return publicGet('/api/meeting/search?from=' + helpers.formatDate(from) + '&to=' + helpers.formatDate(to) + '&_=' + new Date().getTime());
  1069.   }
  1070.  
  1071.   function getMeetingByDateAndTypePublic(date,typeId) {
  1072.     return publicGet('/api/meeting/search?from=' + helpers.formatDate(date) + '&to=' + helpers.formatDate(date, 1) + '&meetingTypeId='+ typeId +'&_=' + new Date().getTime());
  1073.   }
  1074.  
  1075.   function getPublishedDownloadUrl(id){
  1076.     return publicGet('/api/compiledMeetingDocument/getpublisheddownloadurl/'+id);
  1077.   }
  1078.  
  1079.   function getMeetingAgendaHtml(meetingId, templateId){
  1080.     return publicGet('/api/portal/getMeetingBodyHtml?meetingId='+ meetingId +'&templateId='+ templateId);
  1081.   }
  1082.  
  1083.   function getMeetingItemAttachmentsPublic(itemId){
  1084.     return publicGet('/api/meetingitemattachment/ListPublic?meetingItemId='+itemId);
  1085.   }
  1086.  
  1087.   function getMeetingItemDocumentAttachmentsPublic(itemId) {
  1088.     return publicGet('/api/meetingitemattachment/listDocumentAttachmentsPublic?meetingItemId=' + itemId);
  1089.   }
  1090.  
  1091.   function getPdfDownloadUrlPublic(id){
  1092.     return publicGet('/api/meetingitemattachment/GetPublicPdfDownloadUrl/' + id)
  1093.   }
  1094.  
  1095.   function getItemVideoLocationPublic(itemId){
  1096.     return publicGet('/api/meetingitem/getVideoLocation/' + itemId);
  1097.   }
  1098.  
  1099.   function createPublicSpeakerPublic(params) {
  1100.     return publicPost('/api/publicspeaker/post', params);
  1101.   }
  1102.  
  1103.   function getMeetingSectionItemsPublic(sectionId, meetingId) {
  1104.     return publicPost('/api/meetingitem/ListForPreMeetingBySection', {
  1105.       id: sectionId,
  1106.       meetingId: meetingId
  1107.     });
  1108.   }
  1109.  
  1110.   function submitFormPublic(form /* html element */){
  1111.     var formData = new FormData(form);
  1112.     return publicPost('/api/formInstance/postPublic', formData, { headers: { 'Content-Type': undefined } });
  1113.   }
  1114.  
  1115.  
  1116.  
  1117.   /** PRIVATE FUNCTIONS *********************************************************************/
  1118.  
  1119.   function get(url, params){
  1120.     return getAuthToken().then(function(token){
  1121.       if(token){
  1122.         setSessionActivity();
  1123.         return $http.get(apiUrl + url, params).then(function(result){
  1124.           return result.data;
  1125.         });
  1126.       }else{
  1127.         console.log('session has expired');
  1128.         return logout();
  1129.       }
  1130.     });
  1131.   }
  1132.  
  1133.   function post(url, params, options){
  1134.  
  1135.     return getAuthToken().then(function(token){
  1136.       if(token){
  1137.         setSessionActivity();
  1138.         return $http.post(apiUrl + url, params, options).then(function(result){
  1139.           return result.data;
  1140.         });
  1141.       }else{
  1142.         console.log('session has expired');
  1143.         return logout();
  1144.       }
  1145.     });
  1146.   }
  1147.  
  1148.   function publicGet(url, params) {
  1149.     return $http.get(apiUrl + url, params).then(function (result) {
  1150.       return result.data;
  1151.     });
  1152.   }
  1153.  
  1154.   function publicPost(url, params, options) {
  1155.     return $http.post(apiUrl + url, params, options).then(function (result) {
  1156.       return result.data;
  1157.     });
  1158.   }
  1159.  
  1160.   function getAuthToken(un, pw){
  1161.     if(isLoggedIn()) return $q.when(token);
  1162.     if(!un || !pw) return $q.when(false);
  1163.     return $http.post(apiUrl + '/token', $.param({userName: un, password: pw, grant_type: 'password'})).then(function(result){
  1164.       if(result.data && result.data.access_token && result.data.expires_in){
  1165.         token = 'Bearer '+ result.data.access_token;
  1166.         localStorage.setItem('PG_Token', token);
  1167.         localStorage.setItem('PG_TokenTimeout',result.data.expires_in + new Date().getTime());
  1168.         localStorage.setItem('PG_SessionTimeout', new Date().getTime());
  1169.         localStorage.setItem('PG_UserName',result.data.userName);
  1170.         $http.defaults.headers.common['Authorization'] = token;
  1171.         return token;
  1172.       }
  1173.     });
  1174.   }
  1175.  
  1176.  
  1177.   function setSessionActivity(){
  1178.     localStorage.setItem('PG_SessionTimeout', new Date().getTime());
  1179.   }
  1180.  
  1181. }]);
  1182. ;angular.module('pgCore').directive('collapsable', [function() {
  1183.   return {
  1184.     restrict: 'A',
  1185.     scope: {
  1186.       collapsable:"=?collapsable",
  1187.       lineCount: "=?",
  1188.       maxHeight: "=?",
  1189.       toggle: "=?",
  1190.       deepWatch: '=?',
  1191.       disabled: '=?'
  1192.     },
  1193.     link: function(scope, elem) {
  1194.       var collapsedHeight, height, lineHeight, style, expanded;
  1195.       var $wrapper;
  1196.       var $elipse = $('<div class="collapsable-elipse" />');
  1197.       var $elipseBar = $('<div class="collapsable-elipse-bar" />').append($elipse);
  1198.  
  1199.       init();
  1200.  
  1201.       function init(){
  1202.  
  1203.         $wrapper = $('<div class="collapsable-wrapper" />')
  1204.           .html(elem.children())
  1205.           .css({'height':0})
  1206.           .appendTo(elem);
  1207.  
  1208.         elem.on('click', _.debounce(toggleExpand,300,{'leading':true,'trailing':false}))
  1209.           .addClass('collapsable')
  1210.           .append($elipseBar);
  1211.  
  1212.         if(scope.deepWatch){
  1213.           scope.$watchCollection('collapsable',load);
  1214.         }else{
  1215.           scope.$watch('collapsable',load);
  1216.         }
  1217.  
  1218.  
  1219.         scope.$watch('toggle', toggleOveride);
  1220.  
  1221.       }
  1222.  
  1223.       function load(){
  1224.         _.defer(function(){
  1225.  
  1226.           var $trueform = $wrapper.clone()
  1227.             .css({height:''})
  1228.             .addClass('collapsable-trueform')
  1229.             .appendTo(elem.parent());
  1230.  
  1231.  
  1232.           style = window.getComputedStyle($trueform[0]);
  1233.           height = parseInt(style['height'].replace('px',''));
  1234.           lineHeight = parseInt(style['lineHeight'].replace('px', '')) || parseInt(style['fontSize'].replace('px', ''))*1.165;
  1235.           collapsedHeight = (scope.lineCount || 3) * lineHeight;
  1236.  
  1237.           $trueform.remove();
  1238.           $trueform = null;
  1239.  
  1240.           $elipseBar.css({
  1241.             height: lineHeight
  1242.           }).addClass('hide-me');
  1243.  
  1244.           $wrapper.css({
  1245.             height: Math.min(collapsedHeight, height)
  1246.           }).removeClass('expanded scrollable');
  1247.  
  1248.           if(height > collapsedHeight){
  1249.             toggleExpand(null,false);
  1250.           }
  1251.  
  1252.  
  1253.         });
  1254.       }
  1255.  
  1256.       function toggleOveride(){
  1257.         if(height <= collapsedHeight) return;
  1258.         if(scope.toggle){
  1259.           expandElement();
  1260.         }else{
  1261.           collapseElement();
  1262.         }
  1263.         $elipseBar.toggleClass('hide-me',expanded);
  1264.       }
  1265.  
  1266.       function toggleExpand(e,expand){
  1267.         if(height <= collapsedHeight || !_.isUndefined(scope.toggle)) return;
  1268.         expanded = _.isUndefined(expand) ?  !expanded : expand;
  1269.         if(expanded){
  1270.           expandElement();
  1271.         }else{
  1272.           collapseElement();
  1273.         }
  1274.         $elipseBar.toggleClass('hide-me',expanded);
  1275.       }
  1276.  
  1277.       function expandElement(){
  1278.         $wrapper.css({
  1279.           height: height
  1280.         }).addClass('expanded');
  1281.         if(scope.maxHeight && scope.maxHeight < height){
  1282.           $wrapper.css({
  1283.             maxHeight: scope.maxHeight
  1284.           }).addClass('scrollable');
  1285.         }
  1286.       }
  1287.  
  1288.       function collapseElement(){
  1289.         if(scope.disabled) return;
  1290.         $wrapper.css({
  1291.           height: collapsedHeight
  1292.         }).removeClass('expanded scrollable');
  1293.         $wrapper[0].scrollTop = 0;
  1294.       }
  1295.  
  1296.  
  1297.     }
  1298.   }
  1299. }]);
  1300. ;angular.module('pgCore').directive('onEnterDown', ['$timeout',function ($timeout) {
  1301.   return {
  1302.     restrict: 'A',
  1303.     scope: {
  1304.       onEnter: "&onEnterDown"
  1305.     },
  1306.     link: function (scope, elem) {
  1307.       elem.on('keydown',function(e){
  1308.         if (scope.onEnter && e.which === 13){
  1309.           $timeout(function(){
  1310.             scope.onEnter({ $event: e });
  1311.           })
  1312.         }
  1313.       });
  1314.     }
  1315.   }
  1316. }]);
  1317.  
  1318. angular.module('pgCore').directive('onEnterPress', ['$timeout', function ($timeout) {
  1319.   return {
  1320.     restrict: 'A',
  1321.     scope: {
  1322.       onEnter: "&onEnterPress"
  1323.     },
  1324.     link: function (scope, elem) {
  1325.       elem.on('keypress', function (e) {
  1326.         if (scope.onEnter && e.which === 13) {
  1327.           $timeout(function () {
  1328.             scope.onEnter({ $event: e });
  1329.           })
  1330.         }
  1331.       });
  1332.     }
  1333.   }
  1334. }]);
  1335.  
  1336.  
  1337. angular.module('pgCore').directive('onEnterUp', ['$timeout', function ($timeout) {
  1338.   return {
  1339.     restrict: 'A',
  1340.     scope: {
  1341.       onEnter: "&onEnterUp"
  1342.     },
  1343.     link: function (scope, elem) {
  1344.       elem.on('keyup', function (e) {
  1345.         if (scope.onEnter && e.which === 13) {
  1346.           $timeout(function () {
  1347.             scope.onEnter({ $event: e });
  1348.           })
  1349.         }
  1350.       });
  1351.     }
  1352.   }
  1353. }]);
  1354.  
  1355.  
  1356. ;angular.module('pgCore').directive('stopPropagation', [function() {
  1357.   return {
  1358.     restrict: 'A',
  1359.     scope: {
  1360.       events:"@stopPropagation"
  1361.     },
  1362.     link: function(scope, elem) {
  1363.       if(scope.events){
  1364.         if(!scope.events.length) scope.events = 'click';
  1365.         scope.events.split(',').forEach(function(event){
  1366.           elem.on(event,function(e){
  1367.             e.stopPropagation();
  1368.           })
  1369.         });
  1370.       }
  1371.     }
  1372.   }
  1373. }]);
  1374.  
  1375. ;angular.module('pgCore').directive('checkboxInput', [function(){
  1376.   return {
  1377.     restrict: 'E',
  1378.     replace: true,
  1379.     scope: {
  1380.       value: '=?',
  1381.       items: '=?',
  1382.       selected: '=?',
  1383.       label: '=?',
  1384.       placeholder: '=?',
  1385.       disabled: '=?',
  1386.       model: '=?',
  1387.       onSelect: '&?',
  1388.       labelKey: '@',
  1389.       labelTemplate: '=?',
  1390.       optionsVisibleAlways: '=?',
  1391.       labelPosition: '@',
  1392.       boxPosition: '@',
  1393.       sort: '@'
  1394.     },
  1395.     template: '<div red="red\'s" class="form-field checkbox-input"><div class="form-field-container checkbox-wrapper" ng-class="labelPosition"><div class="form-label" ng-show="model.label.length || label.length">{{model.label || label}}</div><div class="form-label zero-state-label" ng-hide="model.label.length || label.length">Checkbox</div><div class="checkbox-container border-radius" ng-show="useSingleItem"><div class="checkbox-input-wrapper" ng-class="boxPosition"><label class="checkbox-mask" for="cb-single-{{:: label}}" ng-class="{checked: value}"><i class="icon-check"></i></label> <input ng-disabled="disabled" id="cb-single-{{:: label}}" type="checkbox" ng-model="value"></div></div><div class="checkbox-container border-radius" ng-showe="items"><div class="checkbox-input-wrapper" ng-class="boxPosition" ng-repeat="item in items | orderBy:(model.sort || sort || model.labelKey || labelKey) | filter:selectedLabel"><label class="checkbox-mask" ng-class="{checked: item.value}" for="cb-multi-{{$index}}"><i class="icon-check"></i></label> <input ng-disabled="disabled" id="cb-multi-{{$index}}" type="checkbox" ng-model="item.value"> <label class="checkbox-label inline" for="cb-multi-{{$index}}">{{item.label}}</label></div></div></div></div>',
  1396.     link: function (scope, elem, attrs) {
  1397.  
  1398.       init();
  1399.  
  1400.       function init() {
  1401.  
  1402.         if(!scope.labelKey) scope.labelKey = 'label';
  1403.  
  1404.         if(!_.isUndefined(scope.value)){
  1405.           scope.useSingleItem = true;
  1406.         }
  1407.  
  1408.       }
  1409.  
  1410.     }
  1411.   }
  1412. }]);;angular.module('pgCore').directive('dropdownInput', [function(){
  1413.   return {
  1414.     restrict: 'E',
  1415.     replace: true,
  1416.     scope: {
  1417.       items: '=?',
  1418.       selected: '=?',
  1419.       label: '=?',
  1420.       placeholder: '=?',
  1421.       disabled: '=?',
  1422.       model: '=?',
  1423.       onSelect: '&?',
  1424.       labelKey: '@',
  1425.       labelTemplate: '=?',
  1426.       optionsVisibleAlways: '=?',
  1427.       labelPosition: '@'
  1428.     },
  1429.     template: '<div class="form-field dropdown-input"><div class="form-field-container dropdown-container" ng-class="labelPosition"><div class="label" ng-class="labelPosition" ng-show="model.label.length || label.length">{{model.label || label}}</div><div class="label zero-state-label" ng-hide="model.label.length || label.length">Dropdown</div><div class="dropdown-input-wrapper" ng-click="focusInput($event)" ng-class="{\'show\':optionsVisible, \'show-always\': optionsVisibleAlways}"><div class="dropdown-input-container"><div class="input-placeholder" ng-hide="optionsVisible" ng-class="{\'placeholder\': !model.selected[labelKey] && !selected[labelKey] }">{{model.selected[labelKey] || selected[labelKey] || model.placeholder || placeholder}}</div><input type="text hidden" ng-blur="onBlur($event)" ng-disabled="disabled" ng-class="{\'visible\':optionsVisible}" placeholder="{{model.selected[labelKey] || selected[labelKey] || model.placeholder || placeholder}}" ng-model="selectedLabel" ng-focus="onFocus($event)"> <span class="dropdown-arrow" ng-click="disabled || toggleOptions($event)"></span></div><div class="dropdown-options" ng-mousedown="onMouseDown($event)" ng-class="{\'show\':optionsVisible, \'show-always\': optionsVisibleAlways}" ng-click="disabled || stopPropagation($event)"><div class="dropdown-option" ng-repeat="item in items | orderBy:(model.labelKey || labelKey) | filter:selectedLabel track by $index" ng-click="disabled || selectItem((model.item || item), $event)">{{model.item[labelKey] || item[labelKey]}}</div></div></div></div></div>',
  1430.     link: function (scope, elem, attrs) {
  1431.       var $input, stopBlurEvent;
  1432.  
  1433.       init();
  1434.  
  1435.       function init(){
  1436.  
  1437.         scope.showOptions = showOptions;
  1438.         scope.hideOptions = hideOptions;
  1439.         scope.toggleOptions = toggleOptions;
  1440.         scope.selectItem = selectItem;
  1441.         scope.onBlur = onBlur;
  1442.         scope.onFocus = onFocus;
  1443.         scope.onMouseDown = onMouseDown;
  1444.         scope.focusInput = focusInput;
  1445.         scope.stopPropagation = stopPropagation;
  1446.  
  1447.         scope.optionsVisible = false;
  1448.         if(!scope.labelKey) scope.labelKey = 'label';
  1449.  
  1450.  
  1451.       }
  1452.  
  1453.       function selectItem(item,e){
  1454.         scope.selected = item;
  1455.         scope.selectedLabel = '';
  1456.         if(scope.onSelect) scope.onSelect({item:scope.selected});
  1457.         hideOptions();
  1458.       }
  1459.  
  1460.       function showOptions(){
  1461.         scope.optionsVisible = true;
  1462.  
  1463.       }
  1464.  
  1465.       function hideOptions(){
  1466.         scope.optionsVisible = false;
  1467.         stopBlurEvent = false;
  1468.       }
  1469.  
  1470.       function toggleOptions(e){
  1471.         stopPropagation(e);
  1472.         scope.optionsVisible ? hideOptions() : showOptions();
  1473.       }
  1474.  
  1475.       function onBlur() {
  1476.         _.defer(function () {
  1477.           if (!stopBlurEvent) {
  1478.             hideOptions();
  1479.             scope.$digest();
  1480.           }
  1481.         });
  1482.       }
  1483.  
  1484.       function onFocus(){
  1485.         showOptions();
  1486.       }
  1487.  
  1488.       function onMouseDown(){
  1489.         stopBlurEvent = true;
  1490.       }
  1491.  
  1492.       function stopPropagation(e){
  1493.         if(!scope.disabled){
  1494.           e.stopPropagation();
  1495.           e.preventDefault();
  1496.           return false;
  1497.         }
  1498.       }
  1499.  
  1500.       function focusInput(e){
  1501.         stopPropagation(e);
  1502.         if(!$input) $input = elem.find('input');
  1503.         $input.focus();
  1504.       }
  1505.  
  1506.     }
  1507.   }
  1508. }]);;angular.module('pgCore').directive('emailInput', [function(){
  1509.   return {
  1510.     restrict: 'E',
  1511.     replace: true,
  1512.     scope: {
  1513.       id: '=?',
  1514.       value: '=?',
  1515.       label: '=?',
  1516.       placeholder: '=?',
  1517.       disabled: '=?',
  1518.       onChange: '=?',
  1519.       labelPosition: '@',
  1520.       hideLabel: '=?',
  1521.       tooltip: '=?'
  1522.     },
  1523.     template: '<div class="form-field email-input"><div class="form-field-container" ng-class="labelPosition"><div class="form-label" ng-show="!hideLabel && label.length">{{label}}</div><div class="form-label zero-state-label" ng-hide="hideLabel || label.length">Email</div><input ng-disabled="disabled" id="{{id}}" type="email" placeholder="{{placeholder}}" ng-model="value" ng-change="onChange()"></div></div>',
  1524.     link: function (scope, elem, attrs) {
  1525.  
  1526.       init();
  1527.  
  1528.       function init(){}
  1529.  
  1530.     }
  1531.   }
  1532. }]);;angular.module('pgCore').directive('multilineInput', [function(){
  1533.   return {
  1534.     restrict: 'E',
  1535.     replace: true,
  1536.     scope: {
  1537.       id: '=?',
  1538.       value: '=?',
  1539.       label: '=?',
  1540.       placeholder: '=?',
  1541.       disabled: '=?',
  1542.       onChange: '=?',
  1543.       labelPosition: '@',
  1544.       hideLabel: '=?',
  1545.       tooltip: '=?'
  1546.     },
  1547.     template: '<div class="form-field multiline-input"><div class="form-field-container" ng-class="labelPosition"><div class="form-label" ng-show="!hideLabel && label.length">{{label}}</div><div class="form-label zero-state-label" ng-hide="hideLabel || label.length">Text</div><textarea ng-disabled="disabled" id="{{id}}" placeholder="{{placeholder}}" ng-model="value" ng-change="onChange()">{{value}}</textarea></div></div>',
  1548.     link: function (scope, elem, attrs) {
  1549.  
  1550.       init();
  1551.  
  1552.       function init(){}
  1553.  
  1554.     }
  1555.   }
  1556. }]);;angular.module('pgCore').directive('numberInput', [function(){
  1557.   return {
  1558.     restrict: 'E',
  1559.     replace: true,
  1560.     scope: {
  1561.       id: '=?',
  1562.       value: '=?',
  1563.       label: '=?',
  1564.       placeholder: '=?',
  1565.       disabled: '=?',
  1566.       onChange: '=?',
  1567.       labelPosition: '@',
  1568.       hideLabel: '=?',
  1569.       tooltip: '=?'
  1570.     },
  1571.     template: '<div class="form-field number-input"><div class="form-field-container" ng-class="labelPosition"><div class="form-label" ng-show="!hideLabel && label.length">{{label}}</div><div class="form-label zero-state-label" ng-hide="hideLabel || label.length">Number</div><input ng-disabled="disabled" id="{{id}}" type="number" placeholder="{{placeholder}}" ng-model="value" ng-change="onChange()"></div></div>',
  1572.     link: function (scope, elem, attrs) {
  1573.  
  1574.       init();
  1575.  
  1576.       function init(){}
  1577.  
  1578.     }
  1579.   }
  1580. }]);;angular.module('pgCore').directive('radioInput', [function(){
  1581.   return {
  1582.     restrict: 'E',
  1583.     replace: true,
  1584.     scope: {
  1585.       items: '=?',
  1586.       selected: '=?',
  1587.       label: '=?',
  1588.       placeholder: '=?',
  1589.       disabled: '=?',
  1590.       model: '=?',
  1591.       onSelect: '&?',
  1592.       labelKey: '@',
  1593.       labelTemplate: '=?',
  1594.       optionsVisibleAlways: '=?',
  1595.       labelPosition: '@',
  1596.       boxPosition: '@',
  1597.       sort: '@'
  1598.     },
  1599.     template: '<div class="form-field radio-input"><div class="form-field-container radio-wrapper" ng-class="labelPosition"><div class="form-label" ng-show="model.label.length || label.length">{{model.label || label}}</div><div class="form-label zero-state-label" ng-hide="model.label.length || label.length">Multiple Choice</div><div class="radio-container border-radius"><div class="radio-input-wrapper" ng-class="boxPosition" ng-repeat="item in items | orderBy:(model.sort || sort || model.labelKey || labelKey) | filter:selectedLabel"><label class="radio-mask" ng-class="{checked: $parent.value === item}" for="rd-multi-{{$index}}"></label> <input id="rd-multi-{{$index}}" type="radio" ng-model="$parent.value" ng-value="item"> <label class="radio-label inline" for="rd-multi-{{$index}}">{{item.label}}</label></div></div></div></div>',
  1600.     link: function (scope, elem, attrs) {
  1601.  
  1602.       init();
  1603.  
  1604.       function init(){
  1605.         if(!scope.labelKey) scope.labelKey = 'label';
  1606.       }
  1607.  
  1608.     }
  1609.   }
  1610. }]);;angular.module('pgCore').directive('sectionHeader', [function(){
  1611.   return {
  1612.     restrict: 'E',
  1613.     replace: true,
  1614.     scope: {
  1615.       field: '=?'
  1616.     },
  1617.     template: '<div class="form-field section-header"><h3 class="section-header-placeholder" ng-hide="field.text">Section Header</h3><h3 class="section-header-label" ng-show="field.text">{{field.text}}</h3><hr></div>',
  1618.     link: function (scope, elem, attrs) {
  1619.  
  1620.       init();
  1621.  
  1622.       function init(){}
  1623.  
  1624.     }
  1625.   }
  1626. }]);;angular.module('pgCore').directive('textInput', [function(){
  1627.   return {
  1628.     restrict: 'E',
  1629.     replace: true,
  1630.     scope: {
  1631.       id: '=?',
  1632.       value: '=?',
  1633.       label: '=?',
  1634.       placeholder: '=?',
  1635.       disabled: '=?',
  1636.       onChange: '=?',
  1637.       labelPosition: '@',
  1638.       hideLabel: '=?',
  1639.       tooltip: '=?'
  1640.     },
  1641.     template: '<div class="form-field text-input"><div class="form-field-container" ng-class="labelPosition"><div class="label" ng-show="!hideLabel && label.length">{{label}}</div><div class="label zero-state-label" ng-hide="hideLabel || label.length">Text</div><input ng-disabled="disabled" id="{{id}}" type="text" placeholder="{{placeholder}}" ng-model="value" ng-change="onChange()"></div></div>',
  1642.     link: function (scope, elem, attrs) {
  1643.  
  1644.       init();
  1645.  
  1646.       function init(){}
  1647.  
  1648.     }
  1649.   }
  1650. }]);;angular.module('pgCore').directive('toggleInput', [function(){
  1651.   return {
  1652.     restrict: 'E',
  1653.     replace: true,
  1654.     scope: {
  1655.       model: '=?',
  1656.       key: '@?',
  1657.       onChange: '&?'
  1658.     },
  1659.     template: '<div class="form-field toggle-input"><label class="form-field-container toggle-wrapper" ng-class="{\'toggle-on\':model[key], \'disabled\':model.disabled}" for="toggle-{{:: uniqId}}"><div class="toggle-button"></div></label> <input class="input-hidden" type="checkbox" ng-model="model[key]" ng-disabled="model.disabled" id="toggle-{{:: uniqId}}" ng-change="onChange(model)"></div>',
  1660.     link: function (scope, elem, attrs) {
  1661.  
  1662.       init();
  1663.  
  1664.       function init() {
  1665.         if(!scope.key){
  1666.           scope.key = 'value';
  1667.         }
  1668.         scope.uniqId = _.uniqueId('toggle_')
  1669.  
  1670.       }
  1671.  
  1672.     }
  1673.   }
  1674. }]);;angular.module('pgCore').directive('header', ['pgService', 'events', 'config', 'headerService', function(pgService, events, config, headerService) {
  1675.   return{
  1676.     restrict: 'E',
  1677.     replace: true,
  1678.     scope: {},
  1679.     template: '<div class="pg-header wrapper"> <div class="left"> <a href="/" class="logo"> <img src="http://primegov.com/wp-content/themes/primegov/images/inverse-logo.png"/></a> <a href="/" class="title" ng-click="goHome()"><span class="platform_title">Live Meeting - Meeting Viewer</span></a> </div><div class="right"> <div class="platform_selection"> <div class="dropdown"> <button class="platform_button btn btn-default dropdown-toggle language-selector" type="button" id="LanguageDropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <img src="http://primegov.com/wp-content/themes/primegov/images/icon_Trans.png"> </button> <ul class="dropdown-menu" aria-labelledby="LanguageDropdown"> <li class="dropdown-header"> <span>PrimeGov Applications</span> </li><li class="first-item"> <a href="http://dev.primegov.com/" target="_blank" data-culture="en-US" class="language-selection"> <img class="pg_icon_black" src="http://primegov.com/wp-content/themes/primegov/images/icon_black_trans.png"> <span>Meetings &amp; Committees</span> </a> </li><li> <a href="http://dev.primegov.com/portal/search" target="_blank" class="language-selection"> <i class="fa fa-search"></i> <span>Search Portal</span> </a> </li><li class="active_platform"> <a href="#" target="_blank" class="language-selection"> <i class="fa fa-group"></i> <span>Live Meeting</span> </a> </li></ul> </div></div><div class="user-profile"> <div class="name" ng-click="userDropdown=true"> <span ng-show="currentUser.id">{{(currentUser.firstName + \' \' + currentUser.lastName)}}</span> <i class="icon-caret-down"></i> </div><div class="user-dropdown" ng-show="userDropdown"> <div class="user-dropdown-overlay" ng-click="userDropdown=false"></div><div class="user-dropdown-items"> <div ng-repeat="item in menuItems | orderBy: \'sort\'" class="user-dropdown-item" ng-click="::onMenuItemClick(item.action)"> <i class="{{::item.icon}}"></i>{{::item.name || item.id}}</div></div></div></div></div></div>',
  1680.     link: function(scope, elem) {
  1681.  
  1682.       var cancellers = [
  1683.         events.loggedIn.on(function(){
  1684.           pgService.getCurrentUser();
  1685.         }),
  1686.         events.menuItemsAdded.on(addMenuItem),
  1687.         events.navItemsAdded.on(addNavItem)
  1688.       ];
  1689.  
  1690.       var defaultMenuItems = [{
  1691.           id: 'logout',
  1692.           name: 'Logout',
  1693.           icon: 'icon-power',
  1694.           action: logout,
  1695.           sort: 0
  1696.         }];
  1697.  
  1698.       var defaultNavItems = [{
  1699.         id: 'logout',
  1700.         name: 'Logout',
  1701.         icon: 'icon-power',
  1702.         action: logout,
  1703.         sort: 0
  1704.       }];
  1705.  
  1706.       scope.$on('$destroy',onDestroy);
  1707.       init();
  1708.  
  1709.       function init() {
  1710.         scope.logout = logout;
  1711.         scope.goHome = goHome;
  1712.         scope.onMenuItemClick = onMenuItemClick;
  1713.         scope.currentUser = pgService.currentUser;
  1714.         scope.userDropdown = false;
  1715.         scope.config = config;
  1716.         scope.menuItems = headerService.getMenuItems();
  1717.         scope.navItems = headerService.getNavItems();
  1718.         headerService.addMenuItems(defaultMenuItems);
  1719.         // headerService.addNavItems(defaultNavItems);
  1720.       }
  1721.  
  1722.       function onMenuItemClick(callback){
  1723.         scope.userDropdown = false;
  1724.         callback && callback();
  1725.       }
  1726.  
  1727.       function addMenuItem(menuItems){
  1728.         scope.menuItems = menuItems;
  1729.       }
  1730.  
  1731.       function addNavItem(items){
  1732.         scope.navItems = items;
  1733.       }
  1734.  
  1735.       function onDestroy(){
  1736.         cancellers.forEach(function(fn){fn();});
  1737.       }
  1738.  
  1739.       function goHome(){
  1740.         window.location = './#/';
  1741.       }
  1742.  
  1743.       function logout(){
  1744.        
  1745.         pgService.logout();
  1746.       }
  1747.  
  1748.     }
  1749.   }
  1750. }]);
  1751. ;'use strict';
  1752. /**
  1753.  * addMenuItems(
  1754.  *  {id, name, action, icon, sort}
  1755.  * )
  1756.  */
  1757.  
  1758. angular.module('pgCore').factory('headerService', ['events',function (events) {
  1759.   var menuItems = [];
  1760.   var navItems = [];
  1761.   var menuItemsMap = {};
  1762.   var navItemsMap = {};
  1763.   return {
  1764.     addMenuItems: function(items){
  1765.       if (!Array.isArray(items)) items = [items]
  1766.       items.forEach(function(item){
  1767.         if (item && item.id && !menuItemsMap[item.id]) {
  1768.           menuItems.push(item);
  1769.           menuItemsMap[item.id] = item
  1770.         }
  1771.       });
  1772.       events.menuItemsAdded.trigger(menuItems);
  1773.     },
  1774.     getMenuItems: function(){
  1775.       return menuItems
  1776.     },
  1777.  
  1778.     addNavItems: function (items) {
  1779.       if (!Array.isArray(items)) items = [items]
  1780.       items.forEach(function (item) {
  1781.         if (item && item.id && !navItemsMap[item.id]) {
  1782.           navItems.push(item);
  1783.           navItemsMap[item.id] = item;
  1784.         }
  1785.       });
  1786.       events.navItemsAdded.trigger(navItems);
  1787.     },
  1788.     getNavItems: function (items) {
  1789.       return navItems;
  1790.     }
  1791.   }
  1792. }]);
  1793. ;angular.module('pgCore').directive('login', ['config', 'pgService', 'events', function(config, pgService, events) {
  1794.   return {
  1795.     restrict: 'E',
  1796.     replace: true,
  1797.     scope: {
  1798.       publicLogin: '=?'
  1799.     },
  1800.     template: '<div class="login-wrapper" ng-class="{\'hide-me\':loggedIn, \'fade-in\': fadeIn, \'public-login\': publicLogin}"><div class="login-container"><div class="login-header"><div class="prime-gov-logo" ng-hide="::config.clientLogoUrl"><i class="icon-prime-gov"></i></div><img class="client-logo" ng-src="{{::config.clientLogoUrl}}" ng-show="::config.clientLogoUrl"><div class="app-name">{{::config.name}}</div></div><form><div class="input-container" ng-class="{\'not-empty\': username.length}"><input type="text" name="username" id="username" ng-model="username" ng-keyup="checkKeyUp($event)"><div class="expanding-label" label="Email"></div></div><div class="input-container" ng-class="{\'not-empty\': password.length || passwordAutoFilled}"><input type="password" name="password" id="password" ng-model="password" ng-keyup="checkKeyUp($event)" ng-change="passwordAutoFilled = false"><div class="expanding-label" label="Password"></div></div><div class="link forgot-password-link" ng-click="openPasswordReset()">Forgot Password?</div><div class="button-container"><div class="button primary slide-on-hover" ng-click="login()"><i class="icon-check-2"></i>Sign in</div></div></form></div></div>',
  1801.     link: function(scope, elem) {
  1802.  
  1803.       var passwordResetWindow, signupWindow;
  1804.       var cancellers = [];
  1805.  
  1806.       init();
  1807.  
  1808.       function init() {
  1809.         scope.login = login;
  1810.         scope.checkKeyUp = checkKeyUp;
  1811.         scope.openPasswordReset = openPasswordReset;
  1812.         scope.openSignup = openSignup;
  1813.         scope.username = '';
  1814.         scope.password = '';
  1815.         scope.config = config;
  1816.  
  1817.         cancellers = [
  1818.           events.loggedIn.on(onLoggedIn),
  1819.           events.loggedOut.on(onLoggedOut)
  1820.         ];
  1821.  
  1822.         scope.$on('$destroy', onDestroy);
  1823.  
  1824.         if(pgService.isLoggedIn()){
  1825.           scope.loggedIn = true;
  1826.           _.defer(function(){
  1827.             events.loggedIn.trigger();
  1828.           })
  1829.         } else if (scope.publicLogin) {
  1830.           config.getConfig().then(function(){
  1831.             if (config.publicEmail && config.publicPassword){
  1832.               scope.username = config.publicEmail;
  1833.               scope.password = config.publicPassword;
  1834.               login();
  1835.             }
  1836.           })
  1837.         }
  1838.  
  1839.         // hack to fix chrome autofill bug on passwords https://bugs.chromium.org/p/chromium/issues/detail?id=636425
  1840.         _.delay(function(){
  1841.           var passwordInput = document.querySelector('input#password');
  1842.           scope.passwordAutoFilled = window.getComputedStyle(passwordInput).backgroundColor !== 'rgb(255, 255, 255)';
  1843.           scope.fadeIn = true;
  1844.           scope.$digest();
  1845.         },500);
  1846.       }
  1847.  
  1848.       function onDestroy(){
  1849.         cancellers.forEach(function(fn){fn();});
  1850.       }
  1851.  
  1852.       function checkKeyUp(e){
  1853.         if(e.which === 13){
  1854.           login();
  1855.         }
  1856.       }
  1857.      
  1858.       function openPasswordReset(){
  1859.         if(passwordResetWindow && !passwordResetWindow.closed){
  1860.           passwordResetWindow.focus();
  1861.         }else{
  1862.           passwordResetWindow = window.open('/account/forgotPassword', '', 'width=900, height=640');
  1863.         }
  1864.       }
  1865.  
  1866.       function openSignup(){
  1867.         if(signupWindow && !signupWindow.closed){
  1868.           signupWindow.focus();
  1869.         }else{
  1870.           signupWindow = window.open('/account/forgotPassword', '', 'width=900, height=640');
  1871.         }
  1872.       }
  1873.  
  1874.       function login(){
  1875.         if(!scope.username.length || !scope.password.length) return;
  1876.         pgService.login(scope.username, scope.password).then(function(data){
  1877.           if(data && data.success){
  1878.             events.loggedIn.trigger();
  1879.           }else{
  1880.             if(data && data.error && data.error.data && data.error.data.error_description){
  1881.               alert(data.error.data.error_description);
  1882.             }else{
  1883.               alert('something went wrong');
  1884.               console.log(data);
  1885.             }
  1886.             scope.password = '';
  1887.           }
  1888.         });
  1889.       }
  1890.  
  1891.       function onLoggedIn(){
  1892.         scope.loggedIn = pgService.isLoggedIn();
  1893.       }
  1894.  
  1895.       function onLoggedOut(){
  1896.         scope.loggedIn = pgService.isLoggedIn();
  1897.         window.location.reload();
  1898.       }
  1899.  
  1900.     }
  1901.   }
  1902. }]);
  1903. ;angular.module('pgCore').directive('pgI18n', ['$sanitize',function ($sanitize) {
  1904.  
  1905.   return {
  1906.     restrict: 'EA',
  1907.     compile: compile
  1908.   };
  1909.  
  1910.  
  1911.   function deepSanitize(data) {
  1912.     var keys;
  1913.     if (typeof data === 'undefined' || data === null) return data; // return undefined
  1914.     if (typeof data === 'string') {
  1915.       // Use $sanitize service to remove <script> tags
  1916.       // and then unescape &#XXXX; characters for multibyte and accents
  1917.       data = $sanitize(data).replace(/&#(\d*);/g, function (_, capture) {
  1918.         return String.fromCharCode(capture);
  1919.       });
  1920.       // remove any double curly braces to prevent sandbox escape
  1921.       data = data.replace(/\{\{/g, '').replace(/\}\}/g, '');
  1922.     } else if (Array.isArray(data)) {
  1923.       data = data.map(function (item) { // map sanitize on arrays
  1924.         return deepSanitize(item);
  1925.       });
  1926.     } else if (typeof data === 'object') { // recursively sanitize object properties
  1927.       keys = Object.keys(data);
  1928.       for (var i = 0; i < keys.length; i++) {
  1929.         data[keys[i]] = deepSanitize(data[keys[i]]);
  1930.       }
  1931.     }
  1932.     return data;
  1933.   }
  1934.  
  1935.  
  1936.   function compile(tElement, tAttrs) {
  1937.     //get the i18n key from the attributes
  1938.     var key = tAttrs.key || tAttrs.dmI18n;
  1939.  
  1940.     //detect if transclusion is being used
  1941.     var isTranscluding = tAttrs.hasOwnProperty("ngTransclude");
  1942.  
  1943.     //use the key and attributes to determine if the template is "static"
  1944.     var isStatic = !isTranscluding && !tAttrs.safeData && !tAttrs.data && key.indexOf("{") == -1;
  1945.  
  1946.     //if the template is static, fix up the template element now, before it's in the DOM (most likely)
  1947.     isStatic && tElement.html(dmI18n.get(key).replace(/\s\n\s/g, '<br>'));
  1948.  
  1949.     //if dynamic, the compilation will happen in the post link. if static, no need to postLink
  1950.     return isStatic ? angular.noop : postLink;
  1951.   }
  1952.  
  1953.  
  1954.   function postLink(scope, element, attrs) {
  1955.     function keyValueChange(key) {
  1956.       if (attrs.data || !key) {
  1957.         return;
  1958.       }
  1959.       getI18nResult(key, attrs.data, scope.$eval(attrs.safeData), attrs.dmI18nAttr);
  1960.     }
  1961.  
  1962.     /**
  1963.      * @param {String} key path to string (eg. "library/history")
  1964.      * @param {Object} data merge fields that should be escaped
  1965.      * @param {Object} data merge fields that should *not* be escaped
  1966.      * @param {String} [attr] attribute to update (default: html)
  1967.      * @return {void}
  1968.      */
  1969.     function getI18nResult(key, data, safeData, attr) {
  1970.       attr = attr || 'html';
  1971.  
  1972.       switch (attr) {
  1973.         case 'html':
  1974.         case 'innerHTML':
  1975.           element.html(dmI18n.get(key, data, safeData).replace(/\s\n\s/g, '<br>'));
  1976.           break;
  1977.  
  1978.         default:
  1979.           element.attr(attr, dmI18n.get(key, data, safeData).replace(/\s\n\s/g, '<br>'));
  1980.           break;
  1981.       }
  1982.     }
  1983.  
  1984.     attrs.$observe('key', keyValueChange, true);
  1985.     attrs.$observe('dmI18n', keyValueChange, true);
  1986.     attrs.$observe('data', dataAttrChange);
  1987.     attrs.$observe('safeData', dataAttrChange);
  1988.  
  1989.     function dataAttrChange(attr) {
  1990.       if (attr) {
  1991.         scope.$watch(attr, function () {
  1992.           getI18nResult(attrs.key || attrs.dmI18n, deepSanitize(scope.$eval(attrs.data)), scope.$eval(attrs.safeData), attrs.dmI18nAttr);
  1993.         }, true);
  1994.       }
  1995.     }
  1996.   }
  1997.  
  1998. }]);
  1999. ;angular.module('pgCore').directive('pgModal', [function() {
  2000.   return {
  2001.     restrict: 'E',
  2002.     replace: true,
  2003.     transclude: true,
  2004.     scope: {
  2005.       show: '=?',
  2006.       minimized: '=?',
  2007.       fullScreen: '=?',
  2008.       hideMinimize: '=?',
  2009.       onOpen: '&?',
  2010.       onClose: '&?',
  2011.       onMaximize: '&?',
  2012.       onMinimize: '&?',
  2013.  
  2014.     },
  2015.     template:'<div class="pg-modal-wrapper" ng-class="{\'show-me\': show && !fullScreen, \'minimized\': minimized && !hideMinimize && !fullScreen, \'full-screen\':fullScreen}"><div class="pg-modal-overlay"></div><div class="pg-modal"><div class="pg-minimized-overlay"></div><div class="pg-modal-buttons"><div class="close-modal" ng-click="close()"><i class="icon-x-2"></i></div><div class="minimize-modal" ng-click="minimize()" ng-if="!hideMinimize"><i class="icon-minimize"></i></div><div class="maximize-modal" ng-click="maximize()"><i class="icon-maximize"></i></div></div><div class="pg-modal-container" ng-transclude></div></div></div>',
  2016.     link: function(scope, elem) {
  2017.  
  2018.       var cancellers =[];
  2019.       init();
  2020.  
  2021.       function init() {
  2022.         scope.open = open;
  2023.         scope.close = close;
  2024.         scope.minimize = minimize;
  2025.         scope.maximize = maximize;
  2026.  
  2027.         scope.$watch('show',function(newVal, oldVal){
  2028.           if(!!oldVal && !newVal){
  2029.             if(scope.onClose) scope.onClose();
  2030.           }
  2031.         });
  2032.         scope.$on('$destroy',onDestroy);
  2033.       }
  2034.  
  2035.       function onDestroy(){
  2036.         cancellers.forEach(function(fn){fn();});
  2037.       }
  2038.  
  2039.       function close(){
  2040.         scope.show = false;
  2041.       }
  2042.  
  2043.       function open(id){
  2044.         scope.show = true;
  2045.         if(scope.onOpen) scope.onOpen();
  2046.       }
  2047.  
  2048.       function minimize(){
  2049.         scope.minimized = true;
  2050.         if(scope.onMinimize) scope.onMinimize();
  2051.       }
  2052.  
  2053.       function maximize(){
  2054.         scope.minimized = false;
  2055.         if(scope.onMaximize) scope.onMaximize();
  2056.       }
  2057.  
  2058.  
  2059.  
  2060.     }
  2061.   }
  2062. }]);
  2063. ;angular.module('pgCore').directive('tooltip', [function() {
  2064.   return {
  2065.     restrict: 'A',
  2066.     scope: {
  2067.       tooltip:"=tooltip",
  2068.       tooltipPosition: "@?",
  2069.       tooltipDelay: "=?"
  2070.     },
  2071.     link: function(scope, elem) {
  2072.       var $tooltip, client;
  2073.       var template = '<div class="tooltip"></div>';
  2074.       var top = 0;
  2075.       var left = 0;
  2076.  
  2077.       init();
  2078.  
  2079.       function init(){
  2080.         if(scope.tooltip && scope.tooltip.length) {
  2081.           elem.on('mouseenter', function () {
  2082.             client = elem[0].getBoundingClientRect();
  2083.             $tooltip = $(template)
  2084.             $tooltip.html(scope.tooltip);
  2085.             $tooltip.addClass(scope.tooltipPosition);
  2086.             $tooltip.css(getPositionCss(client, $tooltip));
  2087.             $('body').append($tooltip);
  2088.             _.delay(function(){
  2089.               if($tooltip) {
  2090.                 $tooltip.addClass('pg-fade-in');
  2091.               }
  2092.             }, (scope.tooltipDelay || 10));
  2093.           });
  2094.  
  2095.           elem.on('mouseleave', function () {
  2096.             if($tooltip){
  2097.               $tooltip.remove();
  2098.               $tooltip = null;
  2099.             }
  2100.           });
  2101.         }
  2102.         scope.$on('$destroy', function () {
  2103.           elem.trigger('mouseleave');
  2104.         });
  2105.       }
  2106.  
  2107.       function getPositionCss(client, $tooltip){
  2108.  
  2109.         switch(scope.tooltipPosition){
  2110.           case 'left':
  2111.             return {top: client.top + (client.height/2) , left: client.left-6};
  2112.           case 'right':
  2113.             return {top: client.top + (client.height/2) , left: client.right+6};
  2114.           case 'bottom':
  2115.             return {top: client.bottom+6, left: client.left + (client.width/2)};
  2116.           default:
  2117.             return {top: client.top-6, left: client.left + (client.width/2)};
  2118.         }
  2119.  
  2120.  
  2121.       }
  2122.  
  2123.  
  2124.     }
  2125.   }
  2126. }]);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement