/* Copyright (C) 2015 Apple Inc. All Rights Reserved. See LICENSE.txt for this sample’s licensing information Abstract: The sample code for syncing a custom zone. Includes a cache for syncTokens with methods for setting and clearing the values as well as a table for the fetched records. */ CKCatalog.tabs['private-sync'] = (function() { var zoneNameForm = new CKCatalog.Form('sync-zone-name-form') .addInputField({ type: 'text', placeholder: 'Zone name', name: 'zone', label: 'zoneName:', value: 'myCustomZone' }); var zoneSyncTokens = {}; var saveSyncToken = function(zone,token) { zoneSyncTokens[zone] = token; }; var getSavedSyncToken = function(zone) { return zoneSyncTokens[zone]; }; var recordsTable; var addRows = function(records) { if(recordsTable) { records.forEach(function (record) { var fields = record.fields; var name = fields['name']; var location = fields['location']; recordsTable.appendRow([ record.recordName, record.recordType, record.recordChangeTag, new Date(record.modified.timestamp), name ? name.value : '', location ? location.value : '' ]); }); } }; var renderRecords = function(zoneName,records,syncToken,moreComing) { var content = document.createElement('div'); var heading = document.createElement('h2'); var p = document.createElement('p'); p.innerHTML = 'At syncToken: ' + '' + syncToken + ' '; var deleteSyncTokenButton = document.createElement('button'); deleteSyncTokenButton.className = 'link small'; deleteSyncTokenButton.textContent = 'delete'; deleteSyncTokenButton.onclick = function() { saveSyncToken(zoneName,null); p.classList.add('hide'); }; p.appendChild(deleteSyncTokenButton); heading.innerHTML = 'Records' + (moreComing ? '' + ' (incomplete)' + ':' : ':'); recordsTable = new CKCatalog.Table([ 'recordName', 'recordType','recordChangeTag', 'modified','name', 'location' ]) .setTextForEmptyRow('No new records'); if(records.length === 0) { recordsTable.appendRow([]); } else { addRows(records); } content.appendChild(heading); content.appendChild(p); content.appendChild(recordsTable.el); return content; }; var shouldAppendRecords = false; var appendRecords = function(records,syncToken,moreComing) { if(recordsTable) { document.getElementById('sync-token').textContent = syncToken; var moreComingClassList = document.getElementById('more-coming').classList; if(moreComing) { moreComingClassList.remove('hide'); } else { moreComingClassList.add('hide'); } addRows(records); } }; var fetchChangedRecordsSample = { title: 'fetchChangedRecords', form: zoneNameForm, run: function() { var zone = this.form.fields['zone'].value; return this.sampleCode(zone); }, sampleCode: function demoFetchChangedRecords(zoneName) { var container = CloudKit.getDefaultContainer(); var privateDB = container.privateCloudDatabase; var zone = { zoneName: zoneName }; var opts = { // We shall restrict our returned fields to these. desiredKeys: ['name','location'], // Limit to 3 results. resultsLimit: 3 }; // Check if we have a saved syncToken for this zone. var savedSyncToken = getSavedSyncToken(zoneName); if(savedSyncToken) { opts.syncToken = savedSyncToken; } else { // If we don't have a syncToken we don't want to // append records to an existing list. shouldAppendRecords = false; } return privateDB.fetchChangedRecords(zone,opts).then(function(response) { if(response.hasErrors) { // Handle the errors. throw response.errors[0]; } else { var syncToken = response.syncToken; var records = response.records; var moreComing = response.moreComing; // Save the new syncToken somewhere. saveSyncToken(zoneName,syncToken); var renderedRecords; if(shouldAppendRecords) { // Append records to an existing list. renderedRecords = appendRecords(records,syncToken,moreComing); } else { // Replace the existing list of records with a new one. renderedRecords = renderRecords(zoneName,records,syncToken,moreComing); } // If there are more records to come, we will append the records instead // of replacing them on the next run. shouldAppendRecords = moreComing; return renderedRecords; } }); } }; return [ fetchChangedRecordsSample ]; })();